diff --git a/DEPS b/DEPS
index 8bb0fda..cc34e1c8 100644
--- a/DEPS
+++ b/DEPS
@@ -78,7 +78,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '0001378a11c6a33928b9a9029dfb17626057038e',
+  'v8_revision': '3bc0f66e73ceaec1a503cdcf0e330f005089426b',
   # 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.
@@ -86,7 +86,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': 'acf2f3adbac07ff91d280e9e2358d4bead0f0e67',
+  'angle_revision': '465835d61f394ba65b20b5951390c90ab55aec7b',
   # 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.
@@ -130,7 +130,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': '37921f135dc61021b8ced4c73375339658ac9953',
+  'catapult_revision': '2ffb57b10257d6577907105f83cbb4ae4063397c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -298,7 +298,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '5fc40ab72e45c14f5d98b3b2498224079b574ebb',
+      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'e46ef54fea48ba00948f829e1335d28e3a5c9fda',
       'condition': 'checkout_linux',
   },
 
@@ -624,7 +624,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'e4919fa03c74bd561dcabf3e61668fa3c7e54353',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '37e489c985ca5d081b0c1feaafd8da39a937b583', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + '619685782677769d90233d4bf1f74e96f72efeb7', # commit position 20628
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
index 3adcef5..5b466f9c 100644
--- a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
+++ b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
@@ -34,6 +34,8 @@
 interface PresentationConnection : EventTarget
 interface PresentationConnectionAvailableEvent : Event
 interface PresentationConnectionCloseEvent : Event
+interface PresentationConnectionList : EventTarget
+interface PresentationReceiver
 interface PresentationRequest : EventTarget
 
 # remoteplayback api not supported in webview crbug.com/521319
diff --git a/ash/multi_profile_uma.cc b/ash/multi_profile_uma.cc
index 47d0ff8..18a5e64 100644
--- a/ash/multi_profile_uma.cc
+++ b/ash/multi_profile_uma.cc
@@ -44,10 +44,4 @@
                            number_of_users);
 }
 
-// static
-void MultiProfileUMA::RecordDiscardedTab(int number_of_users) {
-  UMA_HISTOGRAM_COUNTS_100("MultiProfile.DiscardedTabsPerUser",
-                           number_of_users);
-}
-
 }  // namespace ash
diff --git a/ash/multi_profile_uma.h b/ash/multi_profile_uma.h
index 69c68b74..794c1126 100644
--- a/ash/multi_profile_uma.h
+++ b/ash/multi_profile_uma.h
@@ -73,9 +73,6 @@
   // added.
   static void RecordUserCount(int number_of_users);
 
-  // Record a discarded tab in the number of running users bucket.
-  static void RecordDiscardedTab(int number_of_users);
-
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(MultiProfileUMA);
 };
diff --git a/base/BUILD.gn b/base/BUILD.gn
index f638fc12..516f535 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2648,7 +2648,6 @@
       "android/java/src/org/chromium/base/annotations/NativeCall.java",
       "android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java",
       "android/java/src/org/chromium/base/annotations/RemovableInRelease.java",
-      "android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java",
       "android/java/src/org/chromium/base/annotations/UsedByReflection.java",
       "android/java/src/org/chromium/base/library_loader/LegacyLinker.java",
       "android/java/src/org/chromium/base/library_loader/LibraryLoader.java",
@@ -2793,8 +2792,8 @@
     java_files = [ "test/android/javatests/src/org/chromium/base/test/TestChildProcessConnection.java" ]
   }
 
-  java_library("base_junit_test_support") {
-    # Skip platform checks since Robolectric depends on requires_android targets.
+  android_library("base_junit_test_support") {
+    # Plaform checks are broken for Robolectric.
     bypass_platform_checks = true
     testonly = true
     java_files = [ "android/junit/src/org/chromium/base/metrics/test/ShadowRecordHistogram.java" ]
diff --git a/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java b/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java
deleted file mode 100644
index 89068ac..0000000
--- a/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java
+++ /dev/null
@@ -1,20 +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.
-
-package org.chromium.base.annotations;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- *  @SuppressFBWarnings is used to suppress FindBugs warnings.
- *
- *  The long name of FindBugs warnings can be found at
- *  http://findbugs.sourceforge.net/bugDescriptions.html
- */
-@Retention(RetentionPolicy.CLASS)
-public @interface SuppressFBWarnings {
-    String[] value() default {};
-    String justification() default "";
-}
diff --git a/base/android/proguard/chromium_apk.flags b/base/android/proguard/chromium_apk.flags
index b5ffb7f..82509977 100644
--- a/base/android/proguard/chromium_apk.flags
+++ b/base/android/proguard/chromium_apk.flags
@@ -4,6 +4,9 @@
 
 # Contains flags that we'd like all Chromium .apks to use.
 
+# Not needed for Android and saves a bit of processing time.
+-dontpreverify
+
 # Keep line number information, useful for stack traces.
 -keepattributes SourceFile,LineNumberTable
 
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index a763df4..3df54532 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -260,6 +260,9 @@
   parser.add_option(
       '--deps-configs',
       help='List of paths for dependency\'s build_config files. ')
+  parser.add_option(
+      '--classpath-deps-configs',
+      help='List of paths for classpath dependency\'s build_config files. ')
 
   # android_resources options
   parser.add_option('--srcjar', help='Path to target\'s resources srcjar.')
@@ -381,8 +384,8 @@
           '--supports-android is required when using --requires-android')
 
   direct_deps_config_paths = build_utils.ParseGnList(options.deps_configs)
-  direct_deps_config_paths = _FilterDepsPaths(direct_deps_config_paths,
-                                              options.type)
+  direct_deps_config_paths = _FilterDepsPaths(
+      direct_deps_config_paths, options.type)
 
   deps = Deps(direct_deps_config_paths)
   all_inputs = deps.AllConfigPaths()
@@ -598,15 +601,25 @@
     deps_dex_files = [c['dex_path'] for c in all_library_deps]
 
   if requires_javac_classpath:
-    javac_classpath = [c['jar_path'] for c in direct_library_deps]
-  if requires_full_classpath:
-    java_full_classpath = [c['jar_path'] for c in all_library_deps]
-
+    extra_jars = []
     if options.extra_classpath_jars:
-      extra_jars = build_utils.ParseGnList(options.extra_classpath_jars)
+      extra_jars += build_utils.ParseGnList(options.extra_classpath_jars)
+
+    if options.classpath_deps_configs:
+      config_paths = build_utils.ParseGnList(options.classpath_deps_configs)
+      classpath_deps = Deps(_FilterDepsPaths(config_paths, options.type))
+      extra_jars += [
+          c['jar_path'] for c in classpath_deps.Direct('java_library')]
+
+    javac_classpath = [c['jar_path'] for c in direct_library_deps]
+    if requires_full_classpath:
+      java_full_classpath = [c['jar_path'] for c in all_library_deps]
+
+    if extra_jars:
       deps_info['extra_classpath_jars'] = extra_jars
-      javac_classpath += extra_jars
-      java_full_classpath += extra_jars
+      javac_classpath += [p for p in extra_jars if p not in javac_classpath]
+      java_full_classpath += [
+          p for p in extra_jars if p not in java_full_classpath]
 
   # The java code for an instrumentation test apk is assembled differently for
   # ProGuard vs. non-ProGuard.
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 05553bee..d3b6bad 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -330,6 +330,19 @@
           rebase_path(invoker.bundled_srcjars, root_build_dir)
       args += [ "--bundled-srcjars=$_rebased_bundled_srcjars" ]
     }
+    if (defined(invoker.classpath_deps)) {
+      _classpath_deps_configs = []
+      foreach(d, invoker.classpath_deps) {
+        _target_label = get_label_info(d, "label_no_toolchain")
+        deps += [ "${_target_label}__build_config" ]
+        _dep_gen_dir = get_label_info(d, "target_gen_dir")
+        _dep_name = get_label_info(d, "name")
+        _classpath_deps_configs += [ "$_dep_gen_dir/$_dep_name.build_config" ]
+      }
+      _rebased_classpath_deps_configs =
+          rebase_path(_classpath_deps_configs, root_build_dir)
+      args += [ "--classpath-deps-configs=$_rebased_classpath_deps_configs" ]
+    }
     if (defined(invoker.input_jars_paths)) {
       _rebased_input_jars_paths =
           rebase_path(invoker.input_jars_paths, root_build_dir)
@@ -2690,6 +2703,7 @@
         forward_variables_from(invoker,
                                [
                                  "alternative_android_sdk_ijar",
+                                 "classpath_deps",
                                  "gradle_treat_as_prebuilt",
                                  "input_jars_paths",
                                  "main_class",
@@ -2726,6 +2740,9 @@
       }
       _accumulated_deps += [ ":$build_config_target_name" ]
     }
+    if (defined(invoker.classpath_deps)) {
+      _accumulated_deps += invoker.classpath_deps
+    }
 
     _srcjar_deps = []
     if (defined(invoker.srcjar_deps)) {
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 3de79ce8..26199a12 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1107,6 +1107,8 @@
   # Variables
   #   deps: Specifies the dependencies of this target. Java targets in this list
   #     will be included in the executable (and the javac classpath).
+  #   classpath_deps: Deps that should added to the classpath for this target,
+  #     but not linked into the apk (use this for annotation processors).
   #   java_files: List of .java files included in this library.
   #   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
   #     will be added to java_files and be included in this library.
@@ -1193,6 +1195,7 @@
       _java_sources_file = "$target_gen_dir/target_name.sources"
     }
     write_build_config(_build_config_target_name) {
+      forward_variables_from(invoker, [ "classpath_deps" ])
       type = "junit_binary"
       build_config = _build_config
       main_class = _main_class
@@ -1208,6 +1211,10 @@
       jar_path = "$root_out_dir/lib.java$_target_dir_name/$target_name.jar"
     }
 
+    if (defined(invoker.classpath_deps)) {
+      _deps += invoker.classpath_deps
+    }
+
     _process_resources_target = "${target_name}__process_resources"
     process_resources(_process_resources_target) {
       deps = _deps + [ ":$_build_config_target_name" ]
@@ -1265,6 +1272,8 @@
   # Variables
   #   deps: Specifies the dependencies of this target. Java targets in this list
   #     will be added to the javac classpath.
+  #   classpath_deps: Deps that should added to the classpath for this target,
+  #     but not linked into the apk (use this for annotation processors).
   #
   #   java_files: List of .java files included in this library.
   #   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
@@ -1541,6 +1550,8 @@
   #   deps: Specifies the dependencies of this target. Java targets in this list
   #     will be added to the javac classpath. Android resources in dependencies
   #     will be used when building this library.
+  #   classpath_deps: Deps that should added to the classpath for this target,
+  #     but not linked into the apk (use this for annotation processors).
   #
   #   java_files: List of .java files included in this library.
   #   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
@@ -1701,6 +1712,8 @@
   #     Note: this "transitive closure" actually only includes such targets if
   #     they are depended on through android_library or android_resources targets
   #     (and so not through builtin targets like 'action', 'group', etc).
+  #   classpath_deps: Deps that should added to the classpath for this target,
+  #     but not linked into the apk.
   #   install_script_name: Name of wrapper script (default=target_name).
   #   java_files: List of .java files to include in the apk.
   #   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
@@ -1837,9 +1850,27 @@
       _keystore_password = invoker.keystore_password
     }
 
+    _deps = []
+    if (defined(invoker.deps)) {
+      _deps = invoker.deps
+      set_sources_assignment_filter([ "*manifest*" ])
+      sources = _deps
+      set_sources_assignment_filter([])
+      if (sources != _deps) {
+        _bad_deps = _deps - sources
+        assert(
+            false,
+            "Possible manifest-generating dep found in deps. Use android_manifest_dep for this instead. Found: $_bad_deps")
+      }
+      sources = []
+    }
+    if (emma_coverage && !_emma_never_instrument) {
+      _deps += [ "//third_party/android_tools:emma_device_java" ]
+    }
+
     _srcjar_deps = []
     if (defined(invoker.srcjar_deps)) {
-      _srcjar_deps += invoker.srcjar_deps
+      _srcjar_deps = invoker.srcjar_deps
     }
 
     _use_build_hooks =
@@ -1848,14 +1879,17 @@
       assert(_use_build_hooks,
              "Cannot set no_build_hooks and build_hooks_android_impl_deps at " +
                  "the same time")
-      _build_hooks_android_impl_deps = invoker.build_hooks_android_impl_deps
+      _deps += invoker.build_hooks_android_impl_deps
     } else if (_use_build_hooks) {
-      _build_hooks_android_impl_deps =
-          [ "//build/android/buildhooks:build_hooks_android_impl_java" ]
-    } else {
-      _build_hooks_android_impl_deps = []
+      _deps += [ "//build/android/buildhooks:build_hooks_android_impl_java" ]
     }
 
+    _android_root_manifest_deps = []
+    if (defined(invoker.android_manifest_dep)) {
+      _android_root_manifest_deps = [ invoker.android_manifest_dep ]
+    }
+    _android_root_manifest = invoker.android_manifest
+
     _use_chromium_linker =
         defined(invoker.use_chromium_linker) && invoker.use_chromium_linker
     _pack_relocations =
@@ -1946,24 +1980,6 @@
       }
     }
 
-    if (defined(invoker.deps)) {
-      set_sources_assignment_filter([ "*manifest*" ])
-      sources = invoker.deps
-      set_sources_assignment_filter([])
-      if (sources != invoker.deps) {
-        _bad_deps = invoker.deps - sources
-        assert(
-            false,
-            "Possible manifest-generating dep found in deps. Use android_manifest_dep for this instead. Found: $_bad_deps")
-      }
-      sources = []
-    }
-    _android_root_manifest_deps = []
-    if (defined(invoker.android_manifest_dep)) {
-      _android_root_manifest_deps = [ invoker.android_manifest_dep ]
-    }
-    _android_root_manifest = invoker.android_manifest
-
     _rebased_build_config = rebase_path(_build_config, root_build_dir)
     _create_abi_split =
         defined(invoker.create_abi_split) && invoker.create_abi_split
@@ -2008,7 +2024,11 @@
 
     _build_config_target = "${_template_name}__build_config"
     write_build_config(_build_config_target) {
-      forward_variables_from(invoker, [ "apk_under_test" ])
+      forward_variables_from(invoker,
+                             [
+                               "apk_under_test",
+                               "classpath_deps",
+                             ])
       type = "android_apk"
       jar_path = _jar_path
       dex_path = _final_dex_path
@@ -2024,17 +2044,7 @@
       }
 
       deps = _android_root_manifest_deps
-
-      possible_config_deps = _build_hooks_android_impl_deps
-      if (defined(invoker.deps)) {
-        possible_config_deps += invoker.deps
-      }
-
-      # Added emma to the target's classpath via its .build_config.
-      if (emma_coverage && !_emma_never_instrument) {
-        possible_config_deps +=
-            [ "//third_party/android_tools:emma_device_java" ]
-      }
+      possible_config_deps = _deps
 
       proguard_enabled = _proguard_enabled
       if (_proguard_enabled) {
@@ -2055,6 +2065,10 @@
       }
     }
 
+    if (defined(invoker.classpath_deps)) {
+      _deps += invoker.classpath_deps
+    }
+
     _android_manifest =
         "$target_gen_dir/${_template_name}_manifest/AndroidManifest.xml"
     _android_manifest_target = "${_template_name}__merge_manifests"
@@ -2114,13 +2128,10 @@
       }
 
       build_config = _build_config
-      deps = [
-        ":$_android_manifest_target",
-        ":$_build_config_target",
-      ]
-      if (defined(invoker.deps)) {
-        deps += invoker.deps
-      }
+      deps = _deps + [
+               ":$_android_manifest_target",
+               ":$_build_config_target",
+             ]
     }
     _srcjar_deps += [ ":$_process_resources_target" ]
     _package_resources_target = "${target_name}__package_resources"
@@ -2136,13 +2147,10 @@
                                "support_zh_hk",
                                "xxxhdpi_whitelist",
                              ])
-      deps = [
-        ":$_android_manifest_target",
-        ":$_process_resources_target",
-      ]
-      if (defined(invoker.deps)) {
-        deps += invoker.deps
-      }
+      deps = _deps + [
+               ":$_android_manifest_target",
+               ":$_process_resources_target",
+             ]
       android_manifest = _android_manifest
       version_code = _version_code
       version_name = _version_name
@@ -2243,8 +2251,8 @@
       _srcjar_deps += [ ":${_template_name}__build_config_java" ]
     }
 
-    java_target = "${_template_name}__java"
-    java_library_impl(java_target) {
+    _java_target = "${_template_name}__java"
+    java_library_impl(_java_target) {
       forward_variables_from(invoker,
                              [
                                "chromium_code",
@@ -2255,10 +2263,10 @@
       supports_android = true
       requires_android = true
       override_build_config = _build_config
-      deps = [
+      deps = _deps + [
                ":$_android_manifest_target",
                ":$_build_config_target",
-             ] + _build_hooks_android_impl_deps
+             ]
 
       android_manifest = _android_manifest
       srcjar_deps = _srcjar_deps
@@ -2269,15 +2277,9 @@
         java_sources_file = _java_sources_file
       }
 
-      if (defined(invoker.deps)) {
-        deps += invoker.deps
-      }
       if (defined(invoker.apk_under_test)) {
         deps += [ "${invoker.apk_under_test}__java" ]
       }
-      if (emma_coverage && !_emma_never_instrument) {
-        deps += [ "//third_party/android_tools:emma_device_java" ]
-      }
     }
 
     # TODO(cjhopman): This is only ever needed to calculate the list of tests to
@@ -2294,7 +2296,7 @@
         use_interface_jars = true
         deps = [
           ":$_build_config_target",
-          ":$java_target",
+          ":$_java_target",
         ]
       }
     }
@@ -2313,17 +2315,13 @@
         forward_variables_from(invoker,
                                [
                                  "alternative_android_sdk_jar",
-                                 "deps",
                                  "proguard_jar_path",
                                ])
-        if (!defined(deps)) {
-          deps = []
-        }
-        deps += [
-          ":$_build_config_target",
-          ":$_process_resources_target",
-          ":$java_target",
-        ]
+        deps = _deps + [
+                 ":$_build_config_target",
+                 ":$_process_resources_target",
+                 ":$_java_target",
+               ]
         inputs = [
                    _build_config,
                    _jar_path,
@@ -2378,7 +2376,7 @@
       } else {
         _dex_sources = [ _lib_dex_path ]
       }
-      _dex_deps = [ ":$java_target" ]
+      _dex_deps = [ ":$_java_target" ]
     }
 
     dex("$_final_dex_target_name") {
@@ -2423,11 +2421,6 @@
       _native_libs_file_arg = "@FileArg($_rebased_native_libs_json:files)"
 
       pack_relocation_section(_prepare_native_target_name) {
-        forward_variables_from(invoker,
-                               [
-                                 "deps",
-                                 "public_deps",
-                               ])
         file_list_json = _native_libs_json
         libraries_filearg =
             "@FileArg(${_rebased_build_config}:native:libraries)"
@@ -2435,7 +2428,7 @@
           _build_config,
         ]
 
-        deps += _native_libs_deps
+        deps = _native_libs_deps
         deps += [ ":$_build_config_target" ]
       }
       if (_secondary_abi_native_libs_deps != []) {
@@ -2451,18 +2444,13 @@
             "@FileArg($_rebased_native_libs_json:files)"
 
         pack_relocation_section(_prepare_native_target_name) {
-          forward_variables_from(invoker,
-                                 [
-                                   "deps",
-                                   "public_deps",
-                                 ])
           file_list_json = _native_libs_json
           libraries_filearg = "@FileArg(${_rebased_build_config}:native:secondary_abi_libraries)"
           inputs = [
             _build_config,
           ]
 
-          deps += _secondary_abi_native_libs_deps
+          deps = _secondary_abi_native_libs_deps
           deps += [ ":$_build_config_target" ]
         }
       }
@@ -2529,24 +2517,19 @@
       keystore_password = _keystore_password
 
       # Incremental apk does not use native libs nor final dex.
-      incremental_deps = [
-        ":$_android_manifest_target",
-        ":$_build_config_target",
-        ":$_package_resources_target",
-      ]
+      incremental_deps = _deps + [
+                           ":$_android_manifest_target",
+                           ":$_build_config_target",
+                           ":$_package_resources_target",
+                         ]
 
       # This target generates the input file _all_resources_zip_path.
-      deps = [
-        ":$_android_manifest_target",
-        ":$_build_config_target",
-        ":$_final_dex_target_name",
-        ":$_package_resources_target",
-      ]
-
-      if (defined(invoker.deps)) {
-        deps += invoker.deps
-        incremental_deps += invoker.deps
-      }
+      deps = _deps + [
+               ":$_android_manifest_target",
+               ":$_build_config_target",
+               ":$_final_dex_target_name",
+               ":$_package_resources_target",
+             ]
 
       if ((_native_libs_deps != [] ||
            _extra_native_libs_even_when_incremental != []) &&
@@ -2615,10 +2598,7 @@
                                  "public_deps",
                                ])
 
-        incremental_deps = [ ":$_split_manifest_rule" ]
-        if (defined(invoker.deps)) {
-          incremental_deps += invoker.deps
-        }
+        incremental_deps = _deps + [ ":$_split_manifest_rule" ]
         deps = incremental_deps + _native_libs_deps + _extra_native_libs_deps +
                [ _native_libs_file_arg_dep ]
         native_libs_filearg = _native_libs_file_arg
@@ -2770,9 +2750,9 @@
         # actual target, but instead loads them at runtime, we need to explicitly
         # depend on them here.
         public_deps = [
+          ":${_java_target}",
           ":${_template_name}__create_incremental",
           ":${_write_installer_json_rule_name}",
-          ":${java_target}",
         ]
 
         # Generate incremental apk related operations at runtime.
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index eb4965d..b80509a2 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -194,7 +194,7 @@
   content_root_ = content_root;
   readback_target_ = nullptr;
   ref_file_ = file_name;
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 void LayerTreePixelTest::RunSingleThreadedPixelTest(
@@ -205,7 +205,7 @@
   content_root_ = content_root;
   readback_target_ = nullptr;
   ref_file_ = file_name;
-  RunTest(CompositorMode::SINGLE_THREADED, false);
+  RunTest(CompositorMode::SINGLE_THREADED);
 }
 
 void LayerTreePixelTest::RunPixelTestWithReadbackTarget(
@@ -217,7 +217,7 @@
   content_root_ = content_root;
   readback_target_ = target;
   ref_file_ = file_name;
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 void LayerTreePixelTest::SetupTree() {
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 09a40af..8dd61405 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -902,8 +902,7 @@
     layer_tree_host_->SetNextCommitWaitsForActivation();
 }
 
-void LayerTreeTest::RunTest(CompositorMode mode,
-                            bool using_synchronous_renderer_compositor) {
+void LayerTreeTest::RunTest(CompositorMode mode) {
   mode_ = mode;
   if (mode_ == CompositorMode::THREADED) {
     impl_thread_.reset(new base::Thread("Compositor"));
@@ -928,8 +927,6 @@
   settings_.enable_latency_recovery = false;
   settings_.resource_settings.buffer_to_texture_target_map =
       viz::DefaultBufferToTextureTargetMapForTesting();
-  settings_.using_synchronous_renderer_compositor =
-      using_synchronous_renderer_compositor;
   InitializeSettings(&settings_);
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 2306909..59686cc 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -110,8 +110,7 @@
   virtual void BeginTest() = 0;
   virtual void SetupTree();
 
-  virtual void RunTest(CompositorMode mode,
-                       bool using_synchronous_renderer_compositor);
+  virtual void RunTest(CompositorMode mode);
 
   bool HasImplThread() const { return !!impl_thread_; }
   base::SingleThreadTaskRunner* ImplThreadTaskRunner() {
@@ -177,9 +176,10 @@
   void DispatchCompositeImmediately();
   void DispatchNextCommitWaitsForActivation();
 
-  CompositorMode mode_;
   LayerTreeSettings settings_;
 
+  CompositorMode mode_;
+
   std::unique_ptr<LayerTreeHostClientForTesting> client_;
   std::unique_ptr<LayerTreeHost> layer_tree_host_;
   std::unique_ptr<AnimationHost> animation_host_;
@@ -212,32 +212,24 @@
 
 #define SINGLE_THREAD_TEST_F(TEST_FIXTURE_NAME)                   \
   TEST_F(TEST_FIXTURE_NAME, RunSingleThread_DelegatingRenderer) { \
-    RunTest(CompositorMode::SINGLE_THREADED, false);              \
+    RunTest(CompositorMode::SINGLE_THREADED);                     \
   }                                                               \
   class SingleThreadDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME {}
 
-#define MULTI_THREAD_CC_SCHEDULER_TEST_F(TEST_FIXTURE_NAME)                  \
-  TEST_F(TEST_FIXTURE_NAME, RunMultiThread_CCScheduler_DelegatingRenderer) { \
-    RunTest(CompositorMode::THREADED, false);                                \
-  }                                                                          \
-  class MultiThreadCCSchedulerDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME {}
-
-#define MULTI_THREAD_SYNC_SCHEDULER_TEST_F(TEST_FIXTURE_NAME)                   \
-  TEST_F(TEST_FIXTURE_NAME, RunMultiThread_SyncScheduler_DelegatingRenderer) {  \
-    RunTest(CompositorMode::THREADED, true);                                    \
-  }                                                                             \
-  class                                                                         \
-      MultiThreadSyncSchedulerDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME { \
-  }
-
-#define MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME)         \
-  MULTI_THREAD_CC_SCHEDULER_TEST_F(TEST_FIXTURE_NAME); \
-  MULTI_THREAD_SYNC_SCHEDULER_TEST_F(TEST_FIXTURE_NAME)
+#define MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME)                   \
+  TEST_F(TEST_FIXTURE_NAME, RunMultiThread_DelegatingRenderer) { \
+    RunTest(CompositorMode::THREADED);                           \
+  }                                                              \
+  class MultiThreadDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME {}
 
 #define SINGLE_AND_MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME) \
   SINGLE_THREAD_TEST_F(TEST_FIXTURE_NAME);                \
   MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME)
 
+#define REMOTE_AND_MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME) \
+  MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME);                 \
+  REMOTE_TEST_F(TEST_FIXTURE_NAME)
+
 // Some tests want to control when notify ready for activation occurs,
 // but this is not supported in the single-threaded case.
 #define MULTI_THREAD_BLOCKNOTIFY_TEST_F(TEST_FIXTURE_NAME) \
diff --git a/cc/test/test_context_support.cc b/cc/test/test_context_support.cc
index ba156df..4108dec 100644
--- a/cc/test/test_context_support.cc
+++ b/cc/test/test_context_support.cc
@@ -22,8 +22,8 @@
 void TestContextSupport::FlushPendingWork() {}
 
 void TestContextSupport::SignalSyncToken(const gpu::SyncToken& sync_token,
-                                         const base::Closure& callback) {
-  sync_point_callbacks_.push_back(callback);
+                                         base::OnceClosure callback) {
+  sync_point_callbacks_.push_back(std::move(callback));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&TestContextSupport::CallAllSyncPointCallbacks,
                                 weak_ptr_factory_.GetWeakPtr()));
@@ -34,8 +34,8 @@
 }
 
 void TestContextSupport::SignalQuery(uint32_t query,
-                                     const base::Closure& callback) {
-  sync_point_callbacks_.push_back(callback);
+                                     base::OnceClosure callback) {
+  sync_point_callbacks_.push_back(std::move(callback));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&TestContextSupport::CallAllSyncPointCallbacks,
                                 weak_ptr_factory_.GetWeakPtr()));
@@ -49,12 +49,12 @@
   if (out_of_order_callbacks_) {
     for (size_t i = size; i > 0; --i) {
       base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, sync_point_callbacks_[i - 1]);
+          FROM_HERE, std::move(sync_point_callbacks_[i - 1]));
     }
   } else {
     for (size_t i = 0; i < size; ++i) {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                    sync_point_callbacks_[i]);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, std::move(sync_point_callbacks_[i]));
     }
   }
   sync_point_callbacks_.clear();
diff --git a/cc/test/test_context_support.h b/cc/test/test_context_support.h
index 2c3b4e5..ba32fca 100644
--- a/cc/test/test_context_support.h
+++ b/cc/test/test_context_support.h
@@ -29,9 +29,9 @@
   // gpu::ContextSupport implementation.
   void FlushPendingWork() override;
   void SignalSyncToken(const gpu::SyncToken& sync_token,
-                       const base::Closure& callback) override;
+                       base::OnceClosure callback) override;
   bool IsSyncTokenSignaled(const gpu::SyncToken& sync_token) override;
-  void SignalQuery(uint32_t query, const base::Closure& callback) override;
+  void SignalQuery(uint32_t query, base::OnceClosure callback) override;
   void SetAggressivelyFreeResources(bool aggressively_free_resources) override;
   void Swap() override;
   void SwapWithBounds(const std::vector<gfx::Rect>& rects) override;
@@ -68,7 +68,7 @@
   }
 
  private:
-  std::vector<base::Closure> sync_point_callbacks_;
+  std::vector<base::OnceClosure> sync_point_callbacks_;
   ScheduleOverlayPlaneCallback schedule_overlay_plane_callback_;
   bool out_of_order_callbacks_;
 
diff --git a/cc/trees/layer_tree_host_common_perftest.cc b/cc/trees/layer_tree_host_common_perftest.cc
index 7912400..c1f7908 100644
--- a/cc/trees/layer_tree_host_common_perftest.cc
+++ b/cc/trees/layer_tree_host_common_perftest.cc
@@ -76,7 +76,7 @@
 
 class CalcDrawPropsTest : public LayerTreeHostCommonPerfTest {
  public:
-  void RunCalcDrawProps() { RunTest(CompositorMode::SINGLE_THREADED, false); }
+  void RunCalcDrawProps() { RunTest(CompositorMode::SINGLE_THREADED); }
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
diff --git a/cc/trees/layer_tree_host_perftest.cc b/cc/trees/layer_tree_host_perftest.cc
index 9384ff3..c30afeb6 100644
--- a/cc/trees/layer_tree_host_perftest.cc
+++ b/cc/trees/layer_tree_host_perftest.cc
@@ -167,7 +167,7 @@
 TEST_F(LayerTreeHostPerfTestJsonReader, MAYBE_TenTenSingleThread) {
   SetTestName("10_10_single_thread");
   ReadTestFile("10_10_layer_tree");
-  RunTest(CompositorMode::SINGLE_THREADED, false);
+  RunTest(CompositorMode::SINGLE_THREADED);
 }
 
 // Timed out on Android: http://crbug.com/723821
@@ -179,7 +179,7 @@
 TEST_F(LayerTreeHostPerfTestJsonReader, MAYBE_TenTenThreaded) {
   SetTestName("10_10_threaded_impl_side");
   ReadTestFile("10_10_layer_tree");
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 // Simulates a tab switcher scene with two stacks of 10 tabs each.
@@ -188,14 +188,14 @@
   full_damage_each_frame_ = true;
   SetTestName("10_10_single_thread_full_damage_each_frame");
   ReadTestFile("10_10_layer_tree");
-  RunTest(CompositorMode::SINGLE_THREADED, false);
+  RunTest(CompositorMode::SINGLE_THREADED);
 }
 
 TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreaded_FullDamageEachFrame) {
   full_damage_each_frame_ = true;
   SetTestName("10_10_threaded_impl_side_full_damage_each_frame");
   ReadTestFile("10_10_layer_tree");
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 // Invalidates a leaf layer in the tree on the main thread after every commit.
@@ -229,14 +229,14 @@
 TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenSingleThread) {
   SetTestName("10_10_single_thread_leaf_invalidates");
   ReadTestFile("10_10_layer_tree");
-  RunTest(CompositorMode::SINGLE_THREADED, false);
+  RunTest(CompositorMode::SINGLE_THREADED);
 }
 
 // Timed out on Android: http://crbug.com/723821
 TEST_F(LayerTreeHostPerfTestLeafInvalidates, MAYBE_TenTenThreaded) {
   SetTestName("10_10_threaded_impl_side_leaf_invalidates");
   ReadTestFile("10_10_layer_tree");
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 // Simulates main-thread scrolling on each frame.
@@ -274,7 +274,7 @@
 TEST_F(ScrollingLayerTreePerfTest, MAYBE_LongScrollablePageSingleThread) {
   SetTestName("long_scrollable_page");
   ReadTestFile("long_scrollable_page");
-  RunTest(CompositorMode::SINGLE_THREADED, false);
+  RunTest(CompositorMode::SINGLE_THREADED);
 }
 
 // Timed out on Android: http://crbug.com/723821
@@ -286,7 +286,7 @@
 TEST_F(ScrollingLayerTreePerfTest, MAYBE_LongScrollablePageThreaded) {
   SetTestName("long_scrollable_page_threaded_impl_side");
   ReadTestFile("long_scrollable_page");
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 // Simulates main-thread scrolling on each frame.
@@ -375,7 +375,7 @@
   measure_commit_cost_ = true;
   SetTestName("dense_layer_tree");
   ReadTestFile("dense_layer_tree");
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 // Simulates a page with several large, transformed and animated layers.
@@ -390,7 +390,7 @@
   measure_commit_cost_ = true;
   SetTestName("heavy_page");
   ReadTestFile("heavy_layer_tree");
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 }  // namespace
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 2ecc2934..608d266 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -95,10 +95,9 @@
  public:
   LayerTreeHostTestHasImplThreadTest() : single_threaded_(false) {}
 
-  void RunTest(CompositorMode mode,
-               bool using_synchronous_renderer_compositor) override {
+  void RunTest(CompositorMode mode) override {
     single_threaded_ = mode == CompositorMode::SINGLE_THREADED;
-    LayerTreeHostTest::RunTest(mode, using_synchronous_renderer_compositor);
+    LayerTreeHostTest::RunTest(mode);
   }
 
   void BeginTest() override {
@@ -8132,6 +8131,17 @@
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestImageAnimation);
 
+class LayerTreeHostTestImageAnimationSynchronousScheduling
+    : public LayerTreeHostTestImageAnimation {
+ public:
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    LayerTreeHostTestImageAnimation::InitializeSettings(settings);
+    settings->using_synchronous_renderer_compositor = true;
+  }
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestImageAnimationSynchronousScheduling);
+
 class LayerTreeHostTestImageDecodingHints : public LayerTreeHostTest {
  public:
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index 7bbe2c8d..72f1e49 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -779,29 +779,29 @@
   bool lost_context_;
 };
 
-class LayerTreeHostContextTestLostContextAndEvictTexturesLoseAfterEvict
-    : public LayerTreeHostContextTestLostContextAndEvictTextures {
- public:
-  void SetUp() override {
-    LayerTreeHostContextTestLostContextAndEvictTextures::SetUp();
-    lose_after_evict_ = true;
-  }
-};
+TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
+       LoseAfterEvict_SingleThread) {
+  lose_after_evict_ = true;
+  RunTest(CompositorMode::SINGLE_THREADED);
+}
 
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostContextTestLostContextAndEvictTexturesLoseAfterEvict);
+TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
+       LoseAfterEvict_MultiThread) {
+  lose_after_evict_ = true;
+  RunTest(CompositorMode::THREADED);
+}
 
-class LayerTreeHostContextTestLostContextAndEvictTexturesLoseBeforeEvict
-    : public LayerTreeHostContextTestLostContextAndEvictTextures {
- public:
-  void SetUp() override {
-    LayerTreeHostContextTestLostContextAndEvictTextures::SetUp();
-    lose_after_evict_ = false;
-  }
-};
+TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
+       LoseBeforeEvict_SingleThread) {
+  lose_after_evict_ = false;
+  RunTest(CompositorMode::SINGLE_THREADED);
+}
 
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostContextTestLostContextAndEvictTexturesLoseBeforeEvict);
+TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
+       LoseBeforeEvict_MultiThread) {
+  lose_after_evict_ = false;
+  RunTest(CompositorMode::THREADED);
+}
 
 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
  public:
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 6446a44..d321d96 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -160,42 +160,43 @@
   scoped_refptr<FakePictureLayer> grand_child;
 };
 
-class LayerTreeHostCopyRequestTestMultipleRequestsGLRenderer
-    : public LayerTreeHostCopyRequestTestMultipleRequests {
- public:
-  void SetUp() override {
-    LayerTreeHostCopyRequestTestMultipleRequests::SetUp();
-    use_gl_renderer_ = true;
-  }
-};
+TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
+       GLRenderer_RunSingleThread) {
+  use_gl_renderer_ = true;
+  RunTest(CompositorMode::SINGLE_THREADED);
+}
 
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostCopyRequestTestMultipleRequestsGLRenderer);
+TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
+       GLRenderer_RunMultiThread) {
+  use_gl_renderer_ = true;
+  RunTest(CompositorMode::THREADED);
+}
 
-class LayerTreeHostCopyRequestTestMultipleRequestsGLRendererOutOfOrderCallback
-    : public LayerTreeHostCopyRequestTestMultipleRequests {
- public:
-  void SetUp() override {
-    LayerTreeHostCopyRequestTestMultipleRequests::SetUp();
-    use_gl_renderer_ = true;
-    out_of_order_callbacks_ = true;
-  }
-};
+TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
+       GLRenderer_RunSingleThread_OutOfOrderCallbacks) {
+  use_gl_renderer_ = true;
+  out_of_order_callbacks_ = true;
+  RunTest(CompositorMode::SINGLE_THREADED);
+}
 
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostCopyRequestTestMultipleRequestsGLRendererOutOfOrderCallback);
+TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
+       GLRenderer_RunMultiThread_OutOfOrderCallbacks) {
+  use_gl_renderer_ = true;
+  out_of_order_callbacks_ = true;
+  RunTest(CompositorMode::THREADED);
+}
 
-class LayerTreeHostCopyRequestTestMultipleRequestsSoftwareRenderer
-    : public LayerTreeHostCopyRequestTestMultipleRequests {
- public:
-  void SetUp() override {
-    LayerTreeHostCopyRequestTestMultipleRequests::SetUp();
-    use_gl_renderer_ = false;
-  }
-};
+TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
+       SoftwareRenderer_RunSingleThread) {
+  use_gl_renderer_ = false;
+  RunTest(CompositorMode::SINGLE_THREADED);
+}
 
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostCopyRequestTestMultipleRequestsSoftwareRenderer);
+TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
+       SoftwareRenderer_RunMultiThread) {
+  use_gl_renderer_ = false;
+  RunTest(CompositorMode::THREADED);
+}
 
 // TODO(crbug.com/564832): Remove this test when the workaround it tests is no
 // longer needed.
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index b30fd6a..8298948 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -790,47 +790,40 @@
 TEST_F(LayerTreeHostScrollTestCaseWithChild, DeviceScaleFactor1_ScrollChild) {
   device_scale_factor_ = 1.f;
   scroll_child_layer_ = true;
-  RunTest(CompositorMode::THREADED, false);
-}
-
-TEST_F(LayerTreeHostScrollTestCaseWithChild,
-       DeviceScaleFactor1_ScrollChild_SyncScheduler) {
-  device_scale_factor_ = 1.f;
-  scroll_child_layer_ = true;
-  RunTest(CompositorMode::THREADED, true);
+  RunTest(CompositorMode::THREADED);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild, DeviceScaleFactor15_ScrollChild) {
   device_scale_factor_ = 1.5f;
   scroll_child_layer_ = true;
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild, DeviceScaleFactor2_ScrollChild) {
   device_scale_factor_ = 2.f;
   scroll_child_layer_ = true;
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor1_ScrollRootScrollLayer) {
   device_scale_factor_ = 1.f;
   scroll_child_layer_ = false;
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor15_ScrollRootScrollLayer) {
   device_scale_factor_ = 1.5f;
   scroll_child_layer_ = false;
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor2_ScrollRootScrollLayer) {
   device_scale_factor_ = 2.f;
   scroll_child_layer_ = false;
-  RunTest(CompositorMode::THREADED, false);
+  RunTest(CompositorMode::THREADED);
 }
 
 class LayerTreeHostScrollTestSimple : public LayerTreeHostScrollTest {
@@ -1506,23 +1499,12 @@
 };
 
 TEST_F(LayerTreeHostScrollTestLayerStructureChange, ScrollDestroyLayer) {
-  RunTest(CompositorMode::THREADED, false);
-}
-
-TEST_F(LayerTreeHostScrollTestLayerStructureChange,
-       ScrollDestroyLayer_SyncScheduler) {
-  RunTest(CompositorMode::THREADED, true);
+  RunTest(CompositorMode::THREADED);
 }
 
 TEST_F(LayerTreeHostScrollTestLayerStructureChange, ScrollDestroyWholeTree) {
   scroll_destroy_whole_tree_ = true;
-  RunTest(CompositorMode::THREADED, false);
-}
-
-TEST_F(LayerTreeHostScrollTestLayerStructureChange,
-       ScrollDestroyWholeTree_SyncScheduler) {
-  scroll_destroy_whole_tree_ = true;
-  RunTest(CompositorMode::THREADED, true);
+  RunTest(CompositorMode::THREADED);
 }
 
 class LayerTreeHostScrollTestScrollMFBA : public LayerTreeHostScrollTest {
@@ -1649,12 +1631,7 @@
   int outer_viewport_container_layer_id_;
 };
 
-// This test relies on scheduler's pipelining not overwriting updates, i.e.,
-// a new tree should not be activated until the previous one has been drawn.
-// This is not respected in webview scheduling.
-// TODO(khushalsagar): Update the test above to also work for WebView. MFBA is
-// used in that mode as well.
-MULTI_THREAD_CC_SCHEDULER_TEST_F(LayerTreeHostScrollTestScrollMFBA);
+MULTI_THREAD_TEST_F(LayerTreeHostScrollTestScrollMFBA);
 
 class LayerTreeHostScrollTestScrollAbortedCommitMFBA
     : public LayerTreeHostScrollTest {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java b/chrome/android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java
index 7f44a16..68bfe1e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java
@@ -8,6 +8,7 @@
 import android.content.SharedPreferences;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.tab.Tab;
@@ -19,12 +20,17 @@
 public class RevenueStats {
     private static final String PREF_RLZ_NOTIFIED = "rlz_first_search_notified";
 
-    private static final RevenueStats sInstance = AppHooks.get().createRevenueStatsInstance();
+    private static RevenueStats sInstance;
 
     /**
      * Returns the singleton instance of ExternalAuthUtils, creating it if needed.
      */
     public static RevenueStats getInstance() {
+        assert ThreadUtils.runningOnUiThread();
+        if (sInstance == null) {
+            sInstance = AppHooks.get().createRevenueStatsInstance();
+        }
+
         return sInstance;
     }
 
@@ -33,10 +39,18 @@
      */
     public void tabCreated(Tab tab) {}
 
+    protected static boolean getRlzNotified(Context context) {
+        return getRlzNotified(); // TODO(agrieve): Delete once downstream is updated.
+    }
+
+    protected static void setRlzNotified(Context context, boolean notified) {
+        setRlzNotified(notified); // TODO(agrieve): Delete once downstream is updated.
+    }
+
     /**
      * Returns whether the RLZ provider has been notified that the first search has occurred.
      */
-    protected static boolean getRlzNotified(Context context) {
+    protected static boolean getRlzNotified() {
         return ContextUtils.getAppSharedPreferences().getBoolean(
                 PREF_RLZ_NOTIFIED, false);
     }
@@ -45,7 +59,7 @@
      * Stores whether the RLZ provider has been notified that the first search has occurred as
      * shared preference.
      */
-    protected static void setRlzNotified(Context context, boolean notified) {
+    protected static void setRlzNotified(boolean notified) {
         SharedPreferences.Editor sharedPreferencesEditor =
                 ContextUtils.getAppSharedPreferences().edit();
         sharedPreferencesEditor.putBoolean(PREF_RLZ_NOTIFIED, notified);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
index 34c9e9fa..f74d74d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
@@ -133,14 +133,10 @@
     }
 
     @Override
-    public void navigationEntryCommitted() {
+    public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) {
         if (mTab.getNativePage() != null) {
             mTab.pushNativePageStateToNavigationEntry();
         }
-    }
-
-    @Override
-    public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) {
         if (isMainFrame) mTab.didFinishPageLoad();
         PolicyAuditor auditor = AppHooks.get().getPolicyAuditor();
         auditor.notifyAuditEvent(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
index 8f6e21cd9..40ec86d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -9,6 +9,7 @@
 import android.graphics.Point;
 import android.os.StrictMode;
 import android.util.DisplayMetrics;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.SurfaceHolder;
@@ -536,6 +537,24 @@
     }
 
     @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (mTab.getContentViewCore() != null
+                && mTab.getContentViewCore().dispatchKeyEvent(event)) {
+            return true;
+        }
+        return super.dispatchKeyEvent(event);
+    }
+
+    @Override
+    public boolean onGenericMotionEvent(MotionEvent event) {
+        if (mTab.getContentViewCore() != null
+                && mTab.getContentViewCore().onGenericMotionEvent(event)) {
+            return true;
+        }
+        return super.onGenericMotionEvent(event);
+    }
+
+    @Override
     public void onResume() {
         if (mPaused != null && !mPaused) return;
         mPaused = false;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrInstallUpdateInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrInstallUpdateInfoBarTest.java
index b7e08e4..bf8a0e08 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrInstallUpdateInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrInstallUpdateInfoBarTest.java
@@ -26,6 +26,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.vr_shell.mock.MockVrCoreVersionCheckerImpl;
+import org.chromium.chrome.browser.vr_shell.rules.VrActivityRestriction;
 import org.chromium.chrome.browser.vr_shell.util.VrInfoBarUtils;
 import org.chromium.chrome.browser.vr_shell.util.VrShellDelegateUtils;
 import org.chromium.chrome.browser.vr_shell.util.VrTestRuleUtils;
@@ -120,6 +121,7 @@
      */
     @Test
     @MediumTest
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     public void testInfoBarNotPresentWhenVrServicesCurrent() throws InterruptedException {
         infoBarTestHelper(VrCoreCompatibility.VR_READY);
     }
@@ -129,6 +131,7 @@
      */
     @Test
     @MediumTest
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     public void testInfoBarPresentWhenVrServicesOutdated() throws InterruptedException {
         infoBarTestHelper(VrCoreCompatibility.VR_OUT_OF_DATE);
     }
@@ -138,6 +141,7 @@
      */
     @Test
     @MediumTest
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     public void testInfoBarPresentWhenVrServicesMissing() throws InterruptedException {
         infoBarTestHelper(VrCoreCompatibility.VR_NOT_AVAILABLE);
     }
@@ -148,6 +152,7 @@
      */
     @Test
     @MediumTest
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     public void testInfoBarNotPresentWhenVrServicesNotSupported() throws InterruptedException {
         infoBarTestHelper(VrCoreCompatibility.VR_NOT_SUPPORTED);
     }
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 ea56313..4585bdd 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
@@ -37,6 +37,7 @@
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.vr_shell.rules.VrActivityRestriction;
 import org.chromium.chrome.browser.vr_shell.util.VrShellDelegateUtils;
 import org.chromium.chrome.browser.vr_shell.util.VrTestRuleUtils;
 import org.chromium.chrome.browser.vr_shell.util.VrTransitionUtils;
@@ -87,6 +88,7 @@
     @MediumTest
     @DisableIf.Build(message = "Flaky on K/L crbug.com/762126",
             sdk_is_less_than = Build.VERSION_CODES.M)
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     public void testScreenTapsNotRegistered() throws InterruptedException {
         mVrTestFramework.loadUrlAndAwaitInitialization(
                 VrTestFramework.getHtmlTestFile("test_screen_taps_not_registered"),
@@ -121,6 +123,7 @@
     @Test
     @MediumTest
     @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM)
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     public void testControllerClicksRegisteredOnDaydream() throws InterruptedException {
         EmulatedVrController controller = new EmulatedVrController(mVrTestRule.getActivity());
         mVrTestFramework.loadUrlAndAwaitInitialization(
@@ -168,6 +171,7 @@
     @DisableIf.Build(message = "Flaky on L crbug.com/713781",
             sdk_is_greater_than = Build.VERSION_CODES.KITKAT,
             sdk_is_less_than = Build.VERSION_CODES.M)
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     public void testScreenTapsRegisteredOnCardboard() throws InterruptedException {
         mVrTestFramework.loadUrlAndAwaitInitialization(
                 VrTestFramework.getHtmlTestFile("test_gamepad_button"), PAGE_LOAD_TIMEOUT_S);
@@ -212,6 +216,7 @@
      */
     @Test
     @MediumTest
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     public void testPresentationLocksFocus() throws InterruptedException {
         mVrTestFramework.loadUrlAndAwaitInitialization(
                 VrTestFramework.getHtmlTestFile("test_presentation_locks_focus"),
@@ -247,6 +252,7 @@
     @Test
     @MediumTest
     @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM)
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     @CommandLineFlags.Add({"disable-features=" + ChromeFeatureList.VR_BROWSING})
     public void testAppButtonNoopsWhenBrowsingDisabled() throws InterruptedException {
         mVrTestFramework.loadUrlAndAwaitInitialization(
@@ -265,6 +271,7 @@
     @Test
     @MediumTest
     @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM)
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     public void testFocusUpdatesSynchronously() throws InterruptedException {
         mVrTestFramework.loadUrlAndAwaitInitialization(
                 VrTestFramework.getHtmlTestFile("generic_webvr_page_with_activate_listener"),
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
index 3500bce0..0318b5f8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
@@ -101,6 +101,7 @@
     @Test
     @MediumTest
     @CommandLineFlags.Remove({"enable-webvr"})
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     public void testWebVrDisabledWithoutFlagSet() throws InterruptedException {
         // TODO(bsheedy): Remove this test once WebVR is on by default without
         // requiring an origin trial.
@@ -118,6 +119,8 @@
     @Test
     @MediumTest
     @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM)
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.CTA,
+            VrActivityRestriction.SupportedActivity.CCT})
     public void testNfcFiresVrdisplayactivate() throws InterruptedException {
         mVrTestFramework.loadUrlAndAwaitInitialization(
                 VrTestFramework.getHtmlTestFile("test_nfc_fires_vrdisplayactivate"),
@@ -136,6 +139,7 @@
     @Test
     @MediumTest
     @Restriction({RESTRICTION_TYPE_VIEWER_DAYDREAM, RESTRICTION_TYPE_DON_ENABLED})
+    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
     public void testPresentationPromiseUnresolvedDuringDon() throws InterruptedException {
         mVrTestFramework.loadUrlAndAwaitInitialization(
                 VrTestFramework.getHtmlTestFile("test_presentation_promise_unresolved_during_don"),
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 8626554..f07c1d2 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2555,6 +2555,8 @@
       "resource_coordinator/background_tab_navigation_throttle.cc",
       "resource_coordinator/background_tab_navigation_throttle.h",
       "resource_coordinator/discard_condition.h",
+      "resource_coordinator/discard_metrics_util.cc",
+      "resource_coordinator/discard_metrics_util.h",
       "resource_coordinator/lifecycle_unit.cc",
       "resource_coordinator/lifecycle_unit.h",
       "resource_coordinator/tab_lifecycle_unit.cc",
@@ -3201,6 +3203,7 @@
     ]
     deps += [
       "//components/printing/browser",
+      "//components/printing/service/public/cpp:utils",
       "//components/printing/service/public/interfaces",
       "//printing",
     ]
@@ -4428,6 +4431,10 @@
     "//url/mojo:url_mojom_origin_js",
   ]
 
+  if (is_win || is_mac || is_desktop_linux || is_chromeos) {
+    deps += [ "//chrome/browser/ui/webui/discards:mojo_bindings_js" ]
+  }
+
   if (optimize_webui) {
     deps += [
       "//chrome/browser/resources/md_bookmarks:build",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 1c3220cc..602d55b 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -581,16 +581,6 @@
     {flag_descriptions::kV8CacheOptionsCode, switches::kV8CacheOptions, "code"},
 };
 
-const FeatureEntry::Choice kV8CacheStrategiesForCacheStorageChoices[] = {
-    {flags_ui::kGenericExperimentChoiceDefault, "", ""},
-    {flags_ui::kGenericExperimentChoiceDisabled,
-     switches::kV8CacheStrategiesForCacheStorage, "none"},
-    {flag_descriptions::kV8CacheStrategiesForCacheStorageNormal,
-     switches::kV8CacheStrategiesForCacheStorage, "normal"},
-    {flag_descriptions::kV8CacheStrategiesForCacheStorageAggressive,
-     switches::kV8CacheStrategiesForCacheStorage, "aggressive"},
-};
-
 #if defined(OS_ANDROID)
 const FeatureEntry::Choice kProgressBarCompletionChoices[] = {
     {flags_ui::kGenericExperimentChoiceDefault, "", ""},
@@ -2232,6 +2222,11 @@
      flag_descriptions::kWebVrAutopresentFromIntentDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kWebVrAutopresentFromIntent)},
 #endif  // OS_ANDROID
+#if BUILDFLAG(ENABLE_OPENVR)
+    {"openvr", flag_descriptions::kOpenVRName,
+     flag_descriptions::kOpenVRDescription, kOsWin,
+     FEATURE_VALUE_TYPE(features::kOpenVR)},
+#endif  // ENABLE_OPENVR
 #endif  // ENABLE_VR
 #if defined(OS_CHROMEOS)
     {"disable-accelerated-mjpeg-decode",
@@ -2242,10 +2237,6 @@
     {"v8-cache-options", flag_descriptions::kV8CacheOptionsName,
      flag_descriptions::kV8CacheOptionsDescription, kOsAll,
      MULTI_VALUE_TYPE(kV8CacheOptionsChoices)},
-    {"v8-cache-strategies-for-cache-storage",
-     flag_descriptions::kV8CacheStrategiesForCacheStorageName,
-     flag_descriptions::kV8CacheStrategiesForCacheStorageDescription, kOsAll,
-     MULTI_VALUE_TYPE(kV8CacheStrategiesForCacheStorageChoices)},
     {"simplified-fullscreen-ui", flag_descriptions::kSimplifiedFullscreenUiName,
      flag_descriptions::kSimplifiedFullscreenUiDescription,
      kOsWin | kOsLinux | kOsCrOS,
@@ -2500,11 +2491,6 @@
      flag_descriptions::kEnableContentSuggestionsNewFaviconServerDescription,
      kOsAndroid,
      FEATURE_VALUE_TYPE(ntp_snippets::kPublisherFaviconsFromNewServerFeature)},
-    {"enable-ntp-tiles-favicons-from-server",
-     flag_descriptions::kEnableNtpMostLikelyFaviconsFromServerName,
-     flag_descriptions::kEnableNtpMostLikelyFaviconsFromServerDescription,
-     kOsAndroid,
-     FEATURE_VALUE_TYPE(ntp_tiles::kNtpMostLikelyFaviconsFromServerFeature)},
     {"enable-content-suggestions-thumbnail-dominant-color",
      flag_descriptions::kEnableContentSuggestionsThumbnailDominantColorName,
      flag_descriptions::
diff --git a/chrome/browser/android/vr_shell/vr_gl_thread.cc b/chrome/browser/android/vr_shell/vr_gl_thread.cc
index eff5f1b..c9b14ab 100644
--- a/chrome/browser/android/vr_shell/vr_gl_thread.cc
+++ b/chrome/browser/android/vr_shell/vr_gl_thread.cc
@@ -139,8 +139,8 @@
       FROM_HERE, base::Bind(&VrShell::OnUnsupportedMode, weak_vr_shell_, mode));
 }
 
-void VrGLThread::OnExitVrPromptResult(vr::UiUnsupportedMode reason,
-                                      vr::ExitVrPromptChoice choice) {
+void VrGLThread::OnExitVrPromptResult(vr::ExitVrPromptChoice choice,
+                                      vr::UiUnsupportedMode reason) {
   DCHECK(OnGlThread());
   main_thread_task_runner_->PostTask(
       FROM_HERE, base::Bind(&VrShell::OnExitVrPromptResult, weak_vr_shell_,
diff --git a/chrome/browser/android/vr_shell/vr_gl_thread.h b/chrome/browser/android/vr_shell/vr_gl_thread.h
index a377bc3..629b370 100644
--- a/chrome/browser/android/vr_shell/vr_gl_thread.h
+++ b/chrome/browser/android/vr_shell/vr_gl_thread.h
@@ -60,8 +60,8 @@
   void NavigateBack() override;
   void ExitCct() override;
   void OnUnsupportedMode(vr::UiUnsupportedMode mode) override;
-  void OnExitVrPromptResult(vr::UiUnsupportedMode reason,
-                            vr::ExitVrPromptChoice choice) override;
+  void OnExitVrPromptResult(vr::ExitVrPromptChoice choice,
+                            vr::UiUnsupportedMode reason) override;
   void OnContentScreenBoundsChanged(const gfx::SizeF& bounds) override;
   void SetVoiceSearchActive(bool active) override;
   void StartAutocomplete(const base::string16& string) override;
diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc
index 44d86c8f..71dd22f 100644
--- a/chrome/browser/android/vr_shell/vr_shell.cc
+++ b/chrome/browser/android/vr_shell/vr_shell.cc
@@ -218,10 +218,9 @@
           GetNonNativePageWebContents());
   // TODO(billorr): Make VrMetricsHelper tab-aware and able to track multiple
   // tabs. crbug.com/684661
-  metrics_helper_ =
-      base::MakeUnique<VrMetricsHelper>(GetNonNativePageWebContents());
-  metrics_helper_->SetVRActive(true);
-  metrics_helper_->SetWebVREnabled(webvr_mode_);
+  metrics_helper_ = base::MakeUnique<VrMetricsHelper>(
+      GetNonNativePageWebContents(),
+      webvr_mode_ ? VRMode::WEBVR : VRMode::VR_BROWSER);
 }
 
 void VrShell::SetUiState() {
diff --git a/chrome/browser/android/vr_shell/vr_usage_monitor.cc b/chrome/browser/android/vr_shell/vr_usage_monitor.cc
index 552a4e18..951a858 100644
--- a/chrome/browser/android/vr_shell/vr_usage_monitor.cc
+++ b/chrome/browser/android/vr_shell/vr_usage_monitor.cc
@@ -279,7 +279,10 @@
   mode_ = mode;
 }
 
-VrMetricsHelper::VrMetricsHelper(content::WebContents* contents) {
+VrMetricsHelper::VrMetricsHelper(content::WebContents* contents,
+                                 VRMode initial_mode)
+    : is_webvr_(initial_mode == VRMode::WEBVR),
+      is_vr_enabled_(initial_mode != VRMode::NO_VR) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   num_videos_playing_ = contents->GetCurrentlyPlayingVideoCount();
@@ -292,6 +295,8 @@
   session_video_timer_ =
       base::MakeUnique<SessionTimerImpl<SESSION_VR_WITH_VIDEO>>(
           kMaximumVideoSessionGap, kMinimumVideoSessionDuration);
+
+  UpdateMode();
 }
 
 VrMetricsHelper::~VrMetricsHelper() = default;
diff --git a/chrome/browser/android/vr_shell/vr_usage_monitor.h b/chrome/browser/android/vr_shell/vr_usage_monitor.h
index 3ecfb1b..b99e2ad 100644
--- a/chrome/browser/android/vr_shell/vr_usage_monitor.h
+++ b/chrome/browser/android/vr_shell/vr_usage_monitor.h
@@ -54,7 +54,7 @@
 // This class is not thread-safe and must only be used from the main thread.
 class VrMetricsHelper : public content::WebContentsObserver {
  public:
-  explicit VrMetricsHelper(content::WebContents* contents);
+  explicit VrMetricsHelper(content::WebContents* contents, VRMode initial_mode);
   ~VrMetricsHelper() override;
 
   void SetWebVREnabled(bool is_webvr_presenting);
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index ecedd496..3dcea99 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -78,6 +78,12 @@
       </if>
     </structures>
     <includes>
+      <if expr="is_win or is_macosx or is_linux">
+        <include name="IDR_ABOUT_DISCARDS_CSS" file="resources\discards\discards.css" type="BINDATA" />
+        <include name="IDR_ABOUT_DISCARDS_HTML" file="resources\discards\discards.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+        <include name="IDR_ABOUT_DISCARDS_JS" file="resources\discards\discards.js" type="BINDATA" />
+        <include name="IDR_ABOUT_DISCARDS_MOJO_JS" file="${root_gen_dir}\chrome\browser\ui\webui\discards\discards.mojom.js" use_base_dir="false" type="BINDATA" />
+      </if>
       <if expr="is_win">
         <include name="IDR_ABOUT_CONFLICTS_HTML" file="resources\about_conflicts.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
         <include name="IDR_ABOUT_CONFLICTS_JS" file="resources\about_conflicts.js" type="BINDATA" />
diff --git a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
index 31025dd..256f19f6 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
@@ -155,8 +155,7 @@
     EXPECT_EQ(0, GetSiteDataCount());
     GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html");
     ui_test_utils::NavigateToURL(browser(), url);
-    // We don't want to measure site engagement entries.
-    RemoveSiteEngagement();
+
     EXPECT_EQ(0, GetSiteDataCount());
     EXPECT_FALSE(HasDataForType(type));
 
@@ -175,7 +174,6 @@
     EXPECT_EQ(0, GetSiteDataCount());
     GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html");
     ui_test_utils::NavigateToURL(browser(), url);
-    RemoveSiteEngagement();
     EXPECT_EQ(0, GetSiteDataCount());
     // Opening a store of this type creates a site data entry.
     EXPECT_FALSE(HasDataForType(type));
@@ -192,11 +190,6 @@
     ASSERT_TRUE(RunScriptAndGetBool("set" + type + "()"));
   }
 
-  void RemoveSiteEngagement() {
-    HostContentSettingsMapFactory::GetForProfile(browser()->profile())
-        ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT);
-  }
-
   int GetSiteDataCount() {
     base::RunLoop run_loop;
     int count = -1;
@@ -407,16 +400,6 @@
   block_state = ExternalProtocolHandler::GetBlockState("tel", profile);
   ASSERT_EQ(ExternalProtocolHandler::UNKNOWN, block_state);
 }
-// Visiting a site creates a site engagement entry. Test that it is counted and
-// deleted properly.
-IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, SiteEngagementDeletion) {
-  EXPECT_EQ(0, GetSiteDataCount());
-  GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html");
-  ui_test_utils::NavigateToURL(browser(), url);
-  EXPECT_EQ(1, GetSiteDataCount());
-  RemoveAndWait(ChromeBrowsingDataRemoverDelegate::DATA_TYPE_SITE_DATA);
-  EXPECT_EQ(0, GetSiteDataCount());
-}
 
 IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, CookieDeletion) {
   TestSiteData("Cookie");
@@ -437,16 +420,13 @@
   EXPECT_EQ(0, GetSiteDataCount());
   GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html");
   ui_test_utils::NavigateToURL(browser(), url);
-  RemoveSiteEngagement();
   EXPECT_EQ(0, GetSiteDataCount());
   SetDataForType("SessionStorage");
   EXPECT_EQ(0, GetSiteDataCount());
   EXPECT_TRUE(HasDataForType("SessionStorage"));
 }
 
-// TODO(crbug.com/776711): This test is flaky on all plattforms.
-IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest,
-                       DISABLED_ServiceWorkerDeletion) {
+IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, ServiceWorkerDeletion) {
   TestSiteData("ServiceWorker");
 }
 
diff --git a/chrome/browser/browsing_data/site_data_counting_helper.cc b/chrome/browser/browsing_data/site_data_counting_helper.cc
index 51e9e6e93..003efb0 100644
--- a/chrome/browser/browsing_data/site_data_counting_helper.cc
+++ b/chrome/browser/browsing_data/site_data_counting_helper.cc
@@ -96,8 +96,7 @@
   // Counting site usage data and durable permissions.
   auto* hcsm = HostContentSettingsMapFactory::GetForProfile(profile_);
   const ContentSettingsType content_settings[] = {
-      CONTENT_SETTINGS_TYPE_DURABLE_STORAGE,
-      CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, CONTENT_SETTINGS_TYPE_APP_BANNER};
+      CONTENT_SETTINGS_TYPE_DURABLE_STORAGE, CONTENT_SETTINGS_TYPE_APP_BANNER};
   for (auto type : content_settings) {
     tasks_ += 1;
     GetOriginsFromHostContentSettignsMap(hcsm, type);
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 32ea7b0..ea2768e 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -145,6 +145,7 @@
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/content_settings/core/common/content_settings_utils.h"
+#include "components/content_settings/core/common/pref_names.h"
 #include "components/dom_distiller/core/dom_distiller_switches.h"
 #include "components/dom_distiller/core/url_constants.h"
 #include "components/error_page/common/error_page_switches.h"
@@ -1728,6 +1729,12 @@
           !prefs->GetBoolean(prefs::kAllowDinosaurEasterEgg))
         command_line->AppendSwitch(
             error_page::switches::kDisableDinosaurEasterEgg);
+
+      if (prefs->HasPrefPath(prefs::kUnsafelyTreatInsecureOriginAsSecure)) {
+        command_line->AppendSwitchASCII(
+            switches::kUnsafelyTreatInsecureOriginAsSecure,
+            prefs->GetString(prefs::kUnsafelyTreatInsecureOriginAsSecure));
+      }
     }
 
     if (IsAutoReloadEnabled())
@@ -1829,7 +1836,6 @@
       switches::kProfilingFile,
       switches::kProfilingFlush,
       switches::kReaderModeHeuristics,
-      switches::kUnsafelyTreatInsecureOriginAsSecure,
       translate::switches::kTranslateSecurityOrigin,
     };
 
@@ -1859,7 +1865,6 @@
 #endif
       switches::kPpapiFlashPath,
       switches::kPpapiFlashVersion,
-      switches::kUnsafelyTreatInsecureOriginAsSecure,
     };
 
     command_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
@@ -2778,7 +2783,7 @@
 
 void ChromeContentBrowserClient::GetSchemesBypassingSecureContextCheckWhitelist(
     std::set<std::string>* schemes) {
-  *schemes = ::GetSchemesBypassingSecureContextCheckWhitelist();
+  *schemes = secure_origin_whitelist::GetSchemesBypassingSecureContextCheck();
 }
 
 void ChromeContentBrowserClient::GetURLRequestAutoMountHandlers(
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json
index 5c3210a3..e2faffbf 100644
--- a/chrome/browser/chrome_content_browser_manifest_overlay.json
+++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -85,6 +85,7 @@
 
           // TODO(beng): These should be moved to a separate capability.
           "media::mojom::MediaEngagementScoreDetailsProvider",
+          "mojom::DiscardsDetailsProvider",
           "mojom::InterventionsInternalsPageHandler",
           "mojom::OmniboxPageHandler",
           "mojom::PluginsPageHandler",
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 8d88f81..5fb773c 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -20,7 +20,6 @@
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 
   public_deps = [
-    ":install_attributes_proto",
     "//ash/resources",
     "//ash/strings",
     "//chrome:extra_resources",
@@ -2036,12 +2035,6 @@
   ]
 }
 
-proto_library("install_attributes_proto") {
-  sources = [
-    "policy/proto/install_attributes.proto",
-  ]
-}
-
 proto_library("attestation_proto") {
   sources = [
     "attestation/attestation_key_payload.proto",
diff --git a/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc b/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc
index 94e06c2..80e24660 100644
--- a/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc
+++ b/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc
@@ -6,26 +6,22 @@
 
 #include <memory>
 #include <string>
-#include <utility>
 
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/ash_config.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
-#include "components/arc/common/video_decode_accelerator.mojom.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/gpu_service_registry.h"
-#include "mojo/edk/embedder/embedder.h"
+#include "content/public/common/service_manager_connection.h"
 #include "mojo/edk/embedder/outgoing_broker_client_invitation.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
-#include "services/ui/public/cpp/gpu/gpu.h"
-#include "ui/aura/env.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/ui/public/interfaces/arc.mojom.h"
+#include "services/ui/public/interfaces/constants.mojom.h"
 
 namespace arc {
 
@@ -50,46 +46,80 @@
   ~GpuArcVideoServiceHostFactory() override = default;
 };
 
-}  // namespace
-
 class VideoAcceleratorFactoryService : public mojom::VideoAcceleratorFactory {
  public:
-  VideoAcceleratorFactoryService() = default;
+  VideoAcceleratorFactoryService() {
+    DCHECK_EQ(chromeos::GetAshConfig(), ash::Config::CLASSIC);
+  }
+
+  ~VideoAcceleratorFactoryService() override = default;
 
   void CreateDecodeAccelerator(
       mojom::VideoDecodeAcceleratorRequest request) override {
-    if (chromeos::GetAshConfig() != ash::Config::CLASSIC) {
-      aura::Env::GetInstance()
-          ->GetGpuConnection()
-          ->CreateArcVideoDecodeAccelerator(std::move(request));
-    } else {
-      content::BrowserThread::PostTask(
-          content::BrowserThread::IO, FROM_HERE,
-          base::BindOnce(&content::BindInterfaceInGpuProcess<
-                             mojom::VideoDecodeAccelerator>,
-                         base::Passed(&request)));
-    }
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE,
+        base::BindOnce(
+            &content::BindInterfaceInGpuProcess<mojom::VideoDecodeAccelerator>,
+            std::move(request)));
   }
 
   void CreateEncodeAccelerator(
       mojom::VideoEncodeAcceleratorRequest request) override {
-    if (chromeos::GetAshConfig() != ash::Config::CLASSIC) {
-      aura::Env::GetInstance()
-          ->GetGpuConnection()
-          ->CreateArcVideoEncodeAccelerator(std::move(request));
-    } else {
-      content::BrowserThread::PostTask(
-          content::BrowserThread::IO, FROM_HERE,
-          base::BindOnce(&content::BindInterfaceInGpuProcess<
-                             mojom::VideoEncodeAccelerator>,
-                         base::Passed(&request)));
-    }
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE,
+        base::BindOnce(
+            &content::BindInterfaceInGpuProcess<mojom::VideoEncodeAccelerator>,
+            std::move(request)));
   }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(VideoAcceleratorFactoryService);
 };
 
+class VideoAcceleratorFactoryServiceMus
+    : public mojom::VideoAcceleratorFactory {
+ public:
+  VideoAcceleratorFactoryServiceMus() {
+    DCHECK_NE(chromeos::GetAshConfig(), ash::Config::CLASSIC);
+    DETACH_FROM_THREAD(thread_checker_);
+    auto* connector =
+        content::ServiceManagerConnection::GetForProcess()->GetConnector();
+    connector->BindInterface(ui::mojom::kServiceName, &arc_);
+  }
+
+  ~VideoAcceleratorFactoryServiceMus() override {
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  }
+
+  void CreateDecodeAccelerator(
+      mojom::VideoDecodeAcceleratorRequest request) override {
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    arc_->CreateVideoDecodeAccelerator(std::move(request));
+  }
+
+  void CreateEncodeAccelerator(
+      mojom::VideoEncodeAcceleratorRequest request) override {
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    arc_->CreateVideoEncodeAccelerator(std::move(request));
+  }
+
+ private:
+  THREAD_CHECKER(thread_checker_);
+
+  ui::mojom::ArcPtr arc_;
+
+  DISALLOW_COPY_AND_ASSIGN(VideoAcceleratorFactoryServiceMus);
+};
+
+std::unique_ptr<mojom::VideoAcceleratorFactory>
+CreateVideoAcceleratorFactory() {
+  if (chromeos::GetAshConfig() == ash::Config::CLASSIC)
+    return std::make_unique<VideoAcceleratorFactoryService>();
+  return std::make_unique<VideoAcceleratorFactoryServiceMus>();
+}
+
+}  // namespace
+
 // static
 GpuArcVideoServiceHost* GpuArcVideoServiceHost::GetForBrowserContext(
     content::BrowserContext* context) {
@@ -98,7 +128,9 @@
 
 GpuArcVideoServiceHost::GpuArcVideoServiceHost(content::BrowserContext* context,
                                                ArcBridgeService* bridge_service)
-    : arc_bridge_service_(bridge_service), binding_(this) {
+    : arc_bridge_service_(bridge_service),
+      binding_(this),
+      video_accelerator_factory_(CreateVideoAcceleratorFactory()) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   arc_bridge_service_->video()->AddObserver(this);
 }
@@ -147,8 +179,9 @@
 
   std::move(callback).Run(std::move(child_handle), token);
 
-  mojo::MakeStrongBinding(
-      std::make_unique<VideoAcceleratorFactoryService>(),
+  // The binding will be removed automatically, when the binding is destroyed.
+  video_accelerator_factory_bindings_.AddBinding(
+      video_accelerator_factory_.get(),
       mojom::VideoAcceleratorFactoryRequest(std::move(server_pipe)));
 }
 
diff --git a/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.h b/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.h
index 0792eaaa..699ce3b 100644
--- a/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.h
+++ b/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.h
@@ -10,6 +10,7 @@
 #include "components/arc/connection_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 
 namespace content {
 class BrowserContext;
@@ -49,6 +50,9 @@
  private:
   ArcBridgeService* const arc_bridge_service_;  // Owned by ArcServiceManager.
   mojo::Binding<mojom::VideoHost> binding_;
+  std::unique_ptr<mojom::VideoAcceleratorFactory> video_accelerator_factory_;
+  mojo::BindingSet<mojom::VideoAcceleratorFactory>
+      video_accelerator_factory_bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(GpuArcVideoServiceHost);
 };
diff --git a/chrome/browser/chromeos/settings/install_attributes.cc b/chrome/browser/chromeos/settings/install_attributes.cc
index 07f9420c..fdd5a2d 100644
--- a/chrome/browser/chromeos/settings/install_attributes.cc
+++ b/chrome/browser/chromeos/settings/install_attributes.cc
@@ -18,10 +18,10 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "chrome/browser/chromeos/policy/proto/install_attributes.pb.h"
 #include "chromeos/cryptohome/cryptohome_util.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
+#include "components/policy/proto/install_attributes.pb.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
diff --git a/chrome/browser/chromeos/settings/install_attributes_unittest.cc b/chrome/browser/chromeos/settings/install_attributes_unittest.cc
index d181b3c..043b629 100644
--- a/chrome/browser/chromeos/settings/install_attributes_unittest.cc
+++ b/chrome/browser/chromeos/settings/install_attributes_unittest.cc
@@ -14,12 +14,12 @@
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
-#include "chrome/browser/chromeos/policy/proto/install_attributes.pb.h"
 #include "chromeos/chromeos_paths.h"
 #include "chromeos/cryptohome/cryptohome_util.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
+#include "components/policy/proto/install_attributes.pb.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
index 595376a..0a6aec58 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/extensions/shared_module_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/extensions/command.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/pref_names.h"
@@ -600,6 +601,13 @@
 std::string ExtensionInfoGenerator::GetIconUrlFromImage(
     const gfx::Image& image,
     bool should_greyscale) {
+  // Ignore |should_greyscale| if MD Extensions are enabled.
+  // TODO(dpapad): Remove should_greyscale logic once non-MD Extensions UI is
+  // removed.
+  should_greyscale =
+      should_greyscale &&
+      !base::FeatureList::IsEnabled(features::kMaterialDesignExtensions);
+
   scoped_refptr<base::RefCountedMemory> data;
   if (should_greyscale) {
     color_utils::HSL shift = {-1, 0, 0.6};
diff --git a/chrome/browser/extensions/extension_special_storage_policy.cc b/chrome/browser/extensions/extension_special_storage_policy.cc
index 85a51b0..65041ad 100644
--- a/chrome/browser/extensions/extension_special_storage_policy.cc
+++ b/chrome/browser/extensions/extension_special_storage_policy.cc
@@ -114,6 +114,13 @@
   return cookie_settings_->IsCookieSessionOnly(origin);
 }
 
+bool ExtensionSpecialStoragePolicy::IsStorageSessionOnlyOrBlocked(
+    const GURL& origin) {
+  if (cookie_settings_.get() == NULL)
+    return false;
+  return cookie_settings_->IsCookieSessionOnlyOrBlocked(origin);
+}
+
 bool ExtensionSpecialStoragePolicy::HasSessionOnlyOrigins() {
   if (cookie_settings_.get() == NULL)
     return false;
diff --git a/chrome/browser/extensions/extension_special_storage_policy.h b/chrome/browser/extensions/extension_special_storage_policy.h
index cce5b043..334bc5f 100644
--- a/chrome/browser/extensions/extension_special_storage_policy.h
+++ b/chrome/browser/extensions/extension_special_storage_policy.h
@@ -39,6 +39,7 @@
   bool IsStorageProtected(const GURL& origin) override;
   bool IsStorageUnlimited(const GURL& origin) override;
   bool IsStorageSessionOnly(const GURL& origin) override;
+  bool IsStorageSessionOnlyOrBlocked(const GURL& origin) override;
   bool HasIsolatedStorage(const GURL& origin) override;
   bool HasSessionOnlyOrigins() override;
   bool IsStorageDurable(const GURL& origin) override;
diff --git a/chrome/browser/extensions/mock_extension_special_storage_policy.cc b/chrome/browser/extensions/mock_extension_special_storage_policy.cc
index ca32e2d..ca5e367 100644
--- a/chrome/browser/extensions/mock_extension_special_storage_policy.cc
+++ b/chrome/browser/extensions/mock_extension_special_storage_policy.cc
@@ -20,6 +20,11 @@
   return false;
 }
 
+bool MockExtensionSpecialStoragePolicy::IsStorageSessionOnlyOrBlocked(
+    const GURL& origin) {
+  return false;
+}
+
 bool MockExtensionSpecialStoragePolicy::HasSessionOnlyOrigins() {
   return false;
 }
diff --git a/chrome/browser/extensions/mock_extension_special_storage_policy.h b/chrome/browser/extensions/mock_extension_special_storage_policy.h
index f25676de..1b42b7cf 100644
--- a/chrome/browser/extensions/mock_extension_special_storage_policy.h
+++ b/chrome/browser/extensions/mock_extension_special_storage_policy.h
@@ -23,6 +23,7 @@
   bool IsStorageProtected(const GURL& origin) override;
   bool IsStorageUnlimited(const GURL& origin) override;
   bool IsStorageSessionOnly(const GURL& origin) override;
+  bool IsStorageSessionOnlyOrBlocked(const GURL& origin) override;
   bool HasSessionOnlyOrigins() override;
 
   void AddProtected(const GURL& origin) {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index b579eb5..df1d134 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1505,13 +1505,6 @@
 const char kV8CacheOptionsParse[] = "Cache V8 parser data.";
 const char kV8CacheOptionsCode[] = "Cache V8 compiler data.";
 
-const char kV8CacheStrategiesForCacheStorageName[] =
-    "V8 caching strategy for CacheStorage.";
-const char kV8CacheStrategiesForCacheStorageDescription[] =
-    "Caching strategy of scripts in CacheStorage for the V8 JavaScript engine.";
-const char kV8CacheStrategiesForCacheStorageNormal[] = "Normal";
-const char kV8CacheStrategiesForCacheStorageAggressive[] = "Aggressive";
-
 const char kV8ContextSnapshotName[] = "Use a snapshot to create V8 contexts.";
 const char kV8ContextSnapshotDescription[] =
     "Sets to use a snapshot to create V8 contexts in frame creation.";
@@ -1844,12 +1837,6 @@
     "If enabled, the list of content suggestions on the New Tab page will "
     "contain recent foreign tabs.";
 
-const char kEnableNtpMostLikelyFaviconsFromServerName[] =
-    "Download favicons for NTP tiles from Google.";
-const char kEnableNtpMostLikelyFaviconsFromServerDescription[] =
-    "If enabled, missing favicons for NTP tiles get downloaded from Google. "
-    "This only applies to tiles that originate from synced history.";
-
 const char kEnableNtpOfflinePageDownloadSuggestionsName[] =
     "Show offline page downloads on the New Tab page";
 const char kEnableNtpOfflinePageDownloadSuggestionsDescription[] =
@@ -2751,6 +2738,12 @@
 
 #endif  // OS_ANDROID
 
+#if BUILDFLAG(ENABLE_OPENVR)
+const char kOpenVRName[] = "OpenVR hardware support";
+const char kOpenVRDescription[] =
+    "If enabled, Chrome will use OpenVR devices for VR.";
+#endif  // ENABLE_OPENVR
+
 #endif  // ENABLE_VR
 
 #if BUILDFLAG(ENABLE_NACL)
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 8e04d72..337162e 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -927,11 +927,6 @@
 extern const char kV8CacheOptionsParse[];
 extern const char kV8CacheOptionsCode[];
 
-extern const char kV8CacheStrategiesForCacheStorageName[];
-extern const char kV8CacheStrategiesForCacheStorageDescription[];
-extern const char kV8CacheStrategiesForCacheStorageNormal[];
-extern const char kV8CacheStrategiesForCacheStorageAggressive[];
-
 extern const char kV8ContextSnapshotName[];
 extern const char kV8ContextSnapshotDescription[];
 
@@ -1130,9 +1125,6 @@
 extern const char kEnableNtpForeignSessionsSuggestionsName[];
 extern const char kEnableNtpForeignSessionsSuggestionsDescription[];
 
-extern const char kEnableNtpMostLikelyFaviconsFromServerName[];
-extern const char kEnableNtpMostLikelyFaviconsFromServerDescription[];
-
 extern const char kEnableMidiManagerDynamicInstantiationName[];
 extern const char kEnableMidiManagerDynamicInstantiationDescription[];
 
@@ -1705,6 +1697,11 @@
 
 #endif  // OS_ANDROID
 
+#if BUILDFLAG(ENABLE_OPENVR)
+extern const char kOpenVRName[];
+extern const char kOpenVRDescription[];
+#endif  // ENABLE_OPENVR
+
 #endif  // ENABLE_VR
 
 #if BUILDFLAG(ENABLE_NACL)
diff --git a/chrome/browser/history/history_tab_helper.cc b/chrome/browser/history/history_tab_helper.cc
index e83beee..a05c0f2 100644
--- a/chrome/browser/history/history_tab_helper.cc
+++ b/chrome/browser/history/history_tab_helper.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/frame_navigate_params.h"
+#include "ui/base/page_transition_types.h"
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/android/background_tab_manager.h"
@@ -76,12 +77,25 @@
   const bool consider_for_ntp_most_visited =
       navigation_handle->GetReferrer().url != kChromeContentSuggestionsReferrer;
 
+  const bool status_code_is_error =
+      navigation_handle->GetResponseHeaders() &&
+      (navigation_handle->GetResponseHeaders()->response_code() >= 400) &&
+      (navigation_handle->GetResponseHeaders()->response_code() < 600);
+  // Top-level frame navigations are visible; everything else is hidden.
+  // Also hide top-level navigations that result in an error in order to
+  // prevent the omnibox from suggesting URLs that have never been navigated
+  // to successfully.  (If a top-level navigation to the URL succeeds at some
+  // point, the URL will be unhidden and thus eligible to be suggested by the
+  // omnibox.)
+  const bool hidden =
+      !ui::PageTransitionIsMainFrame(navigation_handle->GetPageTransition()) ||
+      status_code_is_error;
   history::HistoryAddPageArgs add_page_args(
       navigation_handle->GetURL(), timestamp,
-      history::ContextIDForWebContents(web_contents()),
-      nav_entry_id, navigation_handle->GetReferrer().url,
+      history::ContextIDForWebContents(web_contents()), nav_entry_id,
+      navigation_handle->GetReferrer().url,
       navigation_handle->GetRedirectChain(),
-      navigation_handle->GetPageTransition(), history::SOURCE_BROWSED,
+      navigation_handle->GetPageTransition(), hidden, history::SOURCE_BROWSED,
       navigation_handle->DidReplaceEntry(), consider_for_ntp_most_visited);
   if (ui::PageTransitionIsMainFrame(navigation_handle->GetPageTransition()) &&
       virtual_url != navigation_handle->GetURL()) {
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
index bc355c9..602330a 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -179,7 +179,7 @@
     bool incognito) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   base::Optional<mojom::MediaRouteProvider::Id> provider_id =
-      GetProviderIdForSink(sink_id, source_id);
+      GetProviderIdForSink(sink_id);
   if (!provider_id) {
     std::unique_ptr<RouteRequestResult> result = RouteRequestResult::FromError(
         "Sink not found", RouteRequestResult::SINK_NOT_FOUND);
@@ -327,7 +327,7 @@
     MediaSinkSearchResponseCallback sink_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   base::Optional<mojom::MediaRouteProvider::Id> provider_id =
-      GetProviderIdForSink(sink_id, source_id);
+      GetProviderIdForSink(sink_id);
   if (!provider_id) {
     DVLOG_WITH_INSTANCE(1) << __func__ << ": sink not found: " << sink_id;
     std::move(sink_callback).Run("");
@@ -893,19 +893,17 @@
 }
 
 base::Optional<mojom::MediaRouteProvider::Id>
-MediaRouterMojoImpl::GetProviderIdForSink(const MediaSink::Id& sink_id,
-                                          const MediaSource::Id& source_id) {
-  const auto& sinks_query = sinks_queries_.find(source_id);
-  if (sinks_query == sinks_queries_.end())
-    return base::nullopt;
-  for (const auto& provider_to_sinks :
-       sinks_query->second->providers_to_sinks()) {
-    const std::vector<MediaSink>& sinks = provider_to_sinks.second;
-    if (std::find_if(sinks.begin(), sinks.end(),
-                     [&sink_id](const MediaSink& sink) {
-                       return sink.id() == sink_id;
-                     }) != sinks.end()) {
-      return provider_to_sinks.first;
+MediaRouterMojoImpl::GetProviderIdForSink(const MediaSink::Id& sink_id) {
+  for (const auto& sinks_query : sinks_queries_) {
+    for (const auto& provider_to_sinks :
+         sinks_query.second->providers_to_sinks()) {
+      const std::vector<MediaSink>& sinks = provider_to_sinks.second;
+      if (std::find_if(sinks.begin(), sinks.end(),
+                       [&sink_id](const MediaSink& sink) {
+                         return sink.id() == sink_id;
+                       }) != sinks.end()) {
+        return provider_to_sinks.first;
+      }
     }
   }
   return base::nullopt;
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.h b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
index 0b7ed619..7469bcc 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.h
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
@@ -393,8 +393,7 @@
   base::Optional<mojom::MediaRouteProvider::Id> GetProviderIdForRoute(
       const MediaRoute::Id& route_id);
   base::Optional<mojom::MediaRouteProvider::Id> GetProviderIdForSink(
-      const MediaSink::Id& sink_id,
-      const MediaSource::Id& source_id);
+      const MediaSink::Id& sink_id);
   base::Optional<mojom::MediaRouteProvider::Id> GetProviderIdForPresentation(
       const std::string& presentation_id);
 
diff --git a/chrome/browser/notifications/OWNERS b/chrome/browser/notifications/OWNERS
index bedc61b..b7b8817d 100644
--- a/chrome/browser/notifications/OWNERS
+++ b/chrome/browser/notifications/OWNERS
@@ -5,6 +5,9 @@
 stevenjb@chromium.org
 yoshiki@chromium.org
 
+# Android files
+per-file *_android*=awdf@chromium.org
+
 # Mac files
 per-file *_mac*=rsesek@chromium.org
 
diff --git a/chrome/browser/predictors/loading_predictor.cc b/chrome/browser/predictors/loading_predictor.cc
index ffd26d5d..48b8c97 100644
--- a/chrome/browser/predictors/loading_predictor.cc
+++ b/chrome/browser/predictors/loading_predictor.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/predictors/loading_predictor.h"
 
+#include <algorithm>
 #include <vector>
 
 #include "base/memory/ptr_util.h"
@@ -26,16 +27,23 @@
 bool AddInitialUrlToPreconnectPrediction(const GURL& initial_url,
                                          PreconnectPrediction* prediction) {
   GURL initial_origin = initial_url.GetOrigin();
+  // Open minimum 2 sockets to the main frame host to speed up the loading if a
+  // main page has a redirect to the same host. This is because there can be a
+  // race between reading the server redirect response and sending a new request
+  // while the connection is still in use.
+  static const int kMinSockets = 2;
 
-  if ((prediction->preconnect_origins.empty() ||
-       prediction->preconnect_origins.front() != initial_origin) &&
-      initial_origin.is_valid() && initial_origin.SchemeIsHTTPOrHTTPS()) {
-    prediction->preconnect_origins.emplace(
-        prediction->preconnect_origins.begin(), initial_origin);
+  if (!prediction->requests.empty() &&
+      prediction->requests.front().origin == initial_origin) {
+    prediction->requests.front().num_sockets =
+        std::max(prediction->requests.front().num_sockets, kMinSockets);
+  } else if (initial_origin.is_valid() &&
+             initial_origin.SchemeIsHTTPOrHTTPS()) {
+    prediction->requests.emplace(prediction->requests.begin(), initial_origin,
+                                 kMinSockets);
   }
 
-  return !prediction->preconnect_origins.empty() ||
-         !prediction->preresolve_hosts.empty();
+  return !prediction->requests.empty();
 }
 
 }  // namespace
@@ -95,18 +103,13 @@
     has_preconnect_prediction =
         resource_prefetch_predictor_->PredictPreconnectOrigins(url,
                                                                &prediction);
-    // For all but NAVIGATION hint origins it makes sense to preconnect to the
-    // |url| even if the predictor has no prediction. In the NAVIGATION case
-    // it makes less sense because the connection will follow shortly after
-    // the hint with a higher priority.
-    if (origin != HintOrigin::NAVIGATION) {
-      has_preconnect_prediction =
-          AddInitialUrlToPreconnectPrediction(url, &prediction);
-    }
+    // Try to preconnect to the |url| even if the predictor has no
+    // prediction.
+    has_preconnect_prediction =
+        AddInitialUrlToPreconnectPrediction(url, &prediction);
     if (has_preconnect_prediction &&
         config_.IsPreconnectEnabledForOrigin(profile_, origin)) {
-      MaybeAddPreconnect(url, prediction.preconnect_origins,
-                         prediction.preresolve_hosts, origin);
+      MaybeAddPreconnect(url, std::move(prediction.requests), origin);
       hint_activated = true;
     }
   }
@@ -336,15 +339,14 @@
 
 void LoadingPredictor::MaybeAddPreconnect(
     const GURL& url,
-    const std::vector<GURL>& preconnect_origins,
-    const std::vector<GURL>& preresolve_hosts,
+    std::vector<PreconnectRequest>&& requests,
     HintOrigin origin) {
   DCHECK(!shutdown_);
   content::BrowserThread::PostTask(
       content::BrowserThread::IO, FROM_HERE,
       base::BindOnce(&PreconnectManager::Start,
                      base::Unretained(preconnect_manager()), url,
-                     preconnect_origins, preresolve_hosts));
+                     std::move(requests)));
 }
 
 void LoadingPredictor::MaybeRemovePreconnect(const GURL& url) {
diff --git a/chrome/browser/predictors/loading_predictor.h b/chrome/browser/predictors/loading_predictor.h
index 2092f2e..9ed93d15 100644
--- a/chrome/browser/predictors/loading_predictor.h
+++ b/chrome/browser/predictors/loading_predictor.h
@@ -106,11 +106,10 @@
   // If a prefetch exists for |url|, stop it.
   void MaybeRemovePrefetch(const GURL& url);
 
-  // May start a preconnect to |preconnect_origins| and preresolve of
-  // |preresolve_hosts| for |url| with a given hint |origin|.
+  // May start preconnect and preresolve jobs according to |requests| for |url|
+  // with a given hint |origin|.
   void MaybeAddPreconnect(const GURL& url,
-                          const std::vector<GURL>& preconnect_origins,
-                          const std::vector<GURL>& preresolve_hosts,
+                          std::vector<PreconnectRequest>&& requests,
                           HintOrigin origin);
   // If a preconnect exists for |url|, stop it.
   void MaybeRemovePreconnect(const GURL& url);
diff --git a/chrome/browser/predictors/loading_predictor_unittest.cc b/chrome/browser/predictors/loading_predictor_unittest.cc
index 5687b2c7..e46ceeb 100644
--- a/chrome/browser/predictors/loading_predictor_unittest.cc
+++ b/chrome/browser/predictors/loading_predictor_unittest.cc
@@ -31,7 +31,9 @@
 // First two are prefetchable, last one is not (see SetUp()).
 const char kUrl[] = "http://www.google.com/cats";
 const char kUrl2[] = "http://www.google.com/dogs";
-const char kUrl3[] = "https://unknown.website/catsanddogs";
+const char kUrl3[] =
+    "file://unknown.website/catsanddogs";  // Non http(s) scheme to avoid
+                                           // preconnect to the main frame.
 
 class MockPreconnectManager : public PreconnectManager {
  public:
@@ -39,16 +41,20 @@
       base::WeakPtr<Delegate> delegate,
       scoped_refptr<net::URLRequestContextGetter> context_getter);
 
-  MOCK_METHOD3(Start,
+  MOCK_METHOD2(StartProxy,
                void(const GURL& url,
-                    const std::vector<GURL>& preconnect_origins,
-                    const std::vector<GURL>& preresolve_hosts));
+                    const std::vector<PreconnectRequest>& requests));
   MOCK_METHOD1(StartPreresolveHost, void(const GURL& url));
   MOCK_METHOD1(StartPreresolveHosts,
                void(const std::vector<std::string>& hostnames));
   MOCK_METHOD2(StartPreconnectUrl,
                void(const GURL& url, bool allow_credentials));
   MOCK_METHOD1(Stop, void(const GURL& url));
+
+  void Start(const GURL& url,
+             std::vector<PreconnectRequest>&& requests) override {
+    StartProxy(url, requests);
+  }
 };
 
 MockPreconnectManager::MockPreconnectManager(
@@ -310,17 +316,8 @@
       .WillOnce(Return(false));
   EXPECT_CALL(
       *mock_preconnect_manager_,
-      Start(main_frame_url, std::vector<GURL>({GURL("http://search.com")}),
-            std::vector<GURL>()));
-  predictor_->PrepareForPageLoad(main_frame_url, HintOrigin::EXTERNAL);
-}
-
-// Checks that the predictor doesn't preconnect to an initial origin in the case
-// of NAVIGATION hint.
-TEST_F(LoadingPredictorPreconnectTest, TestAddInitialUrlForNavigationHint) {
-  GURL main_frame_url("http://search.com/kittens");
-  EXPECT_CALL(*mock_predictor_, PredictPreconnectOrigins(main_frame_url, _))
-      .WillOnce(Return(false));
+      StartProxy(main_frame_url, std::vector<PreconnectRequest>(
+                                     {{GURL("http://search.com"), 2}})));
   predictor_->PrepareForPageLoad(main_frame_url, HintOrigin::NAVIGATION);
 }
 
@@ -328,17 +325,19 @@
 // if the list already containts the origin.
 TEST_F(LoadingPredictorPreconnectTest, TestAddInitialUrlMatchesPrediction) {
   GURL main_frame_url("http://search.com/kittens");
-  PreconnectPrediction prediction = CreatePreconnectPrediction(
-      "search.com", true,
-      {GURL("http://search.com"), GURL("http://cdn.search.com")},
-      {GURL("http://ads.search.com")});
+  PreconnectPrediction prediction =
+      CreatePreconnectPrediction("search.com", true,
+                                 {{GURL("http://search.com"), 1},
+                                  {GURL("http://cdn.search.com"), 1},
+                                  {GURL("http://ads.search.com"), 0}});
   EXPECT_CALL(*mock_predictor_, PredictPreconnectOrigins(main_frame_url, _))
       .WillOnce(DoAll(SetArgPointee<1>(prediction), Return(true)));
-  EXPECT_CALL(*mock_preconnect_manager_,
-              Start(main_frame_url,
-                    std::vector<GURL>({GURL("http://search.com"),
-                                       GURL("http://cdn.search.com")}),
-                    std::vector<GURL>({GURL("http://ads.search.com")})));
+  EXPECT_CALL(
+      *mock_preconnect_manager_,
+      StartProxy(main_frame_url, std::vector<PreconnectRequest>(
+                                     {{GURL("http://search.com"), 2},
+                                      {GURL("http://cdn.search.com"), 1},
+                                      {GURL("http://ads.search.com"), 0}})));
   predictor_->PrepareForPageLoad(main_frame_url, HintOrigin::EXTERNAL);
 }
 
@@ -347,18 +346,20 @@
 // url redirects to another host.
 TEST_F(LoadingPredictorPreconnectTest, TestAddInitialUrlDoesntMatchPrediction) {
   GURL main_frame_url("http://search.com/kittens");
-  PreconnectPrediction prediction = CreatePreconnectPrediction(
-      "search.com", true,
-      {GURL("http://en.search.com"), GURL("http://cdn.search.com")},
-      {GURL("http://ads.search.com")});
+  PreconnectPrediction prediction =
+      CreatePreconnectPrediction("search.com", true,
+                                 {{GURL("http://en.search.com"), 1},
+                                  {GURL("http://cdn.search.com"), 1},
+                                  {GURL("http://ads.search.com"), 0}});
   EXPECT_CALL(*mock_predictor_, PredictPreconnectOrigins(main_frame_url, _))
       .WillOnce(DoAll(SetArgPointee<1>(prediction), Return(true)));
-  EXPECT_CALL(*mock_preconnect_manager_,
-              Start(main_frame_url,
-                    std::vector<GURL>({GURL("http://search.com"),
-                                       GURL("http://en.search.com"),
-                                       GURL("http://cdn.search.com")}),
-                    std::vector<GURL>({GURL("http://ads.search.com")})));
+  EXPECT_CALL(
+      *mock_preconnect_manager_,
+      StartProxy(main_frame_url, std::vector<PreconnectRequest>(
+                                     {{GURL("http://search.com"), 2},
+                                      {GURL("http://en.search.com"), 1},
+                                      {GURL("http://cdn.search.com"), 1},
+                                      {GURL("http://ads.search.com"), 0}})));
   predictor_->PrepareForPageLoad(main_frame_url, HintOrigin::EXTERNAL);
 }
 
diff --git a/chrome/browser/predictors/loading_stats_collector.cc b/chrome/browser/predictors/loading_stats_collector.cc
index 9e48880e..f9294fe8 100644
--- a/chrome/browser/predictors/loading_stats_collector.cc
+++ b/chrome/browser/predictors/loading_stats_collector.cc
@@ -80,28 +80,18 @@
 
 void ReportPreconnectPredictionAccuracy(const PreconnectPrediction& prediction,
                                         const PageRequestSummary& summary) {
-  if ((prediction.preconnect_origins.empty() &&
-       prediction.preresolve_hosts.empty()) ||
-      summary.origins.empty()) {
+  if (prediction.requests.empty() || summary.origins.empty())
     return;
-  }
 
   const auto& actual_origins = summary.origins;
 
-  size_t correctly_predicted_count = 0;
-  for (const GURL& predicted_origin : prediction.preconnect_origins) {
-    if (actual_origins.find(predicted_origin) != actual_origins.end())
-      ++correctly_predicted_count;
-  }
-  for (const GURL& predicted_origin : prediction.preresolve_hosts) {
-    if (actual_origins.find(predicted_origin) != actual_origins.end())
-      ++correctly_predicted_count;
-  }
-
-  size_t predicted_count =
-      prediction.preconnect_origins.size() + prediction.preresolve_hosts.size();
+  size_t correctly_predicted_count = std::count_if(
+      prediction.requests.begin(), prediction.requests.end(),
+      [&actual_origins](const PreconnectRequest& request) {
+        return actual_origins.find(request.origin) != actual_origins.end();
+      });
   size_t precision_percentage =
-      (100 * correctly_predicted_count) / predicted_count;
+      (100 * correctly_predicted_count) / prediction.requests.size();
   size_t recall_percentage =
       (100 * correctly_predicted_count) / actual_origins.size();
 
@@ -111,7 +101,7 @@
   UMA_HISTOGRAM_PERCENTAGE(internal::kLoadingPredictorPreconnectLearningRecall,
                            recall_percentage);
   UMA_HISTOGRAM_COUNTS_100(internal::kLoadingPredictorPreconnectLearningCount,
-                           predicted_count);
+                           prediction.requests.size());
 
   RedirectStatus redirect_status = GetPredictionRedirectStatus(
       summary.initial_url, summary.main_frame_url, prediction.host,
diff --git a/chrome/browser/predictors/loading_stats_collector_unittest.cc b/chrome/browser/predictors/loading_stats_collector_unittest.cc
index 5f9d83bb..3251c70482 100644
--- a/chrome/browser/predictors/loading_stats_collector_unittest.cc
+++ b/chrome/browser/predictors/loading_stats_collector_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/predictors/loading_stats_collector.h"
 
+#include <vector>
+
 #include "base/memory/ptr_util.h"
 #include "base/test/histogram_tester.h"
 #include "chrome/browser/predictors/loading_test_util.h"
@@ -87,7 +89,7 @@
   {
     PreconnectPrediction prediction = CreatePreconnectPrediction(
         GURL(prediction_url).host(), initial_url != prediction_url,
-        {GURL(script_url).GetOrigin()}, {});
+        {{GURL(script_url).GetOrigin(), 1}});
     EXPECT_CALL(*mock_predictor_,
                 PredictPreconnectOrigins(GURL(initial_url), _))
         .WillOnce(DoAll(SetArgPointee<1>(prediction), Return(true)));
@@ -149,11 +151,12 @@
   };
 
   // Predicts 4 origins: 2 useful, 2 useless.
-  PreconnectPrediction prediction = CreatePreconnectPrediction(
-      GURL(main_frame_url).host(), false,
-      {GURL(main_frame_url).GetOrigin(), GURL(gen(1)).GetOrigin(),
-       GURL(gen(2)).GetOrigin()},
-      {GURL(gen(3)).GetOrigin()});
+  PreconnectPrediction prediction =
+      CreatePreconnectPrediction(GURL(main_frame_url).host(), false,
+                                 {{GURL(main_frame_url).GetOrigin(), 1},
+                                  {GURL(gen(1)).GetOrigin(), 1},
+                                  {GURL(gen(2)).GetOrigin(), 1},
+                                  {GURL(gen(3)).GetOrigin(), 0}});
   EXPECT_CALL(*mock_predictor_,
               PredictPreconnectOrigins(GURL(main_frame_url), _))
       .WillOnce(DoAll(SetArgPointee<1>(prediction), Return(true)));
diff --git a/chrome/browser/predictors/loading_test_util.cc b/chrome/browser/predictors/loading_test_util.cc
index 8236f7f..d8ddb33e 100644
--- a/chrome/browser/predictors/loading_test_util.cc
+++ b/chrome/browser/predictors/loading_test_util.cc
@@ -188,13 +188,11 @@
 PreconnectPrediction CreatePreconnectPrediction(
     std::string host,
     bool is_redirected,
-    std::vector<GURL> preconnect_origins,
-    std::vector<GURL> preresolve_hosts) {
+    const std::vector<PreconnectRequest>& requests) {
   PreconnectPrediction prediction;
   prediction.host = host;
   prediction.is_redirected = is_redirected;
-  prediction.preconnect_origins = preconnect_origins;
-  prediction.preresolve_hosts = preresolve_hosts;
+  prediction.requests = requests;
   return prediction;
 }
 
@@ -381,18 +379,19 @@
   return os << navigation_id.tab_id << "," << navigation_id.main_frame_url;
 }
 
+std::ostream& operator<<(std::ostream& os, const PreconnectRequest& request) {
+  return os << "[" << request.origin << "," << request.num_sockets << ","
+            << request.allow_credentials << "]";
+}
+
 std::ostream& operator<<(std::ostream& os,
                          const PreconnectPrediction& prediction) {
   os << "[" << prediction.host << "," << prediction.is_redirected << "]"
      << std::endl;
 
-  os << "Preconnect:" << std::endl;
-  for (const auto& url : prediction.preconnect_origins)
-    os << "\t\t" << url << std::endl;
+  for (const auto& request : prediction.requests)
+    os << "\t\t" << request << std::endl;
 
-  os << "Preresolve:" << std::endl;
-  for (const auto& url : prediction.preresolve_hosts)
-    os << "\t\t" << url << std::endl;
   return os;
 }
 
@@ -493,11 +492,15 @@
          lhs.accessed_network() == rhs.accessed_network();
 }
 
+bool operator==(const PreconnectRequest& lhs, const PreconnectRequest& rhs) {
+  return lhs.origin == rhs.origin && lhs.num_sockets == rhs.num_sockets &&
+         lhs.allow_credentials == rhs.allow_credentials;
+}
+
 bool operator==(const PreconnectPrediction& lhs,
                 const PreconnectPrediction& rhs) {
   return lhs.is_redirected == rhs.is_redirected && lhs.host == rhs.host &&
-         lhs.preconnect_origins == rhs.preconnect_origins &&
-         lhs.preresolve_hosts == rhs.preresolve_hosts;
+         lhs.requests == rhs.requests;
 }
 
 }  // namespace predictors
diff --git a/chrome/browser/predictors/loading_test_util.h b/chrome/browser/predictors/loading_test_util.h
index e4a5a67..15114413 100644
--- a/chrome/browser/predictors/loading_test_util.h
+++ b/chrome/browser/predictors/loading_test_util.h
@@ -106,8 +106,7 @@
 PreconnectPrediction CreatePreconnectPrediction(
     std::string host,
     bool is_redirected,
-    std::vector<GURL> preconnect_urls,
-    std::vector<GURL> preresolve_urls);
+    const std::vector<PreconnectRequest>& requests);
 
 void PopulateTestConfig(LoadingPredictorConfig* config, bool small_db = true);
 
@@ -195,6 +194,7 @@
 
 std::ostream& operator<<(std::ostream& os, const OriginData& data);
 std::ostream& operator<<(std::ostream& os, const OriginStat& redirect);
+std::ostream& operator<<(std::ostream& os, const PreconnectRequest& request);
 std::ostream& operator<<(std::ostream& os,
                          const PreconnectPrediction& prediction);
 
@@ -208,6 +208,7 @@
                 const OriginRequestSummary& rhs);
 bool operator==(const OriginData& lhs, const OriginData& rhs);
 bool operator==(const OriginStat& lhs, const OriginStat& rhs);
+bool operator==(const PreconnectRequest& lhs, const PreconnectRequest& rhs);
 bool operator==(const PreconnectPrediction& lhs,
                 const PreconnectPrediction& rhs);
 
diff --git a/chrome/browser/predictors/preconnect_manager.cc b/chrome/browser/predictors/preconnect_manager.cc
index cd083eb..3499339 100644
--- a/chrome/browser/predictors/preconnect_manager.cc
+++ b/chrome/browser/predictors/preconnect_manager.cc
@@ -7,9 +7,12 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "chrome/browser/predictors/resource_prefetch_predictor.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_hints.h"
 #include "net/base/net_errors.h"
+#include "net/http/transport_security_state.h"
+#include "net/url_request/url_request_context.h"
 
 namespace predictors {
 
@@ -40,13 +43,15 @@
 PreresolveInfo::~PreresolveInfo() = default;
 
 PreresolveJob::PreresolveJob(const GURL& url,
-                             bool need_preconnect,
+                             int num_sockets,
                              bool allow_credentials,
                              PreresolveInfo* info)
     : url(url),
-      need_preconnect(need_preconnect),
+      num_sockets(num_sockets),
       allow_credentials(allow_credentials),
-      info(info) {}
+      info(info) {
+  DCHECK_GE(num_sockets, 0);
+}
 
 PreresolveJob::PreresolveJob(const PreresolveJob& other) = default;
 PreresolveJob::~PreresolveJob() = default;
@@ -67,28 +72,20 @@
 }
 
 void PreconnectManager::Start(const GURL& url,
-                              const std::vector<GURL>& preconnect_origins,
-                              const std::vector<GURL>& preresolve_hosts) {
+                              std::vector<PreconnectRequest>&& requests) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   const std::string host = url.host();
   if (preresolve_info_.find(host) != preresolve_info_.end())
     return;
 
   auto iterator_and_whether_inserted = preresolve_info_.emplace(
-      host, base::MakeUnique<PreresolveInfo>(
-                url, preconnect_origins.size() + preresolve_hosts.size()));
+      host, base::MakeUnique<PreresolveInfo>(url, requests.size()));
   PreresolveInfo* info = iterator_and_whether_inserted.first->second.get();
 
-  for (const GURL& origin : preconnect_origins) {
-    DCHECK(origin.GetOrigin() == origin);
-    queued_jobs_.emplace_back(origin, true /* need_preconnect */,
-                              kAllowCredentialsOnPreconnectByDefault, info);
-  }
-
-  for (const GURL& host : preresolve_hosts) {
-    DCHECK(host.GetOrigin() == host);
-    queued_jobs_.emplace_back(host, false /* need_preconnect */,
-                              kAllowCredentialsOnPreconnectByDefault, info);
+  for (const auto& request : requests) {
+    DCHECK(request.origin.GetOrigin() == request.origin);
+    queued_jobs_.emplace_back(request.origin, request.num_sockets,
+                              request.allow_credentials, info);
   }
 
   TryToLaunchPreresolveJobs();
@@ -98,7 +95,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   if (!url.SchemeIsHTTPOrHTTPS())
     return;
-  queued_jobs_.emplace_front(url.GetOrigin(), false /* need_preconnect */,
+  queued_jobs_.emplace_front(url.GetOrigin(), 0,
                              kAllowCredentialsOnPreconnectByDefault, nullptr);
 
   TryToLaunchPreresolveJobs();
@@ -109,8 +106,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   // Push jobs in front of the queue due to higher priority.
   for (auto it = hostnames.rbegin(); it != hostnames.rend(); ++it) {
-    queued_jobs_.emplace_front(GURL("http://" + *it),
-                               false /* need_preconnect */,
+    queued_jobs_.emplace_front(GURL("http://" + *it), 0,
                                kAllowCredentialsOnPreconnectByDefault, nullptr);
   }
 
@@ -122,8 +118,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   if (!url.SchemeIsHTTPOrHTTPS())
     return;
-  queued_jobs_.emplace_front(url.GetOrigin(), true /* need_preconnect */,
-                             allow_credentials, nullptr);
+  queued_jobs_.emplace_front(url.GetOrigin(), 1, allow_credentials, nullptr);
 
   TryToLaunchPreresolveJobs();
 }
@@ -140,11 +135,12 @@
 
 void PreconnectManager::PreconnectUrl(const GURL& url,
                                       const GURL& site_for_cookies,
+                                      int num_sockets,
                                       bool allow_credentials) const {
   DCHECK(url.GetOrigin() == url);
   DCHECK(url.SchemeIsHTTPOrHTTPS());
-  content::PreconnectUrl(context_getter_.get(), url, site_for_cookies, 1,
-                         allow_credentials,
+  content::PreconnectUrl(context_getter_.get(), url, site_for_cookies,
+                         num_sockets, allow_credentials,
                          net::HttpRequestInfo::PRECONNECT_MOTIVATED);
 }
 
@@ -208,9 +204,11 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   PreresolveInfo* info = job.info;
   bool need_preconnect =
-      found && job.need_preconnect && (!info || !info->was_canceled);
-  if (need_preconnect)
-    PreconnectUrl(job.url, info ? info->url : GURL(), job.allow_credentials);
+      found && job.need_preconnect() && (!info || !info->was_canceled);
+  if (need_preconnect) {
+    PreconnectUrl(GetHSTSRedirect(job.url), info ? info->url : GURL(),
+                  job.num_sockets, job.allow_credentials);
+  }
   if (info && found)
     info->stats->requests_stats.emplace_back(job.url, cached, need_preconnect);
 }
@@ -228,4 +226,22 @@
   preresolve_info_.erase(it);
 }
 
+GURL PreconnectManager::GetHSTSRedirect(const GURL& url) const {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  if (!url.SchemeIs(url::kHttpScheme))
+    return url;
+
+  auto* transport_security_state =
+      context_getter_->GetURLRequestContext()->transport_security_state();
+  if (!transport_security_state)
+    return url;
+
+  if (!transport_security_state->ShouldUpgradeToSSL(url.host()))
+    return url;
+
+  GURL::Replacements replacements;
+  replacements.SetSchemeStr(url::kHttpsScheme);
+  return url.ReplaceComponents(replacements);
+}
+
 }  // namespace predictors
diff --git a/chrome/browser/predictors/preconnect_manager.h b/chrome/browser/predictors/preconnect_manager.h
index e8395851..e7cbb2b 100644
--- a/chrome/browser/predictors/preconnect_manager.h
+++ b/chrome/browser/predictors/preconnect_manager.h
@@ -8,6 +8,7 @@
 #include <list>
 #include <map>
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/memory/ref_counted.h"
@@ -19,6 +20,8 @@
 
 namespace predictors {
 
+struct PreconnectRequest;
+
 struct PreconnectedRequestStats {
   PreconnectedRequestStats(const GURL& origin,
                            bool was_preresolve_cached,
@@ -63,14 +66,15 @@
 // preconnect for a |url|.
 struct PreresolveJob {
   PreresolveJob(const GURL& url,
-                bool need_preconnect,
+                int num_sockets,
                 bool allow_credentials,
                 PreresolveInfo* info);
   PreresolveJob(const PreresolveJob& other);
   ~PreresolveJob();
+  bool need_preconnect() const { return num_sockets > 0; }
 
   GURL url;
-  bool need_preconnect;
+  int num_sockets;
   bool allow_credentials;
   // Raw pointer usage is fine here because even though PreresolveJob can
   // outlive PreresolveInfo it's only accessed on PreconnectManager class
@@ -111,8 +115,7 @@
 
   // Starts preconnect and preresolve jobs keyed by |url|.
   virtual void Start(const GURL& url,
-                     const std::vector<GURL>& preconnect_origins,
-                     const std::vector<GURL>& preresolve_hosts);
+                     std::vector<PreconnectRequest>&& requests);
 
   // Starts special preconnect and preresolve jobs that are not cancellable and
   // don't report about their completion. They are considered more important
@@ -127,6 +130,7 @@
   // Public for mocking in unit tests. Don't use, internal only.
   virtual void PreconnectUrl(const GURL& url,
                              const GURL& site_for_cookies,
+                             int num_sockets,
                              bool allow_credentials) const;
   virtual int PreresolveUrl(const GURL& url,
                             const net::CompletionCallback& callback) const;
@@ -136,6 +140,7 @@
   void OnPreresolveFinished(const PreresolveJob& job, int result);
   void FinishPreresolve(const PreresolveJob& job, bool found, bool cached);
   void AllPreresolvesForUrlFinished(PreresolveInfo* info);
+  GURL GetHSTSRedirect(const GURL& url) const;
 
   base::WeakPtr<Delegate> delegate_;
   scoped_refptr<net::URLRequestContextGetter> context_getter_;
diff --git a/chrome/browser/predictors/preconnect_manager_unittest.cc b/chrome/browser/predictors/preconnect_manager_unittest.cc
index 95ec402e..d4a58f8 100644
--- a/chrome/browser/predictors/preconnect_manager_unittest.cc
+++ b/chrome/browser/predictors/preconnect_manager_unittest.cc
@@ -4,12 +4,15 @@
 
 #include "chrome/browser/predictors/preconnect_manager.h"
 
+#include <utility>
+
 #include "base/format_macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "chrome/browser/predictors/resource_prefetch_predictor.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -42,9 +45,10 @@
       base::WeakPtr<Delegate> delegate,
       scoped_refptr<net::URLRequestContextGetter> context_getter);
 
-  MOCK_CONST_METHOD3(PreconnectUrl,
+  MOCK_CONST_METHOD4(PreconnectUrl,
                      void(const GURL& url,
                           const GURL& site_for_cookies,
+                          int num_sockets,
                           bool allow_credentials));
   MOCK_CONST_METHOD2(PreresolveUrl,
                      int(const GURL& url,
@@ -89,8 +93,8 @@
   EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preresolve, _))
       .WillOnce(Return(net::OK));
   EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
-  preconnect_manager_->Start(main_frame_url, std::vector<GURL>(),
-                             {url_to_preresolve});
+  preconnect_manager_->Start(main_frame_url,
+                             {PreconnectRequest(url_to_preresolve, 0)});
   // Wait for PreconnectFinished task posted to the UI thread.
   base::RunLoop().RunUntilIdle();
 }
@@ -102,10 +106,10 @@
   EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preconnect, _))
       .WillOnce(Return(net::OK));
   EXPECT_CALL(*preconnect_manager_,
-              PreconnectUrl(url_to_preconnect, main_frame_url, true));
+              PreconnectUrl(url_to_preconnect, main_frame_url, 1, true));
   EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
-  preconnect_manager_->Start(main_frame_url, {url_to_preconnect},
-                             std::vector<GURL>());
+  preconnect_manager_->Start(main_frame_url,
+                             {PreconnectRequest(url_to_preconnect, 1)});
   base::RunLoop().RunUntilIdle();
 }
 
@@ -117,8 +121,8 @@
   // Preconnect job isn't started before preresolve is completed asynchronously.
   EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preconnect, _))
       .WillOnce(DoAll(SaveArg<1>(&callback), Return(net::ERR_IO_PENDING)));
-  preconnect_manager_->Start(main_frame_url, {url_to_preconnect},
-                             std::vector<GURL>());
+  preconnect_manager_->Start(main_frame_url,
+                             {PreconnectRequest(url_to_preconnect, 1)});
 
   // Stop all jobs for |main_frame_url| before we get the callback.
   preconnect_manager_->Stop(main_frame_url);
@@ -133,8 +137,8 @@
   net::CompletionCallback callback;
   EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preconnect, _))
       .WillOnce(DoAll(SaveArg<1>(&callback), Return(net::ERR_IO_PENDING)));
-  preconnect_manager_->Start(main_frame_url, {url_to_preconnect},
-                             std::vector<GURL>());
+  preconnect_manager_->Start(main_frame_url,
+                             {PreconnectRequest(url_to_preconnect, 1)});
 
   // Callback may outlive PreconnectManager but it shouldn't cause a crash.
   preconnect_manager_ = nullptr;
@@ -145,22 +149,20 @@
 TEST_F(PreconnectManagerTest, TestUnqueuedPreresolvesCanceled) {
   GURL main_frame_url("http://google.com");
   size_t count = PreconnectManager::kMaxInflightPreresolves;
-  std::vector<GURL> urls_to_preconnect;
+  std::vector<PreconnectRequest> requests;
   // Allocate the space for callbacks at once because we need stable pointers.
   std::vector<net::CompletionCallback> callbacks(count);
   for (size_t i = 0; i < count; ++i) {
     // Exactly PreconnectManager::kMaxInflightPreresolves should be preresolved.
-    urls_to_preconnect.emplace_back(
-        base::StringPrintf("http://cdn%" PRIuS ".google.com", i));
-    EXPECT_CALL(*preconnect_manager_,
-                PreresolveUrl(urls_to_preconnect.back(), _))
+    requests.emplace_back(
+        GURL(base::StringPrintf("http://cdn%" PRIuS ".google.com", i)), 1);
+    EXPECT_CALL(*preconnect_manager_, PreresolveUrl(requests.back().origin, _))
         .WillOnce(
             DoAll(SaveArg<1>(&callbacks[i]), Return(net::ERR_IO_PENDING)));
   }
   // This url shouldn't be preresolved.
-  urls_to_preconnect.emplace_back("http://no.preresolve.com");
-  preconnect_manager_->Start(main_frame_url, urls_to_preconnect,
-                             std::vector<GURL>());
+  requests.emplace_back(GURL("http://no.preresolve.com"), 1);
+  preconnect_manager_->Start(main_frame_url, std::move(requests));
 
   preconnect_manager_->Stop(main_frame_url);
   EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
@@ -181,17 +183,17 @@
       .WillOnce(DoAll(SaveArg<1>(&callback1), Return(net::ERR_IO_PENDING)));
   EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preconnect2, _))
       .WillOnce(DoAll(SaveArg<1>(&callback2), Return(net::ERR_IO_PENDING)));
-  preconnect_manager_->Start(main_frame_url1, {url_to_preconnect1},
-                             std::vector<GURL>());
-  preconnect_manager_->Start(main_frame_url2, {url_to_preconnect2},
-                             std::vector<GURL>());
+  preconnect_manager_->Start(main_frame_url1,
+                             {PreconnectRequest(url_to_preconnect1, 1)});
+  preconnect_manager_->Start(main_frame_url2,
+                             {PreconnectRequest(url_to_preconnect2, 1)});
   // Check that the first url didn't block the second one.
   Mock::VerifyAndClearExpectations(preconnect_manager_.get());
 
   preconnect_manager_->Stop(main_frame_url2);
   // Stopping the second url shouldn't stop the first one.
   EXPECT_CALL(*preconnect_manager_,
-              PreconnectUrl(url_to_preconnect1, main_frame_url1, true));
+              PreconnectUrl(url_to_preconnect1, main_frame_url1, 1, true));
   EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url1));
   callback1.Run(net::OK);
   // No preconnect for the second url.
@@ -211,15 +213,15 @@
 
   EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preconnect1, _))
       .WillOnce(DoAll(SaveArg<1>(&callback1), Return(net::ERR_IO_PENDING)));
-  preconnect_manager_->Start(main_frame_url1, {url_to_preconnect1},
-                             std::vector<GURL>());
+  preconnect_manager_->Start(main_frame_url1,
+                             {PreconnectRequest(url_to_preconnect1, 1)});
   // This suggestion should be dropped because the PreconnectManager already has
   // a job for the "google.com" host.
-  preconnect_manager_->Start(main_frame_url2, {url_to_preconnect2},
-                             std::vector<GURL>());
+  preconnect_manager_->Start(main_frame_url2,
+                             {PreconnectRequest(url_to_preconnect2, 1)});
 
   EXPECT_CALL(*preconnect_manager_,
-              PreconnectUrl(url_to_preconnect1, main_frame_url1, true));
+              PreconnectUrl(url_to_preconnect1, main_frame_url1, 1, true));
   EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url1));
   callback1.Run(net::OK);
   base::RunLoop().RunUntilIdle();
@@ -261,7 +263,7 @@
   EXPECT_CALL(*preconnect_manager_, PreresolveUrl(origin, _))
       .WillOnce(Return(net::OK));
   EXPECT_CALL(*preconnect_manager_,
-              PreconnectUrl(origin, GURL(), allow_credentials));
+              PreconnectUrl(origin, GURL(), 1, allow_credentials));
   preconnect_manager_->StartPreconnectUrl(url, allow_credentials);
   base::RunLoop().RunUntilIdle();
 
@@ -274,22 +276,20 @@
 TEST_F(PreconnectManagerTest, TestDetachedRequestHasHigherPriority) {
   GURL main_frame_url("http://google.com");
   size_t count = PreconnectManager::kMaxInflightPreresolves;
-  std::vector<GURL> urls_to_preresolve;
+  std::vector<PreconnectRequest> requests;
   std::vector<net::CompletionCallback> callbacks(count);
   // Create enough asynchronous jobs to leave the last one in the queue.
   for (size_t i = 0; i < count; ++i) {
-    urls_to_preresolve.emplace_back(
-        base::StringPrintf("http://cdn%" PRIuS ".google.com", i));
-    EXPECT_CALL(*preconnect_manager_,
-                PreresolveUrl(urls_to_preresolve.back(), _))
+    requests.emplace_back(
+        GURL(base::StringPrintf("http://cdn%" PRIuS ".google.com", i)), 0);
+    EXPECT_CALL(*preconnect_manager_, PreresolveUrl(requests.back().origin, _))
         .WillOnce(
             DoAll(SaveArg<1>(&callbacks[i]), Return(net::ERR_IO_PENDING)));
   }
   // This url will wait in the queue.
   GURL queued_url("http://fonts.google.com");
-  urls_to_preresolve.emplace_back(queued_url);
-  preconnect_manager_->Start(main_frame_url, std::vector<GURL>(),
-                             urls_to_preresolve);
+  requests.emplace_back(queued_url, 0);
+  preconnect_manager_->Start(main_frame_url, std::move(requests));
 
   // This url should come to the front of the queue.
   GURL detached_preresolve("http://ads.google.com");
@@ -313,4 +313,23 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(PreconnectManagerTest, TestHSTSRedirectRespectedForPreconnect) {
+  net::TransportSecurityState transport_security_state;
+  transport_security_state.AddHSTS(
+      "google.com", base::Time::Now() + base::TimeDelta::FromDays(1000), false);
+  context_getter_->GetURLRequestContext()->set_transport_security_state(
+      &transport_security_state);
+
+  GURL url("http://google.com/search");
+  bool allow_credentials = false;
+
+  EXPECT_CALL(*preconnect_manager_, PreresolveUrl(GURL("http://google.com"), _))
+      .WillOnce(Return(net::OK));
+  EXPECT_CALL(
+      *preconnect_manager_,
+      PreconnectUrl(GURL("https://google.com"), GURL(), 1, allow_credentials));
+  preconnect_manager_->StartPreconnectUrl(url, allow_credentials);
+  base::RunLoop().RunUntilIdle();
+}
+
 }  // namespace predictors
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc
index 3c14755..81eba1e 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -121,6 +121,11 @@
 
 }  // namespace
 
+PreconnectRequest::PreconnectRequest(const GURL& origin, int num_sockets)
+    : origin(origin), num_sockets(num_sockets) {
+  DCHECK_GE(num_sockets, 0);
+}
+
 PreconnectPrediction::PreconnectPrediction() = default;
 PreconnectPrediction::PreconnectPrediction(
     const PreconnectPrediction& prediction) = default;
@@ -359,8 +364,7 @@
 bool ResourcePrefetchPredictor::PredictPreconnectOrigins(
     const GURL& url,
     PreconnectPrediction* prediction) const {
-  DCHECK(!prediction || (prediction->preconnect_origins.empty() &&
-                         prediction->preresolve_hosts.empty()));
+  DCHECK(!prediction || prediction->requests.empty());
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (initialization_state_ != INITIALIZED)
     return false;
@@ -389,9 +393,9 @@
     has_any_prediction = true;
     if (prediction) {
       if (confidence > kMinOriginConfidenceToTriggerPreconnect)
-        prediction->preconnect_origins.emplace_back(origin.origin());
+        prediction->requests.emplace_back(GURL(origin.origin()), 1);
       else
-        prediction->preresolve_hosts.emplace_back(origin.origin());
+        prediction->requests.emplace_back(GURL(origin.origin()), 0);
     }
   }
 
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h
index 7253988..eb34045 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -44,10 +44,6 @@
 constexpr char kResourcePrefetchPredictorPrefetchingDurationHistogram[] =
     "ResourcePrefetchPredictor.PrefetchingDuration";
 
-const uint32_t kVersionedRemovedExperiment = 0x03ff25e3;
-const uint32_t kUnusedRemovedExperiment = 0xf7f77166;
-const uint32_t kNoStoreRemovedExperiment = 0xd90a199a;
-
 struct LastVisitTimeCompare {
   template <typename T>
   bool operator()(const T& lhs, const T& rhs) const {
@@ -60,6 +56,19 @@
 class TestObserver;
 class ResourcePrefetcherManager;
 
+// Stores all values needed to trigger a preconnect/preresolve job to a single
+// origin.
+struct PreconnectRequest {
+  PreconnectRequest(const GURL& origin, int num_sockets);
+
+  GURL origin;
+  // A zero-value means that we need to preresolve a host only.
+  int num_sockets = 0;
+  bool allow_credentials = true;
+};
+
+// Stores a result of preconnect prediction. The |requests| vector is the main
+// result of prediction and other fields are used for histograms reporting.
 struct PreconnectPrediction {
   PreconnectPrediction();
   PreconnectPrediction(const PreconnectPrediction& other);
@@ -67,8 +76,7 @@
 
   bool is_redirected = false;
   std::string host;
-  std::vector<GURL> preconnect_origins;
-  std::vector<GURL> preresolve_hosts;
+  std::vector<PreconnectRequest> requests;
 };
 
 // Contains logic for learning what can be prefetched and for kicking off
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
index 1faf3cc..e9aaded0 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
 
+#include <algorithm>
 #include <iostream>
 #include <memory>
 #include <utility>
@@ -1208,9 +1209,10 @@
   EXPECT_TRUE(predictor_->IsUrlPreconnectable(main_frame_url));
   EXPECT_TRUE(
       predictor_->PredictPreconnectOrigins(main_frame_url, prediction.get()));
-  EXPECT_EQ(*prediction, CreatePreconnectPrediction("google.com", false,
-                                                    {GURL(gen_origin(1))},
-                                                    {GURL(gen_origin(2))}));
+  EXPECT_EQ(*prediction,
+            CreatePreconnectPrediction(
+                "google.com", false,
+                {{GURL(gen_origin(1)), 1}, {GURL(gen_origin(2)), 0}}));
 
   // Add a redirect.
   RedirectData redirect = CreateRedirectData("google.com", 3);
@@ -1235,9 +1237,9 @@
   EXPECT_TRUE(predictor_->IsUrlPreconnectable(main_frame_url));
   EXPECT_TRUE(
       predictor_->PredictPreconnectOrigins(main_frame_url, prediction.get()));
-  EXPECT_EQ(*prediction, CreatePreconnectPrediction("www.google.com", true,
-                                                    {GURL(gen_origin(4))},
-                                                    std::vector<GURL>()));
+  EXPECT_EQ(*prediction,
+            CreatePreconnectPrediction("www.google.com", true,
+                                       {{GURL(gen_origin(4)), 1}}));
 }
 
 }  // namespace predictors
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 7202b12..8489a8c1 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -68,6 +68,7 @@
 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
 #include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/common/secure_origin_whitelist.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "components/browsing_data/core/pref_names.h"
 #include "components/certificate_transparency/ct_policy_manager.h"
@@ -488,6 +489,7 @@
   PushMessagingAppIdentifier::RegisterProfilePrefs(registry);
   RegisterBrowserUserPrefs(registry);
   safe_browsing::RegisterProfilePrefs(registry);
+  secure_origin_whitelist::RegisterProfilePrefs(registry);
   SessionStartupPref::RegisterProfilePrefs(registry);
   signin::RegisterAccountConsistencyProfilePrefs(registry);
   syncer::SyncPrefs::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store.cc b/chrome/browser/prefs/chrome_command_line_pref_store.cc
index 40db5d6..08dd0346 100644
--- a/chrome/browser/prefs/chrome_command_line_pref_store.cc
+++ b/chrome/browser/prefs/chrome_command_line_pref_store.cc
@@ -48,6 +48,8 @@
         {switches::kAuthAndroidNegotiateAccountType,
          prefs::kAuthAndroidNegotiateAccountType},
 #endif
+        {switches::kUnsafelyTreatInsecureOriginAsSecure,
+         prefs::kUnsafelyTreatInsecureOriginAsSecure},
 };
 
 const CommandLinePrefStore::SwitchToPreferenceMapEntry
diff --git a/chrome/browser/printing/print_preview_message_handler.cc b/chrome/browser/printing/print_preview_message_handler.cc
index cda7ad2e..baacab95 100644
--- a/chrome/browser/printing/print_preview_message_handler.cc
+++ b/chrome/browser/printing/print_preview_message_handler.cc
@@ -24,6 +24,7 @@
 #include "components/printing/browser/print_composite_client.h"
 #include "components/printing/browser/print_manager_utils.h"
 #include "components/printing/common/print_messages.h"
+#include "components/printing/service/public/cpp/pdf_service_mojo_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
@@ -267,9 +268,8 @@
     DLOG(ERROR) << "Compositing pdf failed with error " << status;
     return;
   }
-  NotifyUIPreviewPageReady(
-      page_number, request_id,
-      PrintCompositeClient::GetDataFromMojoHandle(std::move(handle)));
+  NotifyUIPreviewPageReady(page_number, request_id,
+                           GetDataFromMojoHandle(std::move(handle)));
 }
 
 void PrintPreviewMessageHandler::OnCompositePdfDocumentDone(
@@ -282,9 +282,8 @@
     DLOG(ERROR) << "Compositing pdf failed with error " << status;
     return;
   }
-  NotifyUIPreviewDocumentReady(
-      page_count, request_id,
-      PrintCompositeClient::GetDataFromMojoHandle(std::move(handle)));
+  NotifyUIPreviewDocumentReady(page_count, request_id,
+                               GetDataFromMojoHandle(std::move(handle)));
 }
 
 bool PrintPreviewMessageHandler::OnMessageReceived(
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index e2e5b01..bdc6e4d8 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -32,6 +32,7 @@
 #include "components/printing/browser/print_composite_client.h"
 #include "components/printing/browser/print_manager_utils.h"
 #include "components/printing/common/print_messages.h"
+#include "components/printing/service/public/cpp/pdf_service_mojo_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
@@ -141,9 +142,7 @@
     return;
   }
 
-  UpdateForPrintedPage(
-      params, true,
-      PrintCompositeClient::GetShmFromMojoHandle(std::move(handle)));
+  UpdateForPrintedPage(params, true, GetShmFromMojoHandle(std::move(handle)));
 }
 
 void PrintViewManagerBase::OnDidPrintPage(
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 37347c5..f6f780d 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -169,7 +169,10 @@
 #endif
 
 #if defined(OS_CHROMEOS)
+#include "ash/public/cpp/window_properties.h"
+#include "ash/public/interfaces/window_pin_type.mojom.h"
 #include "chrome/browser/chromeos/arc/intent_helper/open_with_menu.h"
+#include "ui/aura/window.h"
 #endif
 
 using base::UserMetricsAction;
@@ -1545,6 +1548,20 @@
 // Menu delegate functions -----------------------------------------------------
 
 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
+#if defined(OS_CHROMEOS)
+  // Disable context menu in locked fullscreen mode (the menu is not really
+  // disabled as the user can still open it, but all the individual context menu
+  // entries are disabled / greyed out).
+  if (GetBrowser()) {
+    aura::Window* window = GetBrowser()->window()->GetNativeWindow();
+    ash::mojom::WindowPinType type =
+        window->GetProperty(ash::kWindowPinTypeKey);
+    if (type == ash::mojom::WindowPinType::TRUSTED_PINNED) {
+      return false;
+    }
+  }
+#endif
+
   {
     bool enabled = false;
     if (RenderViewContextMenuBase::IsCommandIdKnown(id, &enabled))
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
index 5576784..ac8ce28 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -78,6 +78,12 @@
 #include "third_party/WebKit/public/web/WebContextMenuData.h"
 #include "ui/base/models/menu_model.h"
 
+#if defined(OS_CHROMEOS)
+#include "ash/public/cpp/window_properties.h"
+#include "ash/public/interfaces/window_pin_type.mojom.h"
+#include "ui/aura/window.h"
+#endif
+
 using content::WebContents;
 using extensions::MimeHandlerViewGuest;
 using extensions::TestMimeHandlerViewGuest;
@@ -294,6 +300,31 @@
   EXPECT_TRUE(menu3->IsCommandIdVisible(IDC_CONTENT_CONTEXT_COPYLINKTEXT));
 }
 
+#if defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
+                       ContextMenuEntriesAreDisabledInLockedFullscreen) {
+  int entries_to_test[] = {
+    IDC_VIEW_SOURCE, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
+    IDC_CONTENT_CONTEXT_INSPECTELEMENT,
+  };
+  std::unique_ptr<TestRenderViewContextMenu> menu =
+      CreateContextMenuMediaTypeNone(GURL("http://www.google.com/"),
+                                     GURL("http://www.google.com/"));
+
+  // Entries are enabled.
+  for (auto entry : entries_to_test)
+    EXPECT_TRUE(menu->IsCommandIdEnabled(entry));
+
+  // Set locked fullscreen state.
+  browser()->window()->GetNativeWindow()->SetProperty(
+      ash::kWindowPinTypeKey, ash::mojom::WindowPinType::TRUSTED_PINNED);
+
+  // All entries are disabled in locked fullscreen (testing only a subset here).
+  for (auto entry : entries_to_test)
+    EXPECT_FALSE(menu->IsCommandIdEnabled(entry));
+}
+#endif  // defined(OS_CHROMEOS)
+
 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenEntryPresentForNormalURLs) {
   std::unique_ptr<TestRenderViewContextMenu> menu =
       CreateContextMenuMediaTypeNone(GURL("http://www.google.com/"),
diff --git a/chrome/browser/resource_coordinator/DEPS b/chrome/browser/resource_coordinator/DEPS
index 61242b2..43f360d 100644
--- a/chrome/browser/resource_coordinator/DEPS
+++ b/chrome/browser/resource_coordinator/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
   # TODO(mash): Remove. http://crbug.com/723881
-  "+ash/multi_profile_uma.h",
   "+ash/shell.h",
   "+content/test/test_web_contents.h",
   "+services/resource_coordinator/public",
diff --git a/chrome/browser/resource_coordinator/discard_metrics_util.cc b/chrome/browser/resource_coordinator/discard_metrics_util.cc
new file mode 100644
index 0000000..51384ad
--- /dev/null
+++ b/chrome/browser/resource_coordinator/discard_metrics_util.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 "base/metrics/histogram_macros.h"
+
+namespace resource_coordinator {
+
+void RecordTabDiscarded() {
+  static int discard_count = 0;
+  UMA_HISTOGRAM_CUSTOM_COUNTS("TabManager.Discarding.DiscardCount",
+                              ++discard_count, 1, 1000, 50);
+}
+
+void RecordTabReloaded(base::TimeTicks last_active_time,
+                       base::TimeTicks discard_time,
+                       base::TimeTicks reload_time) {
+  static int reload_count = 0;
+  UMA_HISTOGRAM_CUSTOM_COUNTS("TabManager.Discarding.ReloadCount",
+                              ++reload_count, 1, 1000, 50);
+  auto discard_to_reload_time = reload_time - discard_time;
+  UMA_HISTOGRAM_CUSTOM_TIMES(
+      "TabManager.Discarding.DiscardToReloadTime", discard_to_reload_time,
+      base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(1), 100);
+  if (!last_active_time.is_null()) {
+    auto inactive_to_reload_time = reload_time - last_active_time;
+    UMA_HISTOGRAM_CUSTOM_TIMES(
+        "TabManager.Discarding.InactiveToReloadTime", inactive_to_reload_time,
+        base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(1), 100);
+  }
+}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/discard_metrics_util.h b/chrome/browser/resource_coordinator/discard_metrics_util.h
new file mode 100644
index 0000000..913cc21
--- /dev/null
+++ b/chrome/browser/resource_coordinator/discard_metrics_util.h
@@ -0,0 +1,25 @@
+// 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_RESOURCE_COORDINATOR_DISCARD_METRICS_UTIL_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_DISCARD_METRICS_UTIL_H_
+
+#include "base/time/time.h"
+
+namespace resource_coordinator {
+
+// Records histograms when a tab is discarded.
+void RecordTabDiscarded();
+
+// Records histograms when a discarded tab is reloaded. |last_active_time| is
+// the last time at which the tab was active. |discard_time| is the time at
+// which the tab was discarded. |reload_time| is the time at which the tab was
+// reloaded.
+void RecordTabReloaded(base::TimeTicks last_active_time,
+                       base::TimeTicks discard_time,
+                       base::TimeTicks reload_time);
+
+}  // namespace resource_coordinator
+
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_DISCARD_METRICS_UTIL_H_
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 30ca237..8fcb413 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -53,7 +53,9 @@
 #include "components/metrics/system_memory_stats_recorder.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/favicon_status.h"
 #include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -64,10 +66,7 @@
 #include "ui/gfx/geometry/rect.h"
 
 #if defined(OS_CHROMEOS)
-#include "ash/multi_profile_uma.h"
-#include "ash/shell.h"
 #include "chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h"
-#include "components/user_manager/user_manager.h"
 #endif
 
 using base::TimeDelta;
@@ -95,12 +94,11 @@
 // audible.
 const int kAudioProtectionTimeSeconds = 60;
 
-int FindWebContentsById(const TabStripModel* model,
-                        int64_t target_web_contents_id) {
+int FindWebContentsById(const TabStripModel* model, int32_t tab_id) {
   for (int idx = 0; idx < model->count(); idx++) {
     WebContents* web_contents = model->GetWebContentsAt(idx);
-    int64_t web_contents_id = TabManager::IdFromWebContents(web_contents);
-    if (web_contents_id == target_web_contents_id)
+    auto* data = TabManager::WebContentsData::FromWebContents(web_contents);
+    if (data && tab_id == data->id())
       return idx;
   }
 
@@ -313,13 +311,13 @@
   memory_pressure_listener_.reset();
 }
 
-int TabManager::FindTabStripModelById(int64_t target_web_contents_id,
+int TabManager::FindTabStripModelById(int32_t tab_id,
                                       TabStripModel** model) const {
   DCHECK(model);
 
   for (const auto& browser_info : GetBrowserInfoList()) {
     TabStripModel* local_model = browser_info.tab_strip_model;
-    int idx = FindWebContentsById(local_model, target_web_contents_id);
+    int idx = FindWebContentsById(local_model, tab_id);
     if (idx != -1) {
       *model = local_model;
       return idx;
@@ -354,7 +352,7 @@
 #endif  // defined(OS_CHROMEOS)
 
   TabStripModel* model;
-  const int idx = FindTabStripModelById(tab_stats.tab_contents_id, &model);
+  const int idx = FindTabStripModelById(tab_stats.id, &model);
 
   if (idx == -1)
     return false;
@@ -422,15 +420,15 @@
   DiscardTabImpl(condition);
 }
 
-WebContents* TabManager::DiscardTabById(int64_t target_web_contents_id,
+WebContents* TabManager::DiscardTabById(int32_t tab_id,
                                         DiscardCondition condition) {
   TabStripModel* model;
-  int index = FindTabStripModelById(target_web_contents_id, &model);
+  int index = FindTabStripModelById(tab_id, &model);
 
   if (index == -1)
     return nullptr;
 
-  VLOG(1) << "Discarding tab " << index << " id " << target_web_contents_id;
+  VLOG(1) << "Discarding tab " << index << " id " << tab_id;
 
   return DiscardWebContentsAt(index, model, condition);
 }
@@ -488,15 +486,20 @@
   return GetWebContentsData(contents)->IsAutoDiscardable();
 }
 
+void TabManager::SetTabAutoDiscardableState(int32_t tab_id, bool state) {
+  auto* web_contents = GetWebContentsById(tab_id);
+  if (web_contents)
+    SetTabAutoDiscardableState(web_contents, state);
+}
+
 void TabManager::SetTabAutoDiscardableState(content::WebContents* contents,
                                             bool state) {
   GetWebContentsData(contents)->SetAutoDiscardableState(state);
 }
 
-content::WebContents* TabManager::GetWebContentsById(
-    int64_t tab_contents_id) const {
+content::WebContents* TabManager::GetWebContentsById(int32_t tab_id) const {
   TabStripModel* model = nullptr;
-  int index = FindTabStripModelById(tab_contents_id, &model);
+  int index = FindTabStripModelById(tab_id, &model);
   if (index == -1)
     return nullptr;
   return model->GetWebContentsAt(index);
@@ -508,7 +511,7 @@
   for (auto& tab : tab_stats) {
     if (tab.child_process_host_id != render_process_id)
       continue;
-    WebContents* web_contents = GetWebContentsById(tab.tab_contents_id);
+    WebContents* web_contents = GetWebContentsById(tab.id);
     if (!web_contents)
       return false;
     if (IsMediaTab(web_contents))
@@ -557,8 +560,9 @@
 }
 
 // static
-int64_t TabManager::IdFromWebContents(WebContents* web_contents) {
-  return reinterpret_cast<int64_t>(web_contents);
+int32_t TabManager::IdFromWebContents(WebContents* web_contents) {
+  auto* data = GetWebContentsData(web_contents);
+  return data->id();
 }
 
 void TabManager::OnSessionRestoreStartedLoadingTabs() {
@@ -628,8 +632,7 @@
   // are likely to have open. Most of the benefit is the from NTP URL.
   const char* const kInternalPagePrefixes[] = {
       chrome::kChromeUIDownloadsURL, chrome::kChromeUIHistoryURL,
-      chrome::kChromeUINewTabURL, chrome::kChromeUISettingsURL,
-  };
+      chrome::kChromeUINewTabURL, chrome::kChromeUISettingsURL};
   // Prefix-match against the table above. Use strncmp to avoid allocating
   // memory to convert the URL prefix constants into std::strings.
   for (size_t i = 0; i < arraysize(kInternalPagePrefixes); ++i) {
@@ -646,14 +649,6 @@
   // TODO(jamescook): Maybe incorporate extension count?
   UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.Discard.TabCount", GetTabCount(), 1, 100,
                               50);
-#if defined(OS_CHROMEOS)
-  // Record the discarded tab in relation to the amount of simultaneously
-  // logged in users.
-  if (ash::Shell::HasInstance()) {
-    ash::MultiProfileUMA::RecordDiscardedTab(
-        user_manager::UserManager::Get()->GetLoggedInUsers().size());
-  }
-#endif
   // TODO(jamescook): If the time stats prove too noisy, then divide up users
   // based on how heavily they use Chrome using tab count as a proxy.
   // Bin into <= 1, <= 2, <= 4, <= 8, etc.
@@ -728,13 +723,22 @@
 #if defined(OS_CHROMEOS)
       stats.oom_score = delegate_->GetCachedOomScore(stats.renderer_handle);
 #endif
+      stats.tab_url = contents->GetLastCommittedURL().spec();
+      auto* commit = contents->GetController().GetLastCommittedEntry();
+      if (commit) {
+        const auto& favicon = commit->GetFavicon();
+        if (favicon.valid)
+          stats.favicon_url = favicon.url.spec();
+      }
       stats.title = contents->GetTitle();
-      stats.tab_contents_id = IdFromWebContents(contents);
+      stats.id = IdFromWebContents(contents);
       content::RenderFrameHost* render_frame = contents->GetMainFrame();
       DCHECK(render_frame);
       stats.has_beforeunload_handler =
           render_frame->GetSuddenTerminationDisablerState(
               blink::kBeforeUnloadHandler);
+      stats.is_auto_discardable =
+          GetWebContentsData(contents)->IsAutoDiscardable();
       stats_list->push_back(stats);
     }
   }
@@ -785,7 +789,7 @@
     if (!CanPurgeBackgroundedRenderer(tab.child_process_host_id))
       continue;
 
-    WebContents* content = GetWebContentsById(tab.tab_contents_id);
+    WebContents* content = GetWebContentsById(tab.id);
     if (!content)
       continue;
 
@@ -1025,8 +1029,9 @@
   return delta < TimeDelta::FromSeconds(kAudioProtectionTimeSeconds);
 }
 
+// static
 TabManager::WebContentsData* TabManager::GetWebContentsData(
-    content::WebContents* contents) const {
+    content::WebContents* contents) {
   WebContentsData::CreateForWebContents(contents);
   return WebContentsData::FromWebContents(contents);
 }
@@ -1044,8 +1049,7 @@
   for (TabStatsList::const_reverse_iterator stats_rit = stats.rbegin();
        stats_rit != stats.rend(); ++stats_rit) {
     if (CanDiscardTab(*stats_rit, condition)) {
-      WebContents* new_contents =
-          DiscardTabById(stats_rit->tab_contents_id, condition);
+      WebContents* new_contents = DiscardTabById(stats_rit->id, condition);
       if (new_contents)
         return new_contents;
     }
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 400125f..803351b 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -78,6 +78,10 @@
 // Note that the browser tests are only active for platforms that use
 // TabManager (CrOS only for now) and need to be adjusted accordingly if
 // support for new platforms is added.
+//
+// Tabs are identified by a unique ID vended by this component. These IDs are
+// not reused in a session. They are stable for a given conceptual tab, and will
+// follow it through discards, reloads, tab strip operations, etc.
 class TabManager : public TabStripModelObserver,
                    public chrome::BrowserListObserver {
  public:
@@ -122,7 +126,7 @@
   // tab-strip; clicking on it will reload it. Returns null if the tab cannot
   // be found or cannot be discarded. Otherwise returns the new web_contents
   // of the discarded tab.
-  content::WebContents* DiscardTabById(int64_t target_web_contents_id,
+  content::WebContents* DiscardTabById(int32_t tab_id,
                                        DiscardCondition condition);
 
   // Method used by the extensions API to discard tabs. If |contents| is null,
@@ -160,6 +164,7 @@
   bool IsTabAutoDiscardable(content::WebContents* contents) const;
 
   // Sets/clears the auto-discardable state of the tab.
+  void SetTabAutoDiscardableState(int32_t tab_id, bool state);
   void SetTabAutoDiscardableState(content::WebContents* contents, bool state);
 
   // Returns true when a given renderer can be purged if the specified
@@ -195,9 +200,9 @@
   // |second|.
   static bool CompareTabStats(const TabStats& first, const TabStats& second);
 
-  // Returns a unique ID for a WebContents. Do not cast back to a pointer, as
-  // the WebContents could be deleted if the user closed the tab.
-  static int64_t IdFromWebContents(content::WebContents* web_contents);
+  // Returns the unique ID associated with a tab given the |web_contents|
+  // currently backing that tab.
+  static int32_t IdFromWebContents(content::WebContents* web_contents);
 
   // Return whether tabs are being loaded during session restore.
   bool IsSessionRestoreLoadingTabs() const {
@@ -296,9 +301,8 @@
   const int kDefaultMinMaxTimeToPurgeRatio = 4;
 
   // Finds TabStripModel which has a WebContents whose id is the given
-  // web_contents_id, and returns the WebContents index and the TabStripModel.
-  int FindTabStripModelById(int64_t target_web_contents_id,
-                            TabStripModel** model) const;
+  // |tab_id|, and returns the WebContents index and the TabStripModel.
+  int FindTabStripModelById(int32_t tab_id, TabStripModel** model) const;
 
   // Called by WebContentsData whenever the discard state of a WebContents
   // changes, so that observers can be informed.
@@ -337,8 +341,8 @@
   // that need to be run periodically (see comment in implementation).
   void UpdateTimerCallback();
 
-  // Returns WebContents whose contents id matches the given tab_contents_id.
-  content::WebContents* GetWebContentsById(int64_t tab_contents_id) const;
+  // Returns WebContents whose contents id matches the given |tab_id|.
+  content::WebContents* GetWebContentsById(int32_t tab_id) const;
 
   // Returns a random time-to-purge whose min value is min_time_to_purge and max
   // value is max_time_to_purge.
@@ -399,7 +403,7 @@
 
   // Returns the WebContentsData associated with |contents|. Also takes care of
   // creating one if needed.
-  WebContentsData* GetWebContentsData(content::WebContents* contents) const;
+  static WebContentsData* GetWebContentsData(content::WebContents* contents);
 
   // Implementation of DiscardTab. Returns null if no tab was discarded.
   // Otherwise returns the new web_contents of the discarded tab.
diff --git a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
index 53c6111..5523aa41 100644
--- a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
@@ -611,7 +611,7 @@
                                  DiscardCondition condition) {
   // Check |tab_manager_| is alive before taking tabs into consideration.
   return tab_manager_ && tab_manager_->CanDiscardTab(tab_stats, condition) &&
-         tab_manager_->DiscardTabById(tab_stats.tab_contents_id, condition);
+         tab_manager_->DiscardTabById(tab_stats.id, condition);
 }
 
 chromeos::DebugDaemonClient* TabManagerDelegate::GetDebugDaemonClient() {
diff --git a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc
index 353bc64b..f60ca9be 100644
--- a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc
@@ -43,20 +43,20 @@
                              kNotFocused, 150);
 
   TabStats tab1, tab2, tab3, tab4, tab5;
-  tab1.tab_contents_id = 100;
+  tab1.id = 100;
   tab1.is_pinned = true;
 
-  tab2.tab_contents_id = 200;
+  tab2.id = 200;
   tab2.is_internal_page = true;
 
-  tab3.tab_contents_id = 300;
+  tab3.id = 300;
   tab3.is_pinned = true;
   tab3.is_media = true;
 
-  tab4.tab_contents_id = 400;
+  tab4.id = 400;
   tab4.is_media = true;
 
-  tab5.tab_contents_id = 500;
+  tab5.id = 500;
   tab5.is_app = true;
   TabStatsList tab_list = {tab1, tab2, tab3, tab4, tab5};
 
@@ -79,19 +79,19 @@
   EXPECT_EQ("service", candidates[3].app()->process_name());
   // pinned and media.
   ASSERT_TRUE(candidates[4].tab());
-  EXPECT_EQ(300, candidates[4].tab()->tab_contents_id);
+  EXPECT_EQ(300, candidates[4].tab()->id);
   // media.
   ASSERT_TRUE(candidates[5].tab());
-  EXPECT_EQ(400, candidates[5].tab()->tab_contents_id);
+  EXPECT_EQ(400, candidates[5].tab()->id);
   // pinned.
   ASSERT_TRUE(candidates[6].tab());
-  EXPECT_EQ(100, candidates[6].tab()->tab_contents_id);
+  EXPECT_EQ(100, candidates[6].tab()->id);
   // chrome app.
   ASSERT_TRUE(candidates[7].tab());
-  EXPECT_EQ(500, candidates[7].tab()->tab_contents_id);
+  EXPECT_EQ(500, candidates[7].tab()->id);
   // internal page.
   ASSERT_TRUE(candidates[8].tab());
-  EXPECT_EQ(200, candidates[8].tab()->tab_contents_id);
+  EXPECT_EQ(200, candidates[8].tab()->id);
 }
 
 // Occasionally, Chrome sees both FOCUSED_TAB and FOCUSED_APP at the same time.
@@ -101,7 +101,7 @@
   arc_processes.emplace_back(1, 10, "focused", arc::mojom::ProcessState::TOP,
                              kIsFocused, 100);
   TabStats tab1;
-  tab1.tab_contents_id = 100;
+  tab1.id = 100;
   tab1.is_pinned = true;
   tab1.is_in_active_window = true;
   tab1.is_active = true;
@@ -112,7 +112,7 @@
   ASSERT_EQ(2U, candidates.size());
   // FOCUSED_TAB should be the first one.
   ASSERT_TRUE(candidates[0].tab());
-  EXPECT_EQ(100, candidates[0].tab()->tab_contents_id);
+  EXPECT_EQ(100, candidates[0].tab()->id);
   ASSERT_TRUE(candidates[1].app());
   EXPECT_EQ("focused", candidates[1].app()->process_name());
 }
@@ -160,7 +160,7 @@
   }
 
   bool KillTab(const TabStats& tab_stats, DiscardCondition condition) override {
-    killed_tabs_.push_back(tab_stats.tab_contents_id);
+    killed_tabs_.push_back(tab_stats.id);
     return true;
   }
 
@@ -372,24 +372,24 @@
   TabStats tab1, tab2, tab3, tab4, tab5;
   tab1.is_pinned = true;
   tab1.renderer_handle = 11;
-  tab1.tab_contents_id = 1;
+  tab1.id = 1;
 
   tab2.is_internal_page = true;
   tab2.renderer_handle = 11;
-  tab2.tab_contents_id = 2;
+  tab2.id = 2;
 
   tab3.is_pinned = true;
   tab3.is_media = true;
   tab3.renderer_handle = 12;
-  tab3.tab_contents_id = 3;
+  tab3.id = 3;
 
   tab4.is_media = true;
   tab4.renderer_handle = 12;
-  tab4.tab_contents_id = 4;
+  tab4.id = 4;
 
   tab5.is_app = true;
   tab5.renderer_handle = 12;
-  tab5.tab_contents_id = 5;
+  tab5.id = 5;
   TabStatsList tab_list = {tab1, tab2, tab3, tab4, tab5};
 
   // Sorted order (by GetSortedCandidates):
@@ -399,11 +399,11 @@
   // app "visible2"    pid: 40  nspid 4
   // app "not-visible" pid: 50  nspid 5
   // app "service"     pid: 30  nspid 3
-  // tab3              pid: 12  tab_contents_id 3
-  // tab4              pid: 12  tab_contents_id 4
-  // tab1              pid: 11  tab_contents_id 1
-  // tab5              pid: 12  tab_contents_id 5
-  // tab2              pid: 11  tab_contents_id 2
+  // tab3              pid: 12  id 3
+  // tab4              pid: 12  id 4
+  // tab1              pid: 11  id 1
+  // tab5              pid: 12  id 5
+  // tab2              pid: 11  id 2
   memory_stat->SetTargetMemoryToFreeKB(250000);
   // Entities to be killed.
   memory_stat->SetProcessPss(11, 50000);
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 2c3696d..5f54094f 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -651,14 +651,10 @@
 
   ASSERT_EQ(4U, tab_stats.size());
 
-  EXPECT_EQ(tab_stats[0].tab_contents_id,
-            tab_manager.IdFromWebContents(web_contents1a));
-  EXPECT_EQ(tab_stats[1].tab_contents_id,
-            tab_manager.IdFromWebContents(web_contents1b));
-  EXPECT_EQ(tab_stats[2].tab_contents_id,
-            tab_manager.IdFromWebContents(web_contents2a));
-  EXPECT_EQ(tab_stats[3].tab_contents_id,
-            tab_manager.IdFromWebContents(web_contents2b));
+  EXPECT_EQ(tab_stats[0].id, tab_manager.IdFromWebContents(web_contents1a));
+  EXPECT_EQ(tab_stats[1].id, tab_manager.IdFromWebContents(web_contents1b));
+  EXPECT_EQ(tab_stats[2].id, tab_manager.IdFromWebContents(web_contents2a));
+  EXPECT_EQ(tab_stats[3].id, tab_manager.IdFromWebContents(web_contents2b));
 
   EXPECT_TRUE(tab_stats[0].is_in_visible_window);
   EXPECT_TRUE(tab_stats[1].is_in_visible_window);
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
index 50d3e01..9e41cc5e 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
@@ -7,6 +7,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/time/tick_clock.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/resource_coordinator/discard_metrics_util.h"
 #include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "chrome/browser/resource_coordinator/tab_manager_stats_collector.h"
 #include "chrome/browser/resource_coordinator/time.h"
@@ -122,38 +123,22 @@
   return tab_data_.is_discarded;
 }
 
-void TabManager::WebContentsData::SetDiscardState(bool state) {
-  if (tab_data_.is_discarded == state)
+void TabManager::WebContentsData::SetDiscardState(bool is_discarded) {
+  if (tab_data_.is_discarded == is_discarded)
     return;
 
-  if (!state) {
-    static int reload_count = 0;
-    tab_data_.last_reload_time = NowTicks();
-    UMA_HISTOGRAM_CUSTOM_COUNTS("TabManager.Discarding.ReloadCount",
-                                ++reload_count, 1, 1000, 50);
-    auto delta = tab_data_.last_reload_time - tab_data_.last_discard_time;
-    // Capped to one day for now, will adjust if necessary.
-    UMA_HISTOGRAM_CUSTOM_TIMES("TabManager.Discarding.DiscardToReloadTime",
-                               delta, base::TimeDelta::FromSeconds(1),
-                               base::TimeDelta::FromDays(1), 100);
-
-    if (!tab_data_.last_inactive_time.is_null()) {
-      delta = tab_data_.last_reload_time - tab_data_.last_inactive_time;
-      UMA_HISTOGRAM_CUSTOM_TIMES("TabManager.Discarding.InactiveToReloadTime",
-                                 delta, base::TimeDelta::FromSeconds(1),
-                                 base::TimeDelta::FromDays(1), 100);
-    }
-
-  } else {
-    static int discard_count = 0;
-    UMA_HISTOGRAM_CUSTOM_COUNTS("TabManager.Discarding.DiscardCount",
-                                ++discard_count, 1, 1000, 50);
+  if (is_discarded) {
     tab_data_.last_discard_time = NowTicks();
+    RecordTabDiscarded();
+  } else {
+    tab_data_.last_reload_time = NowTicks();
+    RecordTabReloaded(tab_data_.last_inactive_time, tab_data_.last_discard_time,
+                      tab_data_.last_reload_time);
   }
 
-  tab_data_.is_discarded = state;
+  tab_data_.is_discarded = is_discarded;
   g_browser_process->GetTabManager()->OnDiscardedStateChange(web_contents(),
-                                                             state);
+                                                             is_discarded);
 }
 
 int TabManager::WebContentsData::DiscardCount() {
@@ -221,16 +206,20 @@
 }
 
 TabManager::WebContentsData::Data::Data()
-    : is_discarded(false),
+    : id(0),
+      is_discarded(false),
       discard_count(0),
       is_recently_audible(false),
       is_auto_discardable(true),
       tab_loading_state(TAB_IS_NOT_LOADING),
       is_in_session_restore(false),
-      is_restored_in_foreground(false) {}
+      is_restored_in_foreground(false) {
+  static int32_t next_id = 0;
+  id = ++next_id;
+}
 
 bool TabManager::WebContentsData::Data::operator==(const Data& right) const {
-  return is_discarded == right.is_discarded &&
+  return id == right.id && is_discarded == right.is_discarded &&
          is_recently_audible == right.is_recently_audible &&
          last_audio_change_time == right.last_audio_change_time &&
          last_discard_time == right.last_discard_time &&
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
index 94cfb4d1..2f91896 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
@@ -67,7 +67,7 @@
   bool IsDiscarded();
 
   // Sets/clears the discard state of the tab.
-  void SetDiscardState(bool state);
+  void SetDiscardState(bool is_discarded);
 
   // Returns the number of times the tab has been discarded.
   int DiscardCount();
@@ -146,6 +146,8 @@
     return tab_data_.is_restored_in_foreground;
   }
 
+  int32_t id() const { return tab_data_.id; }
+
  private:
   // Needed to access tab_data_.
   FRIEND_TEST_ALL_PREFIXES(TabManagerWebContentsDataTest, CopyState);
@@ -156,6 +158,10 @@
     bool operator==(const Data& right) const;
     bool operator!=(const Data& right) const;
 
+    // Unique ID associated with this tab. This stays constant through discards
+    // and reloads, and is independent of the underlying WebContents and
+    // TabStripModel index, both of which may change.
+    int32_t id;
     // Is the tab currently discarded?
     bool is_discarded;
     // Number of times the tab has been discarded.
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
index 487e4a6..05a60fee 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
@@ -111,12 +111,12 @@
 TEST_F(TabManagerWebContentsDataTest, CopyState) {
   std::unique_ptr<WebContents> web_contents2;
   auto* tab_data2 = CreateWebContentsAndTabData(&web_contents2);
-
-  EXPECT_EQ(tab_data()->tab_data_, tab_data2->tab_data_);
-  tab_data()->IncrementDiscardCount();
-  tab_data()->SetDiscardState(true);
+  // TabManagerWebContentsData are initially distinct as they each have unique
+  // IDs assigned to them at construction time.
   EXPECT_NE(tab_data()->tab_data_, tab_data2->tab_data_);
 
+  // Copying the state should bring the ID along with it, so they should have
+  // identical content afterwards.
   TabManager::WebContentsData::CopyState(tab_data()->web_contents(),
                                          tab_data2->web_contents());
   EXPECT_EQ(tab_data()->tab_data_, tab_data2->tab_data_);
diff --git a/chrome/browser/resource_coordinator/tab_stats.h b/chrome/browser/resource_coordinator/tab_stats.h
index 2156a0b..77aa50b 100644
--- a/chrome/browser/resource_coordinator/tab_stats.h
+++ b/chrome/browser/resource_coordinator/tab_stats.h
@@ -47,11 +47,15 @@
   content::RenderProcessHost* render_process_host = nullptr;
   base::ProcessHandle renderer_handle = 0;
   int child_process_host_id = 0;
+  std::string tab_url;
+  std::string favicon_url;
   base::string16 title;
 #if defined(OS_CHROMEOS)
   int oom_score = 0;
 #endif
-  int64_t tab_contents_id = 0;  // Unique ID per WebContents.
+  // Unique ID for the tab. This is constant across discards/reloads and
+  // tab strip model manipulations.
+  int32_t id = 0;
   bool is_auto_discardable = true;
 };
 
diff --git a/chrome/browser/resources/discards/.eslintrc.js b/chrome/browser/resources/discards/.eslintrc.js
new file mode 100644
index 0000000..847d6e995
--- /dev/null
+++ b/chrome/browser/resources/discards/.eslintrc.js
@@ -0,0 +1,13 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module.exports = {
+  'env': {
+    'browser': true,
+    'es6': true,
+  },
+  'rules': {
+    'no-var': 'error',
+  },
+};
diff --git a/chrome/browser/resources/discards/OWNERS b/chrome/browser/resources/discards/OWNERS
new file mode 100644
index 0000000..ba3619f
--- /dev/null
+++ b/chrome/browser/resources/discards/OWNERS
@@ -0,0 +1 @@
+file://chrome/services/resource_coordinator/OWNERS
diff --git a/chrome/browser/resources/discards/discards.css b/chrome/browser/resources/discards/discards.css
new file mode 100644
index 0000000..b5a9650
--- /dev/null
+++ b/chrome/browser/resources/discards/discards.css
@@ -0,0 +1,84 @@
+/* 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. */
+
+table {
+  border-collapse: collapse;
+}
+
+table td,
+table th {
+  border: 1px solid #777;
+  padding-left: 4px;
+  padding-right: 4px;
+}
+
+table th {
+  -webkit-padding-end: 16px;
+  background: rgb(224, 236, 255);
+  cursor: pointer;
+  padding-bottom: 4px;
+  padding-top: 4px;
+  white-space: nowrap;
+}
+
+table td.title-cell {
+  max-width: 200px;
+  overflow: hidden;
+  white-space: nowrap;
+}
+
+table td div.title-cell-container {
+  align-items: center;
+  display: flex;
+  justify-content: flex-start;
+}
+
+table td div.favicon-div {
+  height: 16px;
+  margin: 3px;
+  padding: 0;
+  width: 16px;
+}
+
+table td div.favicon-div img {
+  height: 16px;
+  width: 16px;
+}
+
+table td div.title-div {
+  margin: 0;
+  overflow: hidden;
+  padding: 0;
+  white-space: nowrap;
+}
+
+table td.tab-url-cell {
+  max-width: 200px;
+  overflow: hidden;
+  white-space: nowrap;
+}
+
+table td.boolean-cell,
+table td.discard-count-cell {
+  text-align: center;
+}
+
+table td div.is-auto-discardable-link,
+table td.discard-links-cell {
+  font-size: 0.6rem;
+}
+
+table tr:hover {
+  background: rgb(255, 255, 187);
+}
+
+th.sort-column::after {
+  content: 'â–²';
+  position: absolute;
+}
+
+th[data-sort-reverse].sort-column::after {
+  content: 'â–¼';
+  position: absolute;
+}
diff --git a/chrome/browser/resources/discards/discards.html b/chrome/browser/resources/discards/discards.html
new file mode 100644
index 0000000..aaa29306
--- /dev/null
+++ b/chrome/browser/resources/discards/discards.html
@@ -0,0 +1,84 @@
+<!--
+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.
+
+This is an internal only page meant for debugging. It is not intended for
+general use and is not localized.
+-->
+<!doctype html>
+<html lang="en">
+  <head>
+    <title>Discards</title>
+    <meta charset="utf-8">
+    <link rel="stylesheet" href="chrome://resources/css/action_link.css">
+    <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+    <script src="chrome://resources/js/cr.js"></script>
+    <script src="chrome://resources/js/mojo_bindings.js"></script>
+    <script src="chrome://resources/js/util.js"></script>
+    <script src="chrome/browser/ui/webui/discards/discards.mojom.js"></script>
+    <script src="discards.js"></script>
+    <link rel="stylesheet" type="text/css" href="discards.css">
+  </head>
+  <body>
+    <h1>Discards</h1>
+    <div is="action-link" id="discard-now-link">
+      [Discard a tab now]
+    </div>
+    <div is="action-link" id="discard-now-urgent-link">
+      [Urgent discard a tab now]
+    </div>
+    <table id="tab-discard-info-table">
+      <thead>
+        <tr id="tab-discards-info-table-header">
+          <th data-sort-key="utilityRank" class="sort-column">Utility Rank</th>
+          <th data-sort-key="title">Tab Title</th>
+          <th data-sort-key="tabUrl">Tab URL</th>
+          <th data-sort-key="isApp">App</th>
+          <th data-sort-key="isInternal">Internal</th>
+          <th data-sort-key="isMedia">Media</th>
+          <th data-sort-key="isPinned">Pinned</th>
+          <th data-sort-key="isDiscarded">Discarded</th>
+          <th data-sort-key="discardCount">Discard Count</th>
+          <th data-sort-key="isAutoDiscardable">Auto Discardable</th>
+          <th data-sort-key="lastActiveSeconds">Last Active</th>
+        </tr>
+      </thead>
+      <tbody id="tab-discards-info-table-body">
+      </tbody>
+    </table>
+    <template id="tab-discard-info-row">
+      <tr>
+        <td class="utility-rank-cell"></td>
+        <td class="title-cell">
+          <div class="title-cell-container">
+            <div class="favicon-div">
+              <img class="favicon" alt="FavIcon">
+            </div>
+            <div class="title-div"></div>
+          </div>
+        </td>
+        <td class="tab-url-cell"></td>
+        <td class="is-app-cell boolean-cell"></td>
+        <td class="is-internal-cell boolean-cell"></td>
+        <td class="is-media-cell boolean-cell"></td>
+        <td class="is-pinned-cell boolean-cell"></td>
+        <td class="is-discarded-cell boolean-cell"></td>
+        <td class="discard-count-cell"></td>
+        <td class="is-auto-discardable-cell boolean-cell">
+          <div class="is-auto-discardable-div"></div>
+          <div is="action-link" class="is-auto-discardable-link">
+            Toggle
+          </div>
+        </td>
+        <td class="last-active-cell"></td>
+        <td class="discard-links-cell">
+          <div is="action-link" class="discard-link">[Discard]</div>
+          <div is="action-link" class="discard-urgent-link">
+            [Urgent Discard]
+          </div>
+        </td>
+      </tr>
+    </template>
+  </body>
+</html>
diff --git a/chrome/browser/resources/discards/discards.js b/chrome/browser/resources/discards/discards.js
new file mode 100644
index 0000000..210abe9
--- /dev/null
+++ b/chrome/browser/resources/discards/discards.js
@@ -0,0 +1,433 @@
+// 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.
+
+cr.define('discards', function() {
+  'use strict';
+
+  // The following variables are initialized by 'initialize'.
+  // Points to the Mojo WebUI handler.
+  let uiHandler;
+  // After initialization this points to the discard info table body.
+  let tabDiscardsInfoTableBody;
+  // This holds the sorted tab discard infos as retrieved from the uiHandler.
+  let infos;
+  // Holds information about the current sorting of the table.
+  let sortKey;
+  let sortReverse;
+  // Points to the timer that refreshes the table content.
+  let updateTimer;
+
+  // Specifies the update interval of the page, in ms.
+  const UPDATE_INTERVAL_MS = 1000;
+
+  /**
+   * Ensures the discards info table has the appropriate length. Decorates
+   * newly created rows with a 'row-index' attribute to enable event listeners
+   * to quickly determine the index of the row.
+   */
+  function ensureTabDiscardsInfoTableLength() {
+    let rows = tabDiscardsInfoTableBody.querySelectorAll('tr');
+    if (rows.length < infos.length) {
+      for (let i = rows.length; i < infos.length; ++i) {
+        let row = createEmptyTabDiscardsInfoTableRow();
+        row.setAttribute('data-row-index', i.toString());
+        tabDiscardsInfoTableBody.appendChild(row);
+      }
+    } else if (rows.length > infos.length) {
+      for (let i = infos.length; i < rows.length; ++i) {
+        tabDiscardsInfoTableBody.removeChild(rows[i]);
+      }
+    }
+  }
+
+  /**
+   * Compares two TabDiscardsInfos based on the data in the provided sort-key.
+   * @param {string} sortKey The key of the sort. See the "data-sort-key"
+   *     attribute of the table headers for valid sort-keys.
+   * @param {boolean|number|string} a The first value being compared.
+   * @param {boolean|number|string} b The second value being compared.
+   * @return {number} A negative number if a < b, 0 if a == b, and a positive
+   *     number if a > b.
+   */
+  function compareTabDiscardsInfos(sortKey, a, b) {
+    let val1 = a[sortKey];
+    let val2 = b[sortKey];
+
+    // Compares strings.
+    if (sortKey == 'title' || sortKey == 'tabUrl') {
+      val1 = val1.toLowerCase();
+      val2 = val2.toLowerCase();
+      if (val1 == val2)
+        return 0;
+      return val1 > val2 ? 1 : -1;
+    }
+
+    // Compares boolean fields.
+    if ([
+          'isApp', 'isInternal', 'isMedia', 'isPinned', 'isDiscarded',
+          'isAutoDiscardable'
+        ].includes(sortKey)) {
+      if (val1 == val2)
+        return 0;
+      return val1 ? 1 : -1;
+    }
+
+    // Compares numeric fields.
+    if (['discardCount', 'utilityRank', 'lastActiveSeconds'].includes(
+            sortKey)) {
+      return val1 - val2;
+    }
+
+    assertNotReached('Unsupported sort key: ' + sortKey);
+    return 0;
+  }
+
+  /**
+   * Sorts the tab discards info data in |infos| according to the current
+   * |sortKey|.
+   */
+  function sortTabDiscardsInfoTable() {
+    infos = infos.sort((a, b) => {
+      return (sortReverse ? -1 : 1) * compareTabDiscardsInfos(sortKey, a, b);
+    });
+  }
+
+  /**
+   * Pluralizes a string according to the given count. Assumes that appending an
+   * 's' is sufficient to make a string plural.
+   * @param {string} s The string to be made plural if necessary.
+   * @param {number} n The count of the number of ojects.
+   * @return {string} The plural version of |s| if n != 1, otherwise |s|.
+   */
+  function maybeMakePlural(s, n) {
+    return n == 1 ? s : s + 's';
+  }
+
+  /**
+   * Converts a |secondsAgo| last-active time to a user friendly string.
+   * @param {number} secondsAgo The amount of time since the tab was active.
+   * @return {string} An English string representing the last active time.
+   */
+  function lastActiveToString(secondsAgo) {
+    // These constants aren't perfect, but close enough.
+    const SECONDS_PER_MINUTE = 60;
+    const MINUTES_PER_HOUR = 60;
+    const SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
+    const HOURS_PER_DAY = 24;
+    const SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
+    const DAYS_PER_WEEK = 7;
+    const SECONDS_PER_WEEK = SECONDS_PER_DAY * DAYS_PER_WEEK;
+    const SECONDS_PER_MONTH = SECONDS_PER_DAY * 30.5;
+    const SECONDS_PER_YEAR = SECONDS_PER_DAY * 365;
+
+    // Seconds ago.
+    if (secondsAgo < SECONDS_PER_MINUTE)
+      return 'just now';
+
+    // Minutes ago.
+    let minutesAgo = Math.floor(secondsAgo / SECONDS_PER_MINUTE);
+    if (minutesAgo < MINUTES_PER_HOUR) {
+      return minutesAgo.toString() + maybeMakePlural(' minute', minutesAgo) +
+          ' ago';
+    }
+
+    // Hours and minutes and ago.
+    let hoursAgo = Math.floor(secondsAgo / SECONDS_PER_HOUR);
+    minutesAgo = minutesAgo % MINUTES_PER_HOUR;
+    if (hoursAgo < HOURS_PER_DAY) {
+      let s = hoursAgo.toString() + maybeMakePlural(' hour', hoursAgo);
+      if (minutesAgo > 0) {
+        s += ' and ' + minutesAgo.toString() +
+            maybeMakePlural(' minute', minutesAgo);
+      }
+      s += ' ago';
+      return s;
+    }
+
+    // Days ago.
+    let daysAgo = Math.floor(secondsAgo / SECONDS_PER_DAY);
+    if (daysAgo < DAYS_PER_WEEK) {
+      return daysAgo.toString() + maybeMakePlural(' day', daysAgo) + ' ago';
+    }
+
+    // Weeks ago. There's an awkward gap to bridge where 4 weeks can have
+    // elapsed but not quite 1 month. Be sure to use weeks to report that.
+    let weeksAgo = Math.floor(secondsAgo / SECONDS_PER_WEEK);
+    let monthsAgo = Math.floor(secondsAgo / SECONDS_PER_MONTH);
+    if (monthsAgo < 1) {
+      return 'over ' + weeksAgo.toString() +
+          maybeMakePlural(' week', weeksAgo) + ' ago';
+    }
+
+    // Months ago.
+    let yearsAgo = Math.floor(secondsAgo / SECONDS_PER_YEAR);
+    if (yearsAgo < 1) {
+      return 'over ' + monthsAgo.toString() +
+          maybeMakePlural(' month', monthsAgo) + ' ago';
+    }
+
+    // Years ago.
+    return 'over ' + yearsAgo.toString() + maybeMakePlural(' year', yearsAgo) +
+        ' ago';
+  }
+
+  /**
+   * Returns a string representation of a boolean value for display in a table.
+   * @param {boolean} bool A boolean value.
+   * @return {string} A string representing the bool.
+   */
+  function boolToString(bool) {
+    return bool ? '✔' : '\xa0';
+  }
+
+  /**
+   * Returns the index of the row in the table that houses the given |element|.
+   * @param {HTMLElement} element Any element in the DOM.
+   */
+  function getRowIndex(element) {
+    let row = element.closest('tr');
+    return parseInt(row.getAttribute('data-row-index'), 10);
+  }
+
+  /**
+   * Creates an empty tab discards table row with action-link listeners, etc.
+   * By default the links are inactive.
+   */
+  function createEmptyTabDiscardsInfoTableRow() {
+    let template = $('tab-discard-info-row');
+    let content = document.importNode(template.content, true);
+    let row = content.querySelector('tr');
+
+    // Set up the listener for the auto-discardable toggle action.
+    let isAutoDiscardable = row.querySelector('.is-auto-discardable-link');
+    isAutoDiscardable.setAttribute('disabled', '');
+    isAutoDiscardable.addEventListener('click', (e) => {
+      // Get the info backing this row.
+      let info = infos[getRowIndex(e.target)];
+      // Disable the action. The update function is responsible for
+      // re-enabling actions if necessary.
+      e.target.setAttribute('disabled', '');
+      // Perform the action.
+      uiHandler.setAutoDiscardable(info.id, !info.isAutoDiscardable)
+          .then(stableUpdateTabDiscardsInfoTable());
+    });
+
+    // Set up the listeners for discard links.
+    let discardListener = function(e) {
+      // Get the info backing this row.
+      let info = infos[getRowIndex(e.target)];
+      // Determine whether this is urgent or not.
+      let urgent = e.target.classList.contains('discard-urgent-link');
+      // Disable the action. The update function is responsible for
+      // re-enabling actions if necessary.
+      e.target.setAttribute('disabled', '');
+      // Perform the action.
+      uiHandler.discardById(info.id, urgent).then((response) => {
+        stableUpdateTabDiscardsInfoTable();
+      });
+    };
+    let discardLink = row.querySelector('.discard-link');
+    let discardUrgentLink = row.querySelector('.discard-urgent-link');
+    discardLink.addEventListener('click', discardListener);
+    discardUrgentLink.addEventListener('click', discardListener);
+
+    return row;
+  }
+
+  /**
+   * Updates a tab discards info table row in place. Sets/unsets 'disabled'
+   * attributes on action-links as necessary, and populates all contents.
+   */
+  function updateTabDiscardsInfoTableRow(row, info) {
+    // Update the content.
+    row.querySelector('.utility-rank-cell').textContent =
+        info.utilityRank.toString();
+    row.querySelector('.favicon').src =
+        info.faviconUrl ? info.faviconUrl : 'chrome://favicon';
+    row.querySelector('.title-div').textContent = info.title;
+    row.querySelector('.tab-url-cell').textContent = info.tabUrl;
+    row.querySelector('.is-app-cell').textContent = boolToString(info.isApp);
+    row.querySelector('.is-internal-cell').textContent =
+        boolToString(info.isInternal);
+    row.querySelector('.is-media-cell').textContent =
+        boolToString(info.isMedia);
+    row.querySelector('.is-pinned-cell').textContent =
+        boolToString(info.isPinned);
+    row.querySelector('.is-discarded-cell').textContent =
+        boolToString(info.isDiscarded);
+    row.querySelector('.discard-count-cell').textContent =
+        info.discardCount.toString();
+    row.querySelector('.is-auto-discardable-div').textContent =
+        boolToString(info.isAutoDiscardable);
+    row.querySelector('.last-active-cell').textContent =
+        lastActiveToString(info.lastActiveSeconds);
+
+    // Enable/disable action links as appropriate.
+    row.querySelector('.is-auto-discardable-link').removeAttribute('disabled');
+    let discardLink = row.querySelector('.discard-link');
+    let discardUrgentLink = row.querySelector('.discard-urgent-link');
+    if (info.isDiscarded) {
+      discardLink.setAttribute('disabled', '');
+      discardUrgentLink.setAttribute('disabled', '');
+    } else {
+      discardLink.removeAttribute('disabled');
+      discardUrgentLink.removeAttribute('disabled');
+    }
+  }
+
+  /**
+   * Causes the discards info table to be rendered. Reuses existing table rows
+   * in place to minimize disruption to the page.
+   */
+  function renderTabDiscardsInfoTable() {
+    ensureTabDiscardsInfoTableLength();
+    let rows = tabDiscardsInfoTableBody.querySelectorAll('tr');
+    for (let i = 0; i < infos.length; ++i)
+      updateTabDiscardsInfoTableRow(rows[i], infos[i]);
+  }
+
+  /**
+   * Causes the discard info table to be updated in as stable a manner as
+   * possible. That is, rows will stay in their relative positions, even if the
+   * current sort order is violated. Only the addition or removal of rows (tabs)
+   * can cause the layout to change.
+   */
+  function stableUpdateTabDiscardsInfoTableImpl() {
+    uiHandler.getTabDiscardsInfo().then((response) => {
+      let newInfos = response.infos;
+      let stableInfos = [];
+
+      // Update existing infos in place, remove old ones, and append new ones.
+      // This tries to keep the existing ordering stable so that clicking links
+      // is minimally disruptive.
+      for (let i = 0; i < infos.length; ++i) {
+        let oldInfo = infos[i];
+        let newInfo = null;
+        for (let j = 0; j < newInfos.length; ++j) {
+          if (newInfos[j].id == oldInfo.id) {
+            newInfo = newInfos[j];
+            break;
+          }
+        }
+
+        // Old infos that have corresponding new infos are pushed first, in the
+        // current order of the old infos.
+        if (newInfo != null)
+          stableInfos.push(newInfo);
+      }
+
+      // Make sure info about new tabs is appended to the end, in the order they
+      // were originally returned.
+      for (let i = 0; i < newInfos.length; ++i) {
+        let newInfo = newInfos[i];
+        let oldInfo = null;
+        for (let j = 0; j < infos.length; ++j) {
+          if (infos[j].id == newInfo.id) {
+            oldInfo = infos[j];
+            break;
+          }
+        }
+
+        // Entirely new information (has no corresponding old info) is appended
+        // to the end.
+        if (oldInfo == null)
+          stableInfos.push(newInfo);
+      }
+
+      // Swap out the current info with the new stably sorted information.
+      infos = stableInfos;
+
+      // Render the content in place.
+      renderTabDiscardsInfoTable();
+    });
+  }
+
+  /**
+   * A wrapper to stableUpdateTabDiscardsInfoTableImpl that is called due to
+   * user action and not due to the automatic timer. Cancels the existing timer
+   * and reschedules it after rendering instantaneously.
+   */
+  function stableUpdateTabDiscardsInfoTable() {
+    if (updateTimer)
+      clearInterval(updateTimer);
+    stableUpdateTabDiscardsInfoTableImpl();
+    updateTimer =
+        setInterval(stableUpdateTabDiscardsInfoTableImpl, UPDATE_INTERVAL_MS);
+  }
+
+  /**
+   * Initializes this page. Invoked by the DOMContentLoaded event.
+   */
+  function initialize() {
+    uiHandler = new mojom.DiscardsDetailsProviderPtr;
+    Mojo.bindInterface(
+        mojom.DiscardsDetailsProvider.name, mojo.makeRequest(uiHandler).handle);
+
+    tabDiscardsInfoTableBody = $('tab-discards-info-table-body');
+    infos = [];
+    sortKey = 'utilityRank';
+    sortReverse = false;
+    updateTimer = null;
+
+    // Set the column sort handlers.
+    let tabDiscardsInfoTableHeader = $('tab-discards-info-table-header');
+    let headers = tabDiscardsInfoTableHeader.children;
+    for (let header of headers) {
+      header.addEventListener('click', (e) => {
+        let newSortKey = e.target.dataset.sortKey;
+
+        // Skip columns that aren't explicitly labeled with a sort-key
+        // attribute.
+        if (newSortKey == null)
+          return;
+
+        // Reverse the sort key if the key itself hasn't changed.
+        if (sortKey == newSortKey) {
+          sortReverse = !sortReverse;
+        } else {
+          sortKey = newSortKey;
+          sortReverse = false;
+        }
+
+        // Undecorate the old sort column, and decorate the new one.
+        let oldSortColumn = document.querySelector('.sort-column');
+        oldSortColumn.classList.remove('sort-column');
+        e.target.classList.add('sort-column');
+        if (sortReverse)
+          e.target.setAttribute('data-sort-reverse', '');
+        else
+          e.target.removeAttribute('data-sort-reverse');
+
+        sortTabDiscardsInfoTable();
+        renderTabDiscardsInfoTable();
+      });
+    }
+
+    // Setup the "Discard a tab now" links.
+    let discardNow = $('discard-now-link');
+    let discardNowUrgent = $('discard-now-urgent-link');
+    let discardListener = function(e) {
+      e.target.setAttribute('disabled', '');
+      let urgent = e.target.id.includes('urgent');
+      uiHandler.discard(urgent).then(() => {
+        stableUpdateTabDiscardsInfoTable();
+        e.target.removeAttribute('disabled');
+      });
+    };
+    discardNow.addEventListener('click', discardListener);
+    discardNowUrgent.addEventListener('click', discardListener);
+
+    stableUpdateTabDiscardsInfoTable();
+  }
+
+  document.addEventListener('DOMContentLoaded', initialize);
+
+  // These functions are exposed on the 'discards' object created by
+  // cr.define. This allows unittesting of these functions.
+  return {
+    compareTabDiscardsInfos: compareTabDiscardsInfos,
+    lastActiveToString: lastActiveToString,
+    maybeMakePlural: maybeMakePlural
+  };
+});
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.css b/chrome/browser/resources/local_ntp/most_visited_single.css
index 6e51f66f..96742ea 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.css
+++ b/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -146,13 +146,14 @@
   box-shadow: 0 3px 8px 0 rgba(0,0,0,0.2), 0 0 0 1px rgba(0,0,0,0.08);
 }
 
-.mv-tile:focus {
-  -webkit-filter: brightness(92%);
+.mv-tile:focus,
+.mv-tile:focus-within {
+  filter: brightness(92%);
 }
 
 .mv-tile:active {
-  -webkit-filter: brightness(88%);
   box-shadow: 0 3px 8px 0 rgba(0,0,0,0.2), 0 0 0 1px rgba(0,0,0,0.12);
+  filter: brightness(88%);
 }
 
 .mv-tile.blacklisted {
diff --git a/chrome/browser/resources/md_extensions/item.html b/chrome/browser/resources/md_extensions/item.html
index 7a9974d..e41a24ad5 100644
--- a/chrome/browser/resources/md_extensions/item.html
+++ b/chrome/browser/resources/md_extensions/item.html
@@ -38,6 +38,7 @@
       #card {
         @apply(--shadow-elevation-2dp);
         background: white;
+        border-radius: 2px;
         display: flex;
         flex-direction: column;
         height: 160px;
@@ -88,8 +89,8 @@
       }
 
       #button-strip {
-        -webkit-padding-end: 4px;
-        -webkit-padding-start: var(--cr-section-padding);
+        /* Avoid ripple from overlapping container. */
+        -webkit-margin-end: 20px;
         border-top: var(--cr-separator-line);
         box-sizing: border-box;
         height: var(--cr-section-min-height);
@@ -98,7 +99,7 @@
       }
 
       #button-strip paper-button {
-        margin: 0 4px;
+        -webkit-margin-start: 8px;
       }
 
       #learn-more-link {
@@ -152,10 +153,6 @@
         display: block;
       }
 
-      cr-toggle {
-        -webkit-margin-end: 8px;  /* Avoid ripple from overlapping container. */
-      }
-
       .action-button {
         color: var(--google-blue-500);
       }
diff --git a/chrome/browser/safe_search_api/safe_search_url_checker.cc b/chrome/browser/safe_search_api/safe_search_url_checker.cc
index 7a271d3..308ecff 100644
--- a/chrome/browser/safe_search_api/safe_search_url_checker.cc
+++ b/chrome/browser/safe_search_api/safe_search_url_checker.cc
@@ -93,7 +93,7 @@
 struct SafeSearchURLChecker::Check {
   Check(const GURL& url,
         std::unique_ptr<net::URLFetcher> fetcher,
-        const CheckCallback& callback);
+        CheckCallback callback);
   ~Check();
 
   GURL url;
@@ -104,13 +104,18 @@
 
 SafeSearchURLChecker::Check::Check(const GURL& url,
                                    std::unique_ptr<net::URLFetcher> fetcher,
-                                   const CheckCallback& callback)
+                                   CheckCallback callback)
     : url(url),
       fetcher(std::move(fetcher)),
-      callbacks(1, callback),
-      start_time(base::TimeTicks::Now()) {}
+      start_time(base::TimeTicks::Now()) {
+  callbacks.push_back(std::move(callback));
+}
 
-SafeSearchURLChecker::Check::~Check() {}
+SafeSearchURLChecker::Check::~Check() {
+  for (const CheckCallback& callback : callbacks) {
+    DCHECK(!callback);
+  }
+}
 
 SafeSearchURLChecker::CheckResult::CheckResult(Classification classification,
                                                bool uncertain)
@@ -135,20 +140,19 @@
 
 SafeSearchURLChecker::~SafeSearchURLChecker() {}
 
-bool SafeSearchURLChecker::CheckURL(const GURL& url,
-                                    const CheckCallback& callback) {
+bool SafeSearchURLChecker::CheckURL(const GURL& url, CheckCallback callback) {
   // TODO(treib): Hack: For now, allow all Google URLs to save QPS. If we ever
   // remove this, we should find a way to allow at least the NTP.
   if (google_util::IsGoogleDomainUrl(url, google_util::ALLOW_SUBDOMAIN,
                                      google_util::ALLOW_NON_STANDARD_PORTS)) {
-    callback.Run(url, Classification::SAFE, false);
+    std::move(callback).Run(url, Classification::SAFE, false);
     return true;
   }
   // TODO(treib): Hack: For now, allow all YouTube URLs since YouTube has its
   // own Safety Mode anyway.
   if (google_util::IsYoutubeDomainUrl(url, google_util::ALLOW_SUBDOMAIN,
                                       google_util::ALLOW_NON_STANDARD_PORTS)) {
-    callback.Run(url, Classification::SAFE, false);
+    std::move(callback).Run(url, Classification::SAFE, false);
     return true;
   }
 
@@ -160,7 +164,7 @@
       DVLOG(1) << "Cache hit! " << url.spec() << " is "
                << (result.classification == Classification::UNSAFE ? "NOT" : "")
                << " safe; certain: " << !result.uncertain;
-      callback.Run(url, result.classification, result.uncertain);
+      std::move(callback).Run(url, result.classification, result.uncertain);
       return true;
     }
     DVLOG(1) << "Outdated cache entry for " << url.spec() << ", purging";
@@ -171,7 +175,7 @@
   for (const auto& check : checks_in_progress_) {
     if (check->url == url) {
       DVLOG(1) << "Adding to pending check for " << url.spec();
-      check->callbacks.push_back(callback);
+      check->callbacks.push_back(std::move(callback));
       return false;
     }
   }
@@ -182,7 +186,7 @@
       CreateFetcher(this, context_, api_key, url, traffic_annotation_));
   fetcher->Start();
   checks_in_progress_.push_back(
-      base::MakeUnique<Check>(url, std::move(fetcher), callback));
+      std::make_unique<Check>(url, std::move(fetcher), std::move(callback)));
   return false;
 }
 
@@ -200,7 +204,8 @@
   if (!status.is_success()) {
     DLOG(WARNING) << "URL request failed! Letting through...";
     for (size_t i = 0; i < check->callbacks.size(); i++)
-      check->callbacks[i].Run(check->url, Classification::SAFE, true);
+      std::move(check->callbacks[i])
+          .Run(check->url, Classification::SAFE, true);
     checks_in_progress_.erase(it);
     return;
   }
@@ -219,6 +224,6 @@
   cache_.Put(check->url, CheckResult(classification, uncertain));
 
   for (size_t i = 0; i < check->callbacks.size(); i++)
-    check->callbacks[i].Run(check->url, classification, uncertain);
+    std::move(check->callbacks[i]).Run(check->url, classification, uncertain);
   checks_in_progress_.erase(it);
 }
diff --git a/chrome/browser/safe_search_api/safe_search_url_checker.h b/chrome/browser/safe_search_api/safe_search_url_checker.h
index 7a7d6d1..078e881 100644
--- a/chrome/browser/safe_search_api/safe_search_url_checker.h
+++ b/chrome/browser/safe_search_api/safe_search_url_checker.h
@@ -31,7 +31,7 @@
   enum class Classification { SAFE, UNSAFE };
 
   // Returns whether |url| should be blocked. Called from CheckURL.
-  using CheckCallback = base::Callback<
+  using CheckCallback = base::OnceCallback<
       void(const GURL&, Classification classification, bool /* uncertain */)>;
 
   explicit SafeSearchURLChecker(
@@ -44,7 +44,7 @@
   ~SafeSearchURLChecker() override;
 
   // Returns whether |callback| was run synchronously.
-  bool CheckURL(const GURL& url, const CheckCallback& callback);
+  bool CheckURL(const GURL& url, CheckCallback callback);
 
   void SetCacheTimeoutForTesting(const base::TimeDelta& timeout) {
     cache_timeout_ = timeout;
diff --git a/chrome/browser/secure_origin_whitelist_browsertest.cc b/chrome/browser/secure_origin_whitelist_browsertest.cc
new file mode 100644
index 0000000..ddac0c34
--- /dev/null
+++ b/chrome/browser/secure_origin_whitelist_browsertest.cc
@@ -0,0 +1,75 @@
+// 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 "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+
+namespace {
+// SecureOriginWhitelistBrowsertests differ in the setup of the browser. Since
+// the setup is done before the actual test is run, we need to parameterize our
+// tests outside of the actual test bodies. We use test variants for this,
+// instead of the usual setup of mulitple tests.
+enum class TestVariant { kNone, kCommandline };
+}  // namespace
+
+// End-to-end browser test that ensures the secure origin whitelist works when
+// supplied via the command-line.
+// SecureOriginWhitelistUnittest will test the list parsing.
+class SecureOriginWhitelistBrowsertest
+    : public InProcessBrowserTest,
+      public testing::WithParamInterface<TestVariant> {
+ public:
+  void SetUpOnMainThread() override {
+    // We need this, so we can request the test page from 'http://foo.com'.
+    // (Which, unlike 127.0.0.1, is considered an insecure origin.)
+    host_resolver()->AddRule("*", "127.0.0.1");
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // We need to know the server port to know what to add to the command-line.
+    // The port number changes with every test run. Thus, we start the server
+    // here. And since all tests, not just the variant with the command-line,
+    // need the embedded server, we unconditionally start it here.
+    EXPECT_TRUE(embedded_test_server()->Start());
+
+    if (GetParam() != TestVariant::kCommandline)
+      return;
+
+    command_line->AppendSwitchASCII(
+        switches::kUnsafelyTreatInsecureOriginAsSecure, BaseURL());
+  }
+
+  bool ExpectSecureContext() { return GetParam() != TestVariant::kNone; }
+
+  std::string BaseURL() {
+    return embedded_test_server()->GetURL("example.com", "/").spec();
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(SecureOriginWhitelistBrowsertest,
+                        SecureOriginWhitelistBrowsertest,
+                        testing::Values(TestVariant::kNone,
+                                        TestVariant::kCommandline));
+
+IN_PROC_BROWSER_TEST_P(SecureOriginWhitelistBrowsertest, Simple) {
+  GURL url = embedded_test_server()->GetURL(
+      "example.com", "/secure_origin_whitelist_browsertest.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  base::string16 secure(base::ASCIIToUTF16("secure context"));
+  base::string16 insecure(base::ASCIIToUTF16("insecure context"));
+
+  content::TitleWatcher title_watcher(
+      browser()->tab_strip_model()->GetActiveWebContents(), secure);
+  title_watcher.AlsoWaitForTitle(insecure);
+
+  EXPECT_EQ(title_watcher.WaitAndGetTitle(),
+            ExpectSecureContext() ? secure : insecure);
+}
diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc
index a54217631..c32eea8 100644
--- a/chrome/browser/sessions/better_session_restore_browsertest.cc
+++ b/chrome/browser/sessions/better_session_restore_browsertest.cc
@@ -175,6 +175,7 @@
     test_files.push_back("post_with_password.html");
     test_files.push_back("session_cookies.html");
     test_files.push_back("session_storage.html");
+    test_files.push_back("subdomain_cookies.html");
     base::FilePath test_file_dir;
     CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &test_file_dir));
     test_file_dir =
@@ -870,3 +871,25 @@
   new_browser = QuitBrowserAndRestore(new_browser, true);
   StoreDataWithPage(new_browser, "cookies.html");
 }
+
+// Check that cookies are cleared on a wrench menu quit only if cookies are set
+// to current session only, regardless of whether background mode is enabled.
+IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest,
+                       SubdomainCookiesClearedOnCloseAllBrowsers) {
+  StoreDataWithPage("subdomain_cookies.html");
+
+  // Normally cookies are restored.
+  Browser* new_browser = QuitBrowserAndRestore(browser(), true);
+  NavigateAndCheckStoredData(new_browser, "subdomain_cookies.html");
+
+  // ... but not if the content setting is set to clear on exit.
+  auto cookie_settings =
+      CookieSettingsFactory::GetForProfile(new_browser->profile());
+  cookie_settings->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
+  cookie_settings->SetCookieSetting(GURL("http://www.test.com"),
+                                    CONTENT_SETTING_SESSION_ONLY);
+
+  // Cookie for .test.com is created on www.test.com and deleted on shutdown.
+  new_browser = QuitBrowserAndRestore(new_browser, true);
+  StoreDataWithPage(new_browser, "subdomain_cookies.html");
+}
diff --git a/chrome/browser/sessions/session_data_deleter.cc b/chrome/browser/sessions/session_data_deleter.cc
index 318a448..445445ca 100644
--- a/chrome/browser/sessions/session_data_deleter.cc
+++ b/chrome/browser/sessions/session_data_deleter.cc
@@ -108,7 +108,7 @@
   for (const auto& cookie : cookies) {
     GURL url =
         net::cookie_util::CookieOriginToURL(cookie.Domain(), cookie.IsSecure());
-    if (!storage_policy_->IsStorageSessionOnly(url))
+    if (!storage_policy_->IsStorageSessionOnlyOrBlocked(url))
       continue;
 
     // Delete a single cookie by setting its expiration time into the past.
diff --git a/chrome/browser/signin/process_dice_header_observer_impl.cc b/chrome/browser/signin/process_dice_header_observer_impl.cc
index 1d806db..3d0b7843 100644
--- a/chrome/browser/signin/process_dice_header_observer_impl.cc
+++ b/chrome/browser/signin/process_dice_header_observer_impl.cc
@@ -5,13 +5,32 @@
 #include "chrome/browser/signin/process_dice_header_observer_impl.h"
 
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/dice_tab_helper.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
+#include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h"
+#include "chrome/common/webui_url_constants.h"
+#include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/profile_management_switches.h"
 #include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/core/browser/signin_metrics.h"
+#include "url/gurl.h"
+
+namespace {
+
+void RedirectToNtp(content::WebContents* contents) {
+  VLOG(1) << "RedirectToNtp";
+  // Redirect to NTP page.
+  content::OpenURLParams params(GURL(chrome::kChromeUINewTabURL),
+                                content::Referrer(),
+                                WindowOpenDisposition::CURRENT_TAB,
+                                ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false);
+  contents->OpenURL(params);
+}
+
+}  // namespace
 
 ProcessDiceHeaderObserverImpl::ProcessDiceHeaderObserverImpl(
     content::WebContents* web_contents)
@@ -56,10 +75,16 @@
   DiceTabHelper* tab_helper = DiceTabHelper::FromWebContents(web_contents);
   DCHECK(tab_helper);
 
-  // OneClickSigninSyncStarter is suicidal (it will kill itself once it finishes
-  // enabling sync).
+  // After signing in to Chrome, the user should be redirected to the NTP.
+  RedirectToNtp(web_contents);
+
+  // Turn on sync for an existing account.
   VLOG(1) << "Start sync after web sign-in.";
-  new OneClickSigninSyncStarter(
-      profile, browser, gaia_id, email, tab_helper->signin_access_point(),
-      tab_helper->signin_reason(), OneClickSigninSyncStarter::Callback());
+  std::string account_id = AccountTrackerServiceFactory::GetForProfile(profile)
+                               ->PickAccountIdForAccount(gaia_id, email);
+
+  // DiceTurnSyncOnHelper is suicidal (it will kill itself once it finishes
+  // enabling sync).
+  new DiceTurnSyncOnHelper(profile, browser, tab_helper->signin_access_point(),
+                           tab_helper->signin_reason(), account_id);
 }
diff --git a/chrome/browser/supervised_user/supervised_user_browsertest.cc b/chrome/browser/supervised_user/supervised_user_browsertest.cc
index 2f47eec..e9aad6d4 100644
--- a/chrome/browser/supervised_user/supervised_user_browsertest.cc
+++ b/chrome/browser/supervised_user/supervised_user_browsertest.cc
@@ -334,6 +334,24 @@
   EXPECT_EQ(tab, tab_strip->GetActiveWebContents());
 }
 
+// Tests that it's possible to navigate from a blocked page to another blocked
+// page.
+IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest,
+                       NavigateFromBlockedPageToBlockedPage) {
+  GURL test_url("http://www.example.com/simple.html");
+  ui_test_utils::NavigateToURL(browser(), test_url);
+
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+
+  ASSERT_TRUE(ShownPageIsInterstitial(tab));
+
+  GURL test_url2("http://www.a.com/simple.html");
+  ui_test_utils::NavigateToURL(browser(), test_url2);
+
+  ASSERT_TRUE(ShownPageIsInterstitial(tab));
+  EXPECT_EQ(test_url2, tab->GetVisibleURL());
+}
+
 // Tests whether a visit attempt adds a special history entry.
 IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest,
                        HistoryVisitRecorded) {
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_observer.cc b/chrome/browser/supervised_user/supervised_user_navigation_observer.cc
index 01bad11..c76b2182 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_observer.cc
+++ b/chrome/browser/supervised_user/supervised_user_navigation_observer.cc
@@ -71,17 +71,17 @@
 
   url_filter_->GetFilteringBehaviorForURLWithAsyncChecks(
       web_contents()->GetLastCommittedURL(),
-      base::Bind(&SupervisedUserNavigationObserver::URLFilterCheckCallback,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 navigation_handle->GetURL()));
+      base::BindOnce(&SupervisedUserNavigationObserver::URLFilterCheckCallback,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     navigation_handle->GetURL()));
 }
 
 void SupervisedUserNavigationObserver::OnURLFilterChanged() {
   url_filter_->GetFilteringBehaviorForURLWithAsyncChecks(
       web_contents()->GetLastCommittedURL(),
-      base::Bind(&SupervisedUserNavigationObserver::URLFilterCheckCallback,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 web_contents()->GetLastCommittedURL()));
+      base::BindOnce(&SupervisedUserNavigationObserver::URLFilterCheckCallback,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     web_contents()->GetLastCommittedURL()));
 }
 
 void SupervisedUserNavigationObserver::OnRequestBlockedInternal(
@@ -89,10 +89,15 @@
     supervised_user_error_page::FilteringBehaviorReason reason,
     const base::Callback<void(bool)>& callback) {
   Time timestamp = Time::Now();  // TODO(bauerb): Use SaneTime when available.
-  // Create a history entry for the attempt and mark it as such.
+  // Create a history entry for the attempt and mark it as such.  This history
+  // entry should be marked as "not hidden" so the user can see attempted but
+  // blocked navigations.  (This is in contrast to the normal behavior, wherein
+  // Chrome marks navigations that result in an error as hidden.)  This is to
+  // show the user the same thing that the custodian will see on the dashboard
+  // (where it gets via a different mechanism unrelated to history).
   history::HistoryAddPageArgs add_page_args(
       url, timestamp, history::ContextIDForWebContents(web_contents()), 0, url,
-      history::RedirectList(), ui::PAGE_TRANSITION_BLOCKED,
+      history::RedirectList(), ui::PAGE_TRANSITION_BLOCKED, false,
       history::SOURCE_BROWSED, false, true);
 
   // Add the entry to the history database.
@@ -129,7 +134,8 @@
   if (url != web_contents()->GetLastCommittedURL())
     return;
 
-  if (behavior == SupervisedUserURLFilter::FilteringBehavior::BLOCK) {
+  if (!is_showing_interstitial_ &&
+      behavior == SupervisedUserURLFilter::FilteringBehavior::BLOCK) {
     const bool initial_page_load = false;
     MaybeShowInterstitial(url, reason, initial_page_load,
                           base::Callback<void(bool)>());
@@ -141,9 +147,6 @@
     supervised_user_error_page::FilteringBehaviorReason reason,
     bool initial_page_load,
     const base::Callback<void(bool)>& callback) {
-  if (is_showing_interstitial_)
-    return;
-
   is_showing_interstitial_ = true;
   base::Callback<void(bool)> wrapped_callback =
       base::Bind(&SupervisedUserNavigationObserver::OnInterstitialResult,
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter.cc b/chrome/browser/supervised_user/supervised_user_url_filter.cc
index ad0ad69..6d56c9d 100644
--- a/chrome/browser/supervised_user/supervised_user_url_filter.cc
+++ b/chrome/browser/supervised_user/supervised_user_url_filter.cc
@@ -416,7 +416,7 @@
 
 bool SupervisedUserURLFilter::GetFilteringBehaviorForURLWithAsyncChecks(
     const GURL& url,
-    const FilteringBehaviorCallback& callback) const {
+    FilteringBehaviorCallback callback) const {
   supervised_user_error_page::FilteringBehaviorReason reason =
       supervised_user_error_page::DEFAULT;
   FilteringBehavior behavior = GetFilteringBehaviorForURL(url, false, &reason);
@@ -424,7 +424,7 @@
   // Also, if we're blocking anyway, then there's no need to check it.
   if (reason != supervised_user_error_page::DEFAULT || behavior == BLOCK ||
       !async_url_checker_) {
-    callback.Run(behavior, reason, false);
+    std::move(callback).Run(behavior, reason, false);
     for (Observer& observer : observers_)
       observer.OnURLChecked(url, behavior, reason, false);
     return true;
@@ -432,9 +432,8 @@
 
   return async_url_checker_->CheckURL(
       Normalize(url),
-      base::Bind(&SupervisedUserURLFilter::CheckCallback,
-                 base::Unretained(this),
-                 callback));
+      base::BindOnce(&SupervisedUserURLFilter::CheckCallback,
+                     base::Unretained(this), std::move(callback)));
 }
 
 std::map<std::string, base::string16>
@@ -667,7 +666,7 @@
 }
 
 void SupervisedUserURLFilter::CheckCallback(
-    const FilteringBehaviorCallback& callback,
+    FilteringBehaviorCallback callback,
     const GURL& url,
     SafeSearchURLChecker::Classification classification,
     bool uncertain) const {
@@ -676,7 +675,8 @@
   FilteringBehavior behavior =
       GetBehaviorFromSafeSearchClassification(classification);
 
-  callback.Run(behavior, supervised_user_error_page::ASYNC_CHECKER, uncertain);
+  std::move(callback).Run(behavior, supervised_user_error_page::ASYNC_CHECKER,
+                          uncertain);
   for (Observer& observer : observers_) {
     observer.OnURLChecked(url, behavior,
                           supervised_user_error_page::ASYNC_CHECKER, uncertain);
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter.h b/chrome/browser/supervised_user/supervised_user_url_filter.h
index 9bb5171..4431521 100644
--- a/chrome/browser/supervised_user/supervised_user_url_filter.h
+++ b/chrome/browser/supervised_user/supervised_user_url_filter.h
@@ -50,10 +50,10 @@
     INVALID
   };
 
-  using FilteringBehaviorCallback =
-      base::Callback<void(FilteringBehavior,
-                          supervised_user_error_page::FilteringBehaviorReason,
-                          bool /* uncertain */)>;
+  using FilteringBehaviorCallback = base::OnceCallback<void(
+      FilteringBehavior,
+      supervised_user_error_page::FilteringBehaviorReason,
+      bool /* uncertain */)>;
 
   class Observer {
    public:
@@ -124,7 +124,7 @@
   // Returns true if |callback| was called synchronously.
   bool GetFilteringBehaviorForURLWithAsyncChecks(
       const GURL& url,
-      const FilteringBehaviorCallback& callback) const;
+      FilteringBehaviorCallback callback) const;
 
   // Gets all the whitelists that the url is part of. Returns id->name of each
   // whitelist.
@@ -189,7 +189,7 @@
       bool manual_only,
       supervised_user_error_page::FilteringBehaviorReason* reason) const;
 
-  void CheckCallback(const FilteringBehaviorCallback& callback,
+  void CheckCallback(FilteringBehaviorCallback callback,
                      const GURL& url,
                      SafeSearchURLChecker::Classification classification,
                      bool uncertain) const;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index aa3d2c1..9ce6158d 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1,7 +1,6 @@
 # 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.
-
 import("//build/config/chromecast_build.gni")
 import("//build/config/crypto.gni")
 import("//build/config/features.gni")
@@ -532,6 +531,10 @@
   ]
   allow_circular_includes_from = []
 
+  if (is_win || is_mac || is_desktop_linux || is_chromeos) {
+    deps += [ "//chrome/browser/ui/webui/discards:mojo_bindings" ]
+  }
+
   if (!is_fuchsia) {
     # TODO(crbug.com/753619): Enable crash reporting on Fuchsia.
     deps += [
@@ -1551,6 +1554,13 @@
     ]
   }
 
+  if (is_win || is_mac || is_desktop_linux || is_chromeos) {
+    sources += [
+      "webui/discards/discards_ui.cc",
+      "webui/discards/discards_ui.h",
+    ]
+  }
+
   if (is_win || is_mac || is_desktop_linux) {
     sources += [
       "avatar_button_error_controller.cc",
@@ -1606,6 +1616,8 @@
       "webui/signin/signin_error_ui.h",
       "webui/signin/signin_supervised_user_import_handler.cc",
       "webui/signin/signin_supervised_user_import_handler.h",
+      "webui/signin/signin_utils_desktop.cc",
+      "webui/signin/signin_utils_desktop.h",
       "webui/signin/signin_web_dialog_ui.cc",
       "webui/signin/signin_web_dialog_ui.h",
       "webui/signin/sync_confirmation_handler.cc",
@@ -1632,6 +1644,8 @@
 
     if (enable_dice_support) {
       sources += [
+        "webui/signin/dice_turn_sync_on_helper.cc",
+        "webui/signin/dice_turn_sync_on_helper.h",
         "webui/signin/signin_dice_internals_handler.cc",
         "webui/signin/signin_dice_internals_handler.h",
       ]
@@ -2884,6 +2898,8 @@
         "views/accessibility/invert_bubble_view.h",
         "views/autofill/autofill_popup_base_view.cc",
         "views/autofill/autofill_popup_base_view.h",
+        "views/autofill/autofill_popup_view_native_views.cc",
+        "views/autofill/autofill_popup_view_native_views.h",
         "views/autofill/autofill_popup_view_views.cc",
         "views/autofill/autofill_popup_view_views.h",
         "views/autofill/card_unmask_prompt_views_shim.cc",
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
index 0641634..d154f78 100644
--- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
+++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -6,6 +6,7 @@
 
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/search.h"
@@ -128,8 +129,15 @@
 }
 
 // Flaky: crbug.com/267119
+#if defined(OS_WIN)
+#define MAYBE_DispatchMVChangeEventWhileNavigatingBackToNTP \
+  DispatchMVChangeEventWhileNavigatingBackToNTP
+#else
+#define MAYBE_DispatchMVChangeEventWhileNavigatingBackToNTP \
+  DISABLED_DispatchMVChangeEventWhileNavigatingBackToNTP
+#endif
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       DISABLED_DispatchMVChangeEventWhileNavigatingBackToNTP) {
+                       MAYBE_DispatchMVChangeEventWhileNavigatingBackToNTP) {
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
   FocusOmnibox();
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 9885612..05a9722 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/profiles/profile_io_data.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_window.h"
+#include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/signin_tracker_factory.h"
 #include "chrome/browser/signin/signin_util.h"
@@ -70,6 +71,22 @@
                             SIGNIN_CHOICE_SIZE);
 }
 
+std::string GetEmail(Profile* profile, const std::string& account_id) {
+  AccountInfo account_info =
+      AccountTrackerServiceFactory::GetForProfile(profile)->GetAccountInfo(
+          account_id);
+  DCHECK(!account_info.email.empty());
+  return account_info.email;
+}
+
+std::string GetGaiaId(Profile* profile, const std::string& account_id) {
+  AccountInfo account_info =
+      AccountTrackerServiceFactory::GetForProfile(profile)->GetAccountInfo(
+          account_id);
+  DCHECK(!account_info.gaia.empty());
+  return account_info.gaia;
+}
+
 }  // namespace
 
 OneClickSigninSyncStarter::OneClickSigninSyncStarter(
@@ -107,21 +124,21 @@
 OneClickSigninSyncStarter::OneClickSigninSyncStarter(
     Profile* profile,
     Browser* browser,
-    const std::string& gaia_id,
-    const std::string& email,
+    const std::string& account_id,
     signin_metrics::AccessPoint signin_access_point,
     signin_metrics::Reason signin_reason,
+    ProfileMode profile_mode,
     Callback callback)
     : OneClickSigninSyncStarter(
           profile,
           browser,
-          gaia_id,
-          email,
+          GetGaiaId(profile, account_id),
+          GetEmail(profile, account_id),
           std::string() /* password */,
           std::string() /* refresh_token */,
           signin_access_point,
           signin_reason,
-          OneClickSigninSyncStarter::CURRENT_PROFILE,
+          profile_mode,
           OneClickSigninSyncStarter::CONFIRM_SYNC_SETTINGS_FIRST,
           OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN,
           callback) {
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.h b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
index 445452e9..a6efd38 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.h
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
@@ -115,10 +115,10 @@
   // This is only available when DICE is enabled.
   OneClickSigninSyncStarter(Profile* profile,
                             Browser* browser,
-                            const std::string& gaia_id,
-                            const std::string& email,
+                            const std::string& account_id,
                             signin_metrics::AccessPoint signin_access_point,
                             signin_metrics::Reason signin_reason,
+                            ProfileMode profile_mode,
                             Callback callback);
 
   // chrome::BrowserListObserver override.
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
new file mode 100644
index 0000000..bdf217c
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -0,0 +1,142 @@
+// 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/ui/views/autofill/autofill_popup_view_native_views.h"
+
+#include "chrome/browser/ui/autofill/autofill_popup_controller.h"
+#include "chrome/browser/ui/autofill/autofill_popup_layout_model.h"
+#include "components/autofill/core/browser/popup_item_ids.h"
+#include "components/autofill/core/browser/suggestion.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/view.h"
+
+namespace autofill {
+
+namespace {
+
+// Child view only for triggering accessibility events. Rendering for every
+// suggestion type is handled separately.
+class AutofillPopupChildView : public views::View {
+ public:
+  AutofillPopupChildView(AutofillPopupController* controller, int line_number)
+      : controller_(controller), line_number_(line_number) {
+    SetFocusBehavior(FocusBehavior::ALWAYS);
+  }
+
+  ~AutofillPopupChildView() override {}
+
+  void ClearSelection() {}
+  void AcceptSelection() { controller_->AcceptSuggestion(line_number_); }
+
+  // views::Views implementation.
+  // TODO(melandory): These actions are duplicates of what is implemented in
+  // AutofillPopupBaseView. Once migration is finished, code in
+  // AutofillPopupBaseView should be cleaned up.
+  void OnMouseCaptureLost() override { ClearSelection(); }
+
+  bool OnMouseDragged(const ui::MouseEvent& event) override { return true; }
+
+  void OnMouseExited(const ui::MouseEvent& event) override {}
+
+  void OnMouseMoved(const ui::MouseEvent& event) override {}
+
+  bool OnMousePressed(const ui::MouseEvent& event) override { return true; }
+
+  void OnMouseReleased(const ui::MouseEvent& event) override {
+    if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location()))
+      AcceptSelection();
+  }
+
+  void OnGestureEvent(ui::GestureEvent* event) override {}
+
+  bool AcceleratorPressed(const ui::Accelerator& accelerator) override {
+    return true;
+  }
+
+ private:
+  // views::Views implementation
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
+    node_data->role = ui::AX_ROLE_MENU_ITEM;
+    node_data->SetName(controller_->GetSuggestionAt(line_number_).value);
+  }
+
+  AutofillPopupController* controller_;
+  int line_number_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillPopupChildView);
+};
+
+}  // namespace
+
+AutofillPopupViewNativeViews::AutofillPopupViewNativeViews(
+    AutofillPopupController* controller,
+    views::Widget* parent_widget)
+    : AutofillPopupBaseView(controller, parent_widget),
+      controller_(controller) {
+  views::BoxLayout* box_layout =
+      new views::BoxLayout(views::BoxLayout::kVertical);
+  box_layout->set_main_axis_alignment(
+      views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
+  SetLayoutManager(box_layout);
+
+  CreateChildViews();
+  SetBackground(views::CreateThemedSolidBackground(
+      this, ui::NativeTheme::kColorId_ResultsTableNormalBackground));
+}
+
+AutofillPopupViewNativeViews::~AutofillPopupViewNativeViews() {}
+
+void AutofillPopupViewNativeViews::Show() {
+  DoShow();
+}
+
+void AutofillPopupViewNativeViews::Hide() {
+  // The controller is no longer valid after it hides us.
+  controller_ = nullptr;
+
+  DoHide();
+}
+
+void AutofillPopupViewNativeViews::OnSelectedRowChanged(
+    base::Optional<int> previous_row_selection,
+    base::Optional<int> current_row_selection) {}
+
+void AutofillPopupViewNativeViews::OnSuggestionsChanged() {
+  DoUpdateBoundsAndRedrawPopup();
+}
+
+void AutofillPopupViewNativeViews::CreateChildViews() {
+  RemoveAllChildViews(true /* delete_children */);
+  for (int i = 0; i < controller_->GetLineCount(); ++i) {
+    views::View* child_view = new AutofillPopupChildView(controller_, i);
+    if (controller_->GetSuggestionAt(i).frontend_id !=
+        autofill::POPUP_ITEM_ID_SEPARATOR) {
+      // Ignore separators for now.
+      // TODO(melandory): implement the drawing for the separator.
+      views::Label* label = new views::Label(
+          controller_->GetElidedValueAt(i),
+          {controller_->layout_model().GetValueFontListForRow(i)});
+      label->SetBackground(
+          views::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
+              controller_->GetBackgroundColorIDForRow(i))));
+      label->SetEnabledColor(GetNativeTheme()->GetSystemColor(
+          controller_->layout_model().GetValueFontColorIDForRow(i)));
+      label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+      child_view->AddChildView(label);
+
+      auto* box_layout =
+          new views::BoxLayout(views::BoxLayout::kVertical, gfx::Insets(4, 13));
+      box_layout->set_main_axis_alignment(
+          views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
+      child_view->SetLayoutManager(box_layout);
+    }
+    AddChildView(child_view);
+  }
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h
new file mode 100644
index 0000000..8c5459b
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_VIEW_NATIVE_VIEWS_H_
+#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_VIEW_NATIVE_VIEWS_H_
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "chrome/browser/ui/autofill/autofill_popup_view.h"
+#include "chrome/browser/ui/views/autofill/autofill_popup_base_view.h"
+
+namespace autofill {
+
+class AutofillPopupController;
+
+// Views implementation for the autofill and password suggestion.
+// TODO(https://crbug.com/768881): Once this implementation is complete, this
+// class should be renamed to AutofillPopupViewViews and old
+// AutofillPopupViewViews should be removed. The main difference of
+// AutofillPopupViewNativeViews from AutofillPopupViewViews is that child views
+// are drawn using toolkit-views framework, in contrast to
+// AutofillPopupViewViews, where individuals rows are drawn directly on canvas.
+class AutofillPopupViewNativeViews : public AutofillPopupBaseView,
+                                     public AutofillPopupView {
+ public:
+  AutofillPopupViewNativeViews(AutofillPopupController* controller,
+                               views::Widget* parent_widget);
+  ~AutofillPopupViewNativeViews() override;
+
+  void Show() override;
+  void Hide() override;
+
+ private:
+  void OnSelectedRowChanged(base::Optional<int> previous_row_selection,
+                            base::Optional<int> current_row_selection) override;
+  void OnSuggestionsChanged() override;
+
+  // Creates child views based on the suggestions given by |controller_|.
+  void CreateChildViews();
+
+  // Controller for this view.
+  AutofillPopupController* controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillPopupViewNativeViews);
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_VIEW_NATIVE_VIEWS_H_
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
new file mode 100644
index 0000000..98ebfef
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
@@ -0,0 +1,176 @@
+// 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/ui/views/autofill/autofill_popup_view_native_views.h"
+
+#include "build/build_config.h"
+#include "chrome/browser/ui/autofill/autofill_popup_controller.h"
+#include "chrome/browser/ui/autofill/autofill_popup_layout_model.h"
+#include "components/autofill/core/browser/popup_item_ids.h"
+#include "components/autofill/core/browser/suggestion.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/views/test/views_test_base.h"
+
+struct TypeClicks {
+  autofill::PopupItemId id;
+  int click;
+};
+
+const struct TypeClicks kClickTestCase[] = {
+    {autofill::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY, 1},
+    {autofill::POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE, 1},
+    {autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, 1},
+    {autofill::POPUP_ITEM_ID_SEPARATOR, 0},
+    {autofill::POPUP_ITEM_ID_CLEAR_FORM, 1},
+    {autofill::POPUP_ITEM_ID_AUTOFILL_OPTIONS, 1},
+    {autofill::POPUP_ITEM_ID_DATALIST_ENTRY, 1},
+    {autofill::POPUP_ITEM_ID_SCAN_CREDIT_CARD, 1},
+    {autofill::POPUP_ITEM_ID_TITLE, 1},
+    {autofill::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO, 1},
+    {autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE, 1},
+    {autofill::POPUP_ITEM_ID_USERNAME_ENTRY, 1},
+    {autofill::POPUP_ITEM_ID_CREATE_HINT, 1},
+    {autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY, 1},
+    {autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY, 1},
+};
+
+class MockAutofillPopupController : public autofill::AutofillPopupController {
+ public:
+  MockAutofillPopupController() {
+    gfx::FontList::SetDefaultFontDescription("Arial, Times New Roman, 15px");
+    layout_model_ = std::make_unique<autofill::AutofillPopupLayoutModel>(
+        this, false /* is_credit_card_field */);
+  }
+
+  // AutofillPopupViewDelegate
+  MOCK_METHOD0(Hide, void());
+  MOCK_METHOD0(ViewDestroyed, void());
+  MOCK_METHOD1(SetSelectionAtPoint, void(const gfx::Point& point));
+  MOCK_METHOD0(AcceptSelectedLine, bool());
+  MOCK_METHOD0(SelectionCleared, void());
+  MOCK_CONST_METHOD0(popup_bounds, gfx::Rect());
+  MOCK_METHOD0(container_view, gfx::NativeView());
+  MOCK_CONST_METHOD0(element_bounds, const gfx::RectF&());
+  MOCK_CONST_METHOD0(IsRTL, bool());
+  const std::vector<autofill::Suggestion> GetSuggestions() override {
+    return suggestions_;
+  }
+#if !defined(OS_ANDROID)
+  MOCK_METHOD1(GetElidedValueWidthForRow, int(int row));
+  MOCK_METHOD1(GetElidedLabelWidthForRow, int(int row));
+#endif
+
+  // AutofillPopupController
+  MOCK_METHOD0(OnSuggestionsChanged, void());
+  MOCK_METHOD1(AcceptSuggestion, void(int index));
+
+  int GetLineCount() const override { return suggestions_.size(); }
+
+  const autofill::Suggestion& GetSuggestionAt(int row) const override {
+    return suggestions_[row];
+  }
+
+  const base::string16& GetElidedValueAt(int i) const override {
+    return suggestions_[i].value;
+  }
+  MOCK_CONST_METHOD1(GetElidedLabelAt, const base::string16&(int row));
+  MOCK_METHOD3(GetRemovalConfirmationText,
+               bool(int index, base::string16* title, base::string16* body));
+  MOCK_METHOD1(RemoveSuggestion, bool(int index));
+  MOCK_CONST_METHOD1(GetBackgroundColorIDForRow,
+                     ui::NativeTheme::ColorId(int index));
+  MOCK_CONST_METHOD0(selected_line, base::Optional<int>());
+  const autofill::AutofillPopupLayoutModel& layout_model() const override {
+    return *layout_model_;
+  }
+
+  void set_suggestions(const std::vector<int>& ids) {
+    for (const auto& id : ids)
+      suggestions_.push_back(autofill::Suggestion("", "", "", id));
+  }
+
+ private:
+  std::unique_ptr<autofill::AutofillPopupLayoutModel> layout_model_;
+  std::vector<autofill::Suggestion> suggestions_;
+};
+
+class AutofillPopupViewNativeViewsTest : public views::ViewsTestBase {
+ public:
+  AutofillPopupViewNativeViewsTest() = default;
+  ~AutofillPopupViewNativeViewsTest() override = default;
+
+  void SetUp() override {
+    views::ViewsTestBase::SetUp();
+
+    CreateWidget();
+    generator_.reset(new ui::test::EventGenerator(widget_.GetNativeWindow()));
+  }
+
+  void TearDown() override {
+    generator_.reset();
+    if (!widget_.IsClosed())
+      widget_.Close();
+    view_.reset();
+    views::ViewsTestBase::TearDown();
+  }
+
+  void CreateAndShowView(const std::vector<int>& ids) {
+    autofill_popup_controller_.set_suggestions(ids);
+    view_ = base::MakeUnique<autofill::AutofillPopupViewNativeViews>(
+        &autofill_popup_controller_, &widget_);
+    widget_.SetContentsView(view_.get());
+
+    widget_.Show();
+  }
+
+  autofill::AutofillPopupViewNativeViews* view() { return view_.get(); }
+
+ protected:
+  void CreateWidget() {
+    views::Widget::InitParams params =
+        CreateParams(views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+    params.bounds = gfx::Rect(0, 0, 200, 200);
+    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    widget_.Init(params);
+  }
+
+  std::unique_ptr<autofill::AutofillPopupViewNativeViews> view_;
+  MockAutofillPopupController autofill_popup_controller_;
+  views::Widget widget_;
+  std::unique_ptr<ui::test::EventGenerator> generator_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AutofillPopupViewNativeViewsTest);
+};
+
+class AutofillPopupViewNativeViewsForEveryTypeTest
+    : public AutofillPopupViewNativeViewsTest,
+      public ::testing::WithParamInterface<TypeClicks> {};
+
+TEST_F(AutofillPopupViewNativeViewsTest, ShowHideTest) {
+  CreateAndShowView({0});
+  EXPECT_CALL(autofill_popup_controller_, AcceptSuggestion(testing::_))
+      .Times(0);
+  view()->Hide();
+}
+
+TEST_P(AutofillPopupViewNativeViewsForEveryTypeTest, ShowClickTest) {
+  const TypeClicks& click = GetParam();
+  CreateAndShowView({click.id});
+  EXPECT_CALL(autofill_popup_controller_, AcceptSuggestion(::testing::_))
+      .Times(click.click);
+  gfx::Point center = view()->child_at(0)->GetLocalBounds().CenterPoint();
+  generator_->set_current_location(center);
+  generator_->ClickLeftButton();
+  view()->RemoveAllChildViews(true /* delete_children */);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    /* no prefix */,
+    AutofillPopupViewNativeViewsForEveryTypeTest,
+    ::testing::ValuesIn(kClickTestCase));
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc
index f5547de..61c2c0f9 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc
@@ -4,10 +4,13 @@
 
 #include "chrome/browser/ui/views/autofill/autofill_popup_view_views.h"
 
+#include "base/feature_list.h"
 #include "base/optional.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
 #include "chrome/browser/ui/autofill/autofill_popup_layout_model.h"
+#include "chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/autofill/core/browser/popup_item_ids.h"
 #include "components/autofill/core/browser/suggestion.h"
 #include "ui/accessibility/ax_node_data.h"
@@ -264,6 +267,9 @@
   if (!observing_widget)
     return NULL;
 
+  if (base::FeatureList::IsEnabled(autofill::kAutofillExpandedPopupViews))
+    return new AutofillPopupViewNativeViews(controller, observing_widget);
+
   return new AutofillPopupViewViews(controller, observing_widget);
 }
 
diff --git a/chrome/browser/ui/views/extensions/extension_dialog_interactive_uitest.cc b/chrome/browser/ui/views/extensions/extension_dialog_interactive_uitest.cc
index 654c0919..408e0e8 100644
--- a/chrome/browser/ui/views/extensions/extension_dialog_interactive_uitest.cc
+++ b/chrome/browser/ui/views/extensions/extension_dialog_interactive_uitest.cc
@@ -13,13 +13,7 @@
 
 using ExtensionDialogUiTest = ExtensionBrowserTest;
 
-// Flaky on Windows: see https://crbug.com/639072
-#if defined(OS_WIN)
-#define MAYBE_TabFocusLoop DISABLED_TabFocusLoop
-#else
-#define MAYBE_TabFocusLoop TabFocusLoop
-#endif
-IN_PROC_BROWSER_TEST_F(ExtensionDialogUiTest, MAYBE_TabFocusLoop) {
+IN_PROC_BROWSER_TEST_F(ExtensionDialogUiTest, TabFocusLoop) {
   ExtensionTestMessageListener init_listener("ready", false /* will_reply */);
   ExtensionTestMessageListener button1_focus_listener("button1-focused", false);
   ExtensionTestMessageListener button2_focus_listener("button2-focused", false);
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
index 3f99e947..b0b24c2 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
@@ -642,6 +642,9 @@
   // SetSelectedIndex doesn't trigger a perform action notification, which is
   // needed to update the valid state.
   address_combobox->SetSelectedRow(index);
+  // The combobox might be initially disabled in FillContentView, but we've
+  // added an item; check if we should re-enable it.
+  address_combobox->SetEnabled(address_combobox->GetRowCount() > 1);
   // But it needs to be blured at least once.
   address_combobox->OnBlur();
 }
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
index 2f1fb01..e422df5 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
@@ -831,7 +831,7 @@
                    autofill::ADDRESS_HOME_STATE);
   SetEditorTextfieldValue(base::ASCIIToUTF16("BobZip"),
                           autofill::ADDRESS_HOME_ZIP);
-  SetEditorTextfieldValue(base::ASCIIToUTF16("5755555555"),
+  SetEditorTextfieldValue(base::ASCIIToUTF16("+15755555555"),
                           autofill::PHONE_HOME_WHOLE_NUMBER);
 
   // Come back to credit card editor.
@@ -844,6 +844,7 @@
           autofill::ADDRESS_BILLING_LINE1)));
   ASSERT_NE(nullptr, billing_combobox);
   EXPECT_FALSE(billing_combobox->invalid());
+  EXPECT_TRUE(billing_combobox->enabled());
 
   // And then save credit card state and come back to payment sheet.
   ResetEventObserver(DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION);
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
index 9a112475..38b3704 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
@@ -8,6 +8,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/ui/extensions/extension_action_view_controller.h"
@@ -156,9 +157,8 @@
   ToolbarActionsBar::disable_animations_for_testing_ = false;
 }
 
-#if defined(USE_OZONE) || defined(OS_WIN)
+#if defined(USE_OZONE)
 // ozone bringup - http://crbug.com/401304
-// flaky on Windows - http://crbug.com/638692
 #define MAYBE_TestClickingOnOverflowedAction DISABLED_TestClickingOnOverflowedAction
 #else
 #define MAYBE_TestClickingOnOverflowedAction TestClickingOnOverflowedAction
@@ -271,8 +271,8 @@
 
 // Tests that clicking on the toolbar action a second time when the action is
 // already open results in closing the popup, and doesn't re-open it.
-#if defined(OS_WIN) || defined(OS_LINUX) || (OS_CHROMEOS)
-// Flaky on Windows, Linux and ChromeOS; see https://crbug.com/617056.
+#if defined(OS_LINUX) || (OS_CHROMEOS)
+// Flaky on Linux and ChromeOS; see https://crbug.com/617056.
 #define MAYBE_DoubleClickToolbarActionToClose \
     DISABLED_DoubleClickToolbarActionToClose
 #else
diff --git a/chrome/browser/ui/webui/about_ui.cc b/chrome/browser/ui/webui/about_ui.cc
index 9229822..1ff226d0 100644
--- a/chrome/browser/ui/webui/about_ui.cc
+++ b/chrome/browser/ui/webui/about_ui.cc
@@ -330,190 +330,6 @@
   return html;
 }
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
-
-const char kAboutDiscardsRunCommand[] = "run";
-const char kAboutDiscardsSkipUnloadHandlersCommand[] = "skip_unload_handlers";
-
-// Html output helper functions
-
-// Helper function to wrap HTML with a tag.
-std::string WrapWithTag(const std::string& tag, const std::string& text) {
-  return "<" + tag + ">" + text + "</" + tag + ">";
-}
-
-// Helper function to wrap Html with <td> tag.
-std::string WrapWithTD(const std::string& text) {
-  return "<td>" + text + "</td>";
-}
-
-// Helper function to wrap Html with <tr> tag.
-std::string WrapWithTR(const std::string& text) {
-  return "<tr>" + text + "</tr>";
-}
-
-std::string AddStringRow(const std::string& name, const std::string& value) {
-  std::string row;
-  row.append(WrapWithTD(name));
-  row.append(WrapWithTD(value));
-  return WrapWithTR(row);
-}
-
-void AddContentSecurityPolicy(std::string* output) {
-  output->append("<meta http-equiv='Content-Security-Policy' "
-      "content='default-src 'none';'>");
-}
-
-// TODO(stevenjb): L10N AboutDiscards.
-
-std::string BuildAboutDiscardsRunPage() {
-  std::string output;
-  AppendHeader(&output, 0, "About discards");
-  output.append(base::StringPrintf("<meta http-equiv='refresh' content='2;%s'>",
-                                   chrome::kChromeUIDiscardsURL));
-  AddContentSecurityPolicy(&output);
-  output.append(WrapWithTag("p", "Discarding a tab..."));
-  AppendFooter(&output);
-  return output;
-}
-
-std::vector<std::string> GetHtmlTabDescriptorsForDiscardPage() {
-  resource_coordinator::TabManager* tab_manager =
-      g_browser_process->GetTabManager();
-  resource_coordinator::TabStatsList stats = tab_manager->GetTabStats();
-  std::vector<std::string> titles;
-  titles.reserve(stats.size());
-  for (resource_coordinator::TabStatsList::iterator it = stats.begin();
-       it != stats.end(); ++it) {
-    std::string str;
-    str.reserve(4096);
-    str += "<b>";
-    str += it->is_app ? "[App] " : "";
-    str += it->is_internal_page ? "[Internal] " : "";
-    str += it->is_media ? "[Media] " : "";
-    str += it->is_pinned ? "[Pinned] " : "";
-    str += it->is_discarded ? "[Discarded] " : "";
-    str += "</b>";
-    str += net::EscapeForHTML(base::UTF16ToUTF8(it->title));
-#if defined(OS_CHROMEOS)
-    str += base::StringPrintf(" (%d) ", it->oom_score);
-#endif
-    str += base::StringPrintf("&nbsp;&nbsp;(%d discards this session)",
-                              it->discard_count);
-
-    if (!it->is_discarded) {
-      str += "<ul>";
-      str += base::StringPrintf("<li><a href='%s%s/%" PRId64
-                                "'>Discard (safely)</a></li>",
-                                chrome::kChromeUIDiscardsURL,
-                                kAboutDiscardsRunCommand, it->tab_contents_id);
-      str += base::StringPrintf(
-          "<li><a href='%s%s/%" PRId64
-          "?%s'>Discard (allow unsafe process shutdown)</a></li>",
-          chrome::kChromeUIDiscardsURL, kAboutDiscardsRunCommand,
-          it->tab_contents_id, kAboutDiscardsSkipUnloadHandlersCommand);
-      str += "</ul>";
-    }
-    titles.push_back(str);
-  }
-  return titles;
-}
-
-std::string AboutDiscards(const std::string& path) {
-  std::string output;
-  int64_t web_content_id;
-  resource_coordinator::TabManager* tab_manager =
-      g_browser_process->GetTabManager();
-
-  std::vector<std::string> url_split =
-      base::SplitString(path, "?", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-  if (!url_split.empty()) {
-    resource_coordinator::DiscardCondition condition =
-        (url_split.size() > 1 &&
-         url_split[1] == kAboutDiscardsSkipUnloadHandlersCommand)
-            ? resource_coordinator::DiscardCondition::kUrgent
-            : resource_coordinator::DiscardCondition::kProactive;
-
-    std::vector<std::string> path_split = base::SplitString(
-        url_split[0], "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-    if (path_split.size() == 2 && path_split[0] == kAboutDiscardsRunCommand &&
-        base::StringToInt64(path_split[1], &web_content_id)) {
-      tab_manager->DiscardTabById(web_content_id, condition);
-      return BuildAboutDiscardsRunPage();
-    } else if (path_split.size() == 1 &&
-               path_split[0] == kAboutDiscardsRunCommand) {
-      tab_manager->DiscardTab(condition);
-      return BuildAboutDiscardsRunPage();
-    }
-  }
-
-  AppendHeader(&output, 0, "About discards");
-  AddContentSecurityPolicy(&output);
-  AppendBody(&output);
-  output.append("<h3>Discarded Tabs</h3>");
-  output.append(
-      "<p>Tabs sorted from most interesting to least interesting. The least "
-      "interesting tab may be discarded if we run out of physical memory.</p>");
-
-  std::vector<std::string> titles = GetHtmlTabDescriptorsForDiscardPage();
-  if (!titles.empty()) {
-    output.append("<ul>");
-    std::vector<std::string>::iterator it = titles.begin();
-    for ( ; it != titles.end(); ++it) {
-      output.append(WrapWithTag("li", *it));
-    }
-    output.append("</ul>");
-  } else {
-    output.append("<p>None found.  Wait 10 seconds, then refresh.</p>");
-  }
-  output.append(base::StringPrintf("%d discards this session. ",
-                                   tab_manager->discard_count()));
-  output.append(base::StringPrintf(
-      "<a href='%s%s'>Discard tab now (safely)</a>",
-      chrome::kChromeUIDiscardsURL, kAboutDiscardsRunCommand));
-
-  base::SystemMemoryInfoKB meminfo;
-  base::GetSystemMemoryInfo(&meminfo);
-  output.append("<h3>System memory information in MB</h3>");
-  output.append("<table>");
-  // Start with summary statistics.
-  output.append(AddStringRow(
-      "Total", base::IntToString(meminfo.total / 1024)));
-  output.append(AddStringRow(
-      "Free",
-      base::IntToString(base::SysInfo::AmountOfAvailablePhysicalMemory() /
-                        1024 / 1024)));
-#if defined(OS_CHROMEOS)
-  int mem_allocated_kb = meminfo.active_anon + meminfo.inactive_anon;
-#if defined(ARCH_CPU_ARM_FAMILY)
-  // ARM counts allocated graphics memory separately from anonymous.
-  if (meminfo.gem_size != -1)
-    mem_allocated_kb += meminfo.gem_size / 1024;
-#endif
-  output.append(AddStringRow(
-      "Allocated", base::IntToString(mem_allocated_kb / 1024)));
-  // Add some space, then detailed numbers.
-  output.append(AddStringRow("&nbsp;", "&nbsp;"));
-  output.append(AddStringRow(
-      "Buffered", base::IntToString(meminfo.buffers / 1024)));
-  output.append(AddStringRow(
-      "Cached", base::IntToString(meminfo.cached / 1024)));
-  output.append(AddStringRow(
-      "Active Anon", base::IntToString(meminfo.active_anon / 1024)));
-  output.append(AddStringRow(
-      "Inactive Anon", base::IntToString(meminfo.inactive_anon / 1024)));
-  output.append(AddStringRow(
-      "Shared", base::IntToString(meminfo.shmem / 1024)));
-  output.append(AddStringRow(
-      "Graphics", base::IntToString(meminfo.gem_size / 1024 / 1024)));
-#endif  // OS_CHROMEOS
-  output.append("</table>");
-  AppendFooter(&output);
-  return output;
-}
-
-#endif  // OS_WIN || OS_MACOSX || OS_LINUX
-
 // AboutDnsHandler bounces the request back to the IO thread to collect
 // the DNS information.
 class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
@@ -622,7 +438,6 @@
     else if (path == kKeyboardUtilsPath)
       idr = IDR_KEYBOARD_UTILS_JS;
 #endif
-
     if (idr == IDR_ABOUT_UI_CREDITS_HTML) {
       response = about_ui::GetCredits(true /*include_scripts*/);
     } else {
@@ -630,11 +445,6 @@
                      .GetRawDataResource(idr)
                      .as_string();
     }
-
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
-  } else if (source_name_ == chrome::kChromeUIDiscardsHost) {
-    response = AboutDiscards(path);
-#endif
   } else if (source_name_ == chrome::kChromeUIDNSHost) {
     AboutDnsHandler::Start(profile(), callback);
     return;
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index dfd4b590..1b8b6f4 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -178,6 +178,10 @@
 #include "chrome/browser/ui/webui/welcome_win10_ui.h"
 #endif
 
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+#include "chrome/browser/ui/webui/discards/discards_ui.h"
+#endif
+
 #if defined(OS_LINUX) || defined(OS_ANDROID)
 #include "chrome/browser/ui/webui/sandbox_internals_ui.h"
 #endif
@@ -289,9 +293,6 @@
 #if defined(OS_CHROMEOS)
           || url.host_piece() == chrome::kChromeUIOSCreditsHost
 #endif
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
-          || url.host_piece() == chrome::kChromeUIDiscardsHost
-#endif
           );  // NOLINT
 }
 
@@ -595,6 +596,10 @@
     return &NewWebUI<SandboxInternalsUI>;
   }
 #endif
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+  if (url.host_piece() == chrome::kChromeUIDiscardsHost)
+    return &NewWebUI<DiscardsUI>;
+#endif
   if (IsAboutUI(url))
     return &NewWebUI<AboutUI>;
 
diff --git a/chrome/browser/ui/webui/discards/BUILD.gn b/chrome/browser/ui/webui/discards/BUILD.gn
new file mode 100644
index 0000000..a33645ed
--- /dev/null
+++ b/chrome/browser/ui/webui/discards/BUILD.gn
@@ -0,0 +1,13 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+if (is_win || is_mac || is_desktop_linux || is_chromeos) {
+  mojom("mojo_bindings") {
+    sources = [
+      "discards.mojom",
+    ]
+  }
+}
diff --git a/chrome/browser/ui/webui/discards/OWNERS b/chrome/browser/ui/webui/discards/OWNERS
new file mode 100644
index 0000000..98c20001
--- /dev/null
+++ b/chrome/browser/ui/webui/discards/OWNERS
@@ -0,0 +1,4 @@
+file://chrome/services/resource_coordinator/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/ui/webui/discards/discards.mojom b/chrome/browser/ui/webui/discards/discards.mojom
new file mode 100644
index 0000000..c06e60c
--- /dev/null
+++ b/chrome/browser/ui/webui/discards/discards.mojom
@@ -0,0 +1,68 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module mojom;
+
+// Discard related information about a single tab in a browser.
+struct TabDiscardsInfo {
+  // The URL associated with the tab. This corresponds to GetLastCommittedURL,
+  // and is also what is visible in the Omnibox for a given tab.
+  string tab_url;
+  // The URL of the favicon being displayed for a tab.
+  string favicon_url;
+  // The title of the tab, as displayed on the tab itself.
+  string title;
+  // If the tab corresponds to a Chrome App, this is true.
+  bool is_app;
+  // If the tab corresponds to internal Chrome WebUI, this is true.
+  bool is_internal;
+  // If the tab is currently using media functionality (casting, WebRTC, playing
+  // audio, etc) this is true.
+  bool is_media;
+  // If the tab is pinned in its TabStripModel, this is true.
+  bool is_pinned;
+  // If the tab is currently discarded, this is true.
+  bool is_discarded;
+  // The number of times this tab has been discarded in the current browser
+  // session.
+  int32 discard_count;
+  // The rank of the tab in the "importance to user" list. The tab with 1 is the
+  // most important, the tab with N is the least important.
+  int32 utility_rank;
+  // The time the tab was last active (foreground in a window), in seconds.
+  int32 last_active_seconds;
+  // A unique ID for the tab. This is unique for a browser session and follows a
+  // tab across tab strip operations, reloads and discards.
+  int32 id;
+  // Whether or not the tab is eligible for auto-discarding by the browser.
+  // This can be manipulated by the chrome://discards UI, or via the discards
+  // extension API.
+  bool is_auto_discardable;
+};
+
+// Interface for providing information about discards. Lives in the browser
+// process and is invoked in the renderer process via Javascript code running in
+// the chrome://discards WebUI.
+interface DiscardsDetailsProvider {
+  // Returns an array of TabDiscardsInfo containing discard information about
+  // each tab currently open in the browser, across all profiles.
+  GetTabDiscardsInfo() => (array<TabDiscardsInfo> infos);
+
+  // Sets the auto-discardable state of a tab, as specified by its stable
+  // |tab_id|, earlier returned by GetTabDiscardsInfo. Invokes a callback when
+  // the change has been made.
+  SetAutoDiscardable(int32 tab_id, bool is_auto_discardable) => ();
+
+  // Discards a tab given its |tab_id|. If |urgent| is specified the unload
+  // handlers will not be run, and the tab will be unloaded with prejudice.
+  // Invokes a callback when the discard is complete.
+  DiscardById(int32 tab_id, bool urgent) => ();
+
+  // Discards the least important tab. If |urgent| is specified the unload
+  // handlers will not be run, and the tab will be unloaded with prejudice.
+  // This can fail to discard a tab if no tabs are currently considered
+  // eligible for discard. Invokes a callback when the discard is complete, or
+  // if the decision was made not to discard.
+  Discard(bool urgent) => ();
+};
diff --git a/chrome/browser/ui/webui/discards/discards_ui.cc b/chrome/browser/ui/webui/discards/discards_ui.cc
new file mode 100644
index 0000000..58bd830
--- /dev/null
+++ b/chrome/browser/ui/webui/discards/discards_ui.cc
@@ -0,0 +1,137 @@
+// 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/ui/webui/discards/discards_ui.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/discard_condition.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
+#include "chrome/browser/resource_coordinator/tab_stats.h"
+#include "chrome/browser/resource_coordinator/time.h"
+#include "chrome/browser/ui/webui/discards/discards.mojom.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/browser_resources.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "ui/resources/grit/ui_resources.h"
+
+namespace {
+
+namespace {
+
+resource_coordinator::DiscardCondition GetDiscardTabCondition(bool urgent) {
+  return urgent ? resource_coordinator::DiscardCondition::kUrgent
+                : resource_coordinator::DiscardCondition::kProactive;
+}
+
+}  // namespace
+
+class DiscardsDetailsProviderImpl : public mojom::DiscardsDetailsProvider {
+ public:
+  // This instance is deleted when the supplied pipe is destroyed.
+  DiscardsDetailsProviderImpl(
+      mojo::InterfaceRequest<mojom::DiscardsDetailsProvider> request)
+      : binding_(this, std::move(request)) {}
+
+  ~DiscardsDetailsProviderImpl() override {}
+
+  // mojom::DiscardsDetailsProvider overrides:
+  void GetTabDiscardsInfo(GetTabDiscardsInfoCallback callback) override {
+    resource_coordinator::TabManager* tab_manager =
+        g_browser_process->GetTabManager();
+    resource_coordinator::TabStatsList stats = tab_manager->GetTabStats();
+
+    std::vector<mojom::TabDiscardsInfoPtr> infos;
+    infos.reserve(stats.size());
+
+    base::TimeTicks now = resource_coordinator::NowTicks();
+
+    // Convert the TabStatsList to a vector of TabDiscardsInfos.
+    size_t rank = 1;
+    for (const auto& tab : stats) {
+      mojom::TabDiscardsInfoPtr info(mojom::TabDiscardsInfo::New());
+
+      info->tab_url = tab.tab_url;
+      // This can be empty for pages without a favicon. The WebUI takes care of
+      // showing the chrome://favicon default in that case.
+      info->favicon_url = tab.favicon_url;
+      info->title = base::UTF16ToUTF8(tab.title);
+      info->is_app = tab.is_app;
+      info->is_internal = tab.is_internal_page;
+      info->is_media = tab.is_media;
+      info->is_pinned = tab.is_pinned;
+      info->is_discarded = tab.is_discarded;
+      info->discard_count = tab.discard_count;
+      info->utility_rank = rank++;
+      auto elapsed = now - tab.last_active;
+      info->last_active_seconds = static_cast<int32_t>(elapsed.InSeconds());
+      info->is_auto_discardable = tab.is_auto_discardable;
+      info->id = tab.id;
+
+      infos.push_back(std::move(info));
+    }
+
+    std::move(callback).Run(std::move(infos));
+  }
+
+  void SetAutoDiscardable(int32_t tab_id,
+                          bool is_auto_discardable,
+                          SetAutoDiscardableCallback callback) override {
+    resource_coordinator::TabManager* tab_manager =
+        g_browser_process->GetTabManager();
+    tab_manager->SetTabAutoDiscardableState(tab_id, is_auto_discardable);
+    std::move(callback).Run();
+  }
+
+  void DiscardById(int32_t tab_id,
+                   bool urgent,
+                   DiscardByIdCallback callback) override {
+    resource_coordinator::TabManager* tab_manager =
+        g_browser_process->GetTabManager();
+    tab_manager->DiscardTabById(tab_id, GetDiscardTabCondition(urgent));
+    std::move(callback).Run();
+  }
+
+  void Discard(bool urgent, DiscardCallback callback) override {
+    resource_coordinator::TabManager* tab_manager =
+        g_browser_process->GetTabManager();
+    tab_manager->DiscardTab(GetDiscardTabCondition(urgent));
+    std::move(callback).Run();
+  }
+
+ private:
+  mojo::Binding<mojom::DiscardsDetailsProvider> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(DiscardsDetailsProviderImpl);
+};
+
+}  // namespace
+
+DiscardsUI::DiscardsUI(content::WebUI* web_ui)
+    : MojoWebUIController<mojom::DiscardsDetailsProvider>(web_ui) {
+  std::unique_ptr<content::WebUIDataSource> source(
+      content::WebUIDataSource::Create(chrome::kChromeUIDiscardsHost));
+
+  source->AddResourcePath("discards.css", IDR_ABOUT_DISCARDS_CSS);
+  source->AddResourcePath("discards.js", IDR_ABOUT_DISCARDS_JS);
+  // Full paths (relative to src) are important for Mojom generated files.
+  source->AddResourcePath("chrome/browser/ui/webui/discards/discards.mojom.js",
+                          IDR_ABOUT_DISCARDS_MOJO_JS);
+  source->SetDefaultResource(IDR_ABOUT_DISCARDS_HTML);
+
+  Profile* profile = Profile::FromWebUI(web_ui);
+  content::WebUIDataSource::Add(profile, source.release());
+}
+
+DiscardsUI::~DiscardsUI() {}
+
+void DiscardsUI::BindUIHandler(mojom::DiscardsDetailsProviderRequest request) {
+  ui_handler_.reset(new DiscardsDetailsProviderImpl(std::move(request)));
+}
diff --git a/chrome/browser/ui/webui/discards/discards_ui.h b/chrome/browser/ui/webui/discards/discards_ui.h
new file mode 100644
index 0000000..442fd98
--- /dev/null
+++ b/chrome/browser/ui/webui/discards/discards_ui.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_DISCARDS_DISCARDS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_DISCARDS_DISCARDS_UI_H_
+
+#include "base/macros.h"
+#include "chrome/browser/ui/webui/discards/discards.mojom.h"
+#include "chrome/browser/ui/webui/mojo_web_ui_controller.h"
+
+// Controller for chrome://discards. Corresponding resources are in
+// file://chrome/browser/resources/discards.
+class DiscardsUI : public MojoWebUIController<mojom::DiscardsDetailsProvider> {
+ public:
+  explicit DiscardsUI(content::WebUI* web_ui);
+  ~DiscardsUI() override;
+
+ private:
+  // MojoWebUIController overrides:
+  void BindUIHandler(mojom::DiscardsDetailsProviderRequest request) override;
+
+  std::unique_ptr<mojom::DiscardsDetailsProvider> ui_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(DiscardsUI);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_DISCARDS_DISCARDS_UI_H_
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
new file mode 100644
index 0000000..5826d0b
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
@@ -0,0 +1,134 @@
+// 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/ui/webui/signin/dice_turn_sync_on_helper.h"
+
+#include "base/logging.h"
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/account_tracker_service_factory.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/signin_promo.h"
+#include "chrome/browser/signin/signin_util.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/webui/signin/login_ui_service.h"
+#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
+#include "chrome/browser/ui/webui/signin/signin_utils_desktop.h"
+#include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/signin_metrics.h"
+#include "components/signin/core/browser/signin_pref_names.h"
+
+namespace {
+
+AccountInfo GetAccountInfo(Profile* profile, const std::string& account_id) {
+  return AccountTrackerServiceFactory::GetForProfile(profile)->GetAccountInfo(
+      account_id);
+}
+
+}  // namespace
+
+DiceTurnSyncOnHelper::DiceTurnSyncOnHelper(
+    Profile* profile,
+    Browser* browser,
+    signin_metrics::AccessPoint signin_access_point,
+    signin_metrics::Reason signin_reason,
+    const std::string& account_id)
+    : profile_(profile),
+      browser_(browser),
+      signin_access_point_(signin_access_point),
+      signin_reason_(signin_reason),
+      account_info_(GetAccountInfo(profile, account_id)) {
+  DCHECK(profile_);
+  DCHECK(browser_);
+  DCHECK(!account_info_.account_id.empty());
+  DCHECK(!account_info_.email.empty());
+  DCHECK(!account_info_.gaia.empty());
+
+  // Should not start synching if the profile is already authenticated
+  DCHECK(!SigninManagerFactory::GetForProfile(profile_)->IsAuthenticated());
+
+  // Force sign-in uses the modal sign-in flow.
+  DCHECK(!signin_util::IsForceSigninEnabled());
+
+  // One initial sign-in goes throught the DiceTurnSyncOnHelper.
+  DCHECK_EQ(signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT,
+            signin_reason_);
+
+  if (!HandleCanOfferSigninError() && !HandleCrossAccountError()) {
+    CreateSyncStarter(OneClickSigninSyncStarter::CURRENT_PROFILE);
+    base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+  }
+}
+
+DiceTurnSyncOnHelper::~DiceTurnSyncOnHelper() {}
+
+bool DiceTurnSyncOnHelper::HandleCanOfferSigninError() {
+  std::string error_msg;
+  bool can_offer =
+      CanOfferSignin(profile_, CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS,
+                     account_info_.gaia, account_info_.email, &error_msg);
+  if (can_offer)
+    return false;
+
+  // Display the error message
+  LoginUIServiceFactory::GetForProfile(profile_)->DisplayLoginResult(
+      browser_, base::UTF8ToUTF16(error_msg),
+      base::UTF8ToUTF16(account_info_.email));
+  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+  return true;
+}
+
+bool DiceTurnSyncOnHelper::HandleCrossAccountError() {
+  std::string last_email =
+      profile_->GetPrefs()->GetString(prefs::kGoogleServicesLastUsername);
+
+  // TODO(skym): Warn for high risk upgrade scenario, crbug.com/572754.
+  if (!IsCrossAccountError(profile_, account_info_.email, account_info_.gaia))
+    return false;
+
+  content::WebContents* web_contents =
+      browser_->tab_strip_model()->GetActiveWebContents();
+
+  SigninEmailConfirmationDialog::AskForConfirmation(
+      web_contents, profile_, last_email, account_info_.email,
+      base::Bind(&DiceTurnSyncOnHelper::ConfirmEmailAction,
+                 base::Unretained(this), web_contents));
+  return true;
+}
+
+void DiceTurnSyncOnHelper::ConfirmEmailAction(
+    content::WebContents* web_contents,
+    SigninEmailConfirmationDialog::Action action) {
+  switch (action) {
+    case SigninEmailConfirmationDialog::CREATE_NEW_USER:
+      base::RecordAction(
+          base::UserMetricsAction("Signin_ImportDataPrompt_DontImport"));
+      CreateSyncStarter(OneClickSigninSyncStarter::NEW_PROFILE);
+      break;
+    case SigninEmailConfirmationDialog::START_SYNC:
+      base::RecordAction(
+          base::UserMetricsAction("Signin_ImportDataPrompt_ImportData"));
+      CreateSyncStarter(OneClickSigninSyncStarter::CURRENT_PROFILE);
+      break;
+    case SigninEmailConfirmationDialog::CLOSE:
+      base::RecordAction(
+          base::UserMetricsAction("Signin_ImportDataPrompt_Cancel"));
+      break;
+    default:
+      NOTREACHED() << "Invalid action";
+  }
+  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+}
+
+void DiceTurnSyncOnHelper::CreateSyncStarter(
+    OneClickSigninSyncStarter::ProfileMode profile_mode) {
+  // OneClickSigninSyncStarter will delete itself once the job is done.
+  new OneClickSigninSyncStarter(
+      profile_, browser_, account_info_.account_id, signin_access_point_,
+      signin_reason_, profile_mode, OneClickSigninSyncStarter::Callback());
+}
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h
new file mode 100644
index 0000000..31b6be3
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SIGNIN_DICE_TURN_SYNC_ON_HELPER_H_
+#define CHROME_BROWSER_UI_WEBUI_SIGNIN_DICE_TURN_SYNC_ON_HELPER_H_
+
+#include <string>
+
+#include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
+#include "chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.h"
+#include "components/signin/core/browser/account_info.h"
+#include "components/signin/core/browser/signin_metrics.h"
+
+// Handles details of signing the user in with SigninManager and turning on
+// sync for an account that is already present in the token service.
+class DiceTurnSyncOnHelper {
+ public:
+  DiceTurnSyncOnHelper(Profile* profile,
+                       Browser* browser,
+                       signin_metrics::AccessPoint signin_access_point,
+                       signin_metrics::Reason signin_reason,
+                       const std::string& account_id);
+  virtual ~DiceTurnSyncOnHelper();
+
+ private:
+  // Handles can offer sign-in errors.  It returns true if there is an error,
+  // and false otherwise.
+  bool HandleCanOfferSigninError();
+
+  // Handles cross account sign in error. If |account_info_| does not match the
+  // last authenticated account of the current profile, then Chrome will show a
+  // confirmation dialog before starting sync. It returns true if there is a
+  // cross account error, and false otherwise.
+  bool HandleCrossAccountError();
+
+  // Callback used with ConfirmEmailDialogDelegate.
+  void ConfirmEmailAction(content::WebContents* web_contents,
+                          SigninEmailConfirmationDialog::Action action);
+
+  // Creates the sync starter.
+  void CreateSyncStarter(OneClickSigninSyncStarter::ProfileMode profile_mode);
+
+  Profile* profile_;
+  Browser* browser_;
+  signin_metrics::AccessPoint signin_access_point_;
+  signin_metrics::Reason signin_reason_;
+  const AccountInfo account_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(DiceTurnSyncOnHelper);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_DICE_TURN_SYNC_ON_HELPER_H_
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
index 37aa60b..56e9575 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -30,7 +30,6 @@
 #include "chrome/browser/signin/about_signin_internals_factory.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
-#include "chrome/browser/signin/investigator_dependency_provider.h"
 #include "chrome/browser/signin/local_auth.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_error_controller_factory.h"
@@ -48,6 +47,7 @@
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
 #include "chrome/browser/ui/webui/signin/signin_utils.h"
+#include "chrome/browser/ui/webui/signin/signin_utils_desktop.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -136,16 +136,6 @@
   UserManager::Hide();
 }
 
-bool IsCrossAccountError(Profile* profile,
-                         const std::string& email,
-                         const std::string& gaia_id) {
-  InvestigatorDependencyProvider provider(profile);
-  InvestigatedScenario scenario =
-      SigninInvestigator(email, gaia_id, &provider).Investigate();
-
-  return scenario == InvestigatedScenario::DIFFERENT_ACCOUNT;
-}
-
 }  // namespace
 
 InlineSigninHelper::InlineSigninHelper(
@@ -424,101 +414,6 @@
 }
 
 // static
-bool InlineLoginHandlerImpl::CanOffer(Profile* profile,
-                                      CanOfferFor can_offer_for,
-                                      const std::string& gaia_id,
-                                      const std::string& email,
-                                      std::string* error_message) {
-  if (error_message)
-    error_message->clear();
-
-  if (!profile)
-    return false;
-
-  SigninManager* manager = SigninManagerFactory::GetForProfile(profile);
-  if (manager && !manager->IsSigninAllowed())
-    return false;
-
-  if (!ChromeSigninClient::ProfileAllowsSigninCookies(profile))
-    return false;
-
-  if (!email.empty()) {
-    if (!manager)
-      return false;
-
-    // Make sure this username is not prohibited by policy.
-    if (!manager->IsAllowedUsername(email)) {
-      if (error_message) {
-        error_message->assign(
-            l10n_util::GetStringUTF8(IDS_SYNC_LOGIN_NAME_PROHIBITED));
-      }
-      return false;
-    }
-
-    if (can_offer_for == CAN_OFFER_FOR_SECONDARY_ACCOUNT)
-      return true;
-
-    // If the signin manager already has an authenticated name, then this is a
-    // re-auth scenario.  Make sure the email just signed in corresponds to
-    // the one sign in manager expects.
-    std::string current_email = manager->GetAuthenticatedAccountInfo().email;
-    const bool same_email = gaia::AreEmailsSame(current_email, email);
-    if (!current_email.empty() && !same_email) {
-      UMA_HISTOGRAM_ENUMERATION("Signin.Reauth",
-                                signin_metrics::HISTOGRAM_ACCOUNT_MISSMATCH,
-                                signin_metrics::HISTOGRAM_REAUTH_MAX);
-      if (error_message) {
-        error_message->assign(
-            l10n_util::GetStringFUTF8(IDS_SYNC_WRONG_EMAIL,
-                                      base::UTF8ToUTF16(current_email)));
-      }
-      return false;
-    }
-
-    // If some profile, not just the current one, is already connected to this
-    // account, don't show the infobar.
-    if (g_browser_process && !same_email) {
-      ProfileManager* profile_manager = g_browser_process->profile_manager();
-      if (profile_manager) {
-        std::vector<ProfileAttributesEntry*> entries =
-            profile_manager->GetProfileAttributesStorage().
-                GetAllProfilesAttributes();
-
-        for (const ProfileAttributesEntry* entry : entries) {
-          // For backward compatibility, need to check also the username of the
-          // profile, since the GAIA ID may not have been set yet in the
-          // ProfileAttributesStorage.  It will be set once the profile
-          // is opened.
-          std::string profile_gaia_id = entry->GetGAIAId();
-          std::string profile_email = base::UTF16ToUTF8(entry->GetUserName());
-          if (gaia_id == profile_gaia_id ||
-              gaia::AreEmailsSame(email, profile_email)) {
-            if (error_message) {
-              error_message->assign(
-                  l10n_util::GetStringUTF8(IDS_SYNC_USER_NAME_IN_USE_ERROR));
-            }
-            return false;
-          }
-        }
-      }
-    }
-
-    // With force sign in enabled, cross account sign in is not allowed.
-    if (signin_util::IsForceSigninEnabled() &&
-        IsCrossAccountError(profile, email, gaia_id)) {
-      if (error_message) {
-        std::string last_email =
-            profile->GetPrefs()->GetString(prefs::kGoogleServicesLastUsername);
-        error_message->assign(l10n_util::GetStringFUTF8(
-            IDS_SYNC_USED_PROFILE_ERROR, base::UTF8ToUTF16(last_email)));
-      }
-      return false;
-    }
-  }
-
-  return true;
-}
-
 void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) {
   params.SetString("service", "chromiumsync");
 
@@ -751,10 +646,10 @@
       switch_to_advanced ? signin_metrics::HISTOGRAM_WITH_ADVANCED :
                            signin_metrics::HISTOGRAM_WITH_DEFAULTS);
 
-  CanOfferFor can_offer_for = CAN_OFFER_FOR_ALL;
+  CanOfferSigninType can_offer_for = CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS;
   switch (reason) {
     case signin_metrics::Reason::REASON_ADD_SECONDARY_ACCOUNT:
-      can_offer_for = CAN_OFFER_FOR_SECONDARY_ACCOUNT;
+      can_offer_for = CAN_OFFER_SIGNIN_FOR_SECONDARY_ACCOUNT;
       break;
     case signin_metrics::Reason::REASON_REAUTHENTICATION:
     case signin_metrics::Reason::REASON_UNLOCK: {
@@ -763,7 +658,7 @@
               ->GetAuthenticatedAccountInfo()
               .email;
       if (!gaia::AreEmailsSame(default_email, primary_username))
-        can_offer_for = CAN_OFFER_FOR_SECONDARY_ACCOUNT;
+        can_offer_for = CAN_OFFER_SIGNIN_FOR_SECONDARY_ACCOUNT;
       break;
     }
     default:
@@ -772,8 +667,8 @@
   }
 
   std::string error_msg;
-  bool can_offer = CanOffer(profile, can_offer_for, params.gaia_id,
-                            params.email, &error_msg);
+  bool can_offer = CanOfferSignin(profile, can_offer_for, params.gaia_id,
+                                  params.email, &error_msg);
   if (!can_offer) {
     if (params.handler) {
       params.handler->HandleLoginError(error_msg,
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
index 45b2782b..5ee5ba8 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
@@ -43,27 +43,6 @@
                         const base::string16& email);
 
  private:
-  friend class InlineLoginUIBrowserTest;
-  FRIEND_TEST_ALL_PREFIXES(InlineLoginUIBrowserTest, CanOfferNoProfile);
-  FRIEND_TEST_ALL_PREFIXES(InlineLoginUIBrowserTest, CanOffer);
-  FRIEND_TEST_ALL_PREFIXES(InlineLoginUIBrowserTest, CanOfferProfileConnected);
-  FRIEND_TEST_ALL_PREFIXES(InlineLoginUIBrowserTest,
-                           CanOfferUsernameNotAllowed);
-  FRIEND_TEST_ALL_PREFIXES(InlineLoginUIBrowserTest, CanOfferWithRejectedEmail);
-  FRIEND_TEST_ALL_PREFIXES(InlineLoginUIBrowserTest, CanOfferNoSigninCookies);
-
-  // Argument to CanOffer().
-  enum CanOfferFor {
-    CAN_OFFER_FOR_ALL,
-    CAN_OFFER_FOR_SECONDARY_ACCOUNT
-  };
-
-  static bool CanOffer(Profile* profile,
-                       CanOfferFor can_offer_for,
-                       const std::string& gaia_id,
-                       const std::string& email,
-                       std::string* error_message);
-
   // InlineLoginHandler overrides:
   void SetExtraInitParams(base::DictionaryValue& params) override;
   void CompleteLogin(const base::ListValue* args) override;
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc b/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc
index 5b8df42..4212a21 100644
--- a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
 #include "chrome/browser/ui/webui/signin/login_ui_test_utils.h"
+#include "chrome/browser/ui/webui/signin/signin_utils_desktop.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
@@ -374,25 +375,24 @@
 
 IN_PROC_BROWSER_TEST_F(InlineLoginUIBrowserTest, CanOfferNoProfile) {
   std::string error_message;
-  EXPECT_FALSE(InlineLoginHandlerImpl::CanOffer(
-      NULL, InlineLoginHandlerImpl::CAN_OFFER_FOR_ALL,
-      "12345", "user@gmail.com", &error_message));
+  EXPECT_FALSE(CanOfferSignin(NULL, CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS, "12345",
+                              "user@gmail.com", &error_message));
   EXPECT_EQ("", error_message);
 }
 
 IN_PROC_BROWSER_TEST_F(InlineLoginUIBrowserTest, CanOffer) {
   EnableOneClick(true);
-  EXPECT_TRUE(InlineLoginHandlerImpl::CanOffer(
-      browser()->profile(), InlineLoginHandlerImpl::CAN_OFFER_FOR_ALL,
-      "12345", "user@gmail.com", NULL));
+  EXPECT_TRUE(CanOfferSignin(browser()->profile(),
+                             CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS, "12345",
+                             "user@gmail.com", NULL));
 
   EnableOneClick(false);
 
   std::string error_message;
 
-  EXPECT_TRUE(InlineLoginHandlerImpl::CanOffer(
-      browser()->profile(), InlineLoginHandlerImpl::CAN_OFFER_FOR_ALL,
-      "12345", "user@gmail.com", &error_message));
+  EXPECT_TRUE(CanOfferSignin(browser()->profile(),
+                             CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS, "12345",
+                             "user@gmail.com", &error_message));
 }
 
 IN_PROC_BROWSER_TEST_F(InlineLoginUIBrowserTest, CanOfferProfileConnected) {
@@ -401,15 +401,15 @@
 
   std::string error_message;
 
-  EXPECT_TRUE(InlineLoginHandlerImpl::CanOffer(
-      browser()->profile(), InlineLoginHandlerImpl::CAN_OFFER_FOR_ALL,
-      "12345", "foo@gmail.com", &error_message));
-  EXPECT_TRUE(InlineLoginHandlerImpl::CanOffer(
-      browser()->profile(), InlineLoginHandlerImpl::CAN_OFFER_FOR_ALL,
-      "12345", "foo", &error_message));
-  EXPECT_FALSE(InlineLoginHandlerImpl::CanOffer(
-      browser()->profile(), InlineLoginHandlerImpl::CAN_OFFER_FOR_ALL,
-      "12345", "user@gmail.com", &error_message));
+  EXPECT_TRUE(CanOfferSignin(browser()->profile(),
+                             CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS, "12345",
+                             "foo@gmail.com", &error_message));
+  EXPECT_TRUE(CanOfferSignin(browser()->profile(),
+                             CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS, "12345", "foo",
+                             &error_message));
+  EXPECT_FALSE(CanOfferSignin(browser()->profile(),
+                              CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS, "12345",
+                              "user@gmail.com", &error_message));
   EXPECT_EQ(l10n_util::GetStringFUTF8(IDS_SYNC_WRONG_EMAIL,
                                       base::UTF8ToUTF16("foo@gmail.com")),
             error_message);
@@ -419,9 +419,9 @@
   SetAllowedUsernamePattern("*.google.com");
 
   std::string error_message;
-  EXPECT_FALSE(InlineLoginHandlerImpl::CanOffer(
-      browser()->profile(), InlineLoginHandlerImpl::CAN_OFFER_FOR_ALL,
-      "12345", "foo@gmail.com", &error_message));
+  EXPECT_FALSE(CanOfferSignin(browser()->profile(),
+                              CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS, "12345",
+                              "foo@gmail.com", &error_message));
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SYNC_LOGIN_NAME_PROHIBITED),
             error_message);
 }
@@ -433,12 +433,12 @@
   AddEmailToOneClickRejectedList("user@gmail.com");
 
   std::string error_message;
-  EXPECT_TRUE(InlineLoginHandlerImpl::CanOffer(
-      browser()->profile(), InlineLoginHandlerImpl::CAN_OFFER_FOR_ALL,
-      "12345", "foo@gmail.com", &error_message));
-  EXPECT_TRUE(InlineLoginHandlerImpl::CanOffer(
-      browser()->profile(), InlineLoginHandlerImpl::CAN_OFFER_FOR_ALL,
-      "12345", "user@gmail.com", &error_message));
+  EXPECT_TRUE(CanOfferSignin(browser()->profile(),
+                             CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS, "12345",
+                             "foo@gmail.com", &error_message));
+  EXPECT_TRUE(CanOfferSignin(browser()->profile(),
+                             CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS, "12345",
+                             "user@gmail.com", &error_message));
 }
 
 IN_PROC_BROWSER_TEST_F(InlineLoginUIBrowserTest, CanOfferNoSigninCookies) {
@@ -446,9 +446,9 @@
   EnableSigninAllowed(true);
 
   std::string error_message;
-  EXPECT_FALSE(InlineLoginHandlerImpl::CanOffer(
-      browser()->profile(), InlineLoginHandlerImpl::CAN_OFFER_FOR_ALL,
-      "12345", "user@gmail.com", &error_message));
+  EXPECT_FALSE(CanOfferSignin(browser()->profile(),
+                              CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS, "12345",
+                              "user@gmail.com", &error_message));
   EXPECT_EQ("", error_message);
 }
 
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 da7b2c3..5042188 100644
--- a/chrome/browser/ui/webui/signin/signin_dice_internals_handler.cc
+++ b/chrome/browser/ui/webui/signin/signin_dice_internals_handler.cc
@@ -60,7 +60,6 @@
   }
 
   std::string account_id = account_ids[0];
-  std::string gaia_id = tracker->GetAccountInfo(account_id).gaia;
   std::string email = tracker->GetAccountInfo(account_id).email;
   VLOG(1) << "[Dice] Start syncing with account " << email;
 
@@ -68,9 +67,10 @@
   // enabling sync).
   OneClickSigninSyncStarter::Callback callback;
   new OneClickSigninSyncStarter(
-      profile_, browser, gaia_id, email,
+      profile_, browser, account_id,
       signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN,
-      signin_metrics::Reason::REASON_UNKNOWN_REASON, callback);
+      signin_metrics::Reason::REASON_UNKNOWN_REASON,
+      OneClickSigninSyncStarter::CURRENT_PROFILE, callback);
 }
 
 void SigninDiceInternalsHandler::HandleDisableSync(
diff --git a/chrome/browser/ui/webui/signin/signin_utils_desktop.cc b/chrome/browser/ui/webui/signin/signin_utils_desktop.cc
new file mode 100644
index 0000000..7fe0ef7d
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/signin_utils_desktop.cc
@@ -0,0 +1,127 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/signin/signin_utils_desktop.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/chrome_signin_client.h"
+#include "chrome/browser/signin/investigator_dependency_provider.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/signin_util.h"
+#include "chrome/grit/chromium_strings.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/guest_view/browser/guest_view_manager.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/core/browser/signin_pref_names.h"
+#include "ui/base/l10n/l10n_util.h"
+
+bool CanOfferSignin(Profile* profile,
+                    CanOfferSigninType can_offer,
+                    const std::string& gaia_id,
+                    const std::string& email,
+                    std::string* error_message) {
+  if (error_message)
+    error_message->clear();
+
+  if (!profile)
+    return false;
+
+  SigninManager* manager = SigninManagerFactory::GetForProfile(profile);
+  if (manager && !manager->IsSigninAllowed())
+    return false;
+
+  if (!ChromeSigninClient::ProfileAllowsSigninCookies(profile))
+    return false;
+
+  if (!email.empty()) {
+    if (!manager)
+      return false;
+
+    // Make sure this username is not prohibited by policy.
+    if (!manager->IsAllowedUsername(email)) {
+      if (error_message) {
+        error_message->assign(
+            l10n_util::GetStringUTF8(IDS_SYNC_LOGIN_NAME_PROHIBITED));
+      }
+      return false;
+    }
+
+    if (can_offer == CAN_OFFER_SIGNIN_FOR_SECONDARY_ACCOUNT)
+      return true;
+
+    // If the signin manager already has an authenticated name, then this is a
+    // re-auth scenario.  Make sure the email just signed in corresponds to
+    // the one sign in manager expects.
+    std::string current_email = manager->GetAuthenticatedAccountInfo().email;
+    const bool same_email = gaia::AreEmailsSame(current_email, email);
+    if (!current_email.empty() && !same_email) {
+      UMA_HISTOGRAM_ENUMERATION("Signin.Reauth",
+                                signin_metrics::HISTOGRAM_ACCOUNT_MISSMATCH,
+                                signin_metrics::HISTOGRAM_REAUTH_MAX);
+      if (error_message) {
+        error_message->assign(l10n_util::GetStringFUTF8(
+            IDS_SYNC_WRONG_EMAIL, base::UTF8ToUTF16(current_email)));
+      }
+      return false;
+    }
+
+    // If some profile, not just the current one, is already connected to this
+    // account, don't show the infobar.
+    if (g_browser_process && !same_email) {
+      ProfileManager* profile_manager = g_browser_process->profile_manager();
+      if (profile_manager) {
+        std::vector<ProfileAttributesEntry*> entries =
+            profile_manager->GetProfileAttributesStorage()
+                .GetAllProfilesAttributes();
+
+        for (const ProfileAttributesEntry* entry : entries) {
+          // For backward compatibility, need to check also the username of the
+          // profile, since the GAIA ID may not have been set yet in the
+          // ProfileAttributesStorage.  It will be set once the profile
+          // is opened.
+          std::string profile_gaia_id = entry->GetGAIAId();
+          std::string profile_email = base::UTF16ToUTF8(entry->GetUserName());
+          if (gaia_id == profile_gaia_id ||
+              gaia::AreEmailsSame(email, profile_email)) {
+            if (error_message) {
+              error_message->assign(
+                  l10n_util::GetStringUTF8(IDS_SYNC_USER_NAME_IN_USE_ERROR));
+            }
+            return false;
+          }
+        }
+      }
+    }
+
+    // With force sign in enabled, cross account sign in is not allowed.
+    if (signin_util::IsForceSigninEnabled() &&
+        IsCrossAccountError(profile, email, gaia_id)) {
+      if (error_message) {
+        std::string last_email =
+            profile->GetPrefs()->GetString(prefs::kGoogleServicesLastUsername);
+        error_message->assign(l10n_util::GetStringFUTF8(
+            IDS_SYNC_USED_PROFILE_ERROR, base::UTF8ToUTF16(last_email)));
+      }
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool IsCrossAccountError(Profile* profile,
+                         const std::string& email,
+                         const std::string& gaia_id) {
+  InvestigatorDependencyProvider provider(profile);
+  InvestigatedScenario scenario =
+      SigninInvestigator(email, gaia_id, &provider).Investigate();
+
+  return scenario == InvestigatedScenario::DIFFERENT_ACCOUNT;
+}
diff --git a/chrome/browser/ui/webui/signin/signin_utils_desktop.h b/chrome/browser/ui/webui/signin/signin_utils_desktop.h
new file mode 100644
index 0000000..9407fa2
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/signin_utils_desktop.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 CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_UTILS_DESKTOP_H_
+#define CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_UTILS_DESKTOP_H_
+
+#include <string>
+
+class Profile;
+
+// Argument for |CanOfferSignin|.
+enum CanOfferSigninType {
+  CAN_OFFER_SIGNIN_FOR_ALL_ACCOUNTS,
+  CAN_OFFER_SIGNIN_FOR_SECONDARY_ACCOUNT
+};
+
+// Returns true if sign-in is allowed for account with |email| and |gaia_id| to
+// |profile|. If the sign-in is not allowed, then the error message is passed
+// to the called in |out_error_message|
+bool CanOfferSignin(Profile* profile,
+                    CanOfferSigninType can_offer_type,
+                    const std::string& gaia_id,
+                    const std::string& email,
+                    std::string* out_error_message);
+
+// Return true if the account given by |email| and |gaia_id| is signed in to
+// Chrome in a different profile.
+bool IsCrossAccountError(Profile* profile,
+                         const std::string& email,
+                         const std::string& gaia_id);
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_UTILS_DESKTOP_H_
diff --git a/chrome/browser/ui/webui/web_dialog_web_contents_delegate_unittest.cc b/chrome/browser/ui/webui/web_dialog_web_contents_delegate_unittest.cc
index df6506a8..58ee37f 100644
--- a/chrome/browser/ui/webui/web_dialog_web_contents_delegate_unittest.cc
+++ b/chrome/browser/ui/webui/web_dialog_web_contents_delegate_unittest.cc
@@ -66,7 +66,7 @@
   EXPECT_TRUE(test_web_contents_delegate_->IsPopupOrPanel(NULL));
   history::HistoryAddPageArgs should_add_args(
       GURL(), base::Time::Now(), 0, 0, GURL(), history::RedirectList(),
-      ui::PAGE_TRANSITION_TYPED, history::SOURCE_SYNCED, false, true);
+      ui::PAGE_TRANSITION_TYPED, false, history::SOURCE_SYNCED, false, true);
   test_web_contents_delegate_->NavigationStateChanged(
       NULL, content::InvalidateTypes(0));
   test_web_contents_delegate_->ActivateContents(NULL);
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index 9d131fd..cd2c225 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -18,8 +18,6 @@
     "animation_player.cc",
     "animation_player.h",
     "browser_ui_interface.h",
-    "color_scheme.cc",
-    "color_scheme.h",
     "content_input_delegate.cc",
     "content_input_delegate.h",
     "controller_mesh.h",
@@ -40,9 +38,8 @@
     "elements/content_element.h",
     "elements/controller.cc",
     "elements/controller.h",
+    "elements/draw_phase.cc",
     "elements/draw_phase.h",
-    "elements/exclusive_screen_toast.cc",
-    "elements/exclusive_screen_toast.h",
     "elements/exclusive_screen_toast_texture.cc",
     "elements/exclusive_screen_toast_texture.h",
     "elements/exit_prompt.cc",
@@ -74,8 +71,6 @@
     "elements/spinner.h",
     "elements/suggestion.cc",
     "elements/suggestion.h",
-    "elements/system_indicator.cc",
-    "elements/system_indicator.h",
     "elements/system_indicator_texture.cc",
     "elements/system_indicator_texture.h",
     "elements/text.cc",
@@ -117,6 +112,8 @@
     "gltf_parser.cc",
     "gltf_parser.h",
     "macros.h",
+    "model/color_scheme.cc",
+    "model/color_scheme.h",
     "model/controller_model.h",
     "model/modal_prompt_type.cc",
     "model/modal_prompt_type.h",
diff --git a/chrome/browser/vr/color_scheme.cc b/chrome/browser/vr/color_scheme.cc
deleted file mode 100644
index 9a65595..0000000
--- a/chrome/browser/vr/color_scheme.cc
+++ /dev/null
@@ -1,152 +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 "chrome/browser/vr/color_scheme.h"
-
-#include "ui/gfx/color_palette.h"
-
-namespace vr {
-
-namespace {
-
-ColorScheme gColorSchemes[ColorScheme::kNumModes];
-
-void InitializeColorSchemes() {
-  static bool initialized = false;
-  if (initialized)
-    return;
-
-  ColorScheme& normal_scheme = gColorSchemes[ColorScheme::kModeNormal];
-  normal_scheme.world_background = 0xFF999999;
-  normal_scheme.world_background_text = 0xFF363636;
-  normal_scheme.floor = 0xFF8C8C8C;
-  normal_scheme.ceiling = normal_scheme.floor;
-  normal_scheme.floor_grid = 0x26FFFFFF;
-  normal_scheme.element_foreground = 0xFF333333;
-  normal_scheme.element_background = 0xCCB3B3B3;
-  normal_scheme.element_background_hover = 0xFFCCCCCC;
-  normal_scheme.element_background_down = 0xFFF3F3F3;
-  normal_scheme.button_colors.foreground = 0x87000000;
-  normal_scheme.button_colors.background = normal_scheme.element_background;
-  normal_scheme.button_colors.background_hover =
-      normal_scheme.element_background_hover;
-  normal_scheme.button_colors.background_press =
-      normal_scheme.element_background_down;
-  normal_scheme.loading_indicator_foreground = 0xFF2979FF;
-  normal_scheme.loading_indicator_background = 0xFF454545;
-  normal_scheme.exit_warning_foreground = SK_ColorWHITE;
-  normal_scheme.exit_warning_background = 0xCC1A1A1A;
-  normal_scheme.web_vr_transient_toast_foreground = 0xFFF3F3F3;
-  normal_scheme.web_vr_transient_toast_background = SK_ColorBLACK;
-  normal_scheme.exclusive_screen_toast_foreground = 0xCCFFFFFF;
-  normal_scheme.exclusive_screen_toast_background = 0xCC2F2F2F;
-
-  normal_scheme.system_indicator_foreground = 0xFF444444;
-  normal_scheme.system_indicator_background = SK_ColorWHITE;
-  normal_scheme.audio_permission_prompt_icon_foreground = 0xFF4285F4;
-  normal_scheme.audio_permission_prompt_secondary_button_forground = 0xFF4285F4;
-  normal_scheme.audio_permission_prompt_secondary_button_hover = 0x19999999;
-  normal_scheme.audio_permission_prompt_secondary_button_down = 0x33999999;
-  normal_scheme.audio_permission_prompt_primary_button_background = 0xFF4285F4;
-  normal_scheme.audio_permission_prompt_primary_button_hover = 0xFF3E7DE6;
-  normal_scheme.audio_permission_prompt_primary_button_down = 0xFF3E7DE6;
-  normal_scheme.audio_permission_prompt_background = 0xFFF5F5F5;
-  normal_scheme.separator = 0xFF9E9E9E;
-  normal_scheme.prompt_foreground = 0xCC000000;
-  normal_scheme.prompt_primary_button_forground = 0xA6000000;
-  normal_scheme.prompt_secondary_button_foreground = 0xA6000000;
-  normal_scheme.prompt_primary_button_background = 0xBFFFFFFF;
-  normal_scheme.prompt_secondary_button_background = 0x66FFFFFF;
-  normal_scheme.prompt_button_background_hover = 0xFFFFFFFF;
-  normal_scheme.prompt_button_background_down = 0xE6FFFFFF;
-  normal_scheme.secure = gfx::kGoogleGreen700;
-  normal_scheme.insecure = gfx::kGoogleRed700;
-  normal_scheme.url_emphasized = SK_ColorBLACK;
-  normal_scheme.url_deemphasized = 0xFF5A5A5A;
-  normal_scheme.offline_page_warning = 0xFF242424;
-  normal_scheme.disabled = 0x33333333;
-  normal_scheme.dimmer_inner = 0xCC0D0D0D;
-  normal_scheme.dimmer_outer = 0xE6000000;
-  normal_scheme.splash_screen_background = SK_ColorBLACK;
-  normal_scheme.splash_screen_text_color = 0xA6FFFFFF;
-  normal_scheme.spinner_background = SK_ColorBLACK;
-  normal_scheme.spinner_color = 0xFFF3F3F3;
-  normal_scheme.timeout_message_background = 0xFF444444;
-  normal_scheme.timeout_message_foreground = normal_scheme.spinner_color;
-  normal_scheme.speech_recognition_circle_background = 0xFF4285F4;
-
-  gColorSchemes[ColorScheme::kModeFullscreen] =
-      gColorSchemes[ColorScheme::kModeNormal];
-  ColorScheme& fullscreen_scheme = gColorSchemes[ColorScheme::kModeFullscreen];
-  fullscreen_scheme.world_background = 0xFF000714;
-  fullscreen_scheme.floor = 0xFF070F1C;
-  fullscreen_scheme.ceiling = 0xFF04080F;
-  fullscreen_scheme.floor_grid = 0x40A3E0FF;
-  fullscreen_scheme.element_foreground = 0x80FFFFFF;
-  fullscreen_scheme.element_background = 0xCC2B3E48;
-  fullscreen_scheme.element_background_hover = 0xCC536B77;
-  fullscreen_scheme.element_background_down = 0xCC96AFBB;
-
-  fullscreen_scheme.button_colors.foreground =
-      fullscreen_scheme.element_foreground;
-  fullscreen_scheme.button_colors.background =
-      fullscreen_scheme.element_background;
-  fullscreen_scheme.button_colors.background_hover =
-      fullscreen_scheme.element_background_hover;
-  fullscreen_scheme.button_colors.background_press =
-      fullscreen_scheme.element_background_down;
-
-  gColorSchemes[ColorScheme::kModeIncognito] =
-      gColorSchemes[ColorScheme::kModeNormal];
-  ColorScheme& incognito_scheme = gColorSchemes[ColorScheme::kModeIncognito];
-  incognito_scheme.world_background = 0xFF2E2E2E;
-  incognito_scheme.world_background_text = 0xFF878787;
-  incognito_scheme.floor = 0xFF282828;
-  incognito_scheme.ceiling = 0xFF2F2F2F;
-  incognito_scheme.floor_grid = 0xCC595959;
-  incognito_scheme.element_foreground = 0xFFBCBCBC;
-  incognito_scheme.element_background = 0xCC454545;
-  incognito_scheme.element_background_hover = 0xCC505050;
-  incognito_scheme.element_background_down = 0xCC888888;
-  incognito_scheme.button_colors.foreground =
-      fullscreen_scheme.element_foreground;
-  incognito_scheme.button_colors.background =
-      fullscreen_scheme.element_background;
-  incognito_scheme.button_colors.background_hover =
-      fullscreen_scheme.element_background_hover;
-  incognito_scheme.button_colors.background_press =
-      fullscreen_scheme.element_background_down;
-  incognito_scheme.separator = 0xFF474747;
-  incognito_scheme.secure = 0xFFEDEDED;
-  incognito_scheme.insecure = incognito_scheme.secure;
-  incognito_scheme.url_emphasized = incognito_scheme.secure;
-  incognito_scheme.url_deemphasized = 0xFF878787;
-  incognito_scheme.offline_page_warning = incognito_scheme.secure;
-  incognito_scheme.prompt_foreground = 0xCCFFFFFF;
-  incognito_scheme.prompt_primary_button_forground = 0xD9000000;
-  incognito_scheme.prompt_secondary_button_foreground = 0xD9000000;
-  incognito_scheme.prompt_primary_button_background = 0xD9FFFFFF;
-  incognito_scheme.prompt_secondary_button_background = 0x80FFFFFF;
-  incognito_scheme.prompt_button_background_hover = 0xFF8C8C8C;
-  incognito_scheme.prompt_button_background_down = 0xE6FFFFFF;
-  incognito_scheme.disabled = 0x33E6E6E6;
-
-  initialized = true;
-}
-
-}  // namespace
-
-bool ButtonColors::operator==(const ButtonColors& other) const {
-  return background == other.background &&
-         background_hover == other.background_hover &&
-         background_press == other.background_press &&
-         foreground == other.foreground;
-}
-
-const ColorScheme& ColorScheme::GetColorScheme(ColorScheme::Mode mode) {
-  InitializeColorSchemes();
-  return gColorSchemes[static_cast<int>(mode)];
-}
-
-}  // namespace vr
diff --git a/chrome/browser/vr/elements/audio_permission_prompt.cc b/chrome/browser/vr/elements/audio_permission_prompt.cc
index 29c024c9..df9294b 100644
--- a/chrome/browser/vr/elements/audio_permission_prompt.cc
+++ b/chrome/browser/vr/elements/audio_permission_prompt.cc
@@ -58,6 +58,19 @@
   OnStateUpdated(position);
 }
 
+void AudioPermissionPrompt::SetPrimaryButtonColors(const ButtonColors& colors) {
+  texture_->SetPrimaryButtonColors(colors);
+}
+
+void AudioPermissionPrompt::SetSecondaryButtonColors(
+    const ButtonColors& colors) {
+  texture_->SetSecondaryButtonColors(colors);
+}
+
+void AudioPermissionPrompt::SetIconColor(SkColor color) {
+  texture_->SetIconColor(color);
+}
+
 void AudioPermissionPrompt::OnStateUpdated(const gfx::PointF& position) {
   const bool primary_hovered = texture_->HitsPrimaryButton(position);
   const bool secondary_hovered = texture_->HitsSecondaryButton(position);
diff --git a/chrome/browser/vr/elements/audio_permission_prompt.h b/chrome/browser/vr/elements/audio_permission_prompt.h
index 99a6561..51801386 100644
--- a/chrome/browser/vr/elements/audio_permission_prompt.h
+++ b/chrome/browser/vr/elements/audio_permission_prompt.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "chrome/browser/vr/elements/textured_element.h"
+#include "chrome/browser/vr/model/color_scheme.h"
 
 namespace vr {
 
@@ -32,6 +33,10 @@
   void OnButtonDown(const gfx::PointF& position) override;
   void OnButtonUp(const gfx::PointF& position) override;
 
+  void SetPrimaryButtonColors(const ButtonColors& colors);
+  void SetSecondaryButtonColors(const ButtonColors& colors);
+  void SetIconColor(SkColor color);
+
  private:
   UiTexture* GetTexture() const override;
 
diff --git a/chrome/browser/vr/elements/audio_permission_prompt_texture.cc b/chrome/browser/vr/elements/audio_permission_prompt_texture.cc
index cf0e8d1..7c01e5b 100644
--- a/chrome/browser/vr/elements/audio_permission_prompt_texture.cc
+++ b/chrome/browser/vr/elements/audio_permission_prompt_texture.cc
@@ -6,7 +6,6 @@
 
 #include "base/i18n/case_conversion.h"
 #include "cc/paint/skia_paint_canvas.h"
-#include "chrome/browser/vr/color_scheme.h"
 #include "chrome/browser/vr/elements/vector_icon.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/strings/grit/components_strings.h"
@@ -55,16 +54,15 @@
   gfx::Canvas* canvas = &gfx_canvas;
 
   SkPaint back_paint;
-  back_paint.setColor(color_scheme().audio_permission_prompt_background);
+  back_paint.setColor(background_color());
   sk_canvas->drawRoundRect(SkRect::MakeWH(size_.width(), size_.height()),
                            ToPixels(kCornerRadius), ToPixels(kCornerRadius),
                            back_paint);
 
   // Icon
   gfx::PointF icon_location(ToPixels(kPadding), ToPixels(kPadding));
-  VectorIcon::DrawVectorIcon(
-      canvas, vector_icons::kMicrophoneIcon, ToPixels(kIconSize), icon_location,
-      color_scheme().audio_permission_prompt_icon_foreground);
+  VectorIcon::DrawVectorIcon(canvas, vector_icons::kMicrophoneIcon,
+                             ToPixels(kIconSize), icon_location, icon_color_);
 
   // Prompt description.
   auto text = l10n_util::GetStringUTF16(
@@ -72,9 +70,9 @@
   gfx::FontList fonts;
   GetFontList(ToPixels(kFontSizePromptText), text, &fonts);
   gfx::Rect prompt_text_size(size_.width(), 0);
-  std::vector<std::unique_ptr<gfx::RenderText>> lines = PrepareDrawStringRect(
-      text, fonts, color_scheme().element_foreground, &prompt_text_size,
-      kTextAlignmentNone, kWrappingBehaviorWrap);
+  std::vector<std::unique_ptr<gfx::RenderText>> lines =
+      PrepareDrawStringRect(text, fonts, foreground_color(), &prompt_text_size,
+                            kTextAlignmentNone, kWrappingBehaviorWrap);
   canvas->Save();
   canvas->Translate(
       gfx::Vector2d(ToPixels(IsRTL() ? kPadding + kTextLeftMargin
@@ -88,20 +86,20 @@
   SkPaint paint;
   gfx::Rect button_text_size(ToPixels(kButtonWidth), 0);
   float radius = ToPixels(kButtonRadius);
-  GetFontList(ToPixels(kFontSizePromptButtonText), text, &fonts);
 
   // Secondary button area.
   text = base::i18n::ToUpper(l10n_util::GetStringUTF16(
       IDS_VR_SHELL_AUDIO_PERMISSION_PROMPT_ABORT_BUTTON));
+  GetFontList(ToPixels(kFontSizePromptButtonText), text, &fonts);
   lines = PrepareDrawStringRect(
-      text, fonts,
-      color_scheme().audio_permission_prompt_secondary_button_forground,
-      &button_text_size, kTextAlignmentCenter, kWrappingBehaviorWrap);
+      text, fonts, secondary_button_colors_.foreground, &button_text_size,
+      kTextAlignmentCenter, kWrappingBehaviorWrap);
   secondary_button_rect_.SetRect(
       ToPixels(kWidth - kPadding - kButtonsDistance - 2 * kButtonWidth),
       ToPixels(kPadding + kIconSize + kVerticalGap), ToPixels(kButtonWidth),
       ToPixels(kButtonHeight));
-  paint.setColor(GetSecondaryButtonColor());
+  paint.setColor(secondary_button_colors_.GetBackgroundColor(
+      secondary_hovered_, secondary_pressed_));
   canvas->Save();
   canvas->Translate(
       gfx::Vector2d(secondary_button_rect_.x(), secondary_button_rect_.y()));
@@ -117,14 +115,16 @@
   // Primary button area.
   text = base::i18n::ToUpper(l10n_util::GetStringUTF16(
       IDS_VR_SHELL_AUDIO_PERMISSION_PROMPT_CONTINUE_BUTTON));
+  GetFontList(ToPixels(kFontSizePromptButtonText), text, &fonts);
   button_text_size.set_size(gfx::Size(ToPixels(kButtonWidth), 0));
-  lines = PrepareDrawStringRect(
-      text, fonts, color_scheme().audio_permission_prompt_background,
-      &button_text_size, kTextAlignmentCenter, kWrappingBehaviorWrap);
+  lines = PrepareDrawStringRect(text, fonts, primary_button_colors_.foreground,
+                                &button_text_size, kTextAlignmentCenter,
+                                kWrappingBehaviorWrap);
   primary_button_rect_.SetRect(ToPixels(kWidth - kPadding - kButtonWidth),
                                ToPixels(kPadding + kIconSize + kVerticalGap),
                                ToPixels(kButtonWidth), ToPixels(kButtonHeight));
-  paint.setColor(GetPrimaryButtonColor());
+  paint.setColor(primary_button_colors_.GetBackgroundColor(primary_hovered_,
+                                                           primary_pressed_));
   canvas->Save();
   canvas->Translate(
       gfx::Vector2d(primary_button_rect_.x(), primary_button_rect_.y()));
@@ -147,22 +147,6 @@
   return gfx::PointF(percent.x() * size_.width(), percent.y() * size_.height());
 }
 
-SkColor AudioPermissionPromptTexture::GetPrimaryButtonColor() const {
-  if (primary_pressed_)
-    return color_scheme().audio_permission_prompt_primary_button_down;
-  if (primary_hovered_)
-    return color_scheme().audio_permission_prompt_primary_button_hover;
-  return color_scheme().audio_permission_prompt_primary_button_background;
-}
-
-SkColor AudioPermissionPromptTexture::GetSecondaryButtonColor() const {
-  if (secondary_pressed_)
-    return color_scheme().audio_permission_prompt_secondary_button_down;
-  if (secondary_hovered_)
-    return color_scheme().audio_permission_prompt_secondary_button_hover;
-  return color_scheme().audio_permission_prompt_background;
-}
-
 bool AudioPermissionPromptTexture::HitsPrimaryButton(
     const gfx::PointF& position) const {
   return primary_button_rect_.Contains(PercentToPixels(position));
@@ -174,27 +158,33 @@
 }
 
 void AudioPermissionPromptTexture::SetPrimaryButtonHovered(bool hovered) {
-  if (primary_hovered_ != hovered)
-    set_dirty();
-  primary_hovered_ = hovered;
+  SetAndDirty(&primary_hovered_, hovered);
 }
 
 void AudioPermissionPromptTexture::SetPrimaryButtonPressed(bool pressed) {
-  if (primary_pressed_ != pressed)
-    set_dirty();
-  primary_pressed_ = pressed;
+  SetAndDirty(&primary_pressed_, pressed);
 }
 
 void AudioPermissionPromptTexture::SetSecondaryButtonHovered(bool hovered) {
-  if (secondary_hovered_ != hovered)
-    set_dirty();
-  secondary_hovered_ = hovered;
+  SetAndDirty(&secondary_hovered_, hovered);
 }
 
 void AudioPermissionPromptTexture::SetSecondaryButtonPressed(bool pressed) {
-  if (secondary_pressed_ != pressed)
-    set_dirty();
-  secondary_pressed_ = pressed;
+  SetAndDirty(&secondary_pressed_, pressed);
+}
+
+void AudioPermissionPromptTexture::SetPrimaryButtonColors(
+    const ButtonColors& colors) {
+  SetAndDirty(&primary_button_colors_, colors);
+}
+
+void AudioPermissionPromptTexture::SetSecondaryButtonColors(
+    const ButtonColors& colors) {
+  SetAndDirty(&secondary_button_colors_, colors);
+}
+
+void AudioPermissionPromptTexture::SetIconColor(SkColor color) {
+  SetAndDirty(&icon_color_, color);
 }
 
 gfx::Size AudioPermissionPromptTexture::GetPreferredTextureSize(
diff --git a/chrome/browser/vr/elements/audio_permission_prompt_texture.h b/chrome/browser/vr/elements/audio_permission_prompt_texture.h
index f5953cc6..5abeb43 100644
--- a/chrome/browser/vr/elements/audio_permission_prompt_texture.h
+++ b/chrome/browser/vr/elements/audio_permission_prompt_texture.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/vr/elements/ui_texture.h"
+#include "chrome/browser/vr/model/color_scheme.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace gfx {
@@ -30,11 +31,13 @@
   virtual bool HitsSecondaryButton(const gfx::PointF& position) const;
   virtual bool HitsPrimaryButton(const gfx::PointF& position) const;
 
+  void SetPrimaryButtonColors(const ButtonColors& colors);
+  void SetSecondaryButtonColors(const ButtonColors& colors);
+  void SetIconColor(SkColor color);
+
  private:
   void Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) override;
 
-  SkColor GetPrimaryButtonColor() const;
-  SkColor GetSecondaryButtonColor() const;
   float ToPixels(float meters) const;
   gfx::PointF PercentToPixels(const gfx::PointF& percent) const;
 
@@ -47,6 +50,10 @@
   bool secondary_hovered_ = false;
   bool secondary_pressed_ = false;
 
+  ButtonColors primary_button_colors_;
+  ButtonColors secondary_button_colors_;
+  SkColor icon_color_ = SK_ColorBLACK;
+
   DISALLOW_COPY_AND_ASSIGN(AudioPermissionPromptTexture);
 };
 
diff --git a/chrome/browser/vr/elements/button.cc b/chrome/browser/vr/elements/button.cc
index 37f25c3..1eb31d6 100644
--- a/chrome/browser/vr/elements/button.cc
+++ b/chrome/browser/vr/elements/button.cc
@@ -24,7 +24,7 @@
 }  // namespace
 
 Button::Button(base::Callback<void()> click_handler,
-               int draw_phase,
+               DrawPhase draw_phase,
                float width,
                float height,
                float hover_offset,
@@ -130,14 +130,8 @@
     hit_plane_->SetScale(1.0f, 1.0f, 1.0f);
   }
 
-  if (pressed_) {
-    background_->SetColor(colors_.background_press);
-  } else if (hovered_) {
-    background_->SetColor(colors_.background_hover);
-  } else {
-    background_->SetColor(colors_.background);
-  }
-  foreground_->SetColor(colors_.foreground);
+  background_->SetColor(colors_.GetBackgroundColor(hovered_, pressed_));
+  foreground_->SetColor(colors_.GetForegroundColor(disabled_));
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/elements/button.h b/chrome/browser/vr/elements/button.h
index 1e5aa635..527c786 100644
--- a/chrome/browser/vr/elements/button.h
+++ b/chrome/browser/vr/elements/button.h
@@ -9,9 +9,10 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "chrome/browser/vr/color_scheme.h"
+#include "chrome/browser/vr/elements/draw_phase.h"
 #include "chrome/browser/vr/elements/invisible_hit_target.h"
 #include "chrome/browser/vr/elements/ui_element.h"
+#include "chrome/browser/vr/model/color_scheme.h"
 #include "ui/gfx/vector_icon_types.h"
 
 namespace gfx {
@@ -28,7 +29,7 @@
 class Button : public UiElement {
  public:
   Button(base::Callback<void()> click_handler,
-         int draw_phase,
+         DrawPhase draw_phase,
          float width,
          float height,
          float hover_offset,
@@ -55,6 +56,7 @@
 
   bool hovered_ = false;
   bool pressed_ = false;
+  bool disabled_ = false;
   base::Callback<void()> click_handler_;
   float hover_offset_;
   ButtonColors colors_;
diff --git a/chrome/browser/vr/elements/content_element.cc b/chrome/browser/vr/elements/content_element.cc
index 83646512..b7a9f29 100644
--- a/chrome/browser/vr/elements/content_element.cc
+++ b/chrome/browser/vr/elements/content_element.cc
@@ -5,13 +5,28 @@
 #include "chrome/browser/vr/elements/content_element.h"
 
 #include "chrome/browser/vr/ui_element_renderer.h"
+#include "chrome/browser/vr/vr_gl_util.h"
 #include "third_party/WebKit/public/platform/WebGestureEvent.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace vr {
 
-ContentElement::ContentElement(ContentInputDelegate* delegate)
-    : delegate_(delegate) {
+namespace {
+
+// If the screen space bounds or the aspect ratio of the content quad change
+// beyond these thresholds we propagate the new content bounds so that the
+// content's resolution can be adjusted.
+static constexpr float kContentBoundsPropagationThreshold = 0.2f;
+// Changes of the aspect ratio lead to a
+// distorted content much more quickly. Thus, have a smaller threshold here.
+static constexpr float kContentAspectRatioPropagationThreshold = 0.01f;
+
+}  // namespace
+
+ContentElement::ContentElement(
+    ContentInputDelegate* delegate,
+    ContentElement::ScreenBoundsChangedCallback bounds_changed_callback)
+    : delegate_(delegate), bounds_changed_callback_(bounds_changed_callback) {
   DCHECK(delegate);
   set_scrollable(true);
 }
@@ -75,10 +90,62 @@
   delegate_->OnContentScrollEnd(std::move(gesture), position);
 }
 
-void ContentElement::SetTexture(unsigned int texture_id,
-                                UiElementRenderer::TextureLocation location) {
+void ContentElement::SetTextureId(unsigned int texture_id) {
   texture_id_ = texture_id;
+}
+
+void ContentElement::SetTextureLocation(
+    UiElementRenderer::TextureLocation location) {
   texture_location_ = location;
 }
 
+void ContentElement::SetProjectionMatrix(const gfx::Transform& matrix) {
+  projection_matrix_ = matrix;
+}
+
+bool ContentElement::OnBeginFrame(const base::TimeTicks& time,
+                                  const gfx::Vector3dF& look_at) {
+  // Determine if the projected size of the content quad changed more than a
+  // given threshold. If so, propagate this info so that the content's
+  // resolution and size can be adjusted. For the calculation, we cannot take
+  // the content quad's actual size (main_content_->size()) if this property
+  // is animated. If we took the actual size during an animation we would
+  // surpass the threshold with differing projected sizes and aspect ratios
+  // (depending on the animation's timing). The differing values may cause
+  // visual artefacts if, for instance, the fullscreen aspect ratio is not 16:9.
+  // As a workaround, take the final size of the content quad after the
+  // animation as the basis for the calculation.
+  gfx::SizeF target_size = GetTargetSize();
+  // We take the target transform in case the content quad's parent's translate
+  // is animated. This approach only works with the current scene hierarchy and
+  // set of animated properties.
+  gfx::Transform target_transform = ComputeTargetWorldSpaceTransform();
+  gfx::SizeF screen_size =
+      CalculateScreenSize(projection_matrix_, target_transform, target_size);
+
+  float aspect_ratio = target_size.width() / target_size.height();
+  gfx::SizeF screen_bounds;
+  if (screen_size.width() < screen_size.height() * aspect_ratio) {
+    screen_bounds.set_width(screen_size.height() * aspect_ratio);
+    screen_bounds.set_height(screen_size.height());
+  } else {
+    screen_bounds.set_width(screen_size.width());
+    screen_bounds.set_height(screen_size.width() / aspect_ratio);
+  }
+
+  if (std::abs(screen_bounds.width() - last_content_screen_bounds_.width()) >
+          kContentBoundsPropagationThreshold ||
+      std::abs(screen_bounds.height() - last_content_screen_bounds_.height()) >
+          kContentBoundsPropagationThreshold ||
+      std::abs(aspect_ratio - last_content_aspect_ratio_) >
+          kContentAspectRatioPropagationThreshold) {
+    bounds_changed_callback_.Run(screen_bounds);
+    last_content_screen_bounds_.set_width(screen_bounds.width());
+    last_content_screen_bounds_.set_height(screen_bounds.height());
+    last_content_aspect_ratio_ = aspect_ratio;
+    return true;
+  }
+  return false;
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/elements/content_element.h b/chrome/browser/vr/elements/content_element.h
index 5b18c189..937d551 100644
--- a/chrome/browser/vr/elements/content_element.h
+++ b/chrome/browser/vr/elements/content_element.h
@@ -14,7 +14,10 @@
 
 class ContentElement : public UiElement {
  public:
-  explicit ContentElement(ContentInputDelegate* delegate);
+  typedef typename base::Callback<void(const gfx::SizeF&)>
+      ScreenBoundsChangedCallback;
+
+  ContentElement(ContentInputDelegate* delegate, ScreenBoundsChangedCallback);
   ~ContentElement() override;
 
   void OnHoverEnter(const gfx::PointF& position) override;
@@ -32,18 +35,25 @@
                       const gfx::PointF& position) override;
   void OnScrollEnd(std::unique_ptr<blink::WebGestureEvent> gesture,
                    const gfx::PointF& position) override;
+  bool OnBeginFrame(const base::TimeTicks& time,
+                    const gfx::Vector3dF& look_at) override;
 
   void Render(UiElementRenderer* renderer,
               const CameraModel& model) const final;
 
-  void SetTexture(unsigned int texture_id,
-                  UiElementRenderer::TextureLocation location);
+  void SetTextureId(unsigned int texture_id);
+  void SetTextureLocation(UiElementRenderer::TextureLocation location);
+  void SetProjectionMatrix(const gfx::Transform& matrix);
 
  private:
   ContentInputDelegate* delegate_ = nullptr;
+  ScreenBoundsChangedCallback bounds_changed_callback_;
   unsigned int texture_id_ = 0;
   UiElementRenderer::TextureLocation texture_location_ =
       UiElementRenderer::kTextureLocationExternal;
+  gfx::SizeF last_content_screen_bounds_;
+  float last_content_aspect_ratio_ = 0.0f;
+  gfx::Transform projection_matrix_;
 
   DISALLOW_COPY_AND_ASSIGN(ContentElement);
 };
diff --git a/chrome/browser/vr/elements/draw_phase.cc b/chrome/browser/vr/elements/draw_phase.cc
new file mode 100644
index 0000000..c317e40
--- /dev/null
+++ b/chrome/browser/vr/elements/draw_phase.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 "chrome/browser/vr/elements/draw_phase.h"
+
+#include "base/macros.h"
+
+namespace vr {
+
+namespace {
+
+static const char* g_draw_phase_strings[] = {
+    "kPhaseNone",         "kPhaseBackground", "kPhaseOverlayBackground",
+    "kPhaseFloorCeiling", "kPhaseForeground", "kPhaseOverlayForeground",
+};
+
+static_assert(
+    kNumDrawPhases + 1 == arraysize(g_draw_phase_strings),
+    "Mismatch between the DrawPhase enum and the corresponding strings");
+
+}  // namespace
+
+std::string DrawPhaseToString(DrawPhase phase) {
+  return g_draw_phase_strings[phase];
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/elements/draw_phase.h b/chrome/browser/vr/elements/draw_phase.h
index 0df6a54c..dbca452 100644
--- a/chrome/browser/vr/elements/draw_phase.h
+++ b/chrome/browser/vr/elements/draw_phase.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_VR_ELEMENTS_DRAW_PHASE_H_
 #define CHROME_BROWSER_VR_ELEMENTS_DRAW_PHASE_H_
 
+#include <string>
+
 namespace vr {
 
 // Each draw phase is rendered independently in the order specified below.
@@ -16,8 +18,11 @@
   kPhaseFloorCeiling,
   kPhaseForeground,
   kPhaseOverlayForeground,
+  kNumDrawPhases = kPhaseOverlayForeground
 };
 
+std::string DrawPhaseToString(DrawPhase phase);
+
 }  // namespace vr
 
 #endif  // CHROME_BROWSER_VR_ELEMENTS_DRAW_PHASE_H_
diff --git a/chrome/browser/vr/elements/exclusive_screen_toast.cc b/chrome/browser/vr/elements/exclusive_screen_toast.cc
deleted file mode 100644
index e0498d7..0000000
--- a/chrome/browser/vr/elements/exclusive_screen_toast.cc
+++ /dev/null
@@ -1,26 +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 "chrome/browser/vr/elements/exclusive_screen_toast.h"
-
-#include "chrome/browser/vr/elements/textured_element.h"
-#include "chrome/browser/vr/elements/ui_texture.h"
-
-namespace vr {
-
-ExclusiveScreenToast::ExclusiveScreenToast(int preferred_width)
-    : SimpleTexturedElement(preferred_width) {}
-
-ExclusiveScreenToast::~ExclusiveScreenToast() = default;
-
-void ExclusiveScreenToast::UpdateElementSize() {
-  // Adjust the width of this element according to the texture. The width is
-  // decided by the length of the text to show.
-  gfx::SizeF drawn_size = GetTexture()->GetDrawnSize();
-  float width =
-      drawn_size.width() / drawn_size.height() * stale_size().height();
-  SetSize(width, stale_size().height());
-}
-
-}  // namespace vr
diff --git a/chrome/browser/vr/elements/exclusive_screen_toast.h b/chrome/browser/vr/elements/exclusive_screen_toast.h
deleted file mode 100644
index 066c5c7..0000000
--- a/chrome/browser/vr/elements/exclusive_screen_toast.h
+++ /dev/null
@@ -1,28 +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 CHROME_BROWSER_VR_ELEMENTS_EXCLUSIVE_SCREEN_TOAST_H_
-#define CHROME_BROWSER_VR_ELEMENTS_EXCLUSIVE_SCREEN_TOAST_H_
-
-#include "base/macros.h"
-#include "chrome/browser/vr/elements/exclusive_screen_toast_texture.h"
-#include "chrome/browser/vr/elements/simple_textured_element.h"
-
-namespace vr {
-
-class ExclusiveScreenToast
-    : public SimpleTexturedElement<ExclusiveScreenToastTexture> {
- public:
-  explicit ExclusiveScreenToast(int preferred_width);
-  ~ExclusiveScreenToast() override;
-
- private:
-  void UpdateElementSize() override;
-
-  DISALLOW_COPY_AND_ASSIGN(ExclusiveScreenToast);
-};
-
-}  // namespace vr
-
-#endif  // CHROME_BROWSER_VR_ELEMENTS_EXCLUSIVE_SCREEN_TOAST_H_
diff --git a/chrome/browser/vr/elements/exclusive_screen_toast_texture.cc b/chrome/browser/vr/elements/exclusive_screen_toast_texture.cc
index 38565072..59f54b718 100644
--- a/chrome/browser/vr/elements/exclusive_screen_toast_texture.cc
+++ b/chrome/browser/vr/elements/exclusive_screen_toast_texture.cc
@@ -39,16 +39,16 @@
   SkPaint paint;
   float meter_to_pixel_ratio = texture_size.height() / kHeight;
 
-  paint.setColor(color_scheme().exclusive_screen_toast_background);
+  paint.setColor(background_color());
   auto text = l10n_util::GetStringUTF16(IDS_PRESS_APP_TO_EXIT);
   gfx::FontList fonts;
   int pixel_font_size = meter_to_pixel_ratio * kFontHeight;
   GetFontList(pixel_font_size, text, &fonts);
   gfx::Rect text_size(0, pixel_font_size);
 
-  std::vector<std::unique_ptr<gfx::RenderText>> lines = PrepareDrawStringRect(
-      text, fonts, color_scheme().exclusive_screen_toast_foreground, &text_size,
-      kTextAlignmentNone, kWrappingBehaviorNoWrap);
+  std::vector<std::unique_ptr<gfx::RenderText>> lines =
+      PrepareDrawStringRect(text, fonts, foreground_color(), &text_size,
+                            kTextAlignmentNone, kWrappingBehaviorNoWrap);
 
   int pixel_padding = meter_to_pixel_ratio * kWidthPadding;
   size_.set_width(2 * pixel_padding + text_size.width());
diff --git a/chrome/browser/vr/elements/exit_prompt.cc b/chrome/browser/vr/elements/exit_prompt.cc
index bc5f3f9..8a992ae9f 100644
--- a/chrome/browser/vr/elements/exit_prompt.cc
+++ b/chrome/browser/vr/elements/exit_prompt.cc
@@ -11,11 +11,11 @@
 
 ExitPrompt::ExitPrompt(int preferred_width,
                        const ExitPrompt::Callback& primary_button_callback,
-                       const ExitPrompt::Callback& secondary_buttton_callback)
+                       const ExitPrompt::Callback& secondary_button_callback)
     : TexturedElement(preferred_width),
       texture_(base::MakeUnique<ExitPromptTexture>()),
       primary_button_callback_(primary_button_callback),
-      secondary_buttton_callback_(secondary_buttton_callback) {}
+      secondary_button_callback_(secondary_button_callback) {}
 
 ExitPrompt::~ExitPrompt() = default;
 
@@ -52,7 +52,7 @@
   if (primary_down_ && texture_->HitsPrimaryButton(position))
     primary_button_callback_.Run(reason_);
   else if (secondary_down_ && texture_->HitsSecondaryButton(position))
-    secondary_buttton_callback_.Run(reason_);
+    secondary_button_callback_.Run(reason_);
 
   primary_down_ = false;
   secondary_down_ = false;
@@ -60,6 +60,22 @@
   OnStateUpdated(position);
 }
 
+void ExitPrompt::SetPrimaryButtonColors(const ButtonColors& colors) {
+  texture_->SetPrimaryButtonColors(colors);
+}
+
+void ExitPrompt::SetSecondaryButtonColors(const ButtonColors& colors) {
+  texture_->SetSecondaryButtonColors(colors);
+}
+
+void ExitPrompt::ClickPrimaryButtonForTesting() {
+  primary_button_callback_.Run(reason_);
+}
+
+void ExitPrompt::ClickSecondaryButtonForTesting() {
+  secondary_button_callback_.Run(reason_);
+}
+
 void ExitPrompt::OnStateUpdated(const gfx::PointF& position) {
   const bool primary_hovered = texture_->HitsPrimaryButton(position);
   const bool secondary_hovered = texture_->HitsSecondaryButton(position);
diff --git a/chrome/browser/vr/elements/exit_prompt.h b/chrome/browser/vr/elements/exit_prompt.h
index 348807c6..034acd0 100644
--- a/chrome/browser/vr/elements/exit_prompt.h
+++ b/chrome/browser/vr/elements/exit_prompt.h
@@ -15,6 +15,7 @@
 namespace vr {
 
 class ExitPromptTexture;
+struct ButtonColors;
 
 class ExitPrompt : public TexturedElement {
  public:
@@ -36,6 +37,12 @@
   void OnButtonDown(const gfx::PointF& position) override;
   void OnButtonUp(const gfx::PointF& position) override;
 
+  void SetPrimaryButtonColors(const ButtonColors& colors);
+  void SetSecondaryButtonColors(const ButtonColors& colors);
+
+  void ClickPrimaryButtonForTesting();
+  void ClickSecondaryButtonForTesting();
+
  private:
   UiTexture* GetTexture() const override;
 
@@ -48,7 +55,7 @@
   std::unique_ptr<ExitPromptTexture> texture_;
 
   Callback primary_button_callback_;
-  Callback secondary_buttton_callback_;
+  Callback secondary_button_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(ExitPrompt);
 };
diff --git a/chrome/browser/vr/elements/exit_prompt_texture.cc b/chrome/browser/vr/elements/exit_prompt_texture.cc
index 277e952c..ac1e331 100644
--- a/chrome/browser/vr/elements/exit_prompt_texture.cc
+++ b/chrome/browser/vr/elements/exit_prompt_texture.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/vr/elements/exit_prompt_texture.h"
 
 #include "cc/paint/skia_paint_canvas.h"
-#include "chrome/browser/vr/color_scheme.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -50,27 +49,28 @@
   gfx::FontList fonts;
   GetFontList(ToPixels(kFontSizePromptText), text, &fonts);
   gfx::Rect prompt_text_size(size_.width(), 0);
-  std::vector<std::unique_ptr<gfx::RenderText>> lines = PrepareDrawStringRect(
-      text, fonts, color_scheme().prompt_foreground, &prompt_text_size,
-      kTextAlignmentCenter, kWrappingBehaviorWrap);
+  std::vector<std::unique_ptr<gfx::RenderText>> lines =
+      PrepareDrawStringRect(text, fonts, foreground_color(), &prompt_text_size,
+                            kTextAlignmentCenter, kWrappingBehaviorWrap);
   for (auto& render_text : lines)
     render_text->Draw(canvas);
 
   SkPaint paint;
   gfx::Rect button_text_size(ToPixels(kButtonWidth), 0);
   float radius = size_.width() * kButtonRadiusFactor;
-  GetFontList(ToPixels(kFontSizePromptButtonText), text, &fonts);
 
   // Secondary button area.
   text = l10n_util::GetStringUTF16(IDS_VR_SHELL_EXIT_PROMPT_EXIT_VR_BUTTON);
+  GetFontList(ToPixels(kFontSizePromptButtonText), text, &fonts);
   lines = PrepareDrawStringRect(
-      text, fonts, color_scheme().prompt_secondary_button_foreground,
-      &button_text_size, kTextAlignmentCenter, kWrappingBehaviorWrap);
+      text, fonts, secondary_button_colors_.foreground, &button_text_size,
+      kTextAlignmentCenter, kWrappingBehaviorWrap);
   secondary_button_rect_.SetRect(
       ToPixels(kWidth / 2 - kButtonsSeperatorWidth - kButtonWidth),
       prompt_text_size.height() + ToPixels(kPromptTextButtonSeperatorHeight),
       ToPixels(kButtonWidth), ToPixels(kButtonHeight));
-  paint.setColor(GetSecondaryButtonColor());
+  paint.setColor(secondary_button_colors_.GetBackgroundColor(
+      secondary_hovered_, secondary_pressed_));
   canvas->Save();
   canvas->Translate(
       gfx::Vector2d(secondary_button_rect_.x(), secondary_button_rect_.y()));
@@ -85,15 +85,17 @@
 
   // Primary button area.
   text = l10n_util::GetStringUTF16(IDS_OK);
+  GetFontList(ToPixels(kFontSizePromptButtonText), text, &fonts);
   button_text_size.set_size(gfx::Size(ToPixels(kButtonWidth), 0));
-  lines = PrepareDrawStringRect(
-      text, fonts, color_scheme().prompt_primary_button_forground,
-      &button_text_size, kTextAlignmentCenter, kWrappingBehaviorWrap);
+  lines = PrepareDrawStringRect(text, fonts, primary_button_colors_.foreground,
+                                &button_text_size, kTextAlignmentCenter,
+                                kWrappingBehaviorWrap);
   primary_button_rect_.SetRect(
       ToPixels(kWidth / 2 + kButtonsSeperatorWidth),
       prompt_text_size.height() + ToPixels(kPromptTextButtonSeperatorHeight),
       ToPixels(kButtonWidth), ToPixels(kButtonHeight));
-  paint.setColor(GetPrimaryButtonColor());
+  paint.setColor(primary_button_colors_.GetBackgroundColor(primary_hovered_,
+                                                           primary_pressed_));
   canvas->Save();
   canvas->Translate(
       gfx::Vector2d(primary_button_rect_.x(), primary_button_rect_.y()));
@@ -116,22 +118,6 @@
   return gfx::PointF(percent.x() * size_.width(), percent.y() * size_.height());
 }
 
-SkColor ExitPromptTexture::GetPrimaryButtonColor() const {
-  if (primary_pressed_)
-    return color_scheme().prompt_button_background_down;
-  if (primary_hovered_)
-    return color_scheme().prompt_button_background_hover;
-  return color_scheme().prompt_primary_button_background;
-}
-
-SkColor ExitPromptTexture::GetSecondaryButtonColor() const {
-  if (secondary_pressed_)
-    return color_scheme().prompt_button_background_down;
-  if (secondary_hovered_)
-    return color_scheme().prompt_button_background_hover;
-  return color_scheme().prompt_secondary_button_background;
-}
-
 bool ExitPromptTexture::HitsPrimaryButton(const gfx::PointF& position) const {
   return primary_button_rect_.Contains(PercentToPixels(position));
 }
@@ -141,32 +127,31 @@
 }
 
 void ExitPromptTexture::SetPrimaryButtonHovered(bool hovered) {
-  if (primary_hovered_ != hovered)
-    set_dirty();
-  primary_hovered_ = hovered;
+  SetAndDirty(&primary_hovered_, hovered);
 }
 
 void ExitPromptTexture::SetPrimaryButtonPressed(bool pressed) {
-  if (primary_pressed_ != pressed)
-    set_dirty();
-  primary_pressed_ = pressed;
+  SetAndDirty(&primary_pressed_, pressed);
 }
 
 void ExitPromptTexture::SetSecondaryButtonHovered(bool hovered) {
-  if (secondary_hovered_ != hovered)
-    set_dirty();
-  secondary_hovered_ = hovered;
+  SetAndDirty(&secondary_hovered_, hovered);
 }
 
 void ExitPromptTexture::SetSecondaryButtonPressed(bool pressed) {
-  if (secondary_pressed_ != pressed)
-    set_dirty();
-  secondary_pressed_ = pressed;
+  SetAndDirty(&secondary_pressed_, pressed);
 }
 
 void ExitPromptTexture::SetContentMessageId(int message_id) {
-  content_message_id_ = message_id;
-  set_dirty();
+  SetAndDirty(&content_message_id_, message_id);
+}
+
+void ExitPromptTexture::SetPrimaryButtonColors(const ButtonColors& colors) {
+  SetAndDirty(&primary_button_colors_, colors);
+}
+
+void ExitPromptTexture::SetSecondaryButtonColors(const ButtonColors& colors) {
+  SetAndDirty(&secondary_button_colors_, colors);
 }
 
 gfx::Size ExitPromptTexture::GetPreferredTextureSize(int maximum_width) const {
diff --git a/chrome/browser/vr/elements/exit_prompt_texture.h b/chrome/browser/vr/elements/exit_prompt_texture.h
index 3f5de11..cea62ca 100644
--- a/chrome/browser/vr/elements/exit_prompt_texture.h
+++ b/chrome/browser/vr/elements/exit_prompt_texture.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/vr/elements/ui_texture.h"
+#include "chrome/browser/vr/model/color_scheme.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace gfx {
@@ -31,11 +32,12 @@
   virtual bool HitsSecondaryButton(const gfx::PointF& position) const;
   virtual bool HitsPrimaryButton(const gfx::PointF& position) const;
 
+  void SetPrimaryButtonColors(const ButtonColors& colors);
+  void SetSecondaryButtonColors(const ButtonColors& colors);
+
  private:
   void Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) override;
 
-  SkColor GetPrimaryButtonColor() const;
-  SkColor GetSecondaryButtonColor() const;
   float ToPixels(float meters) const;
   gfx::PointF PercentToPixels(const gfx::PointF& percent) const;
 
@@ -49,6 +51,9 @@
   bool secondary_pressed_ = false;
   int content_message_id_ = -1;
 
+  ButtonColors primary_button_colors_;
+  ButtonColors secondary_button_colors_;
+
   DISALLOW_COPY_AND_ASSIGN(ExitPromptTexture);
 };
 
diff --git a/chrome/browser/vr/elements/exit_warning_texture.cc b/chrome/browser/vr/elements/exit_warning_texture.cc
index d17cae5..5807d48 100644
--- a/chrome/browser/vr/elements/exit_warning_texture.cc
+++ b/chrome/browser/vr/elements/exit_warning_texture.cc
@@ -39,16 +39,16 @@
   size_.set_width(texture_size.width());
   SkPaint paint;
 
-  paint.setColor(color_scheme().exit_warning_background);
+  paint.setColor(background_color());
   auto text =
       l10n_util::GetStringUTF16(IDS_PAGE_INFO_VR_BROWSER_UNSUPPORTED_MODE);
   gfx::FontList fonts;
   GetFontList(size_.width() * kFontSizeFactor, text, &fonts);
   gfx::Rect text_size(size_.width() * kTextWidthFactor, 0);
 
-  std::vector<std::unique_ptr<gfx::RenderText>> lines = PrepareDrawStringRect(
-      text, fonts, color_scheme().exit_warning_foreground, &text_size,
-      kTextAlignmentCenter, kWrappingBehaviorWrap);
+  std::vector<std::unique_ptr<gfx::RenderText>> lines =
+      PrepareDrawStringRect(text, fonts, foreground_color(), &text_size,
+                            kTextAlignmentCenter, kWrappingBehaviorWrap);
 
   DCHECK_LE(text_size.height(),
             static_cast<int>((1.0 - 2 * kBorderFactor) * size_.width()));
diff --git a/chrome/browser/vr/elements/simple_textured_element.h b/chrome/browser/vr/elements/simple_textured_element.h
index 4bab0c0..43a9581 100644
--- a/chrome/browser/vr/elements/simple_textured_element.h
+++ b/chrome/browser/vr/elements/simple_textured_element.h
@@ -11,20 +11,18 @@
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/vr/elements/exclusive_screen_toast_texture.h"
 #include "chrome/browser/vr/elements/exit_warning_texture.h"
+#include "chrome/browser/vr/elements/system_indicator_texture.h"
 #include "chrome/browser/vr/elements/textured_element.h"
 #include "chrome/browser/vr/elements/transient_element.h"
 #include "chrome/browser/vr/elements/ui_texture.h"
 
 namespace vr {
 
-template <class T>
+template <typename T, typename R>
 class SimpleTexturedElement : public TexturedElement {
  public:
-  // |preferred_width| is the element's desired width in meters. Constraints
-  // implied by the texture being rendered may or may not allow it to be
-  // rendered exactly at the preferred width.
   explicit SimpleTexturedElement(int maximum_width)
-      : TexturedElement(maximum_width), texture_(base::MakeUnique<T>()) {}
+      : TexturedElement(maximum_width, R()), texture_(base::MakeUnique<T>()) {}
   ~SimpleTexturedElement() override {}
   T* GetDerivedTexture() { return texture_.get(); }
 
@@ -37,7 +35,15 @@
   DISALLOW_COPY_AND_ASSIGN(SimpleTexturedElement);
 };
 
-typedef SimpleTexturedElement<ExitWarningTexture> ExitWarning;
+typedef SimpleTexturedElement<ExitWarningTexture,
+                              TexturedElement::ResizeVertically>
+    ExitWarning;
+typedef SimpleTexturedElement<ExclusiveScreenToastTexture,
+                              TexturedElement::ResizeHorizontally>
+    ExclusiveScreenToast;
+typedef SimpleTexturedElement<SystemIndicatorTexture,
+                              TexturedElement::ResizeHorizontally>
+    SystemIndicator;
 
 }  // namespace vr
 
diff --git a/chrome/browser/vr/elements/spinner.cc b/chrome/browser/vr/elements/spinner.cc
index 81529b1..c4ed845c 100644
--- a/chrome/browser/vr/elements/spinner.cc
+++ b/chrome/browser/vr/elements/spinner.cc
@@ -34,25 +34,10 @@
   SpinnerTexture() {}
   ~SpinnerTexture() override {}
 
-  void SetAngleSweep(float angle) {
-    angle_sweep_ = angle;
-    set_dirty();
-  }
-
-  void SetAngleStart(float angle) {
-    angle_start_ = angle;
-    set_dirty();
-  }
-
-  void SetRotation(float angle) {
-    rotation_ = angle;
-    set_dirty();
-  }
-
-  void SetColor(SkColor color) {
-    color_ = color;
-    set_dirty();
-  }
+  void SetAngleSweep(float angle) { SetAndDirty(&angle_sweep_, angle); }
+  void SetAngleStart(float angle) { SetAndDirty(&angle_start_, angle); }
+  void SetRotation(float angle) { SetAndDirty(&rotation_, angle); }
+  void SetColor(SkColor color) { SetAndDirty(&color_, color); }
 
  private:
   gfx::Size GetPreferredTextureSize(int width) const override {
diff --git a/chrome/browser/vr/elements/system_indicator.cc b/chrome/browser/vr/elements/system_indicator.cc
deleted file mode 100644
index 42c0a2c3..0000000
--- a/chrome/browser/vr/elements/system_indicator.cc
+++ /dev/null
@@ -1,36 +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 "chrome/browser/vr/elements/system_indicator.h"
-
-#include "base/memory/ptr_util.h"
-#include "chrome/browser/vr/elements/system_indicator_texture.h"
-
-namespace vr {
-
-SystemIndicator::SystemIndicator(int preferred_width,
-                                 float height_meters,
-                                 const gfx::VectorIcon& icon,
-                                 int string_id)
-    : TexturedElement(preferred_width), height_meters_(height_meters) {
-  if (string_id != 0) {
-    texture_ = base::MakeUnique<SystemIndicatorTexture>(icon, string_id);
-  } else {
-    texture_ = base::MakeUnique<SystemIndicatorTexture>(icon);
-  }
-}
-
-void SystemIndicator::UpdateElementSize() {
-  gfx::SizeF drawn_size = GetTexture()->GetDrawnSize();
-  float width = height_meters_ * drawn_size.width() / drawn_size.height();
-  SetSize(width, height_meters_);
-}
-
-SystemIndicator::~SystemIndicator() = default;
-
-UiTexture* SystemIndicator::GetTexture() const {
-  return texture_.get();
-}
-
-}  // namespace vr
diff --git a/chrome/browser/vr/elements/system_indicator.h b/chrome/browser/vr/elements/system_indicator.h
deleted file mode 100644
index 8440765e..0000000
--- a/chrome/browser/vr/elements/system_indicator.h
+++ /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.
-
-#ifndef CHROME_BROWSER_VR_ELEMENTS_SYSTEM_INDICATOR_H_
-#define CHROME_BROWSER_VR_ELEMENTS_SYSTEM_INDICATOR_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "chrome/browser/vr/elements/textured_element.h"
-#include "ui/gfx/vector_icon_types.h"
-
-namespace vr {
-
-class UiTexture;
-
-class SystemIndicator : public TexturedElement {
- public:
-  explicit SystemIndicator(int preferred_width,
-                           float heigh_meters,
-                           const gfx::VectorIcon& icon,
-                           int string_id);
-  ~SystemIndicator() override;
-
- protected:
-  void UpdateElementSize() override;
-
- private:
-  UiTexture* GetTexture() const override;
-  std::unique_ptr<UiTexture> texture_;
-  float height_meters_;
-
-  DISALLOW_COPY_AND_ASSIGN(SystemIndicator);
-};
-
-}  // namespace vr
-
-#endif  // CHROME_BROWSER_VR_ELEMENTS_SYSTEM_INDICATOR_H_
diff --git a/chrome/browser/vr/elements/system_indicator_texture.cc b/chrome/browser/vr/elements/system_indicator_texture.cc
index 3240896..b36c5fee 100644
--- a/chrome/browser/vr/elements/system_indicator_texture.cc
+++ b/chrome/browser/vr/elements/system_indicator_texture.cc
@@ -24,15 +24,17 @@
 
 }  // namespace
 
-SystemIndicatorTexture::SystemIndicatorTexture(const gfx::VectorIcon& icon,
-                                               int message_id)
-    : icon_(icon), message_id_(message_id), has_text_(true) {}
-
-SystemIndicatorTexture::SystemIndicatorTexture(const gfx::VectorIcon& icon)
-    : icon_(icon), has_text_(false) {}
-
+SystemIndicatorTexture::SystemIndicatorTexture() = default;
 SystemIndicatorTexture::~SystemIndicatorTexture() = default;
 
+void SystemIndicatorTexture::SetIcon(const gfx::VectorIcon& icon) {
+  SetAndDirty(&icon_.path, icon.path);
+}
+
+void SystemIndicatorTexture::SetMessageId(int id) {
+  SetAndDirty(&message_id_, id);
+}
+
 void SystemIndicatorTexture::Draw(SkCanvas* sk_canvas,
                                   const gfx::Size& texture_size) {
   cc::SkiaPaintCanvas paint_canvas(sk_canvas);
@@ -46,20 +48,19 @@
   size_.set_width(icon_pixels + 2 * border_pixels);
 
   SkPaint paint;
-  paint.setColor(color_scheme().system_indicator_background);
+  paint.setColor(background_color());
 
   std::unique_ptr<gfx::RenderText> rendered_text;
 
-  if (has_text_) {
+  if (message_id_) {
     base::string16 text = l10n_util::GetStringUTF16(message_id_);
 
     gfx::FontList fonts;
     GetFontList(size_.height() * kFontSizeFactor, text, &fonts);
     gfx::Rect text_size(0, size_.height());
     std::vector<std::unique_ptr<gfx::RenderText>> lines;
-    lines = PrepareDrawStringRect(
-        text, fonts, color_scheme().system_indicator_foreground, &text_size,
-        kTextAlignmentNone, kWrappingBehaviorNoWrap);
+    lines = PrepareDrawStringRect(text, fonts, foreground_color(), &text_size,
+                                  kTextAlignmentNone, kWrappingBehaviorNoWrap);
     DCHECK_EQ(lines.size(), 1u);
     rendered_text = std::move(lines.front());
 
@@ -74,8 +75,7 @@
       (IsRTL() ? size_.width() - border_pixels - icon_pixels : border_pixels),
       (size_.height() - icon_pixels) / 2.0);
   VectorIcon::DrawVectorIcon(canvas, icon_, size_.height() * kIconSizeFactor,
-                             icon_location,
-                             color_scheme().system_indicator_foreground);
+                             icon_location, foreground_color());
 
   if (rendered_text) {
     canvas->Save();
@@ -91,7 +91,7 @@
   // All indicators need to be the same height, so compute height, and then
   // re-compute with based on whether the indicator has text or not.
   int height = maximum_width / kHeightWidthRatio;
-  return gfx::Size(has_text_ ? maximum_width : height, height);
+  return gfx::Size(message_id_ ? maximum_width : height, height);
 }
 
 gfx::SizeF SystemIndicatorTexture::GetDrawnSize() const {
diff --git a/chrome/browser/vr/elements/system_indicator_texture.h b/chrome/browser/vr/elements/system_indicator_texture.h
index ea6fd86..2571664 100644
--- a/chrome/browser/vr/elements/system_indicator_texture.h
+++ b/chrome/browser/vr/elements/system_indicator_texture.h
@@ -11,21 +11,23 @@
 
 namespace vr {
 
+// TODO(asimjour): compose the system indicator out of primitives.
 class SystemIndicatorTexture : public UiTexture {
  public:
-  SystemIndicatorTexture(const gfx::VectorIcon& icon, int message_id);
-  explicit SystemIndicatorTexture(const gfx::VectorIcon& icon);
+  SystemIndicatorTexture();
   ~SystemIndicatorTexture() override;
-  gfx::Size GetPreferredTextureSize(int width) const override;
-  gfx::SizeF GetDrawnSize() const override;
+
+  void SetIcon(const gfx::VectorIcon& icon);
+  void SetMessageId(int id);
 
  private:
+  gfx::Size GetPreferredTextureSize(int width) const override;
+  gfx::SizeF GetDrawnSize() const override;
   void Draw(SkCanvas* canvas, const gfx::Size& texture_size) override;
 
   gfx::SizeF size_;
-  const gfx::VectorIcon& icon_;
-  int message_id_;
-  bool has_text_;
+  gfx::VectorIcon icon_;
+  int message_id_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(SystemIndicatorTexture);
 };
diff --git a/chrome/browser/vr/elements/text.cc b/chrome/browser/vr/elements/text.cc
index 3fc795b..18cbac0 100644
--- a/chrome/browser/vr/elements/text.cc
+++ b/chrome/browser/vr/elements/text.cc
@@ -21,25 +21,12 @@
       : font_height_(font_height), text_width_(text_width) {}
   ~TextTexture() override {}
 
-  void SetText(const base::string16& text) {
-    if (text_ == text)
-      return;
-    text_ = text;
-    set_dirty();
-  }
+  void SetText(const base::string16& text) { SetAndDirty(&text_, text); }
 
-  void SetColor(SkColor color) {
-    if (color_ == color)
-      return;
-    color_ = color;
-    set_dirty();
-  }
+  void SetColor(SkColor color) { SetAndDirty(&color_, color); }
 
   void SetAlignment(TextAlignment alignment) {
-    if (alignment_ == alignment)
-      return;
-    alignment_ = alignment;
-    set_dirty();
+    SetAndDirty(&alignment_, alignment);
   }
 
  private:
diff --git a/chrome/browser/vr/elements/textured_element.cc b/chrome/browser/vr/elements/textured_element.cc
index 879524f1..3dd3e061 100644
--- a/chrome/browser/vr/elements/textured_element.cc
+++ b/chrome/browser/vr/elements/textured_element.cc
@@ -21,6 +21,12 @@
 TexturedElement::TexturedElement(int maximum_width)
     : maximum_width_(maximum_width) {}
 
+TexturedElement::TexturedElement(int maximum_width, ResizeVertically unused)
+    : maximum_width_(maximum_width), resize_vertically_(true) {}
+
+TexturedElement::TexturedElement(int maximum_width, ResizeHorizontally unused)
+    : maximum_width_(maximum_width), resize_vertically_(false) {}
+
 TexturedElement::~TexturedElement() = default;
 
 void TexturedElement::Initialize(SkiaSurfaceProvider* provider) {
@@ -57,12 +63,27 @@
   return true;
 }
 
+void TexturedElement::SetForegroundColor(SkColor color) {
+  GetTexture()->SetForegroundColor(color);
+}
+
+void TexturedElement::SetBackgroundColor(SkColor color) {
+  GetTexture()->SetBackgroundColor(color);
+}
+
 void TexturedElement::UpdateElementSize() {
-  // Updating the height according to width is a hack.  This may be overridden.
+  // Adjust the width/height of this element according to the texture. Size in
+  // the other direction is determined by the associated texture.
   gfx::SizeF drawn_size = GetTexture()->GetDrawnSize();
-  float height =
-      drawn_size.height() / drawn_size.width() * stale_size().width();
-  SetSize(stale_size().width(), height);
+  if (resize_vertically_) {
+    float height =
+        drawn_size.height() / drawn_size.width() * stale_size().width();
+    SetSize(stale_size().width(), height);
+  } else {
+    float width =
+        drawn_size.width() / drawn_size.height() * stale_size().height();
+    SetSize(width, stale_size().height());
+  }
 }
 
 void TexturedElement::Render(UiElementRenderer* renderer,
@@ -81,10 +102,6 @@
       computed_opacity(), size(), corner_radius());
 }
 
-void TexturedElement::OnSetMode() {
-  GetTexture()->SetMode(mode());
-}
-
 bool TexturedElement::PrepareToDraw() {
   return UpdateTexture();
 }
diff --git a/chrome/browser/vr/elements/textured_element.h b/chrome/browser/vr/elements/textured_element.h
index 2c106cc0..7372c6bb 100644
--- a/chrome/browser/vr/elements/textured_element.h
+++ b/chrome/browser/vr/elements/textured_element.h
@@ -19,10 +19,22 @@
 
 class TexturedElement : public UiElement {
  public:
+  // These types are used to statically choose the right constructor for simple
+  // textured elements.
+  struct ResizeVertically {};
+  struct ResizeHorizontally {};
+
   // |preferred_width| is the element's desired width in meters. Constraints
   // implied by the texture being rendered may or may not allow it to be
   // rendered exactly at the preferred width.
   explicit TexturedElement(int maximum_width);
+
+  // These constructors set up the |resize_vertically_| member which determine
+  // how the textured element responds to a size change in the associated
+  // texture. (I.e., which dimension should be resized in order for this element
+  // to match the texture's aspect ratio).
+  TexturedElement(int maximum_width, ResizeVertically);
+  TexturedElement(int maximum_width, ResizeHorizontally);
   ~TexturedElement() override;
 
   void Initialize(SkiaSurfaceProvider* provider) final;
@@ -33,21 +45,25 @@
   static void SetInitializedForTesting();
   static void SetRerenderIfNotDirtyForTesting();
 
+  // Foreground and background colors are used pervasively in textured elements,
+  // but more element-specific colors should be set on the appropriate element.
+  void SetForegroundColor(SkColor color);
+  void SetBackgroundColor(SkColor color);
+
  protected:
   virtual UiTexture* GetTexture() const = 0;
-  virtual void UpdateElementSize();
+  void UpdateElementSize();
 
   bool PrepareToDraw() final;
 
  private:
   bool UpdateTexture();
 
-  void OnSetMode() override;
-
   gfx::Size texture_size_;
   GLuint texture_handle_ = 0;
   int maximum_width_;
   bool initialized_ = false;
+  bool resize_vertically_ = true;
 
   sk_sp<SkSurface> surface_;
   SkiaSurfaceProvider* provider_ = nullptr;
diff --git a/chrome/browser/vr/elements/transient_element.cc b/chrome/browser/vr/elements/transient_element.cc
index 6b1df267..8e8dc49 100644
--- a/chrome/browser/vr/elements/transient_element.cc
+++ b/chrome/browser/vr/elements/transient_element.cc
@@ -14,8 +14,9 @@
 TransientElement::~TransientElement() {}
 
 void TransientElement::SetVisible(bool visible) {
+  bool will_be_visible = GetTargetOpacity() == opacity_when_visible();
   // We're already at the desired visibility, no-op.
-  if (visible == (GetTargetOpacity() == opacity_when_visible()))
+  if (visible == will_be_visible)
     return;
 
   if (visible)
@@ -104,8 +105,8 @@
   return false;
 }
 
-void ShowUntilSignalTransientElement::Signal() {
-  signaled_ = true;
+void ShowUntilSignalTransientElement::Signal(bool value) {
+  signaled_ = value;
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/elements/transient_element.h b/chrome/browser/vr/elements/transient_element.h
index a10ccf7..1c60ce0 100644
--- a/chrome/browser/vr/elements/transient_element.h
+++ b/chrome/browser/vr/elements/transient_element.h
@@ -72,7 +72,7 @@
   ~ShowUntilSignalTransientElement() override;
 
   // This must be called before the set timeout to hide the element.
-  void Signal();
+  void Signal(bool value);
 
  private:
   bool OnBeginFrame(const base::TimeTicks& time,
diff --git a/chrome/browser/vr/elements/transient_element_unittest.cc b/chrome/browser/vr/elements/transient_element_unittest.cc
index aa04a7b..2935869 100644
--- a/chrome/browser/vr/elements/transient_element_unittest.cc
+++ b/chrome/browser/vr/elements/transient_element_unittest.cc
@@ -92,7 +92,6 @@
       base::MakeUnique<SimpleTransientElement>(base::TimeDelta::FromSeconds(2));
   SimpleTransientElement* parent = transient_element.get();
   transient_element->set_opacity_when_visible(0.5);
-  transient_element->set_draw_phase(0);
   scene.AddUiElement(kRoot, std::move(transient_element));
 
   // Create child.
@@ -100,7 +99,6 @@
   UiElement* child = element.get();
   element->set_opacity_when_visible(0.5);
   element->SetVisible(true);
-  element->set_draw_phase(0);
   parent->AddChild(std::move(element));
 
   // Child hidden because parent is hidden.
@@ -170,7 +168,7 @@
   EXPECT_EQ(element().opacity_when_visible(), element().opacity());
 
   // Signal, element should still be visible since time < min duration.
-  element().Signal();
+  element().Signal(true);
   EXPECT_FALSE(element().DoBeginFrame(MsToTicks(200), kForwardVector));
   EXPECT_EQ(element().opacity_when_visible(), element().opacity());
 
@@ -208,7 +206,7 @@
   element().SetVisible(true);
   EXPECT_EQ(element().opacity_when_visible(), element().opacity());
   EXPECT_FALSE(element().DoBeginFrame(MsToTicks(1000), kForwardVector));
-  element().Signal();
+  element().Signal(true);
 
   // Refresh visibility, and ensure that the element still transiently
   // disappears, but at a later time.
diff --git a/chrome/browser/vr/elements/ui_element.cc b/chrome/browser/vr/elements/ui_element.cc
index e9ae8f5..02e4b87 100644
--- a/chrome/browser/vr/elements/ui_element.cc
+++ b/chrome/browser/vr/elements/ui_element.cc
@@ -20,6 +20,13 @@
 
 namespace {
 
+static constexpr char kRed[] = "\x1b[31m";
+static constexpr char kGreen[] = "\x1b[32m";
+static constexpr char kYellow[] = "\x1b[33m";
+static constexpr char kBlue[] = "\x1b[34m";
+static constexpr char kCyan[] = "\x1b[36m";
+static constexpr char kReset[] = "\x1b[0m";
+
 static constexpr float kHitTestResolutionInMeter = 0.000001f;
 
 int AllocateId() {
@@ -232,6 +239,15 @@
       TargetProperty::TRANSFORM, transform_operations_);
 }
 
+gfx::Transform UiElement::ComputeTargetWorldSpaceTransform() const {
+  gfx::Transform m;
+  for (const UiElement* current = this; current; current = current->parent()) {
+    m.ConcatTransform(current->layout_offset_.Apply() *
+                      current->GetTargetTransform().Apply());
+  }
+  return m;
+}
+
 float UiElement::GetTargetOpacity() const {
   return animation_player_.GetTargetFloatValue(TargetProperty::OPACITY,
                                                opacity_);
@@ -294,16 +310,6 @@
   }
 }
 
-void UiElement::SetMode(ColorScheme::Mode mode) {
-  for (auto& child : children_) {
-    child->SetMode(mode);
-  }
-  if (mode_ == mode)
-    return;
-  mode_ = mode;
-  OnSetMode();
-}
-
 const gfx::Transform& UiElement::world_space_transform() const {
   DCHECK_LE(kUpdatedWorldSpaceTransform, phase_);
   return world_space_transform_;
@@ -317,7 +323,74 @@
   return UiElementNameToString(name());
 }
 
-void UiElement::OnSetMode() {}
+void UiElement::DumpHierarchy(std::vector<size_t> counts,
+                              std::ostringstream* os) const {
+  // Put our ancestors in a vector for easy reverse traversal.
+  std::vector<const UiElement*> ancestors;
+  for (const UiElement* ancestor = parent(); ancestor;
+       ancestor = ancestor->parent()) {
+    ancestors.push_back(ancestor);
+  }
+  DCHECK_EQ(counts.size(), ancestors.size());
+
+  *os << kBlue;
+  for (size_t i = 0; i < counts.size(); ++i) {
+    if (i + 1 == counts.size()) {
+      *os << "+-";
+    } else if (ancestors[ancestors.size() - i - 1]->children().size() >
+               counts[i] + 1) {
+      *os << "| ";
+    } else {
+      *os << "  ";
+    }
+  }
+  *os << kReset;
+
+  if (!IsVisible()) {
+    *os << kYellow << "(h) " << kReset;
+  }
+
+  *os << DebugName() << " ";
+  *os << kCyan << DrawPhaseToString(draw_phase_) << " " << kReset;
+
+  float z = -GetCenter().z();
+  if (draw_phase_ != kPhaseNone && std::abs(z) > 1e-4) {
+    *os << kRed << "[" << (size().width() / z) << "DMM, "
+        << (size().height() / z) << "DMM] " << kReset;
+  }
+
+  *os << kGreen;
+  if (!transform_operations_.at(0).IsIdentity()) {
+    const auto& translate = transform_operations_.at(0).translate;
+    *os << "t(" << translate.x << ", " << translate.y << ", " << translate.z
+        << ") ";
+  }
+
+  if (!transform_operations_.at(1).IsIdentity()) {
+    const auto& rotate = transform_operations_.at(1).rotate;
+    if (rotate.axis.x > 0.0f) {
+      *os << "rx(" << rotate.angle << ") ";
+    } else if (rotate.axis.y > 0.0f) {
+      *os << "ry(" << rotate.angle << ") ";
+    } else if (rotate.axis.z > 0.0f) {
+      *os << "rz(" << rotate.angle << ") ";
+    }
+  }
+
+  if (!transform_operations_.at(2).IsIdentity()) {
+    const auto& scale = transform_operations_.at(2).scale;
+    *os << "t(" << scale.x << ", " << scale.y << ", " << scale.z << ") ";
+  }
+  *os << kReset;
+  *os << std::endl;
+
+  counts.push_back(0u);
+  for (auto& child : children_) {
+    child->DumpHierarchy(counts, os);
+    counts.back()++;
+  }
+}
+
 void UiElement::OnUpdatedWorldSpaceTransform() {}
 
 gfx::SizeF UiElement::stale_size() const {
diff --git a/chrome/browser/vr/elements/ui_element.h b/chrome/browser/vr/elements/ui_element.h
index 3da84c9..bb8a2cde 100644
--- a/chrome/browser/vr/elements/ui_element.h
+++ b/chrome/browser/vr/elements/ui_element.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_VR_ELEMENTS_UI_ELEMENT_H_
 
 #include <memory>
+#include <sstream>
 #include <string>
 #include <vector>
 
@@ -14,14 +15,12 @@
 #include "cc/animation/animation_target.h"
 #include "cc/animation/transform_operations.h"
 #include "chrome/browser/vr/animation_player.h"
-#include "chrome/browser/vr/color_scheme.h"
 #include "chrome/browser/vr/databinding/binding_base.h"
 #include "chrome/browser/vr/elements/draw_phase.h"
 #include "chrome/browser/vr/elements/ui_element_iterator.h"
 #include "chrome/browser/vr/elements/ui_element_name.h"
 #include "chrome/browser/vr/model/camera_model.h"
 #include "chrome/browser/vr/target_property.h"
-#include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/point3_f.h"
 #include "ui/gfx/geometry/quaternion.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -252,8 +251,8 @@
     y_padding_ = y_padding;
   }
 
-  int draw_phase() const { return draw_phase_; }
-  void set_draw_phase(int draw_phase) { draw_phase_ = draw_phase; }
+  DrawPhase draw_phase() const { return draw_phase_; }
+  void set_draw_phase(DrawPhase draw_phase) { draw_phase_ = draw_phase; }
 
   const gfx::Transform& inheritable_transform() const {
     return inheritable_transform_;
@@ -265,14 +264,13 @@
   UiElementName name() const { return name_; }
   void set_name(UiElementName name) { name_ = name; }
 
-  void SetMode(ColorScheme::Mode mode);
-  ColorScheme::Mode mode() const { return mode_; }
-
   const gfx::Transform& world_space_transform() const;
   void set_world_space_transform(const gfx::Transform& transform) {
     world_space_transform_ = transform;
   }
 
+  gfx::Transform ComputeTargetWorldSpaceTransform() const;
+
   // Transformations are applied relative to the parent element, rather than
   // absolutely.
   void AddChild(std::unique_ptr<UiElement> child);
@@ -376,6 +374,13 @@
 
   std::string DebugName() const;
 
+  // Writes a pretty-printed version of the UiElement subtree to |os|. The
+  // vector of counts represents where each ancestor on the ancestor chain is
+  // situated in its parent's list of children. This is used to determine
+  // whether each ancestor is the last child (which affects the lines we draw in
+  // the tree).
+  void DumpHierarchy(std::vector<size_t> counts, std::ostringstream* os) const;
+
  protected:
   AnimationPlayer& animation_player() { return animation_player_; }
 
@@ -386,7 +391,6 @@
   gfx::SizeF stale_size() const;
 
  private:
-  virtual void OnSetMode();
   virtual void OnUpdatedWorldSpaceTransform();
 
   // Returns true if the element has been updated in any visible way.
@@ -457,7 +461,7 @@
 
   AnimationPlayer animation_player_;
 
-  int draw_phase_ = kPhaseNone;
+  DrawPhase draw_phase_ = kPhaseNone;
 
   // This is the time as of the last call to |Animate|. It is needed when
   // reversing transitions.
@@ -483,8 +487,6 @@
   // |inheritable_transform_|, |transform_|, and anchoring adjustments.
   gfx::Transform world_space_transform_;
 
-  ColorScheme::Mode mode_ = ColorScheme::kModeNormal;
-
   UiElement* parent_ = nullptr;
   std::vector<std::unique_ptr<UiElement>> children_;
 
diff --git a/chrome/browser/vr/elements/ui_texture.cc b/chrome/browser/vr/elements/ui_texture.cc
index 2e2ca9f..31428df 100644
--- a/chrome/browser/vr/elements/ui_texture.cc
+++ b/chrome/browser/vr/elements/ui_texture.cc
@@ -55,23 +55,10 @@
   return false;
 }
 
-void UiTexture::SetMode(ColorScheme::Mode mode) {
-  if (mode_ == mode)
-    return;
-  mode_ = mode;
-  OnSetMode();
-}
-
 void UiTexture::OnInitialized() {
   set_dirty();
 }
 
-void UiTexture::OnSetMode() {}
-
-const ColorScheme& UiTexture::color_scheme() const {
-  return ColorScheme::GetColorScheme(mode());
-}
-
 std::vector<std::unique_ptr<gfx::RenderText>> UiTexture::PrepareDrawStringRect(
     const base::string16& text,
     const gfx::FontList& font_list,
@@ -216,6 +203,20 @@
   return true;
 }
 
+void UiTexture::SetForegroundColor(SkColor color) {
+  if (foreground_color_ == color)
+    return;
+  foreground_color_ = color;
+  set_dirty();
+}
+
+void UiTexture::SetBackgroundColor(SkColor color) {
+  if (background_color_ == color)
+    return;
+  background_color_ = color;
+  set_dirty();
+}
+
 void UiTexture::SetForceFontFallbackFailureForTesting(bool force) {
   force_font_fallback_failure_for_testing_ = force;
 }
diff --git a/chrome/browser/vr/elements/ui_texture.h b/chrome/browser/vr/elements/ui_texture.h
index 74be3994..c09cfd7d 100644
--- a/chrome/browser/vr/elements/ui_texture.h
+++ b/chrome/browser/vr/elements/ui_texture.h
@@ -10,7 +10,6 @@
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/vr/color_scheme.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
@@ -40,9 +39,13 @@
 
   bool dirty() const { return dirty_; }
 
-  void SetMode(ColorScheme::Mode mode);
   void OnInitialized();
 
+  // Foreground and background colors are used pervasively in textures, but more
+  // element-specific colors should be set on the appropriate class.
+  void SetForegroundColor(SkColor color);
+  void SetBackgroundColor(SkColor color);
+
   // This function sets |font_list| to a list of available fonts for |text|. If
   // no font supports |text|, it returns false and leave |font_list| untouched.
   static bool GetFontList(int size,
@@ -64,9 +67,12 @@
  protected:
   virtual void Draw(SkCanvas* canvas, const gfx::Size& texture_size) = 0;
 
-  virtual void OnSetMode();
-  ColorScheme::Mode mode() const { return mode_; }
-  const ColorScheme& color_scheme() const;
+  template <typename T>
+  void SetAndDirty(T* target, const T& value) {
+    if (*target != value)
+      set_dirty();
+    *target = value;
+  }
 
   // Prepares a set of RenderText objects with the given color and fonts.
   // Attempts to fit the text within the provided size. |flags| specifies how
@@ -90,15 +96,19 @@
       SkColor color,
       TextAlignment text_alignment);
 
-  void set_dirty() { dirty_ = true; }
-
   static bool IsRTL();
   static gfx::FontList GetDefaultFontList(int size);
   static void SetForceFontFallbackFailureForTesting(bool force);
 
+  void set_dirty() { dirty_ = true; }
+
+  SkColor foreground_color() const { return foreground_color_; }
+  SkColor background_color() const { return background_color_; }
+
  private:
   bool dirty_ = true;
-  ColorScheme::Mode mode_ = ColorScheme::kModeNormal;
+  SkColor foreground_color_;
+  SkColor background_color_;
 
   DISALLOW_COPY_AND_ASSIGN(UiTexture);
 };
diff --git a/chrome/browser/vr/elements/url_bar.cc b/chrome/browser/vr/elements/url_bar.cc
index 87216245..6bb55858 100644
--- a/chrome/browser/vr/elements/url_bar.cc
+++ b/chrome/browser/vr/elements/url_bar.cc
@@ -11,12 +11,11 @@
 
 UrlBar::UrlBar(int preferred_width,
                const base::Callback<void()>& back_button_callback,
-               const base::Callback<void()>& security_icon_callback,
                const base::Callback<void(UiUnsupportedMode)>& failure_callback)
     : TexturedElement(preferred_width),
       texture_(base::MakeUnique<UrlBarTexture>(failure_callback)),
       back_button_callback_(back_button_callback),
-      security_icon_callback_(security_icon_callback) {}
+      failure_callback_(failure_callback) {}
 
 UrlBar::~UrlBar() = default;
 
@@ -51,7 +50,7 @@
   if (can_go_back_ && texture_->HitsBackButton(position))
     back_button_callback_.Run();
   else if (security_region_down_ && texture_->HitsSecurityRegion(position))
-    security_icon_callback_.Run();
+    failure_callback_.Run(UiUnsupportedMode::kUnhandledPageInfo);
   security_region_down_ = false;
 }
 
@@ -68,6 +67,10 @@
   texture_->SetHistoryButtonsEnabled(can_go_back_);
 }
 
+void UrlBar::SetColors(const UrlBarColors& colors) {
+  texture_->SetColors(colors);
+}
+
 void UrlBar::OnStateUpdated(const gfx::PointF& position) {
   const bool hovered = texture_->HitsBackButton(position);
   const bool pressed = hovered ? down_ : false;
diff --git a/chrome/browser/vr/elements/url_bar.h b/chrome/browser/vr/elements/url_bar.h
index 436bfdc6..090f634 100644
--- a/chrome/browser/vr/elements/url_bar.h
+++ b/chrome/browser/vr/elements/url_bar.h
@@ -19,12 +19,12 @@
 
 class UrlBarTexture;
 struct ToolbarState;
+struct UrlBarColors;
 
 class UrlBar : public TexturedElement {
  public:
   UrlBar(int preferred_width,
          const base::Callback<void()>& back_button_callback,
-         const base::Callback<void()>& security_icon_callback,
          const base::Callback<void(UiUnsupportedMode)>& failure_callback);
   ~UrlBar() override;
 
@@ -38,13 +38,15 @@
   void SetHistoryButtonsEnabled(bool can_go_back);
   void SetToolbarState(const ToolbarState& state);
 
+  void SetColors(const UrlBarColors& colors);
+
  private:
   UiTexture* GetTexture() const override;
   void OnStateUpdated(const gfx::PointF& position);
 
   std::unique_ptr<UrlBarTexture> texture_;
   base::Callback<void()> back_button_callback_;
-  base::Callback<void()> security_icon_callback_;
+  base::Callback<void(UiUnsupportedMode)> failure_callback_;
   bool can_go_back_ = false;
   bool down_ = false;
   bool security_region_down_ = false;
diff --git a/chrome/browser/vr/elements/url_bar_texture.cc b/chrome/browser/vr/elements/url_bar_texture.cc
index 7d35afae..f268fc2 100644
--- a/chrome/browser/vr/elements/url_bar_texture.cc
+++ b/chrome/browser/vr/elements/url_bar_texture.cc
@@ -8,9 +8,9 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "cc/paint/skia_paint_canvas.h"
-#include "chrome/browser/vr/color_scheme.h"
 #include "chrome/browser/vr/elements/render_text_wrapper.h"
 #include "chrome/browser/vr/elements/vector_icon.h"
+#include "chrome/browser/vr/model/color_scheme.h"
 #include "components/url_formatter/elide_url.h"
 #include "components/url_formatter/url_formatter.h"
 #include "components/vector_icons/vector_icons.h"
@@ -42,37 +42,36 @@
 using security_state::SecurityLevel;
 
 // See LocationBarView::GetSecureTextColor().
-SkColor GetSchemeColor(SecurityLevel level, const ColorScheme& color_scheme) {
+SkColor GetSchemeColor(SecurityLevel level, const UrlBarColors& colors) {
   switch (level) {
     case SecurityLevel::NONE:
     case SecurityLevel::HTTP_SHOW_WARNING:
-      return color_scheme.url_deemphasized;
+      return colors.deemphasized;
     case SecurityLevel::EV_SECURE:
     case SecurityLevel::SECURE:
-      return color_scheme.secure;
+      return colors.secure;
     case SecurityLevel::SECURE_WITH_POLICY_INSTALLED_CERT:  // ChromeOS only.
-      return color_scheme.insecure;
+      return colors.insecure;
     case SecurityLevel::DANGEROUS:
-      return color_scheme.insecure;
+      return colors.insecure;
     default:
       NOTREACHED();
-      return color_scheme.insecure;
+      return colors.insecure;
   }
 }
 
 SkColor GetSecurityChipColor(SecurityLevel level,
                              bool offline_page,
-                             const ColorScheme& color_scheme) {
-  return offline_page ? color_scheme.offline_page_warning
-                      : GetSchemeColor(level, color_scheme);
+                             const UrlBarColors& colors) {
+  return offline_page ? colors.offline_page_warning
+                      : GetSchemeColor(level, colors);
 }
 
 void SetEmphasis(RenderTextWrapper* render_text,
                  bool emphasis,
                  const gfx::Range& range,
-                 const ColorScheme& color_scheme) {
-  SkColor color =
-      emphasis ? color_scheme.url_emphasized : color_scheme.url_deemphasized;
+                 const UrlBarColors& colors) {
+  SkColor color = emphasis ? colors.emphasized : colors.deemphasized;
   if (range.IsValid()) {
     render_text->ApplyColor(color, range);
   } else {
@@ -144,28 +143,21 @@
 }
 
 void UrlBarTexture::SetBackButtonHovered(bool hovered) {
-  if (back_hovered_ != hovered)
-    set_dirty();
-  back_hovered_ = hovered;
+  SetAndDirty(&back_hovered_, hovered);
 }
 
 void UrlBarTexture::SetBackButtonPressed(bool pressed) {
-  if (back_pressed_ != pressed)
-    set_dirty();
-  back_pressed_ = pressed;
+  SetAndDirty(&back_pressed_, pressed);
+}
+
+void UrlBarTexture::SetColors(const UrlBarColors& colors) {
+  SetAndDirty(&colors_, colors);
 }
 
 SkColor UrlBarTexture::BackButtonColor() const {
-  if (can_go_back_ && back_pressed_)
-    return color_scheme().element_background_down;
-  if (can_go_back_ && back_hovered_)
-    return color_scheme().element_background_hover;
-  return color_scheme().element_background;
-}
-
-void UrlBarTexture::OnSetMode() {
-  url_dirty_ = true;
-  set_dirty();
+  if (!can_go_back_)
+    return colors_.back_button.background;
+  return colors_.back_button.GetBackgroundColor(back_hovered_, back_pressed_);
 }
 
 void UrlBarTexture::Draw(SkCanvas* canvas, const gfx::Size& texture_size) {
@@ -199,17 +191,17 @@
       &gfx_canvas, vector_icons::kBackArrowIcon, ToPixels(kBackIconSize),
       {ToPixels(kBackButtonWidth / 2 + kBackIconOffset - kBackIconSize / 2),
        ToPixels(kHeight - kBackIconSize) / 2},
-      can_go_back_ ? color_scheme().element_foreground
-                   : color_scheme().disabled);
+      can_go_back_ ? colors_.back_button.foreground
+                   : colors_.back_button.foreground_disabled);
 
   // Security indicator and URL area.
-  paint.setColor(color_scheme().element_background);
+  paint.setColor(background_color());
   SkVector right_corners[4] = {{0, 0}, rounded_corner, rounded_corner, {0, 0}};
   round_rect.setRectRadii({height, 0, width, height}, right_corners);
   canvas->drawRRect(round_rect, paint);
 
   // Back button / URL separator vertical line.
-  paint.setColor(color_scheme().separator);
+  paint.setColor(colors_.separator);
   canvas->drawRect(SkRect::MakeXYWH(ToPixels(kBackButtonWidth), 0,
                                     ToPixels(kSeparatorWidth), height),
                    paint);
@@ -225,7 +217,7 @@
         &gfx_canvas, *state_.vector_icon, ToPixels(kSecurityIconSize),
         {ToPixels(icon_region.x()), ToPixels(icon_region.y())},
         GetSecurityChipColor(state_.security_level, state_.offline_page,
-                             color_scheme()));
+                             colors_));
     security_hit_region_ = icon_region;
     left_edge += kSecurityIconSize + kFieldSpacing;
   }
@@ -239,8 +231,8 @@
                           ToPixels(kHeight));
 
     int pixel_font_height = texture_size.height() * kFontHeight / kHeight;
-    SkColor chip_color = GetSecurityChipColor(
-        state_.security_level, state_.offline_page, color_scheme());
+    SkColor chip_color = GetSecurityChipColor(state_.security_level,
+                                              state_.offline_page, colors_);
     const base::string16& chip_text = state_.secure_verbose_text;
     DCHECK(!chip_text.empty());
 
@@ -268,7 +260,7 @@
 
     // Separator line between security text and URL.
     left_edge += kFieldSpacing;
-    paint.setColor(color_scheme().url_deemphasized);
+    paint.setColor(colors_.deemphasized);
     canvas->drawRect(
         SkRect::MakeXYWH(ToPixels(left_edge), ToPixels(kChipTextLineMargin),
                          ToPixels(kSeparatorWidth),
@@ -324,7 +316,7 @@
 
   RenderTextWrapper vr_render_text(render_text.get());
   ApplyUrlStyling(text, parsed, state_.security_level, &vr_render_text,
-                  color_scheme());
+                  colors_);
 
   url_render_text_ = std::move(render_text);
 }
@@ -337,7 +329,7 @@
     const url::Parsed& parsed,
     const security_state::SecurityLevel security_level,
     RenderTextWrapper* render_text,
-    const ColorScheme& color_scheme) {
+    const UrlBarColors& colors) {
   const url::Component& scheme = parsed.scheme;
   const url::Component& host = parsed.host;
 
@@ -365,20 +357,20 @@
                                 : gfx::Range::InvalidRange();
   switch (deemphasize) {
     case EVERYTHING:
-      SetEmphasis(render_text, false, gfx::Range::InvalidRange(), color_scheme);
+      SetEmphasis(render_text, false, gfx::Range::InvalidRange(), colors);
       break;
     case NOTHING:
-      SetEmphasis(render_text, true, gfx::Range::InvalidRange(), color_scheme);
+      SetEmphasis(render_text, true, gfx::Range::InvalidRange(), colors);
       break;
     case ALL_BUT_SCHEME:
       DCHECK(scheme_range.IsValid());
-      SetEmphasis(render_text, false, gfx::Range::InvalidRange(), color_scheme);
-      SetEmphasis(render_text, true, scheme_range, color_scheme);
+      SetEmphasis(render_text, false, gfx::Range::InvalidRange(), colors);
+      SetEmphasis(render_text, true, scheme_range, colors);
       break;
     case ALL_BUT_HOST:
-      SetEmphasis(render_text, false, gfx::Range::InvalidRange(), color_scheme);
+      SetEmphasis(render_text, false, gfx::Range::InvalidRange(), colors);
       SetEmphasis(render_text, true, gfx::Range(host.begin, host.end()),
-                  color_scheme);
+                  colors);
       break;
   }
 
@@ -388,7 +380,7 @@
   // applied to the scheme text range by SetEmphasis().
   if (scheme_range.IsValid() && security_level != security_state::NONE &&
       security_level != security_state::HTTP_SHOW_WARNING) {
-    render_text->ApplyColor(GetSchemeColor(security_level, color_scheme),
+    render_text->ApplyColor(GetSchemeColor(security_level, colors),
                             scheme_range);
     if (security_level == SecurityLevel::DANGEROUS) {
       render_text->SetStrikeThicknessFactor(kStrikeThicknessFactor);
diff --git a/chrome/browser/vr/elements/url_bar_texture.h b/chrome/browser/vr/elements/url_bar_texture.h
index 1277a6a..3f230885 100644
--- a/chrome/browser/vr/elements/url_bar_texture.h
+++ b/chrome/browser/vr/elements/url_bar_texture.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "chrome/browser/vr/elements/ui_texture.h"
+#include "chrome/browser/vr/model/color_scheme.h"
 #include "chrome/browser/vr/model/toolbar_state.h"
 #include "chrome/browser/vr/ui_unsupported_mode.h"
 #include "components/security_state/core/security_state.h"
@@ -25,7 +26,6 @@
 namespace vr {
 
 class RenderTextWrapper;
-struct ColorScheme;
 
 class UrlBarTexture : public UiTexture {
  public:
@@ -50,12 +50,14 @@
   void SetBackButtonHovered(bool hovered);
   void SetBackButtonPressed(bool pressed);
 
+  void SetColors(const UrlBarColors& colors);
+
  protected:
   static void ApplyUrlStyling(const base::string16& formatted_url,
                               const url::Parsed& parsed,
                               security_state::SecurityLevel security_level,
                               RenderTextWrapper* render_text,
-                              const ColorScheme& color_scheme);
+                              const UrlBarColors& colors);
 
   std::unique_ptr<gfx::RenderText> url_render_text_;
 
@@ -72,7 +74,6 @@
   float ToMeters(float pixels) const;
   bool HitsTransparentRegion(const gfx::PointF& meters, bool left) const;
   void RenderUrl(const gfx::Size& texture_size, const gfx::Rect& text_bounds);
-  void OnSetMode() override;
   SkColor BackButtonColor() const;
 
   gfx::SizeF size_;
@@ -83,6 +84,7 @@
   ToolbarState state_;
 
   bool url_dirty_ = true;
+  UrlBarColors colors_;
 
   base::Callback<void(UiUnsupportedMode)> failure_callback_;
   gfx::RectF security_hit_region_ = gfx::RectF(0, 0, 0, 0);
diff --git a/chrome/browser/vr/elements/url_bar_texture_unittest.cc b/chrome/browser/vr/elements/url_bar_texture_unittest.cc
index 88698e3f..8942ef9 100644
--- a/chrome/browser/vr/elements/url_bar_texture_unittest.cc
+++ b/chrome/browser/vr/elements/url_bar_texture_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/vr/elements/render_text_wrapper.h"
+#include "chrome/browser/vr/model/color_scheme.h"
 #include "chrome/browser/vr/model/toolbar_state.h"
 #include "components/security_state/core/security_state.h"
 #include "components/toolbar/vector_icons.h"
@@ -65,9 +66,8 @@
                              const url::Parsed& parsed,
                              security_state::SecurityLevel security_level,
                              vr::RenderTextWrapper* render_text,
-                             const ColorScheme& color_scheme) {
-    ApplyUrlStyling(formatted_url, parsed, security_level, render_text,
-                    color_scheme);
+                             const UrlBarColors& colors) {
+    ApplyUrlStyling(formatted_url, parsed, security_level, render_text, colors);
   }
 
   void SetForceFontFallbackFailure(bool force) {
@@ -111,6 +111,7 @@
     : UrlBarTexture(base::Bind(&TestUrlBarTexture::OnUnsupportedFeature,
                                base::Unretained(this))) {
   gfx::FontList::SetDefaultFontDescription("Arial, Times New Roman, 15px");
+  SetColors(ColorScheme::GetColorScheme(ColorScheme::kModeNormal).url_bar);
 }
 
 class MockRenderText : public RenderTextWrapper {
@@ -142,10 +143,10 @@
     EXPECT_EQ(formatted_url, base::UTF8ToUTF16(expected_string));
     TestUrlBarTexture::TestUrlStyling(
         formatted_url, parsed, level, &mock_,
-        ColorScheme::GetColorScheme(ColorScheme::kModeNormal));
+        ColorScheme::GetColorScheme(ColorScheme::kModeNormal).url_bar);
     TestUrlBarTexture::TestUrlStyling(
         formatted_url, parsed, level, &mock_,
-        ColorScheme::GetColorScheme(ColorScheme::kModeIncognito));
+        ColorScheme::GetColorScheme(ColorScheme::kModeIncognito).url_bar);
   }
 
   testing::InSequence in_sequence_;
diff --git a/chrome/browser/vr/elements/vector_icon.cc b/chrome/browser/vr/elements/vector_icon.cc
index 23a1e53e..76780fb2 100644
--- a/chrome/browser/vr/elements/vector_icon.cc
+++ b/chrome/browser/vr/elements/vector_icon.cc
@@ -17,20 +17,12 @@
   VectorIconTexture() {}
   ~VectorIconTexture() override {}
 
-  void SetColor(SkColor color) {
-    if (color == color_)
-      return;
-    color_ = color;
-    set_dirty();
-  }
+  void SetColor(SkColor color) { SetAndDirty(&color_, color); }
 
   SkColor GetColor() const { return color_; }
 
   void SetIcon(const gfx::VectorIcon& icon) {
-    if (icon_no_1x_.path == icon.path)
-      return;
-    icon_no_1x_.path = icon.path;
-    set_dirty();
+    SetAndDirty(&icon_no_1x_.path, icon.path);
   }
 
  private:
diff --git a/chrome/browser/vr/elements/webvr_url_toast_texture.cc b/chrome/browser/vr/elements/webvr_url_toast_texture.cc
index 7191bb7..df4b5c3 100644
--- a/chrome/browser/vr/elements/webvr_url_toast_texture.cc
+++ b/chrome/browser/vr/elements/webvr_url_toast_texture.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/vr/elements/webvr_url_toast_texture.h"
 
 #include "cc/paint/skia_paint_canvas.h"
-#include "chrome/browser/vr/color_scheme.h"
 #include "chrome/browser/vr/elements/vector_icon.h"
 #include "components/url_formatter/url_formatter.h"
 #include "ui/gfx/canvas.h"
@@ -60,7 +59,7 @@
 
   // Draw background.
   SkPaint paint;
-  paint.setColor(color_scheme().web_vr_transient_toast_background);
+  paint.setColor(background_color());
   paint.setAlpha(255);
   canvas->drawRoundRect(
       SkRect::MakeXYWH(0, 0, ToPixels(kWidth), ToPixels(kHeight)),
@@ -73,11 +72,11 @@
   // Site security state icon.
   if ((state_.security_level != security_state::NONE || state_.offline_page) &&
       state_.vector_icon != nullptr && state_.should_display_url) {
-    VectorIcon::DrawVectorIcon(
-        &gfx_canvas, *state_.vector_icon, ToPixels(kSecurityIconSize),
-        {ToPixels(kSecurityIconOffsetLeft),
-         ToPixels((kHeight - kSecurityIconSize) / 2)},
-        color_scheme().web_vr_transient_toast_foreground);
+    VectorIcon::DrawVectorIcon(&gfx_canvas, *state_.vector_icon,
+                               ToPixels(kSecurityIconSize),
+                               {ToPixels(kSecurityIconOffsetLeft),
+                                ToPixels((kHeight - kSecurityIconSize) / 2)},
+                               foreground_color());
   }
 
   if (state_.should_display_url) {
@@ -122,7 +121,7 @@
   std::unique_ptr<gfx::RenderText> render_text(CreateRenderText());
   render_text->SetDisplayRect(text_bounds);
   render_text->SetFontList(font_list);
-  render_text->SetColor(color_scheme().web_vr_transient_toast_foreground);
+  render_text->SetColor(foreground_color());
   render_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   render_text->SetElideBehavior(gfx::ELIDE_HEAD);
   render_text->SetDirectionalityMode(gfx::DIRECTIONALITY_FORCE_LTR);
diff --git a/chrome/browser/vr/model/color_scheme.cc b/chrome/browser/vr/model/color_scheme.cc
new file mode 100644
index 0000000..52d4b65
--- /dev/null
+++ b/chrome/browser/vr/model/color_scheme.cc
@@ -0,0 +1,254 @@
+// 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/vr/model/color_scheme.h"
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "ui/gfx/color_palette.h"
+
+namespace vr {
+
+namespace {
+
+base::LazyInstance<ColorScheme>::Leaky g_normal_scheme =
+    LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<ColorScheme>::Leaky g_fullscreen_scheme =
+    LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<ColorScheme>::Leaky g_incognito_scheme =
+    LAZY_INSTANCE_INITIALIZER;
+
+void InitializeColorSchemes() {
+  static bool initialized = false;
+  if (initialized)
+    return;
+
+  ColorScheme& normal_scheme = g_normal_scheme.Get();
+  normal_scheme.world_background = 0xFF999999;
+  normal_scheme.world_background_text = 0xFF363636;
+  normal_scheme.floor = 0xFF8C8C8C;
+  normal_scheme.ceiling = normal_scheme.floor;
+  normal_scheme.floor_grid = 0x26FFFFFF;
+  normal_scheme.element_foreground = 0xFF333333;
+  normal_scheme.element_background = 0xCCB3B3B3;
+  normal_scheme.element_background_hover = 0xFFCCCCCC;
+  normal_scheme.element_background_down = 0xFFF3F3F3;
+  normal_scheme.button_colors.foreground = 0x87000000;
+  normal_scheme.button_colors.background = normal_scheme.element_background;
+  normal_scheme.button_colors.background_hover =
+      normal_scheme.element_background_hover;
+  normal_scheme.button_colors.background_down =
+      normal_scheme.element_background_down;
+  normal_scheme.button_colors.foreground_disabled = 0x33333333;
+  normal_scheme.loading_indicator_foreground = 0xFF2979FF;
+  normal_scheme.loading_indicator_background = 0xFF454545;
+  normal_scheme.exit_warning_foreground = SK_ColorWHITE;
+  normal_scheme.exit_warning_background = 0xCC1A1A1A;
+  normal_scheme.web_vr_transient_toast_foreground = 0xFFF3F3F3;
+  normal_scheme.web_vr_transient_toast_background = SK_ColorBLACK;
+  normal_scheme.exclusive_screen_toast_foreground = 0xCCFFFFFF;
+  normal_scheme.exclusive_screen_toast_background = 0xCC2F2F2F;
+
+  normal_scheme.system_indicator_foreground = 0xFF444444;
+  normal_scheme.system_indicator_background = SK_ColorWHITE;
+  normal_scheme.audio_permission_prompt_icon_foreground = 0xFF4285F4;
+  normal_scheme.audio_permission_prompt_background = 0xFFF5F5F5;
+  normal_scheme.audio_permission_prompt_secondary_button_colors.foreground =
+      0xFF4285F4;
+  normal_scheme.audio_permission_prompt_secondary_button_colors
+      .foreground_disabled = normal_scheme.button_colors.foreground_disabled;
+  normal_scheme.audio_permission_prompt_secondary_button_colors.background =
+      normal_scheme.audio_permission_prompt_background;
+  normal_scheme.audio_permission_prompt_secondary_button_colors
+      .background_hover = 0x19999999;
+  normal_scheme.audio_permission_prompt_secondary_button_colors
+      .background_down = 0x33999999;
+  normal_scheme.audio_permission_prompt_primary_button_colors.foreground =
+      normal_scheme.audio_permission_prompt_background;
+  normal_scheme.audio_permission_prompt_secondary_button_colors
+      .foreground_disabled = normal_scheme.button_colors.foreground_disabled;
+  normal_scheme.audio_permission_prompt_primary_button_colors.background =
+      0xFF4285F4;
+  normal_scheme.audio_permission_prompt_primary_button_colors.background_hover =
+      0xFF3E7DE6;
+  normal_scheme.audio_permission_prompt_primary_button_colors.background_down =
+      0xFF3E7DE6;
+
+  normal_scheme.url_bar.deemphasized = 0xFF5A5A5A;
+  normal_scheme.url_bar.emphasized = SK_ColorBLACK;
+  normal_scheme.url_bar.secure = gfx::kGoogleGreen700;
+  normal_scheme.url_bar.insecure = gfx::kGoogleRed700;
+  normal_scheme.url_bar.offline_page_warning = 0xFF242424;
+  normal_scheme.url_bar.separator = 0xFF9E9E9E;
+  normal_scheme.url_bar.back_button.background =
+      normal_scheme.element_background;
+  normal_scheme.url_bar.back_button.background_down =
+      normal_scheme.element_background_down;
+  normal_scheme.url_bar.back_button.background_hover =
+      normal_scheme.element_background_hover;
+  normal_scheme.url_bar.back_button.foreground =
+      normal_scheme.element_foreground;
+  normal_scheme.url_bar.back_button.foreground_disabled = 0x33333333;
+
+  normal_scheme.prompt_foreground = 0xCC000000;
+  normal_scheme.prompt_primary_button_colors.foreground = 0xA6000000;
+  normal_scheme.prompt_primary_button_colors.foreground_disabled = 0xA6000000;
+  normal_scheme.prompt_primary_button_colors.background = 0xBFFFFFFF;
+  normal_scheme.prompt_primary_button_colors.background_hover = 0xFFFFFFFF;
+  normal_scheme.prompt_primary_button_colors.background_down = 0xE6FFFFFF;
+  normal_scheme.prompt_secondary_button_colors.foreground = 0xA6000000;
+  normal_scheme.prompt_secondary_button_colors.foreground_disabled = 0xA6000000;
+  normal_scheme.prompt_secondary_button_colors.background = 0x66FFFFFF;
+  normal_scheme.prompt_secondary_button_colors.background_hover = 0xFFFFFFFF;
+  normal_scheme.prompt_secondary_button_colors.background_down = 0xE6FFFFFF;
+  normal_scheme.dimmer_inner = 0xCC0D0D0D;
+  normal_scheme.dimmer_outer = 0xE6000000;
+  normal_scheme.splash_screen_background = SK_ColorBLACK;
+  normal_scheme.splash_screen_text_color = 0xA6FFFFFF;
+  normal_scheme.spinner_background = SK_ColorBLACK;
+  normal_scheme.spinner_color = 0xFFF3F3F3;
+  normal_scheme.timeout_message_background = 0xFF444444;
+  normal_scheme.timeout_message_foreground = normal_scheme.spinner_color;
+  normal_scheme.speech_recognition_circle_background = 0xFF4285F4;
+
+  g_fullscreen_scheme.Get() = normal_scheme;
+  ColorScheme& fullscreen_scheme = g_fullscreen_scheme.Get();
+  fullscreen_scheme.world_background = 0xFF000714;
+  fullscreen_scheme.floor = 0xFF070F1C;
+  fullscreen_scheme.ceiling = 0xFF04080F;
+  fullscreen_scheme.floor_grid = 0x40A3E0FF;
+  fullscreen_scheme.element_foreground = 0x80FFFFFF;
+  fullscreen_scheme.element_background = 0xCC2B3E48;
+  fullscreen_scheme.element_background_hover = 0xCC536B77;
+  fullscreen_scheme.element_background_down = 0xCC96AFBB;
+
+  fullscreen_scheme.button_colors.foreground =
+      fullscreen_scheme.element_foreground;
+  fullscreen_scheme.button_colors.foreground_disabled =
+      fullscreen_scheme.element_foreground;
+  fullscreen_scheme.button_colors.background =
+      fullscreen_scheme.element_background;
+  fullscreen_scheme.button_colors.background_hover =
+      fullscreen_scheme.element_background_hover;
+  fullscreen_scheme.button_colors.background_down =
+      fullscreen_scheme.element_background_down;
+
+  g_incognito_scheme.Get() = normal_scheme;
+  ColorScheme& incognito_scheme = g_incognito_scheme.Get();
+  incognito_scheme.world_background = 0xFF2E2E2E;
+  incognito_scheme.world_background_text = 0xFF878787;
+  incognito_scheme.floor = 0xFF282828;
+  incognito_scheme.ceiling = 0xFF2F2F2F;
+  incognito_scheme.floor_grid = 0xCC595959;
+  incognito_scheme.element_foreground = 0xFFBCBCBC;
+  incognito_scheme.element_background = 0xCC454545;
+  incognito_scheme.element_background_hover = 0xCC505050;
+  incognito_scheme.element_background_down = 0xCC888888;
+  incognito_scheme.button_colors.foreground =
+      fullscreen_scheme.element_foreground;
+  incognito_scheme.button_colors.foreground_disabled = 0x33E6E6E6;
+  incognito_scheme.button_colors.background =
+      fullscreen_scheme.element_background;
+  incognito_scheme.button_colors.background_hover =
+      fullscreen_scheme.element_background_hover;
+  incognito_scheme.button_colors.background_down =
+      fullscreen_scheme.element_background_down;
+
+  incognito_scheme.url_bar.secure = 0xFFEDEDED;
+  incognito_scheme.url_bar.insecure = incognito_scheme.url_bar.secure;
+  incognito_scheme.url_bar.emphasized = incognito_scheme.url_bar.secure;
+  incognito_scheme.url_bar.deemphasized = 0xFF878787;
+  incognito_scheme.url_bar.offline_page_warning =
+      incognito_scheme.url_bar.secure;
+  incognito_scheme.url_bar.separator = 0xFF474747;
+  incognito_scheme.url_bar.back_button.background =
+      incognito_scheme.element_background;
+  incognito_scheme.url_bar.back_button.background_down =
+      incognito_scheme.element_background_down;
+  incognito_scheme.url_bar.back_button.background_hover =
+      incognito_scheme.element_background_hover;
+  incognito_scheme.url_bar.back_button.foreground =
+      incognito_scheme.element_foreground;
+  incognito_scheme.url_bar.back_button.foreground_disabled = 0x33E6E6E6;
+
+  incognito_scheme.prompt_foreground = 0xCCFFFFFF;
+  incognito_scheme.prompt_primary_button_colors.foreground = 0xD9000000;
+  incognito_scheme.prompt_primary_button_colors.foreground_disabled =
+      0xD9000000;
+  incognito_scheme.prompt_primary_button_colors.background = 0xD9FFFFFF;
+  incognito_scheme.prompt_primary_button_colors.background_hover = 0xFF8C8C8C;
+  incognito_scheme.prompt_primary_button_colors.background_down = 0xE6FFFFFF;
+  incognito_scheme.prompt_secondary_button_colors.foreground = 0xD9000000;
+  incognito_scheme.prompt_secondary_button_colors.foreground_disabled =
+      0xD9000000;
+  incognito_scheme.prompt_secondary_button_colors.background = 0x80FFFFFF;
+  incognito_scheme.prompt_secondary_button_colors.background_hover = 0xFF8C8C8C;
+  incognito_scheme.prompt_secondary_button_colors.background_down = 0xE6FFFFFF;
+
+  initialized = true;
+}
+
+static constexpr size_t kButtonColorsSize = 20;
+static constexpr size_t kUrlBarColorsSize = 44;
+
+}  // namespace
+
+ColorScheme::ColorScheme() = default;
+ColorScheme::ColorScheme(const ColorScheme& other) {
+  *this = other;
+}
+
+static_assert(kButtonColorsSize == sizeof(ButtonColors),
+              "If the new colors are added to ButtonColors, we must explicitly "
+              "bump this size and update operator== below");
+
+bool ButtonColors::operator==(const ButtonColors& other) const {
+  return background == other.background &&
+         background_hover == other.background_hover &&
+         background_down == other.background_down &&
+         foreground == other.foreground &&
+         foreground_disabled == other.foreground_disabled;
+}
+
+bool ButtonColors::operator!=(const ButtonColors& other) const {
+  return !(*this == other);
+}
+
+SkColor ButtonColors::GetBackgroundColor(bool hovered, bool pressed) const {
+  if (pressed)
+    return background_down;
+  if (hovered)
+    return background_hover;
+  return background;
+}
+
+SkColor ButtonColors::GetForegroundColor(bool disabled) const {
+  return disabled ? foreground_disabled : foreground;
+}
+
+static_assert(kUrlBarColorsSize == sizeof(UrlBarColors),
+              "If the new colors are added to UrlBarColors, we must explicitly "
+              "bump this size and update operator== below");
+
+bool UrlBarColors::operator==(const UrlBarColors& other) const {
+  return deemphasized == other.deemphasized && emphasized == other.emphasized &&
+         secure == other.secure && insecure == other.insecure &&
+         offline_page_warning == other.offline_page_warning &&
+         separator == other.separator && back_button == other.back_button;
+}
+
+bool UrlBarColors::operator!=(const UrlBarColors& other) const {
+  return !(*this == other);
+}
+
+const ColorScheme& ColorScheme::GetColorScheme(ColorScheme::Mode mode) {
+  InitializeColorSchemes();
+  if (mode == kModeIncognito)
+    return g_incognito_scheme.Get();
+  if (mode == kModeFullscreen)
+    return g_fullscreen_scheme.Get();
+  return g_normal_scheme.Get();
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/color_scheme.h b/chrome/browser/vr/model/color_scheme.h
similarity index 64%
rename from chrome/browser/vr/color_scheme.h
rename to chrome/browser/vr/model/color_scheme.h
index 89d12496..6c3708a 100644
--- a/chrome/browser/vr/color_scheme.h
+++ b/chrome/browser/vr/model/color_scheme.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_VR_COLOR_SCHEME_H_
-#define CHROME_BROWSER_VR_COLOR_SCHEME_H_
+#ifndef CHROME_BROWSER_VR_MODEL_COLOR_SCHEME_H_
+#define CHROME_BROWSER_VR_MODEL_COLOR_SCHEME_H_
 
 #include "third_party/skia/include/core/SkColor.h"
 
@@ -11,10 +11,28 @@
 
 struct ButtonColors {
   bool operator==(const ButtonColors& other) const;
-  SkColor background;
-  SkColor background_hover;
-  SkColor background_press;
-  SkColor foreground;
+  bool operator!=(const ButtonColors& other) const;
+
+  SkColor GetBackgroundColor(bool hovered, bool pressed) const;
+  SkColor GetForegroundColor(bool disabled) const;
+
+  SkColor background = SK_ColorBLACK;
+  SkColor background_hover = SK_ColorBLACK;
+  SkColor background_down = SK_ColorBLACK;
+  SkColor foreground = SK_ColorBLACK;
+  SkColor foreground_disabled = SK_ColorBLACK;
+};
+
+struct UrlBarColors {
+  bool operator==(const UrlBarColors& other) const;
+  bool operator!=(const UrlBarColors& other) const;
+  SkColor deemphasized = SK_ColorBLACK;
+  SkColor emphasized = SK_ColorBLACK;
+  SkColor secure = SK_ColorBLACK;
+  SkColor insecure = SK_ColorBLACK;
+  SkColor offline_page_warning = SK_ColorBLACK;
+  SkColor separator = SK_ColorBLACK;
+  ButtonColors back_button;
 };
 
 struct ColorScheme {
@@ -27,6 +45,9 @@
 
   static const ColorScheme& GetColorScheme(Mode mode);
 
+  ColorScheme();
+  ColorScheme(const ColorScheme& other);
+
   // These colors should be named generically, if possible, so that they can be
   // meaningfully reused by multiple elements.
   SkColor world_background;
@@ -57,35 +78,15 @@
   SkColor system_indicator_background;
   SkColor audio_permission_prompt_icon_foreground;
   SkColor audio_permission_prompt_background;
-  SkColor audio_permission_prompt_secondary_button_forground;
-  SkColor audio_permission_prompt_secondary_button_hover;
-  SkColor audio_permission_prompt_secondary_button_down;
-  SkColor audio_permission_prompt_primary_button_background;
-  SkColor audio_permission_prompt_primary_button_hover;
-  SkColor audio_permission_prompt_primary_button_down;
+  ButtonColors audio_permission_prompt_secondary_button_colors;
+  ButtonColors audio_permission_prompt_primary_button_colors;
 
   // The colors used for text and buttons on prompts.
   SkColor prompt_foreground;
-  SkColor prompt_primary_button_forground;
-  SkColor prompt_secondary_button_foreground;
-  SkColor prompt_primary_button_background;
-  SkColor prompt_secondary_button_background;
-  SkColor prompt_button_background_hover;
-  SkColor prompt_button_background_down;
+  ButtonColors prompt_secondary_button_colors;
+  ButtonColors prompt_primary_button_colors;
 
-  // If you have a segmented element, its separators should use this color.
-  SkColor separator;
-
-  // Some content changes color based on the security level. Those visuals
-  // should respect these colors.
-  SkColor secure;
-  SkColor insecure;
-  SkColor url_emphasized;
-  SkColor url_deemphasized;
-  SkColor offline_page_warning;
-
-  // The color used for disabled icons.
-  SkColor disabled;
+  UrlBarColors url_bar;
 
   // Screen dimmer colors.
   SkColor dimmer_outer;
@@ -108,4 +109,4 @@
 
 }  // namespace vr
 
-#endif  // CHROME_BROWSER_VR_COLOR_SCHEME_H_
+#endif  // CHROME_BROWSER_VR_MODEL_COLOR_SCHEME_H_
diff --git a/chrome/browser/vr/model/model.cc b/chrome/browser/vr/model/model.cc
index 994ec49..7cf0b69 100644
--- a/chrome/browser/vr/model/model.cc
+++ b/chrome/browser/vr/model/model.cc
@@ -10,4 +10,13 @@
 
 Model::~Model() {}
 
+const ColorScheme& Model::color_scheme() const {
+  ColorScheme::Mode mode = ColorScheme::kModeNormal;
+  if (fullscreen)
+    mode = ColorScheme::kModeFullscreen;
+  if (incognito)
+    mode = ColorScheme::kModeIncognito;
+  return ColorScheme::GetColorScheme(mode);
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/model/model.h b/chrome/browser/vr/model/model.h
index 1a5f4c9..c48d79a 100644
--- a/chrome/browser/vr/model/model.h
+++ b/chrome/browser/vr/model/model.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_VR_MODEL_MODEL_H_
 #define CHROME_BROWSER_VR_MODEL_MODEL_H_
 
+#include "chrome/browser/vr/model/color_scheme.h"
 #include "chrome/browser/vr/model/controller_model.h"
 #include "chrome/browser/vr/model/modal_prompt_type.h"
 #include "chrome/browser/vr/model/omnibox_suggestions.h"
@@ -13,6 +14,8 @@
 #include "chrome/browser/vr/model/speech_recognition_model.h"
 #include "chrome/browser/vr/model/toolbar_state.h"
 #include "chrome/browser/vr/model/web_vr_timeout_state.h"
+#include "chrome/browser/vr/ui_element_renderer.h"
+#include "ui/gfx/transform.h"
 
 namespace vr {
 
@@ -20,26 +23,49 @@
   Model();
   ~Model();
 
+  // VR browsing state.
+  bool browsing_disabled = false;
   bool loading = false;
   float load_progress = 0.0f;
-
-  WebVrTimeoutState web_vr_timeout_state = kWebVrNoTimeoutPending;
-  bool started_for_autopresentation = false;
-
+  bool fullscreen = false;
+  bool incognito = false;
+  bool in_cct = false;
+  bool can_navigate_back = false;
+  ToolbarState toolbar_state;
+  std::vector<OmniboxSuggestion> omnibox_suggestions;
+  bool omnibox_input_active = false;
   SpeechRecognitionModel speech;
+  const ColorScheme& color_scheme() const;
+  gfx::Transform projection_matrix;
+  unsigned int content_texture_id = 0;
+  UiElementRenderer::TextureLocation content_location =
+      UiElementRenderer::kTextureLocationLocal;
+
+  // WebVR state.
+  bool web_vr_mode = false;
+  bool web_vr_show_toast = false;
+  bool web_vr_show_splash_screen = false;
+  // Indicates that we're waiting for the first WebVR frame to show up before we
+  // hide the splash screen. This is used in the case of WebVR auto-
+  // presentation.
+  bool web_vr_started_for_autopresentation = false;
+  bool should_render_web_vr() const {
+    return web_vr_mode && !web_vr_show_splash_screen;
+  }
+  bool browsing_mode() const {
+    return !web_vr_mode && !web_vr_show_splash_screen;
+  }
+  WebVrTimeoutState web_vr_timeout_state = kWebVrNoTimeoutPending;
+
+  // Controller state.
   ControllerModel controller;
   ReticleModel reticle;
 
-  bool experimental_features_enabled = false;
-  bool incognito = false;
-
+  // State affecting both VR browsing and WebVR.
   ModalPromptType active_modal_prompt_type = kModalPromptTypeNone;
-
   PermissionsModel permissions;
-
-  ToolbarState toolbar_state;
-  bool omnibox_input_active = false;
-  std::vector<OmniboxSuggestion> omnibox_suggestions;
+  bool experimental_features_enabled = false;
+  bool exiting_vr = false;
 };
 
 }  // namespace vr
diff --git a/chrome/browser/vr/service/vr_device_manager.cc b/chrome/browser/vr/service/vr_device_manager.cc
index 45b77fc..8e6a9588 100644
--- a/chrome/browser/vr/service/vr_device_manager.cc
+++ b/chrome/browser/vr/service/vr_device_manager.cc
@@ -10,6 +10,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/singleton.h"
 #include "build/build_config.h"
+#include "chrome/common/chrome_features.h"
 #include "device/vr/features/features.h"
 
 #if defined(OS_ANDROID)
@@ -35,7 +36,8 @@
 #endif
 
 #if BUILDFLAG(ENABLE_OPENVR)
-    providers.emplace_back(std::make_unique<device::OpenVRDeviceProvider>());
+    if (base::FeatureList::IsEnabled(features::kOpenVR))
+      providers.emplace_back(std::make_unique<device::OpenVRDeviceProvider>());
 #endif
     new VRDeviceManager(std::move(providers));
   }
@@ -48,7 +50,6 @@
 
 VRDeviceManager::VRDeviceManager(ProviderList providers)
     : providers_(std::move(providers)) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   CHECK(!g_vr_device_manager);
   g_vr_device_manager = this;
 }
diff --git a/chrome/browser/vr/test/mock_browser_interface.h b/chrome/browser/vr/test/mock_browser_interface.h
index 594d2858..5f0699a 100644
--- a/chrome/browser/vr/test/mock_browser_interface.h
+++ b/chrome/browser/vr/test/mock_browser_interface.h
@@ -23,7 +23,7 @@
   MOCK_METHOD0(ExitCct, void());
   MOCK_METHOD1(OnUnsupportedMode, void(UiUnsupportedMode mode));
   MOCK_METHOD2(OnExitVrPromptResult,
-               void(UiUnsupportedMode reason, ExitVrPromptChoice choice));
+               void(ExitVrPromptChoice choice, UiUnsupportedMode reason));
   MOCK_METHOD1(OnContentScreenBoundsChanged, void(const gfx::SizeF& bounds));
   MOCK_METHOD1(SetVoiceSearchActive, void(bool active));
   MOCK_METHOD1(StartAutocomplete, void(const base::string16& string));
diff --git a/chrome/browser/vr/test/ui_scene_manager_test.cc b/chrome/browser/vr/test/ui_scene_manager_test.cc
index b915dcc4..0dba545 100644
--- a/chrome/browser/vr/test/ui_scene_manager_test.cc
+++ b/chrome/browser/vr/test/ui_scene_manager_test.cc
@@ -43,34 +43,14 @@
 
 void UiSceneManagerTest::SetUp() {
   browser_ = base::MakeUnique<testing::NiceMock<MockBrowserInterface>>();
-  content_input_delegate_ =
-      base::MakeUnique<testing::NiceMock<MockContentInputDelegate>>();
 }
 
 void UiSceneManagerTest::MakeManager(InCct in_cct, InWebVr in_web_vr) {
-  scene_ = base::MakeUnique<UiScene>();
-  model_ = base::MakeUnique<Model>();
-
-  UiInitialState ui_initial_state;
-  ui_initial_state.in_cct = in_cct;
-  ui_initial_state.in_web_vr = in_web_vr;
-  ui_initial_state.web_vr_autopresentation_expected = false;
-  manager_ = base::MakeUnique<UiSceneManager>(browser_.get(), scene_.get(),
-                                              content_input_delegate_.get(),
-                                              model_.get(), ui_initial_state);
+  MakeManagerInternal(in_cct, in_web_vr, kNotAutopresented);
 }
 
 void UiSceneManagerTest::MakeAutoPresentedManager() {
-  scene_ = base::MakeUnique<UiScene>();
-  model_ = base::MakeUnique<Model>();
-
-  UiInitialState ui_initial_state;
-  ui_initial_state.in_cct = false;
-  ui_initial_state.in_web_vr = false;
-  ui_initial_state.web_vr_autopresentation_expected = true;
-  manager_ = base::MakeUnique<UiSceneManager>(browser_.get(), scene_.get(),
-                                              content_input_delegate_.get(),
-                                              model_.get(), ui_initial_state);
+  MakeManagerInternal(kNotInCct, kNotInWebVr, kAutopresented);
 }
 
 bool UiSceneManagerTest::IsVisible(UiElementName name) const {
@@ -87,7 +67,6 @@
 
 void UiSceneManagerTest::SetIncognito(bool incognito) {
   model_->incognito = incognito;
-  manager_->SetIncognito(incognito);
 }
 
 void UiSceneManagerTest::VerifyElementsVisible(
@@ -218,6 +197,7 @@
 }
 
 void UiSceneManagerTest::GetBackgroundColor(SkColor* background_color) const {
+  OnBeginFrame();
   Rect* front =
       static_cast<Rect*>(scene_->GetUiElementByName(kBackgroundFront));
   ASSERT_NE(nullptr, front);
@@ -236,4 +216,23 @@
   *background_color = color;
 }
 
+void UiSceneManagerTest::MakeManagerInternal(
+    InCct in_cct,
+    InWebVr in_web_vr,
+    WebVrAutopresented web_vr_autopresented) {
+  auto content_input_delegate =
+      base::MakeUnique<testing::NiceMock<MockContentInputDelegate>>();
+  content_input_delegate_ = content_input_delegate.get();
+
+  UiInitialState ui_initial_state;
+  ui_initial_state.in_cct = in_cct;
+  ui_initial_state.in_web_vr = in_web_vr;
+  ui_initial_state.web_vr_autopresentation_expected = web_vr_autopresented;
+  ui_ =
+      base::MakeUnique<Ui>(std::move(browser_.get()),
+                           std::move(content_input_delegate), ui_initial_state);
+  scene_ = ui_->scene();
+  model_ = ui_->model_for_test();
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/test/ui_scene_manager_test.h b/chrome/browser/vr/test/ui_scene_manager_test.h
index d25503d9..b887b47 100644
--- a/chrome/browser/vr/test/ui_scene_manager_test.h
+++ b/chrome/browser/vr/test/ui_scene_manager_test.h
@@ -13,6 +13,7 @@
 #include "chrome/browser/vr/target_property.h"
 #include "chrome/browser/vr/test/mock_browser_interface.h"
 #include "chrome/browser/vr/test/mock_content_input_delegate.h"
+#include "chrome/browser/vr/ui.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkColor.h"
 
@@ -20,7 +21,6 @@
 
 class UiElement;
 class UiScene;
-class UiSceneManager;
 struct Model;
 
 class UiSceneManagerTest : public testing::Test {
@@ -49,6 +49,7 @@
   void MakeManager(InCct in_cct, InWebVr in_web_vr);
   void MakeAutoPresentedManager();
 
+ protected:
   bool IsVisible(UiElementName name) const;
 
   void SetIncognito(bool incognito);
@@ -88,11 +89,17 @@
 
   void GetBackgroundColor(SkColor* background_color) const;
 
+  std::unique_ptr<Ui> ui_;
   std::unique_ptr<MockBrowserInterface> browser_;
-  std::unique_ptr<MockContentInputDelegate> content_input_delegate_;
-  std::unique_ptr<UiScene> scene_;
-  std::unique_ptr<Model> model_;
-  std::unique_ptr<UiSceneManager> manager_;
+  MockContentInputDelegate* content_input_delegate_ = nullptr;
+  Model* model_ = nullptr;
+  UiScene* scene_ = nullptr;
+
+ private:
+  void MakeManagerInternal(InCct in_cct,
+                           InWebVr in_web_vr,
+                           WebVrAutopresented web_vr_autopresented);
+
   base::TimeTicks current_time_;
 };
 
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc
index e8ca33f..deca2c5 100644
--- a/chrome/browser/vr/testapp/vr_test_context.cc
+++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -124,14 +124,15 @@
         incognito_ = !incognito_;
         ui_->SetIncognito(incognito_);
         break;
-      case ui::DomCode::US_S: {
+      case ui::DomCode::US_S:
         CreateFakeOmniboxSuggestions();
         break;
-        case ui::DomCode::US_V:
-          ui_->SetVideoCaptureEnabled(
-              !model_->permissions.video_capture_enabled);
-          break;
-      }
+      case ui::DomCode::US_D:
+        ui_->Dump();
+        break;
+      case ui::DomCode::US_V:
+        ui_->SetVideoCaptureEnabled(!model_->permissions.video_capture_enabled);
+        break;
       default:
         break;
     }
@@ -331,9 +332,8 @@
     ui_->SetExitVrPromptEnabled(true, mode);
   }
 }
-
-void VrTestContext::OnExitVrPromptResult(vr::UiUnsupportedMode reason,
-                                         vr::ExitVrPromptChoice choice) {
+void VrTestContext::OnExitVrPromptResult(vr::ExitVrPromptChoice choice,
+                                         vr::UiUnsupportedMode reason) {
   LOG(ERROR) << "exit prompt result: " << choice;
   ui_->SetExitVrPromptEnabled(false, UiUnsupportedMode::kCount);
 }
diff --git a/chrome/browser/vr/testapp/vr_test_context.h b/chrome/browser/vr/testapp/vr_test_context.h
index 62320f2..37ff12f3 100644
--- a/chrome/browser/vr/testapp/vr_test_context.h
+++ b/chrome/browser/vr/testapp/vr_test_context.h
@@ -40,8 +40,8 @@
   void NavigateBack() override;
   void ExitCct() override;
   void OnUnsupportedMode(vr::UiUnsupportedMode mode) override;
-  void OnExitVrPromptResult(vr::UiUnsupportedMode reason,
-                            vr::ExitVrPromptChoice choice) override;
+  void OnExitVrPromptResult(vr::ExitVrPromptChoice choice,
+                            vr::UiUnsupportedMode reason) override;
   void OnContentScreenBoundsChanged(const gfx::SizeF& bounds) override;
   void SetVoiceSearchActive(bool active) override;
   void StartAutocomplete(const base::string16& string) override;
diff --git a/chrome/browser/vr/ui.cc b/chrome/browser/vr/ui.cc
index 6960a62..a1ea992 100644
--- a/chrome/browser/vr/ui.cc
+++ b/chrome/browser/vr/ui.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <iomanip>
+#include <sstream>
+
 #include "chrome/browser/vr/ui.h"
 
 #include "base/memory/ptr_util.h"
@@ -26,23 +29,34 @@
 Ui::Ui(UiBrowserInterface* browser,
        ContentInputForwarder* content_input_forwarder,
        const UiInitialState& ui_initial_state)
+    : Ui(browser,
+         base::MakeUnique<ContentInputDelegate>(content_input_forwarder),
+         ui_initial_state) {}
+
+Ui::Ui(UiBrowserInterface* browser,
+       std::unique_ptr<ContentInputDelegate> content_input_delegate,
+       const UiInitialState& ui_initial_state)
     : browser_(browser),
       scene_(base::MakeUnique<UiScene>()),
       model_(base::MakeUnique<Model>()),
-      content_input_delegate_(
-          base::MakeUnique<ContentInputDelegate>(content_input_forwarder)),
+      content_input_delegate_(std::move(content_input_delegate)),
       input_manager_(base::MakeUnique<UiInputManager>(scene_.get())),
       weak_ptr_factory_(this) {
-  model_->started_for_autopresentation =
+  model_->web_vr_started_for_autopresentation =
+      ui_initial_state.web_vr_autopresentation_expected;
+  model_->web_vr_show_splash_screen =
       ui_initial_state.web_vr_autopresentation_expected;
   model_->experimental_features_enabled =
       base::FeatureList::IsEnabled(features::kVrBrowsingExperimentalFeatures);
   model_->speech.has_or_can_request_audio_permission =
       ui_initial_state.has_or_can_request_audio_permission;
+  model_->web_vr_mode = ui_initial_state.in_web_vr;
+  model_->in_cct = ui_initial_state.in_cct;
+  model_->browsing_disabled = ui_initial_state.browsing_disabled;
 
-  scene_manager_ = base::MakeUnique<UiSceneManager>(
-      browser, scene_.get(), content_input_delegate_.get(), model_.get(),
-      ui_initial_state);
+  UiSceneManager(browser, scene_.get(), content_input_delegate_.get(),
+                 model_.get())
+      .CreateScene();
 }
 
 Ui::~Ui() = default;
@@ -54,11 +68,16 @@
 void Ui::SetWebVrMode(bool enabled, bool show_toast) {
   model_->web_vr_timeout_state =
       enabled ? kWebVrAwaitingFirstFrame : kWebVrNoTimeoutPending;
-  scene_manager_->SetWebVrMode(enabled, show_toast);
+  model_->web_vr_mode = enabled;
+  model_->web_vr_show_toast = show_toast;
+  if (!enabled) {
+    model_->web_vr_show_splash_screen = false;
+    model_->web_vr_started_for_autopresentation = false;
+  }
 }
 
 void Ui::SetFullscreen(bool enabled) {
-  scene_manager_->SetFullscreen(enabled);
+  model_->fullscreen = enabled;
 }
 
 void Ui::SetToolbarState(const ToolbarState& state) {
@@ -67,7 +86,6 @@
 
 void Ui::SetIncognito(bool enabled) {
   model_->incognito = enabled;
-  scene_manager_->SetIncognito(enabled);
 }
 
 void Ui::SetLoading(bool loading) {
@@ -79,11 +97,12 @@
 }
 
 void Ui::SetIsExiting() {
-  scene_manager_->SetIsExiting();
+  model_->exiting_vr = true;
 }
 
 void Ui::SetHistoryButtonsEnabled(bool can_go_back, bool can_go_forward) {
-  scene_manager_->SetHistoryButtonsEnabled(can_go_back, can_go_forward);
+  // We don't yet support forward navigation so we ignore this parameter.
+  model_->can_navigate_back = can_go_back;
 }
 
 void Ui::SetVideoCaptureEnabled(bool enabled) {
@@ -114,8 +133,8 @@
 
   if (model_->active_modal_prompt_type != kModalPromptTypeNone) {
     browser_->OnExitVrPromptResult(
-        GetReasonForPrompt(model_->active_modal_prompt_type),
-        ExitVrPromptChoice::CHOICE_NONE);
+        ExitVrPromptChoice::CHOICE_NONE,
+        GetReasonForPrompt(model_->active_modal_prompt_type));
   }
 
   switch (reason) {
@@ -151,7 +170,7 @@
 }
 
 bool Ui::ShouldRenderWebVr() {
-  return scene_manager_->ShouldRenderWebVr();
+  return model_->should_render_web_vr();
 }
 
 void Ui::OnGlInitialized(unsigned int content_texture_id,
@@ -165,17 +184,29 @@
   } else {
     provider_ = base::MakeUnique<CpuSurfaceProvider>();
   }
-  scene_manager_->OnGlInitialized(content_texture_id, content_location,
-                                  provider_.get());
+  scene_->OnGlInitialized(provider_.get());
+  model_->content_texture_id = content_texture_id;
+  model_->content_location = content_location;
 }
 
 void Ui::OnAppButtonClicked() {
-  scene_manager_->OnAppButtonClicked();
+  // App button clicks should be a no-op when auto-presenting WebVR.
+  if (model_->web_vr_started_for_autopresentation) {
+    return;
+  }
+
+  // If browsing mode is disabled, the app button should no-op.
+  if (model_->browsing_disabled) {
+    return;
+  }
+
+  // App button click exits the WebVR presentation and fullscreen.
+  browser_->ExitPresent();
+  browser_->ExitFullscreen();
 }
 
 void Ui::OnAppButtonGesturePerformed(
     PlatformController::SwipeDirection direction) {
-  scene_manager_->OnAppButtonGesturePerformed(direction);
 }
 
 void Ui::OnControllerUpdated(const ControllerModel& controller_model,
@@ -186,12 +217,11 @@
 }
 
 void Ui::OnProjMatrixChanged(const gfx::Transform& proj_matrix) {
-  scene_manager_->OnProjMatrixChanged(proj_matrix);
+  model_->projection_matrix = proj_matrix;
 }
 
 void Ui::OnWebVrFrameAvailable() {
   model_->web_vr_timeout_state = kWebVrNoTimeoutPending;
-  scene_manager_->OnWebVrFrameAvailable();
 }
 
 void Ui::OnWebVrTimeoutImminent() {
@@ -219,4 +249,12 @@
   return controller_group && controller_group->GetTargetOpacity() > 0.0f;
 }
 
+void Ui::Dump() {
+  std::ostringstream os;
+  os << std::setprecision(3);
+  os << std::endl;
+  scene_->root_element().DumpHierarchy(std::vector<size_t>(), &os);
+  LOG(ERROR) << os.str();
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/ui.h b/chrome/browser/vr/ui.h
index ded6cda..53546c7 100644
--- a/chrome/browser/vr/ui.h
+++ b/chrome/browser/vr/ui.h
@@ -22,7 +22,6 @@
 class UiInputManager;
 class UiRenderer;
 class UiScene;
-class UiSceneManager;
 struct ControllerModel;
 struct Model;
 struct OmniboxSuggestions;
@@ -43,6 +42,11 @@
   Ui(UiBrowserInterface* browser,
      ContentInputForwarder* content_input_forwarder,
      const UiInitialState& ui_initial_state);
+
+  Ui(UiBrowserInterface* browser,
+     std::unique_ptr<ContentInputDelegate> content_input_delegate,
+     const UiInitialState& ui_initial_state);
+
   ~Ui() override;
 
   // TODO(crbug.com/767957): Refactor to hide these behind the UI interface.
@@ -96,6 +100,8 @@
 
   Model* model_for_test() { return model_.get(); }
 
+  void Dump();
+
  private:
   UiBrowserInterface* browser_;
 
@@ -103,7 +109,6 @@
   std::unique_ptr<vr::UiScene> scene_;
   std::unique_ptr<vr::Model> model_;
   std::unique_ptr<vr::ContentInputDelegate> content_input_delegate_;
-  std::unique_ptr<vr::UiSceneManager> scene_manager_;
   std::unique_ptr<vr::UiElementRenderer> ui_element_renderer_;
   std::unique_ptr<vr::UiInputManager> input_manager_;
   std::unique_ptr<vr::UiRenderer> ui_renderer_;
diff --git a/chrome/browser/vr/ui_browser_interface.h b/chrome/browser/vr/ui_browser_interface.h
index bad7a49..09202cf 100644
--- a/chrome/browser/vr/ui_browser_interface.h
+++ b/chrome/browser/vr/ui_browser_interface.h
@@ -24,8 +24,8 @@
   virtual void NavigateBack() = 0;
   virtual void ExitCct() = 0;
   virtual void OnUnsupportedMode(UiUnsupportedMode mode) = 0;
-  virtual void OnExitVrPromptResult(UiUnsupportedMode reason,
-                                    ExitVrPromptChoice choice) = 0;
+  virtual void OnExitVrPromptResult(ExitVrPromptChoice choice,
+                                    UiUnsupportedMode reason) = 0;
   virtual void OnContentScreenBoundsChanged(const gfx::SizeF& bounds) = 0;
   virtual void SetVoiceSearchActive(bool active) = 0;
   virtual void StartAutocomplete(const base::string16& string) = 0;
diff --git a/chrome/browser/vr/ui_input_manager_unittest.cc b/chrome/browser/vr/ui_input_manager_unittest.cc
index 83963a6..99533f8 100644
--- a/chrome/browser/vr/ui_input_manager_unittest.cc
+++ b/chrome/browser/vr/ui_input_manager_unittest.cc
@@ -90,12 +90,12 @@
   void SetUp() override {
     UiSceneManagerTest::SetUp();
     MakeManager(kNotInCct, kNotInWebVr);
-    input_manager_ = base::MakeUnique<UiInputManager>(scene_.get());
+    input_manager_ = ui_->input_manager();
     EXPECT_TRUE(scene_->OnBeginFrame(MicrosecondsToTicks(1), kForwardVector));
   }
 
  protected:
-  std::unique_ptr<UiInputManager> input_manager_;
+  UiInputManager* input_manager_;
 };
 
 TEST_F(UiInputManagerTest, ReticleRenderTarget) {
diff --git a/chrome/browser/vr/ui_scene.cc b/chrome/browser/vr/ui_scene.cc
index 06d9725b..adf2d71 100644
--- a/chrome/browser/vr/ui_scene.cc
+++ b/chrome/browser/vr/ui_scene.cc
@@ -245,8 +245,6 @@
 
 UiScene::~UiScene() = default;
 
-// TODO(vollick): we should bind to gl-initialized state. Elements will
-// initialize when the binding fires, automatically.
 void UiScene::OnGlInitialized(SkiaSurfaceProvider* provider) {
   gl_initialized_ = true;
   provider_ = provider;
diff --git a/chrome/browser/vr/ui_scene.h b/chrome/browser/vr/ui_scene.h
index 7ef5d2d2a..d06328b 100644
--- a/chrome/browser/vr/ui_scene.h
+++ b/chrome/browser/vr/ui_scene.h
@@ -10,7 +10,6 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/vr/color_scheme.h"
 #include "chrome/browser/vr/elements/ui_element.h"
 #include "chrome/browser/vr/elements/ui_element_iterator.h"
 #include "chrome/browser/vr/elements/ui_element_name.h"
@@ -63,14 +62,6 @@
   float background_distance() const { return background_distance_; }
   void set_background_distance(float d) { background_distance_ = d; }
 
-  bool web_vr_rendering_enabled() const { return webvr_rendering_enabled_; }
-  void set_web_vr_rendering_enabled(bool enabled) {
-    webvr_rendering_enabled_ = enabled;
-  }
-  bool reticle_rendering_enabled() const { return reticle_rendering_enabled_; }
-  void set_reticle_rendering_enabled(bool enabled) {
-    reticle_rendering_enabled_ = enabled;
-  }
   int first_foreground_draw_phase() const {
     return first_foreground_draw_phase_;
   }
@@ -85,8 +76,6 @@
   std::unique_ptr<UiElement> root_element_;
 
   float background_distance_ = 10.0f;
-  bool webvr_rendering_enabled_ = false;
-  bool reticle_rendering_enabled_ = true;
   bool gl_initialized_ = false;
   int first_foreground_draw_phase_ = 0;
   bool initialized_scene_ = false;
diff --git a/chrome/browser/vr/ui_scene_constants.h b/chrome/browser/vr/ui_scene_constants.h
index 3e9fb3c9..01c3220b 100644
--- a/chrome/browser/vr/ui_scene_constants.h
+++ b/chrome/browser/vr/ui_scene_constants.h
@@ -95,11 +95,15 @@
 static constexpr float kButtonZOffsetHoverDMM = 0.048;
 
 static constexpr float kCloseButtonDistance = 2.4f;
+static constexpr float kCloseButtonVerticalOffset =
+    kFullscreenVerticalOffset - (kFullscreenHeight * 0.5f) - 0.35f;
 static constexpr float kCloseButtonHeight =
     kUrlBarHeightDMM * kCloseButtonDistance;
 static constexpr float kCloseButtonWidth =
     kUrlBarHeightDMM * kCloseButtonDistance;
 static constexpr float kCloseButtonFullscreenDistance = 2.9f;
+static constexpr float kCloseButtonFullscreenVerticalOffset =
+    kFullscreenVerticalOffset - (kFullscreenHeight / 2) - 0.35f;
 static constexpr float kCloseButtonFullscreenHeight =
     kUrlBarHeightDMM * kCloseButtonFullscreenDistance;
 static constexpr float kCloseButtonFullscreenWidth =
@@ -178,14 +182,6 @@
 static constexpr float kTimeoutButtonTextVerticalOffset =
     kTimeoutButtonTextHeight;
 
-// If the screen space bounds or the aspect ratio of the content quad change
-// beyond these thresholds we propagate the new content bounds so that the
-// content's resolution can be adjusted.
-static constexpr float kContentBoundsPropagationThreshold = 0.2f;
-// Changes of the aspect ratio lead to a
-// distorted content much more quickly. Thus, have a smaller threshold here.
-static constexpr float kContentAspectRatioPropagationThreshold = 0.01f;
-
 static constexpr float kScreenDimmerOpacity = 0.9f;
 
 static constexpr gfx::Point3F kOrigin = {0.0f, 0.0f, 0.0f};
diff --git a/chrome/browser/vr/ui_scene_manager.cc b/chrome/browser/vr/ui_scene_manager.cc
index 55259bc3..8728c128 100644
--- a/chrome/browser/vr/ui_scene_manager.cc
+++ b/chrome/browser/vr/ui_scene_manager.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/vr/ui_scene_manager.h"
 
-#include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/memory/ptr_util.h"
@@ -16,7 +15,6 @@
 #include "chrome/browser/vr/elements/content_element.h"
 #include "chrome/browser/vr/elements/controller.h"
 #include "chrome/browser/vr/elements/draw_phase.h"
-#include "chrome/browser/vr/elements/exclusive_screen_toast.h"
 #include "chrome/browser/vr/elements/exit_prompt.h"
 #include "chrome/browser/vr/elements/full_screen_rect.h"
 #include "chrome/browser/vr/elements/grid.h"
@@ -25,9 +23,9 @@
 #include "chrome/browser/vr/elements/linear_layout.h"
 #include "chrome/browser/vr/elements/rect.h"
 #include "chrome/browser/vr/elements/reticle.h"
+#include "chrome/browser/vr/elements/simple_textured_element.h"
 #include "chrome/browser/vr/elements/spinner.h"
 #include "chrome/browser/vr/elements/suggestion.h"
-#include "chrome/browser/vr/elements/system_indicator.h"
 #include "chrome/browser/vr/elements/text.h"
 #include "chrome/browser/vr/elements/throbber.h"
 #include "chrome/browser/vr/elements/transient_element.h"
@@ -46,7 +44,6 @@
 #include "chrome/browser/vr/ui_scene.h"
 #include "chrome/browser/vr/ui_scene_constants.h"
 #include "chrome/browser/vr/vector_icons/vector_icons.h"
-#include "chrome/browser/vr/vr_gl_util.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -56,32 +53,22 @@
 
 namespace {
 
-template <typename P>
-void BindColor(UiSceneManager* model, Rect* rect, P p) {
-  rect->AddBinding(base::MakeUnique<Binding<SkColor>>(
-      base::Bind([](UiSceneManager* m, P p) { return (m->color_scheme()).*p; },
-                 base::Unretained(model), p),
-      base::Bind([](Rect* r, const SkColor& c) { r->SetColor(c); },
-                 base::Unretained(rect))));
+template <typename V, typename C, typename S>
+void BindColor(Model* model, V* view, C color, S setter) {
+  view->AddBinding(base::MakeUnique<Binding<SkColor>>(
+      base::Bind([](Model* m, C c) { return (m->color_scheme()).*c; },
+                 base::Unretained(model), color),
+      base::Bind([](V* v, S s, const SkColor& value) { (v->*s)(value); },
+                 base::Unretained(view), setter)));
 }
 
-template <typename P>
-void BindColor(UiSceneManager* model, Text* text, P p) {
-  text->AddBinding(base::MakeUnique<Binding<SkColor>>(
-      base::Bind([](UiSceneManager* m, P p) { return (m->color_scheme()).*p; },
-                 base::Unretained(model), p),
-      base::Bind([](Text* t, const SkColor& c) { t->SetColor(c); },
-                 base::Unretained(text))));
-}
-
-template <typename P>
-void BindColor(UiSceneManager* model, Button* button, P p) {
-  button->AddBinding(base::MakeUnique<Binding<ButtonColors>>(
-      base::Bind([](UiSceneManager* m, P p) { return (m->color_scheme()).*p; },
-                 base::Unretained(model), p),
-      base::Bind(
-          [](Button* b, const ButtonColors& c) { b->SetButtonColors(c); },
-          base::Unretained(button))));
+template <typename V, typename C, typename S>
+void BindButtonColors(Model* model, V* view, C colors, S setter) {
+  view->AddBinding(base::MakeUnique<Binding<ButtonColors>>(
+      base::Bind([](Model* m, C c) { return (m->color_scheme()).*c; },
+                 base::Unretained(model), colors),
+      base::Bind([](V* v, S s, const ButtonColors& value) { (v->*s)(value); },
+                 base::Unretained(view), setter)));
 }
 
 typedef VectorBinding<OmniboxSuggestion, Suggestion> SuggestionSetBinding;
@@ -153,52 +140,64 @@
   scene->RemoveUiElement(binding->view()->id());
 }
 
+TransientElement* AddTransientParent(UiElementName name,
+                                     UiElementName parent_name,
+                                     int timeout_seconds,
+                                     bool animate_opacity,
+                                     UiScene* scene) {
+  auto element = base::MakeUnique<SimpleTransientElement>(
+      base::TimeDelta::FromSeconds(timeout_seconds));
+  TransientElement* to_return = element.get();
+  element->set_name(name);
+  element->SetVisible(false);
+  element->set_hit_testable(false);
+  if (animate_opacity)
+    element->SetTransitionedProperties({OPACITY});
+  scene->AddUiElement(parent_name, std::move(element));
+  return to_return;
+}
+
 }  // namespace
 
 UiSceneManager::UiSceneManager(UiBrowserInterface* browser,
                                UiScene* scene,
                                ContentInputDelegate* content_input_delegate,
-                               Model* model,
-                               const UiInitialState& ui_initial_state)
+                               Model* model)
     : browser_(browser),
       scene_(scene),
-      in_cct_(ui_initial_state.in_cct),
-      web_vr_mode_(ui_initial_state.in_web_vr),
-      started_for_autopresentation_(
-          ui_initial_state.web_vr_autopresentation_expected),
-      showing_web_vr_splash_screen_(
-          ui_initial_state.web_vr_autopresentation_expected),
-      browsing_disabled_(ui_initial_state.browsing_disabled) {
-  Create2dBrowsingSubtreeRoots(model);
-  CreateWebVrRoot();
-  CreateBackground();
-  CreateViewportAwareRoot();
-  CreateContentQuad(content_input_delegate);
-  CreateExitPrompt(model);
-  CreateAudioPermissionPrompt(model);
-  CreateWebVRExitWarning();
-  CreateSystemIndicators(model);
-  CreateUrlBar(model);
-  CreateSuggestionList(model);
-  CreateWebVrUrlToast(model);
-  CreateCloseButton();
-  CreateScreenDimmer();
-  CreateToasts(model);
-  CreateSplashScreen(model);
-  CreateUnderDevelopmentNotice();
-  CreateVoiceSearchUiGroup(model);
-  CreateController(model);
-
-  ConfigureScene();
-}
+      content_input_delegate_(content_input_delegate),
+      model_(model) {}
 
 UiSceneManager::~UiSceneManager() {}
 
-void UiSceneManager::Create2dBrowsingSubtreeRoots(Model* model) {
+void UiSceneManager::CreateScene() {
+  Create2dBrowsingSubtreeRoots();
+  CreateWebVrRoot();
+  CreateBackground();
+  CreateViewportAwareRoot();
+  CreateContentQuad();
+  CreateExitPrompt();
+  CreateAudioPermissionPrompt();
+  CreateWebVRExitWarning();
+  CreateSystemIndicators();
+  CreateUrlBar();
+  CreateSuggestionList();
+  CreateWebVrUrlToast();
+  CreateCloseButton();
+  CreateToasts();
+  CreateSplashScreen();
+  CreateUnderDevelopmentNotice();
+  CreateVoiceSearchUiGroup();
+  CreateController();
+}
+
+void UiSceneManager::Create2dBrowsingSubtreeRoots() {
   auto element = base::MakeUnique<UiElement>();
   element->set_name(k2dBrowsingRoot);
   element->SetVisible(true);
   element->set_hit_testable(false);
+  element->AddBinding(VR_BIND_FUNC(bool, Model, model_, browsing_mode(),
+                                   UiElement, element.get(), SetVisible));
   scene_->AddUiElement(kRoot, std::move(element));
 
   element = base::MakeUnique<UiElement>();
@@ -207,12 +206,6 @@
   element->set_hit_testable(false);
   scene_->AddUiElement(k2dBrowsingRoot, std::move(element));
 
-  auto browsing_mode_toggle = base::MakeUnique<UiElement>();
-  browsing_mode_toggle->set_hit_testable(false);
-  browsing_mode_toggle->AddBinding(
-      VR_BIND_FUNC(bool, UiSceneManager, this, browsing_mode(), UiElement,
-                   browsing_mode_toggle.get(), SetVisible));
-
   element = base::MakeUnique<UiElement>();
   element->set_name(k2dBrowsingForeground);
   element->set_hit_testable(false);
@@ -221,7 +214,7 @@
       kSpeechRecognitionOpacityAnimationDurationMs));
   element->AddBinding(base::MakeUnique<Binding<ModalPromptType>>(
       base::Bind([](Model* m) { return m->active_modal_prompt_type; },
-                 base::Unretained(model)),
+                 base::Unretained(model_)),
       base::Bind(
           [](UiElement* e, const ModalPromptType& t) {
             if (t == kModalPromptTypeExitVRForSiteInfo) {
@@ -234,8 +227,7 @@
           },
           base::Unretained(element.get()))));
 
-  browsing_mode_toggle->AddChild(std::move(element));
-  scene_->AddUiElement(k2dBrowsingRoot, std::move(browsing_mode_toggle));
+  scene_->AddUiElement(k2dBrowsingRoot, std::move(element));
 
   element = base::MakeUnique<UiElement>();
   element->set_name(k2dBrowsingContentGroup);
@@ -243,6 +235,11 @@
   element->SetSize(kContentWidth, kContentHeight);
   element->set_hit_testable(false);
   element->SetTransitionedProperties({TRANSFORM});
+  element->AddBinding(VR_BIND(
+      bool, Model, model_, fullscreen, UiElement, element.get(),
+      SetTranslate(0,
+                   value ? kFullscreenVerticalOffset : kContentVerticalOffset,
+                   value ? -kFullscreenToastDistance : -kContentDistance)));
   scene_->AddUiElement(k2dBrowsingForeground, std::move(element));
 }
 
@@ -251,43 +248,43 @@
   element->set_name(kWebVrRoot);
   element->SetVisible(true);
   element->set_hit_testable(false);
+  element->AddBinding(VR_BIND_FUNC(bool, Model, model_,
+                                   browsing_mode() == false, UiElement,
+                                   element.get(), SetVisible));
   scene_->AddUiElement(kRoot, std::move(element));
 }
 
-void UiSceneManager::CreateScreenDimmer() {
-  auto element = base::MakeUnique<FullScreenRect>();
-  element->set_name(kScreenDimmer);
-  element->set_draw_phase(kPhaseOverlayBackground);
-  element->SetVisible(false);
-  element->set_hit_testable(false);
-  element->SetOpacity(kScreenDimmerOpacity);
-  element->SetCenterColor(color_scheme().dimmer_inner);
-  element->SetEdgeColor(color_scheme().dimmer_outer);
-  screen_dimmer_ = element.get();
-  scene_->AddUiElement(k2dBrowsingRoot, std::move(element));
-}
-
 void UiSceneManager::CreateWebVRExitWarning() {
-  std::unique_ptr<UiElement> element;
+  auto scrim = base::MakeUnique<FullScreenRect>();
+  scrim->set_name(kScreenDimmer);
+  scrim->set_draw_phase(kPhaseOverlayBackground);
+  scrim->SetVisible(false);
+  scrim->set_hit_testable(false);
+  scrim->SetOpacity(kScreenDimmerOpacity);
+  scrim->SetCenterColor(model_->color_scheme().dimmer_inner);
+  scrim->SetEdgeColor(model_->color_scheme().dimmer_outer);
+  scrim->AddBinding(VR_BIND_FUNC(bool, Model, model_, exiting_vr, UiElement,
+                                 scrim.get(), SetVisible));
+  scene_->AddUiElement(k2dBrowsingRoot, std::move(scrim));
 
   // TODO(mthiesse): Programatically compute the proper texture size for these
   // textured UI elements.
   // Create transient exit warning.
-  element = base::MakeUnique<ExitWarning>(1024);
-  element->set_name(kExitWarning);
-  element->set_draw_phase(kPhaseOverlayForeground);
-  element->SetSize(kExitWarningWidth, kExitWarningHeight);
-  element->SetTranslate(0, 0, -kExitWarningDistance);
-  element->SetScale(kExitWarningDistance, kExitWarningDistance, 1);
-  element->SetVisible(false);
-  element->set_hit_testable(false);
-  exit_warning_ = element.get();
-  scene_->AddUiElement(k2dBrowsingViewportAwareRoot, std::move(element));
+  auto exit_warning = base::MakeUnique<ExitWarning>(1024);
+  exit_warning->set_name(kExitWarning);
+  exit_warning->set_draw_phase(kPhaseOverlayForeground);
+  exit_warning->SetSize(kExitWarningWidth, kExitWarningHeight);
+  exit_warning->SetTranslate(0, 0, -kExitWarningDistance);
+  exit_warning->SetScale(kExitWarningDistance, kExitWarningDistance, 1);
+  exit_warning->SetVisible(false);
+  exit_warning->set_hit_testable(false);
+  exit_warning->AddBinding(VR_BIND_FUNC(bool, Model, model_, exiting_vr,
+                                        UiElement, exit_warning.get(),
+                                        SetVisible));
+  scene_->AddUiElement(k2dBrowsingViewportAwareRoot, std::move(exit_warning));
 }
 
-void UiSceneManager::CreateSystemIndicators(Model* model) {
-  std::unique_ptr<UiElement> element;
-
+void UiSceneManager::CreateSystemIndicators() {
   struct Indicator {
     UiElementName name;
     const gfx::VectorIcon& icon;
@@ -319,23 +316,29 @@
                                  kIndicatorDistanceOffset);
   indicator_layout->set_margin(kIndicatorGap);
   indicator_layout->AddBinding(
-      VR_BIND_FUNC(bool, UiSceneManager, this, fullscreen() == false, UiElement,
+      VR_BIND_FUNC(bool, Model, model_, fullscreen == false, UiElement,
                    indicator_layout.get(), SetVisible));
   scene_->AddUiElement(k2dBrowsingContentGroup, std::move(indicator_layout));
 
   for (const auto& indicator : indicators) {
-    element = base::MakeUnique<SystemIndicator>(
-        512, kIndicatorHeight, indicator.icon, indicator.resource_string);
+    auto element = base::MakeUnique<SystemIndicator>(512);
+    element->GetDerivedTexture()->SetIcon(indicator.icon);
+    element->GetDerivedTexture()->SetMessageId(indicator.resource_string);
     element->set_name(indicator.name);
     element->set_draw_phase(kPhaseForeground);
     element->set_requires_layout(false);
+    element->SetSize(0, kIndicatorHeight);
     element->SetVisible(false);
+    BindColor(model_, element.get(), &ColorScheme::system_indicator_background,
+              &TexturedElement::SetBackgroundColor);
+    BindColor(model_, element.get(), &ColorScheme::system_indicator_foreground,
+              &TexturedElement::SetForegroundColor);
     element->AddBinding(base::MakeUnique<Binding<bool>>(
         base::Bind(
             [](Model* m, bool PermissionsModel::*permission) {
               return m->permissions.*permission;
             },
-            base::Unretained(model), indicator.signal),
+            base::Unretained(model_), indicator.signal),
         base::Bind(
             [](UiElement* e, const bool& v) {
               e->SetVisible(v);
@@ -346,7 +349,7 @@
   }
 }
 
-void UiSceneManager::CreateContentQuad(ContentInputDelegate* delegate) {
+void UiSceneManager::CreateContentQuad() {
   // Place an invisible but hittable plane behind the content quad, to keep the
   // reticle roughly planar with the content if near content.
   auto hit_plane = base::MakeUnique<InvisibleHitTarget>();
@@ -356,13 +359,28 @@
   hit_plane->SetTranslate(0, 0, -kTextureOffset);
   scene_->AddUiElement(k2dBrowsingContentGroup, std::move(hit_plane));
 
-  auto main_content = base::MakeUnique<ContentElement>(delegate);
+  auto main_content = base::MakeUnique<ContentElement>(
+      content_input_delegate_,
+      base::Bind(&UiBrowserInterface::OnContentScreenBoundsChanged,
+                 base::Unretained(browser_)));
   main_content->set_name(kContentQuad);
   main_content->set_draw_phase(kPhaseForeground);
   main_content->SetSize(kContentWidth, kContentHeight);
   main_content->set_corner_radius(kContentCornerRadius);
   main_content->SetTransitionedProperties({BOUNDS});
-  main_content_ = main_content.get();
+  main_content->AddBinding(
+      VR_BIND(bool, Model, model_, fullscreen, UiElement, main_content.get(),
+              SetSize(value ? kFullscreenWidth : kContentWidth,
+                      value ? kFullscreenHeight : kContentHeight)));
+  main_content->AddBinding(
+      VR_BIND_FUNC(gfx::Transform, Model, model_, projection_matrix,
+                   ContentElement, main_content.get(), SetProjectionMatrix));
+  main_content->AddBinding(VR_BIND_FUNC(unsigned int, Model, model_,
+                                        content_texture_id, ContentElement,
+                                        main_content.get(), SetTextureId));
+  main_content->AddBinding(VR_BIND_FUNC(
+      UiElementRenderer::TextureLocation, Model, model_, content_location,
+      ContentElement, main_content.get(), SetTextureLocation));
   scene_->AddUiElement(k2dBrowsingContentGroup, std::move(main_content));
 
   // Limit reticle distance to a sphere based on content distance.
@@ -370,7 +388,7 @@
                                   kBackgroundDistanceMultiplier);
 }
 
-void UiSceneManager::CreateSplashScreen(Model* model) {
+void UiSceneManager::CreateSplashScreen() {
   auto element = base::MakeUnique<UiElement>();
   element->set_name(kSplashScreenRoot);
   element->SetVisible(true);
@@ -390,20 +408,36 @@
   auto transient_parent = base::MakeUnique<ShowUntilSignalTransientElement>(
       base::TimeDelta::FromSeconds(kSplashScreenMinDurationSeconds),
       base::TimeDelta::Max(),
-      base::Bind(&UiSceneManager::OnSplashScreenHidden,
-                 base::Unretained(this)));
+      base::Bind(
+          [](Model* model, UiBrowserInterface* browser,
+             TransientElementHideReason reason) {
+            // NOTE: we are setting the model here. May want to post a task or
+            // fire an event object instead of setting it here directly.
+            model->web_vr_show_splash_screen = false;
+            if (reason == TransientElementHideReason::kTimeout) {
+              browser->ExitPresent();
+            }
+          },
+          base::Unretained(model_), base::Unretained(browser_)));
   transient_parent->set_name(kSplashScreenTransientParent);
-  transient_parent->SetVisible(started_for_autopresentation_);
+  transient_parent->AddBinding(
+      VR_BIND_FUNC(bool, Model, model_, web_vr_show_splash_screen, UiElement,
+                   transient_parent.get(), SetVisible));
   transient_parent->set_hit_testable(false);
   transient_parent->SetTransitionedProperties({OPACITY});
-  splash_screen_transient_parent_ = transient_parent.get();
+  transient_parent->AddBinding(VR_BIND_FUNC(
+      bool, Model, model_,
+      web_vr_show_splash_screen &&
+          model->web_vr_timeout_state == kWebVrNoTimeoutPending,
+      ShowUntilSignalTransientElement, transient_parent.get(), Signal));
   scene_->AddUiElement(kSplashScreenViewportAwareRoot,
                        std::move(transient_parent));
 
   // Add "Powered by Chrome" text.
   auto text = base::MakeUnique<Text>(512, kSplashScreenTextFontHeightM,
                                      kSplashScreenTextWidthM);
-  BindColor(this, text.get(), &ColorScheme::splash_screen_text_color);
+  BindColor(model_, text.get(), &ColorScheme::splash_screen_text_color,
+            &Text::SetColor);
   text->SetText(l10n_util::GetStringUTF16(IDS_VR_POWERED_BY_CHROME_MESSAGE));
   text->set_name(kSplashScreenText);
   text->SetVisible(true);
@@ -420,7 +454,7 @@
   bg->set_draw_phase(kPhaseOverlayBackground);
   bg->SetVisible(true);
   bg->set_hit_testable(false);
-  bg->SetColor(color_scheme().splash_screen_background);
+  bg->SetColor(model_->color_scheme().splash_screen_background);
   scene_->AddUiElement(kSplashScreenText, std::move(bg));
 
   auto spinner = base::MakeUnique<Spinner>(512);
@@ -429,9 +463,9 @@
   spinner->SetVisible(false);
   spinner->SetSize(kSpinnerWidth, kSpinnerHeight);
   spinner->SetTranslate(0, kSpinnerVerticalOffset, -kSpinnerDistance);
-  spinner->SetColor(color_scheme().spinner_color);
+  spinner->SetColor(model_->color_scheme().spinner_color);
   spinner->AddBinding(VR_BIND_FUNC(
-      bool, Model, model, web_vr_timeout_state == kWebVrTimeoutImminent,
+      bool, Model, model_, web_vr_timeout_state == kWebVrTimeoutImminent,
       Spinner, spinner.get(), SetVisible));
   spinner->SetTransitionedProperties({OPACITY});
   scene_->AddUiElement(kSplashScreenViewportAwareRoot, std::move(spinner));
@@ -443,11 +477,11 @@
   spinner_bg->set_draw_phase(kPhaseOverlayBackground);
   spinner_bg->SetVisible(false);
   spinner_bg->set_hit_testable(false);
-  spinner_bg->SetColor(color_scheme().spinner_background);
+  spinner_bg->SetColor(model_->color_scheme().spinner_background);
   spinner_bg->SetTransitionedProperties({OPACITY});
   spinner_bg->SetTransitionDuration(base::TimeDelta::FromMilliseconds(200));
   spinner_bg->AddBinding(VR_BIND_FUNC(
-      bool, Model, model, web_vr_timeout_state != kWebVrNoTimeoutPending,
+      bool, Model, model_, web_vr_timeout_state != kWebVrNoTimeoutPending,
       FullScreenRect, spinner_bg.get(), SetVisible));
   scene_->AddUiElement(kSplashScreenRoot, std::move(spinner_bg));
 
@@ -461,9 +495,9 @@
   timeout_message->set_corner_radius(kTimeoutMessageCornerRadius);
   timeout_message->SetTransitionedProperties({OPACITY});
   timeout_message->AddBinding(
-      VR_BIND_FUNC(bool, Model, model, web_vr_timeout_state == kWebVrTimedOut,
+      VR_BIND_FUNC(bool, Model, model_, web_vr_timeout_state == kWebVrTimedOut,
                    Rect, timeout_message.get(), SetVisible));
-  timeout_message->SetColor(color_scheme().timeout_message_background);
+  timeout_message->SetColor(model_->color_scheme().timeout_message_background);
   scene_->AddUiElement(kSplashScreenViewportAwareRoot,
                        std::move(timeout_message));
 
@@ -486,7 +520,7 @@
       512, kTimeoutMessageTextFontHeightM, kTimeoutMessageTextWidthM);
   timeout_text->SetText(
       l10n_util::GetStringUTF16(IDS_VR_WEB_VR_TIMEOUT_MESSAGE));
-  timeout_text->SetColor(color_scheme().timeout_message_foreground);
+  timeout_text->SetColor(model_->color_scheme().timeout_message_foreground);
   timeout_text->SetTextAlignment(UiTexture::kTextAlignmentLeft);
   timeout_text->set_name(kWebVrTimeoutMessageText);
   timeout_text->set_draw_phase(kPhaseOverlayForeground);
@@ -495,7 +529,7 @@
   scene_->AddUiElement(kWebVrTimeoutMessageLayout, std::move(timeout_text));
 
   auto button = base::MakeUnique<Button>(
-      base::Bind(&UiSceneManager::OnWebVrTimedOut, base::Unretained(this)),
+      base::Bind(&UiBrowserInterface::ExitPresent, base::Unretained(browser_)),
       kPhaseOverlayForeground, kTimeoutButtonWidth, kTimeoutButtonHeight,
       kButtonZOffsetHoverDMM * kTimeoutButtonDistance,
       vector_icons::kClose16Icon);
@@ -505,10 +539,11 @@
                        -kTimeoutButtonDistance);
   button->SetRotate(1, 0, 0, kTimeoutButtonRotationRad);
   button->SetTransitionedProperties({OPACITY});
-  button->AddBinding(VR_BIND_FUNC(bool, Model, model,
+  button->AddBinding(VR_BIND_FUNC(bool, Model, model_,
                                   web_vr_timeout_state == kWebVrTimedOut,
                                   Button, button.get(), SetVisible));
-  BindColor(this, button.get(), &ColorScheme::button_colors);
+  BindButtonColors(model_, button.get(), &ColorScheme::button_colors,
+                   &Button::SetButtonColors);
   scene_->AddUiElement(kSplashScreenViewportAwareRoot, std::move(button));
 
   timeout_text = base::MakeUnique<Text>(512, kTimeoutMessageTextFontHeightM,
@@ -516,7 +551,7 @@
   timeout_text->SetText(
       l10n_util::GetStringUTF16(IDS_VR_WEB_VR_EXIT_BUTTON_LABEL));
   timeout_text->set_name(kWebVrTimeoutMessageButtonText);
-  timeout_text->SetColor(color_scheme().spinner_color);
+  timeout_text->SetColor(model_->color_scheme().spinner_color);
   timeout_text->set_draw_phase(kPhaseOverlayForeground);
   timeout_text->SetVisible(true);
   timeout_text->SetSize(kTimeoutButtonTextWidth, kTimeoutButtonTextHeight);
@@ -528,7 +563,8 @@
 void UiSceneManager::CreateUnderDevelopmentNotice() {
   auto text = base::MakeUnique<Text>(512, kUnderDevelopmentNoticeFontHeightM,
                                      kUnderDevelopmentNoticeWidthM);
-  BindColor(this, text.get(), &ColorScheme::world_background_text);
+  BindColor(model_, text.get(), &ColorScheme::world_background_text,
+            &Text::SetColor);
   text->SetText(l10n_util::GetStringUTF16(IDS_VR_UNDER_DEVELOPMENT_NOTICE));
   text->set_name(kUnderDevelopmentNotice);
   text->set_draw_phase(kPhaseForeground);
@@ -571,7 +607,11 @@
     panel_element->SetRotate(panel.x_rotation, panel.y_rotation, 0,
                              base::kPiFloat / 2 * panel.angle);
     panel_element->set_hit_testable(false);
-    background_panels_.push_back(panel_element.get());
+    BindColor(model_, panel_element.get(), &ColorScheme::world_background,
+              &Rect::SetColor);
+    panel_element->AddBinding(
+        VR_BIND_FUNC(bool, Model, model_, should_render_web_vr() == false,
+                     UiElement, panel_element.get(), SetVisible));
     scene_->AddUiElement(k2dBrowsingBackground, std::move(panel_element));
   }
 
@@ -583,7 +623,10 @@
   floor->SetTranslate(0.0, -kSceneHeight / 2, 0.0);
   floor->SetRotate(1, 0, 0, -base::kPiFloat / 2);
   floor->set_gridline_count(kFloorGridlineCount);
-  floor_ = floor.get();
+  BindColor(model_, floor.get(), &ColorScheme::floor, &Grid::SetCenterColor);
+  BindColor(model_, floor.get(), &ColorScheme::world_background,
+            &Grid::SetEdgeColor);
+  BindColor(model_, floor.get(), &ColorScheme::floor_grid, &Grid::SetGridColor);
   scene_->AddUiElement(k2dBrowsingBackground, std::move(floor));
 
   // Ceiling.
@@ -593,7 +636,10 @@
   ceiling->SetSize(kSceneSize, kSceneSize);
   ceiling->SetTranslate(0.0, kSceneHeight / 2, 0.0);
   ceiling->SetRotate(1, 0, 0, base::kPiFloat / 2);
-  ceiling_ = ceiling.get();
+  BindColor(model_, ceiling.get(), &ColorScheme::ceiling,
+            &Rect::SetCenterColor);
+  BindColor(model_, ceiling.get(), &ColorScheme::world_background,
+            &Rect::SetEdgeColor);
   scene_->AddUiElement(k2dBrowsingBackground, std::move(ceiling));
 
   scene_->set_first_foreground_draw_phase(kPhaseForeground);
@@ -613,10 +659,10 @@
   scene_->AddUiElement(k2dBrowsingRoot, std::move(element));
 }
 
-void UiSceneManager::CreateVoiceSearchUiGroup(Model* model) {
+void UiSceneManager::CreateVoiceSearchUiGroup() {
   auto voice_search_button = base::MakeUnique<Button>(
-      base::Bind(&UiSceneManager::OnVoiceSearchButtonClicked,
-                 base::Unretained(this)),
+      base::Bind(&UiBrowserInterface::SetVoiceSearchActive,
+                 base::Unretained(browser_), true),
       kPhaseForeground, kVoiceSearchButtonWidth, kVoiceSearchButtonHeight,
       kButtonZOffsetHoverDMM * kUrlBarDistance, vector_icons::kMicrophoneIcon);
   voice_search_button->set_name(kVoiceSearchButton);
@@ -628,10 +674,11 @@
             return !m->incognito &&
                    m->speech.has_or_can_request_audio_permission;
           },
-          base::Unretained(model)),
+          base::Unretained(model_)),
       base::Bind([](UiElement* e, const bool& v) { e->SetVisible(v); },
                  voice_search_button.get())));
-  BindColor(this, voice_search_button.get(), &ColorScheme::button_colors);
+  BindButtonColors(model_, voice_search_button.get(),
+                   &ColorScheme::button_colors, &Button::SetButtonColors);
   scene_->AddUiElement(kUrlBar, std::move(voice_search_button));
 
   auto speech_recognition_root = base::MakeUnique<UiElement>();
@@ -642,7 +689,7 @@
 
   TransientElement* speech_result_parent =
       AddTransientParent(kSpeechRecognitionResult, kSpeechRecognitionRoot,
-                         kSpeechRecognitionResultTimeoutSeconds, false);
+                         kSpeechRecognitionResultTimeoutSeconds, false, scene_);
   // We need to explicitly set the initial visibility of
   // kSpeechRecognitionResult as k2dBrowsingForeground's visibility depends on
   // it in a binding. However, k2dBrowsingForeground's binding updated before
@@ -654,7 +701,7 @@
       kSpeechRecognitionOpacityAnimationDurationMs));
   speech_result_parent->AddBinding(base::MakeUnique<Binding<bool>>(
       base::Bind([](Model* m) { return m->speech.recognition_result.empty(); },
-                 base::Unretained(model)),
+                 base::Unretained(model_)),
       base::Bind(
           [](UiElement* e, const bool& v) {
             if (v) {
@@ -671,8 +718,9 @@
   speech_result->SetTranslate(0.f, kSpeechRecognitionResultTextYOffset, 0.f);
   speech_result->set_hit_testable(false);
   speech_result->SetTextAlignment(UiTexture::kTextAlignmentCenter);
-  BindColor(this, speech_result.get(), &ColorScheme::prompt_foreground);
-  speech_result->AddBinding(VR_BIND_FUNC(base::string16, Model, model,
+  BindColor(model_, speech_result.get(), &ColorScheme::prompt_foreground,
+            &Text::SetColor);
+  speech_result->AddBinding(VR_BIND_FUNC(base::string16, Model, model_,
                                          speech.recognition_result, Text,
                                          speech_result.get(), SetText));
   speech_result_parent->AddChild(std::move(speech_result));
@@ -684,8 +732,9 @@
   circle->set_corner_radius(kCloseButtonWidth);
   circle->SetTranslate(0.0, 0.0, -kTextureOffset);
   circle->set_hit_testable(false);
-  BindColor(this, circle.get(),
-            &ColorScheme::speech_recognition_circle_background);
+  BindColor(model_, circle.get(),
+            &ColorScheme::speech_recognition_circle_background,
+            &Rect::SetColor);
   scene_->AddUiElement(kSpeechRecognitionResult, std::move(circle));
 
   auto microphone = base::MakeUnique<VectorIcon>(512);
@@ -716,7 +765,7 @@
           kSpeechRecognitionOpacityAnimationDurationMs));
   speech_recognition_listening->AddBinding(base::MakeUnique<Binding<bool>>(
       base::Bind([](Model* m) { return m->speech.recognizing_speech; },
-                 base::Unretained(model)),
+                 base::Unretained(model_)),
       base::Bind(
           [](UiElement* listening, UiElement* result, const bool& value) {
             if (result->GetTargetOpacity() != 0.f && !value) {
@@ -737,10 +786,11 @@
   growing_circle->set_corner_radius(kCloseButtonWidth);
   growing_circle->SetTranslate(0.0, 0.0, -kTextureOffset * 2);
   growing_circle->set_hit_testable(false);
-  BindColor(this, growing_circle.get(),
-            &ColorScheme::speech_recognition_circle_background);
+  BindColor(model_, growing_circle.get(),
+            &ColorScheme::speech_recognition_circle_background,
+            &Rect::SetColor);
   growing_circle->AddBinding(VR_BIND(
-      int, Model, model, speech.speech_recognition_state, Throbber,
+      int, Model, model_, speech.speech_recognition_state, Throbber,
       growing_circle.get(),
       SetCircleGrowAnimationEnabled(value == SPEECH_RECOGNITION_IN_SPEECH ||
                                     value == SPEECH_RECOGNITION_RECOGNIZING ||
@@ -754,8 +804,9 @@
   inner_circle->set_corner_radius(kCloseButtonWidth);
   inner_circle->SetTranslate(0.0, 0.0, -kTextureOffset);
   inner_circle->set_hit_testable(false);
-  BindColor(this, inner_circle.get(),
-            &ColorScheme::speech_recognition_circle_background);
+  BindColor(model_, inner_circle.get(),
+            &ColorScheme::speech_recognition_circle_background,
+            &Rect::SetColor);
   scene_->AddUiElement(kSpeechRecognitionListening, std::move(inner_circle));
 
   auto microphone_icon = base::MakeUnique<VectorIcon>(512);
@@ -767,14 +818,15 @@
   scene_->AddUiElement(kSpeechRecognitionListening, std::move(microphone_icon));
 
   auto close_button = base::MakeUnique<Button>(
-      base::Bind(&UiSceneManager::OnExitRecognizingSpeechClicked,
-                 base::Unretained(this)),
+      base::Bind(&UiBrowserInterface::SetVoiceSearchActive,
+                 base::Unretained(browser_), false),
       kPhaseForeground, kVoiceSearchCloseButtonWidth,
       kVoiceSearchCloseButtonHeight, kButtonZOffsetHoverDMM * kContentDistance,
       vector_icons::kClose16Icon);
   close_button->set_name(kSpeechRecognitionListeningCloseButton);
   close_button->SetTranslate(0.0, -kVoiceSearchCloseButtonYOffset, 0.f);
-  BindColor(this, close_button.get(), &ColorScheme::button_colors);
+  BindButtonColors(model_, close_button.get(), &ColorScheme::button_colors,
+                   &Button::SetButtonColors);
   scene_->AddUiElement(kSpeechRecognitionListening, std::move(close_button));
 
   UiElement* browser_foregroud =
@@ -795,20 +847,15 @@
                  base::Unretained(browser_foregroud))));
 }
 
-void UiSceneManager::CreateController(Model* model) {
+void UiSceneManager::CreateController() {
   auto root = base::MakeUnique<UiElement>();
   root->set_name(kControllerRoot);
   root->SetVisible(true);
   root->set_hit_testable(false);
-  root->AddBinding(base::MakeUnique<Binding<bool>>(
-      base::Bind(
-          [](Model* m, UiSceneManager* mgr) {
-            return mgr->browsing_mode() ||
-                   m->web_vr_timeout_state == kWebVrTimedOut;
-          },
-          base::Unretained(model), base::Unretained(this)),
-      base::Bind([](UiElement* v, const bool& b) { v->SetVisible(b); },
-                 base::Unretained(root.get()))));
+  root->AddBinding(VR_BIND_FUNC(
+      bool, Model, model_,
+      browsing_mode() || model->web_vr_timeout_state == kWebVrTimedOut,
+      UiElement, root.get(), SetVisible));
   scene_->AddUiElement(kRoot, std::move(root));
 
   auto group = base::MakeUnique<UiElement>();
@@ -818,7 +865,7 @@
   group->SetTransitionedProperties({OPACITY});
   group->AddBinding(base::MakeUnique<Binding<bool>>(
       base::Bind([](Model* m) { return !m->controller.quiescent; },
-                 base::Unretained(model)),
+                 base::Unretained(model_)),
       base::Bind(
           [](UiElement* e, const bool& visible) {
             e->SetTransitionDuration(base::TimeDelta::FromMilliseconds(
@@ -830,52 +877,58 @@
 
   auto controller = base::MakeUnique<Controller>();
   controller->set_draw_phase(kPhaseForeground);
-  controller->AddBinding(VR_BIND_FUNC(gfx::Transform, Model, model,
+  controller->AddBinding(VR_BIND_FUNC(gfx::Transform, Model, model_,
                                       controller.transform, Controller,
                                       controller.get(), set_local_transform));
   controller->AddBinding(
-      VR_BIND_FUNC(bool, Model, model,
+      VR_BIND_FUNC(bool, Model, model_,
                    controller.touchpad_button_state == UiInputManager::DOWN,
                    Controller, controller.get(), set_touchpad_button_pressed));
   controller->AddBinding(VR_BIND_FUNC(
-      bool, Model, model, controller.app_button_state == UiInputManager::DOWN,
+      bool, Model, model_, controller.app_button_state == UiInputManager::DOWN,
       Controller, controller.get(), set_app_button_pressed));
   controller->AddBinding(VR_BIND_FUNC(
-      bool, Model, model, controller.home_button_state == UiInputManager::DOWN,
+      bool, Model, model_, controller.home_button_state == UiInputManager::DOWN,
       Controller, controller.get(), set_home_button_pressed));
-  controller->AddBinding(VR_BIND_FUNC(float, Model, model, controller.opacity,
+  controller->AddBinding(VR_BIND_FUNC(float, Model, model_, controller.opacity,
                                       Controller, controller.get(),
                                       SetOpacity));
   scene_->AddUiElement(kControllerGroup, std::move(controller));
 
-  auto laser = base::MakeUnique<Laser>(model);
+  auto laser = base::MakeUnique<Laser>(model_);
   laser->set_draw_phase(kPhaseForeground);
-  laser->AddBinding(VR_BIND_FUNC(float, Model, model, controller.opacity, Laser,
-                                 laser.get(), SetOpacity));
+  laser->AddBinding(VR_BIND_FUNC(float, Model, model_, controller.opacity,
+                                 Laser, laser.get(), SetOpacity));
   scene_->AddUiElement(kControllerGroup, std::move(laser));
 
-  auto reticle = base::MakeUnique<Reticle>(scene_, model);
+  auto reticle = base::MakeUnique<Reticle>(scene_, model_);
   reticle->set_draw_phase(kPhaseForeground);
   scene_->AddUiElement(kControllerGroup, std::move(reticle));
 }
 
-void UiSceneManager::CreateUrlBar(Model* model) {
+void UiSceneManager::CreateUrlBar() {
   auto url_bar = base::MakeUnique<UrlBar>(
       512,
-      base::Bind(&UiSceneManager::OnBackButtonClicked, base::Unretained(this)),
-      base::Bind(&UiSceneManager::OnSecurityIconClicked,
-                 base::Unretained(this)),
-      base::Bind(&UiSceneManager::OnUnsupportedMode, base::Unretained(this)));
+      base::Bind(&UiBrowserInterface::NavigateBack, base::Unretained(browser_)),
+      base::Bind(&UiBrowserInterface::OnUnsupportedMode,
+                 base::Unretained(browser_)));
   url_bar->set_name(kUrlBar);
   url_bar->set_draw_phase(kPhaseForeground);
   url_bar->SetTranslate(0, kUrlBarVerticalOffset, -kUrlBarDistance);
   url_bar->SetRotate(1, 0, 0, kUrlBarRotationRad);
   url_bar->SetSize(kUrlBarWidth, kUrlBarHeight);
-  url_bar->AddBinding(VR_BIND(bool, UiSceneManager, this, fullscreen(),
-                              UiElement, url_bar.get(), SetVisible(!value)));
-  url_bar->AddBinding(VR_BIND_FUNC(ToolbarState, Model, model, toolbar_state,
+  url_bar->AddBinding(VR_BIND_FUNC(bool, Model, model_, fullscreen == false,
+                                   UiElement, url_bar.get(), SetVisible));
+  url_bar->AddBinding(VR_BIND_FUNC(ToolbarState, Model, model_, toolbar_state,
                                    UrlBar, url_bar.get(), SetToolbarState));
-  url_bar_ = url_bar.get();
+  url_bar->AddBinding(VR_BIND_FUNC(UrlBarColors, Model, model_,
+                                   color_scheme().url_bar, UrlBar,
+                                   url_bar.get(), SetColors));
+  url_bar->AddBinding(VR_BIND_FUNC(bool, Model, model_, can_navigate_back,
+                                   UrlBar, url_bar.get(),
+                                   SetHistoryButtonsEnabled));
+  BindColor(model_, url_bar.get(), &ColorScheme::element_background,
+            &TexturedElement::SetBackgroundColor);
   scene_->AddUiElement(k2dBrowsingForeground, std::move(url_bar));
 
   auto indicator_bg = base::MakeUnique<Rect>();
@@ -887,10 +940,10 @@
   indicator_bg->set_y_anchoring(TOP);
   indicator_bg->SetTransitionedProperties({OPACITY});
   indicator_bg->set_corner_radius(kLoadingIndicatorHeight * 0.5f);
-  indicator_bg->AddBinding(VR_BIND_FUNC(bool, Model, model, loading, Rect,
+  indicator_bg->AddBinding(VR_BIND_FUNC(bool, Model, model_, loading, Rect,
                                         indicator_bg.get(), SetVisible));
-  BindColor(this, indicator_bg.get(),
-            &ColorScheme::loading_indicator_background);
+  BindColor(model_, indicator_bg.get(),
+            &ColorScheme::loading_indicator_background, &Rect::SetColor);
 
   scene_->AddUiElement(kUrlBar, std::move(indicator_bg));
 
@@ -900,11 +953,11 @@
   indicator_fg->set_x_anchoring(LEFT);
   indicator_fg->set_corner_radius(kLoadingIndicatorHeight * 0.5f);
   indicator_fg->set_hit_testable(false);
-  BindColor(this, indicator_fg.get(),
-            &ColorScheme::loading_indicator_foreground);
+  BindColor(model_, indicator_fg.get(),
+            &ColorScheme::loading_indicator_foreground, &Rect::SetColor);
   indicator_fg->AddBinding(base::MakeUnique<Binding<float>>(
       base::Bind([](Model* m) { return m->load_progress; },
-                 base::Unretained(model)),
+                 base::Unretained(model_)),
       base::Bind(
           [](Rect* r, const float& value) {
             r->SetSize(kLoadingIndicatorWidth * value, kLoadingIndicatorHeight);
@@ -915,7 +968,7 @@
   scene_->AddUiElement(kLoadingIndicator, std::move(indicator_fg));
 }
 
-void UiSceneManager::CreateSuggestionList(Model* model) {
+void UiSceneManager::CreateSuggestionList() {
   auto layout = base::MakeUnique<LinearLayout>(LinearLayout::kDown);
 
   layout->set_name(kSuggestionLayout);
@@ -928,39 +981,28 @@
 
   SuggestionSetBinding::ModelAddedCallback added_callback =
       base::Bind(&OnSuggestionModelAdded, base::Unretained(scene_),
-                 base::Unretained(browser_), base::Unretained(model));
+                 base::Unretained(browser_), base::Unretained(model_));
   SuggestionSetBinding::ModelRemovedCallback removed_callback =
       base::Bind(&OnSuggestionModelRemoved, base::Unretained(scene_));
 
   auto binding = base::MakeUnique<SuggestionSetBinding>(
-      &model->omnibox_suggestions, added_callback, removed_callback);
+      &model_->omnibox_suggestions, added_callback, removed_callback);
   layout->AddBinding(std::move(binding));
   scene_->AddUiElement(kUrlBar, std::move(layout));
 }
 
-TransientElement* UiSceneManager::AddTransientParent(UiElementName name,
-                                                     UiElementName parent_name,
-                                                     int timeout_seconds,
-                                                     bool animate_opacity) {
-  auto element = base::MakeUnique<SimpleTransientElement>(
-      base::TimeDelta::FromSeconds(timeout_seconds));
-  TransientElement* to_return = element.get();
-  element->set_name(name);
-  element->SetVisible(false);
-  element->set_hit_testable(false);
-  if (animate_opacity)
-    element->SetTransitionedProperties({OPACITY});
-  scene_->AddUiElement(parent_name, std::move(element));
-  return to_return;
-}
-
-void UiSceneManager::CreateWebVrUrlToast(Model* model) {
-  webvr_url_toast_transient_parent_ =
+void UiSceneManager::CreateWebVrUrlToast() {
+  auto* parent =
       AddTransientParent(kWebVrUrlToastTransientParent, kWebVrViewportAwareRoot,
-                         kWebVrUrlToastTimeoutSeconds, true);
+                         kWebVrUrlToastTimeoutSeconds, true, scene_);
+  parent->AddBinding(VR_BIND_FUNC(
+      bool, Model, model_,
+      web_vr_started_for_autopresentation && !model->web_vr_show_splash_screen,
+      UiElement, parent, SetVisible));
+
   auto element = base::MakeUnique<WebVrUrlToast>(
-      512,
-      base::Bind(&UiSceneManager::OnUnsupportedMode, base::Unretained(this)));
+      512, base::Bind(&UiBrowserInterface::OnUnsupportedMode,
+                      base::Unretained(browser_)));
   element->set_name(kWebVrUrlToast);
   element->set_opacity_when_visible(0.8f);
   element->set_draw_phase(kPhaseOverlayForeground);
@@ -970,28 +1012,60 @@
                         -kWebVrToastDistance * cos(kWebVrUrlToastRotationRad));
   element->SetRotate(1, 0, 0, kWebVrUrlToastRotationRad);
   element->SetSize(kWebVrUrlToastWidth, kWebVrUrlToastHeight);
-  element->AddBinding(VR_BIND_FUNC(ToolbarState, Model, model, toolbar_state,
+  BindColor(model_, element.get(),
+            &ColorScheme::web_vr_transient_toast_background,
+            &TexturedElement::SetBackgroundColor);
+  BindColor(model_, element.get(),
+            &ColorScheme::web_vr_transient_toast_foreground,
+            &TexturedElement::SetForegroundColor);
+  element->AddBinding(VR_BIND_FUNC(ToolbarState, Model, model_, toolbar_state,
                                    WebVrUrlToast, element.get(),
                                    SetToolbarState));
-  webvr_url_toast_ = element.get();
   scene_->AddUiElement(kWebVrUrlToastTransientParent, std::move(element));
 }
 
 void UiSceneManager::CreateCloseButton() {
   std::unique_ptr<Button> element = base::MakeUnique<Button>(
-      base::Bind(&UiSceneManager::OnCloseButtonClicked, base::Unretained(this)),
+      base::Bind(
+          [](Model* model, UiBrowserInterface* browser) {
+            if (model->fullscreen) {
+              browser->ExitFullscreen();
+            }
+            if (model->in_cct) {
+              browser->ExitCct();
+            }
+          },
+          base::Unretained(model_), base::Unretained(browser_)),
       kPhaseForeground, kCloseButtonWidth, kCloseButtonHeight,
       kButtonZOffsetHoverDMM * kCloseButtonDistance,
       vector_icons::kClose16Icon);
   element->set_name(kCloseButton);
-  element->SetTranslate(0, kContentVerticalOffset - (kContentHeight / 2) - 0.3f,
-                        -kCloseButtonDistance);
-  BindColor(this, element.get(), &ColorScheme::button_colors);
-  close_button_ = element.get();
+  element->SetTranslate(0, kCloseButtonVerticalOffset, -kCloseButtonDistance);
+  BindButtonColors(model_, element.get(), &ColorScheme::button_colors,
+                   &Button::SetButtonColors);
+
+  // Close button is a special control element that needs to be hidden when in
+  // WebVR, but it needs to be visible when in cct or fullscreen.
+  element->AddBinding(
+      VR_BIND_FUNC(bool, Model, model_,
+                   browsing_mode() && (model->fullscreen || model->in_cct),
+                   UiElement, element.get(), SetVisible));
+  element->AddBinding(
+      VR_BIND(bool, Model, model_, fullscreen, UiElement, element.get(),
+              SetTranslate(0,
+                           value ? kCloseButtonFullscreenVerticalOffset
+                                 : kCloseButtonVerticalOffset,
+                           value ? -kCloseButtonFullscreenDistance
+                                 : -kCloseButtonDistance)));
+  element->AddBinding(VR_BIND(
+      bool, Model, model_, fullscreen, UiElement, element.get(),
+      SetSize(value ? kCloseButtonFullscreenWidth : kCloseButtonWidth,
+              value ? kCloseButtonFullscreenHeight : kCloseButtonHeight)));
+
   scene_->AddUiElement(k2dBrowsingForeground, std::move(element));
 }
 
-void UiSceneManager::CreateExitPrompt(Model* model) {
+void UiSceneManager::CreateExitPrompt() {
   std::unique_ptr<UiElement> element;
 
   // Place an invisible but hittable plane behind the exit prompt, to keep the
@@ -1005,32 +1079,41 @@
                           kTextureOffset - kContentDistance);
   EventHandlers event_handlers;
   event_handlers.button_up = base::Bind(
-      [](UiSceneManager* manager, Model* m) {
-        manager->OnExitPromptBackplaneClicked(
+      [](UiBrowserInterface* browser, Model* m) {
+        browser->OnExitVrPromptResult(
+            ExitVrPromptChoice::CHOICE_NONE,
             GetReasonForPrompt(m->active_modal_prompt_type));
       },
-      base::Unretained(this), base::Unretained(model));
+      base::Unretained(browser_), base::Unretained(model_));
   backplane->set_event_handlers(event_handlers);
   backplane->AddBinding(VR_BIND_FUNC(
-      bool, Model, model,
+      bool, Model, model_,
       active_modal_prompt_type == kModalPromptTypeExitVRForSiteInfo, UiElement,
       backplane.get(), SetVisible));
   scene_->AddUiElement(k2dBrowsingRoot, std::move(backplane));
 
   std::unique_ptr<ExitPrompt> exit_prompt = base::MakeUnique<ExitPrompt>(
       512,
-      base::Bind(&UiSceneManager::OnExitPromptChoice, base::Unretained(this),
-                 false),
-      base::Bind(&UiSceneManager::OnExitPromptChoice, base::Unretained(this),
-                 true));
+      base::Bind(&UiBrowserInterface::OnExitVrPromptResult,
+                 base::Unretained(browser_), ExitVrPromptChoice::CHOICE_STAY),
+      base::Bind(&UiBrowserInterface::OnExitVrPromptResult,
+                 base::Unretained(browser_), ExitVrPromptChoice::CHOICE_EXIT));
   exit_prompt->set_name(kExitPrompt);
   exit_prompt->set_draw_phase(kPhaseForeground);
   exit_prompt->SetVisible(true);
   exit_prompt->SetSize(kExitPromptWidth, kExitPromptHeight);
   exit_prompt->SetTranslate(0.0, 0.0, kTextureOffset);
+  BindColor(model_, exit_prompt.get(), &ColorScheme::prompt_foreground,
+            &TexturedElement::SetForegroundColor);
+  BindButtonColors(model_, exit_prompt.get(),
+                   &ColorScheme::prompt_primary_button_colors,
+                   &ExitPrompt::SetPrimaryButtonColors);
+  BindButtonColors(model_, exit_prompt.get(),
+                   &ColorScheme::prompt_secondary_button_colors,
+                   &ExitPrompt::SetSecondaryButtonColors);
   exit_prompt->AddBinding(base::MakeUnique<Binding<ModalPromptType>>(
       base::Bind([](Model* m) { return m->active_modal_prompt_type; },
-                 base::Unretained(model)),
+                 base::Unretained(model_)),
       base::Bind(
           [](ExitPrompt* e, const ModalPromptType& p) {
             e->set_reason(GetReasonForPrompt(p));
@@ -1048,7 +1131,7 @@
   scene_->AddUiElement(kExitPromptBackplane, std::move(exit_prompt));
 }
 
-void UiSceneManager::CreateAudioPermissionPrompt(Model* model) {
+void UiSceneManager::CreateAudioPermissionPrompt() {
   std::unique_ptr<UiElement> element;
 
   // Place an invisible but hittable plane behind the exit prompt, to keep the
@@ -1060,16 +1143,17 @@
   backplane->SetTranslate(0.0, kContentVerticalOffset, -kOverlayPlaneDistance);
   EventHandlers event_handlers;
   event_handlers.button_up = base::Bind(
-      [](UiSceneManager* manager, Model* m) {
-        manager->OnExitPromptBackplaneClicked(
+      [](UiBrowserInterface* browser, Model* m) {
+        browser->OnExitVrPromptResult(
+            ExitVrPromptChoice::CHOICE_NONE,
             GetReasonForPrompt(m->active_modal_prompt_type));
       },
-      base::Unretained(this), base::Unretained(model));
+      base::Unretained(browser_), base::Unretained(model_));
   backplane->set_event_handlers(event_handlers);
   backplane->SetVisible(false);
   backplane->SetTransitionedProperties({OPACITY});
   backplane->AddBinding(VR_BIND_FUNC(
-      bool, Model, model,
+      bool, Model, model_,
       active_modal_prompt_type == kModalPromptTypeExitVRForAudioPermission,
       UiElement, backplane.get(), SetVisible));
 
@@ -1081,43 +1165,49 @@
   std::unique_ptr<AudioPermissionPrompt> prompt =
       base::MakeUnique<AudioPermissionPrompt>(
           1024,
-          base::Bind(&UiSceneManager::OnExitPromptChoice,
-                     base::Unretained(this), true,
+          base::Bind(&UiBrowserInterface::OnExitVrPromptResult,
+                     base::Unretained(browser_),
+                     ExitVrPromptChoice::CHOICE_EXIT,
                      UiUnsupportedMode::kAndroidPermissionNeeded),
-          base::Bind(&UiSceneManager::OnExitPromptChoice,
-                     base::Unretained(this), false,
+          base::Bind(&UiBrowserInterface::OnExitVrPromptResult,
+                     base::Unretained(browser_),
+                     ExitVrPromptChoice::CHOICE_STAY,
                      UiUnsupportedMode::kAndroidPermissionNeeded));
   prompt->set_name(kAudioPermissionPrompt);
   prompt->set_draw_phase(kPhaseForeground);
   prompt->SetSize(kAudioPermissionPromptWidth, kAudioPermissionPromptHeight);
   prompt->SetTranslate(0.0, 0.0f, kAudionPermisionPromptDepth);
+  BindButtonColors(model_, prompt.get(),
+                   &ColorScheme::audio_permission_prompt_primary_button_colors,
+                   &AudioPermissionPrompt::SetPrimaryButtonColors);
+  BindButtonColors(
+      model_, prompt.get(),
+      &ColorScheme::audio_permission_prompt_secondary_button_colors,
+      &AudioPermissionPrompt::SetSecondaryButtonColors);
+  BindColor(model_, prompt.get(),
+            &ColorScheme::audio_permission_prompt_icon_foreground,
+            &AudioPermissionPrompt::SetIconColor);
+  BindColor(model_, prompt.get(),
+            &ColorScheme::audio_permission_prompt_background,
+            &TexturedElement::SetBackgroundColor);
+  BindColor(model_, prompt.get(), &ColorScheme::element_foreground,
+            &TexturedElement::SetForegroundColor);
   shadow->AddChild(std::move(prompt));
   backplane->AddChild(std::move(shadow));
   scene_->AddUiElement(k2dBrowsingRoot, std::move(backplane));
 }
 
-void UiSceneManager::CreateToasts(Model* model) {
+void UiSceneManager::CreateToasts() {
   // Create fullscreen toast.
-  exclusive_screen_toast_transient_parent_ =
-      AddTransientParent(kExclusiveScreenToastTransientParent,
-                         k2dBrowsingForeground, kToastTimeoutSeconds, false);
+  auto* parent = AddTransientParent(kExclusiveScreenToastTransientParent,
+                                    k2dBrowsingForeground, kToastTimeoutSeconds,
+                                    false, scene_);
   // This binding toggles fullscreen toast's visibility if fullscreen state
-  // changed.
-  exclusive_screen_toast_transient_parent_->AddBinding(
-      VR_BIND_FUNC(bool, UiSceneManager, this, fullscreen(), UiElement,
-                   exclusive_screen_toast_transient_parent_, SetVisible));
-  // This binding makes sure fullscreen toast becomes invisible if entering
+  // changed and makes sure fullscreen toast becomes invisible if entering
   // webvr mode.
-  exclusive_screen_toast_transient_parent_->AddBinding(
-      base::MakeUnique<Binding<bool>>(
-          base::Bind([](UiSceneManager* mgr) { return mgr->web_vr_mode(); },
-                     base::Unretained(this)),
-          base::Bind(
-              [](UiElement* v, const bool& b) {
-                if (b)
-                  v->SetVisible(false);
-              },
-              base::Unretained(exclusive_screen_toast_transient_parent_))));
+  parent->AddBinding(VR_BIND_FUNC(bool, Model, model_,
+                                  fullscreen && !model->web_vr_mode, UiElement,
+                                  parent, SetVisible));
 
   auto element = base::MakeUnique<ExclusiveScreenToast>(512);
   element->set_name(kExclusiveScreenToast);
@@ -1130,28 +1220,27 @@
       -kFullscreenToastDistance);
   element->SetScale(kFullscreenToastDistance, kFullscreenToastDistance, 1);
   element->set_hit_testable(false);
+  BindColor(model_, element.get(),
+            &ColorScheme::exclusive_screen_toast_background,
+            &TexturedElement::SetBackgroundColor);
+  BindColor(model_, element.get(),
+            &ColorScheme::exclusive_screen_toast_foreground,
+            &TexturedElement::SetForegroundColor);
   scene_->AddUiElement(kExclusiveScreenToastTransientParent,
                        std::move(element));
 
   // Create WebVR toast.
-  exclusive_screen_toast_viewport_aware_transient_parent_ =
-      AddTransientParent(kExclusiveScreenToastViewportAwareTransientParent,
-                         kWebVrViewportAwareRoot, kToastTimeoutSeconds, false);
+  parent = AddTransientParent(kExclusiveScreenToastViewportAwareTransientParent,
+                              kWebVrViewportAwareRoot, kToastTimeoutSeconds,
+                              false, scene_);
   // When we first get a web vr frame, we switch states to
   // kWebVrNoTimeoutPending, when that happens, we want to SetVisible(true) to
   // kick the visibility of this element.
-  exclusive_screen_toast_viewport_aware_transient_parent_->AddBinding(
-      base::MakeUnique<Binding<bool>>(
-          base::Bind(
-              [](Model* m, UiSceneManager* mgr) {
-                return m->web_vr_timeout_state == kWebVrNoTimeoutPending &&
-                       mgr->web_vr_mode() && mgr->web_vr_show_toast();
-              },
-              base::Unretained(model), base::Unretained(this)),
-          base::Bind(
-              [](UiElement* v, const bool& b) { v->SetVisible(b); },
-              base::Unretained(
-                  exclusive_screen_toast_viewport_aware_transient_parent_))));
+  parent->AddBinding(
+      VR_BIND_FUNC(bool, Model, model_,
+                   web_vr_timeout_state == kWebVrNoTimeoutPending &&
+                       model->web_vr_mode && model->web_vr_show_toast,
+                   UiElement, parent, SetVisible));
 
   element = base::MakeUnique<ExclusiveScreenToast>(512);
   element->set_name(kExclusiveScreenToastViewportAware);
@@ -1162,290 +1251,14 @@
   element->SetRotate(1, 0, 0, kWebVrAngleRadians);
   element->SetScale(kWebVrToastDistance, kWebVrToastDistance, 1);
   element->set_hit_testable(false);
+  BindColor(model_, element.get(),
+            &ColorScheme::exclusive_screen_toast_background,
+            &TexturedElement::SetBackgroundColor);
+  BindColor(model_, element.get(),
+            &ColorScheme::exclusive_screen_toast_foreground,
+            &TexturedElement::SetForegroundColor);
   scene_->AddUiElement(kExclusiveScreenToastViewportAwareTransientParent,
                        std::move(element));
 }
 
-void UiSceneManager::SetWebVrMode(bool web_vr, bool show_toast) {
-  if (web_vr_mode_ == web_vr && web_vr_show_toast_ == show_toast) {
-    return;
-  }
-
-  web_vr_mode_ = web_vr;
-  web_vr_show_toast_ = show_toast;
-  if (!web_vr_mode_) {
-    showing_web_vr_splash_screen_ = false;
-    started_for_autopresentation_ = false;
-  }
-  ConfigureScene();
-
-  // Because we may be transitioning from and to fullscreen, where the toast is
-  // also shown, explicitly kick or end visibility here.
-  if (web_vr)
-    exclusive_screen_toast_viewport_aware_transient_parent_->RefreshVisible();
-}
-
-void UiSceneManager::OnWebVrFrameAvailable() {
-  if (!showing_web_vr_splash_screen_)
-    return;
-
-  splash_screen_transient_parent_->Signal();
-}
-
-void UiSceneManager::OnWebVrTimedOut() {
-  browser_->ExitPresent();
-}
-
-void UiSceneManager::OnSplashScreenHidden(TransientElementHideReason reason) {
-  showing_web_vr_splash_screen_ = false;
-  if (reason == TransientElementHideReason::kTimeout) {
-    OnWebVrTimedOut();
-    return;
-  }
-  ConfigureScene();
-}
-
-void UiSceneManager::OnProjMatrixChanged(const gfx::Transform& proj_matrix) {
-  // Determine if the projected size of the content quad changed more than a
-  // given threshold. If so, propagate this info so that the content's
-  // resolution and size can be adjusted. For the calculation, we cannot take
-  // the content quad's actual size (main_content_->size()) if this property
-  // is animated. If we took the actual size during an animation we would
-  // surpass the threshold with differing projected sizes and aspect ratios
-  // (depending on the animation's timing). The differing values may cause
-  // visual artefacts if, for instance, the fullscreen aspect ratio is not 16:9.
-  // As a workaround, take the final size of the content quad after the
-  // animation as the basis for the calculation.
-  DCHECK(main_content_);
-
-  gfx::SizeF main_content_size = main_content_->GetTargetSize();
-  // We take the target transform in case the content quad's parent's translate
-  // is animated. This approach only works with the current scene hierarchy and
-  // set of animated properties.
-  // TODO(crbug.com/766318): Find a way to get the target value of the
-  // inheritable transfrom that works with any scene hierarchy and set of
-  // animated properties.
-  gfx::Transform main_content_transform =
-      scene_->GetUiElementByName(k2dBrowsingContentGroup)
-          ->GetTargetTransform()
-          .Apply();
-  gfx::SizeF screen_size = CalculateScreenSize(
-      proj_matrix, main_content_transform, main_content_size);
-
-  float aspect_ratio = main_content_size.width() / main_content_size.height();
-  gfx::SizeF screen_bounds;
-  if (screen_size.width() < screen_size.height() * aspect_ratio) {
-    screen_bounds.set_width(screen_size.height() * aspect_ratio);
-    screen_bounds.set_height(screen_size.height());
-  } else {
-    screen_bounds.set_width(screen_size.width());
-    screen_bounds.set_height(screen_size.width() / aspect_ratio);
-  }
-
-  if (std::abs(screen_bounds.width() - last_content_screen_bounds_.width()) >
-          kContentBoundsPropagationThreshold ||
-      std::abs(screen_bounds.height() - last_content_screen_bounds_.height()) >
-          kContentBoundsPropagationThreshold ||
-      std::abs(aspect_ratio - last_content_aspect_ratio_) >
-          kContentAspectRatioPropagationThreshold) {
-    browser_->OnContentScreenBoundsChanged(screen_bounds);
-
-    last_content_screen_bounds_.set_width(screen_bounds.width());
-    last_content_screen_bounds_.set_height(screen_bounds.height());
-    last_content_aspect_ratio_ = aspect_ratio;
-  }
-}
-
-void UiSceneManager::ConfigureScene() {
-  // Everything we do to configure scenes here should eventually be moved to
-  // bindings.
-  base::AutoReset<bool> configuring(&configuring_scene_, true);
-
-  // We disable WebVR rendering if we're expecting to auto present so that we
-  // can continue to show the 2D splash screen while the site submits the first
-  // WebVR frame.
-  bool showing_web_vr_content = web_vr_mode_ && !showing_web_vr_splash_screen_;
-  scene_->set_web_vr_rendering_enabled(showing_web_vr_content);
-
-  // Exit warning.
-  exit_warning_->SetVisible(exiting_);
-  screen_dimmer_->SetVisible(exiting_);
-
-  scene_->GetUiElementByName(k2dBrowsingRoot)->SetVisible(browsing_mode());
-  scene_->GetUiElementByName(kWebVrRoot)->SetVisible(!browsing_mode());
-
-  // Close button is a special control element that needs to be hidden when in
-  // WebVR, but it needs to be visible when in cct or fullscreen.
-  close_button_->SetVisible(browsing_mode() && (fullscreen_ || in_cct_));
-
-  // Background elements.
-  for (UiElement* element : background_panels_) {
-    element->SetVisible(!showing_web_vr_content);
-  }
-  floor_->SetVisible(browsing_mode());
-  ceiling_->SetVisible(browsing_mode());
-
-  // Update content quad parameters depending on fullscreen.
-  if (fullscreen_) {
-    scene_->GetUiElementByName(k2dBrowsingContentGroup)
-        ->SetTranslate(0, kFullscreenVerticalOffset, -kFullscreenDistance);
-    main_content_->SetSize(kFullscreenWidth, kFullscreenHeight);
-    close_button_->SetTranslate(
-        0, kFullscreenVerticalOffset - (kFullscreenHeight / 2) - 0.35f,
-        -kCloseButtonFullscreenDistance);
-    close_button_->SetSize(kCloseButtonFullscreenWidth,
-                           kCloseButtonFullscreenHeight);
-  } else {
-    // Note that main_content_ is already visible in this case.
-    scene_->GetUiElementByName(k2dBrowsingContentGroup)
-        ->SetTranslate(0, kContentVerticalOffset, -kContentDistance);
-    main_content_->SetSize(kContentWidth, kContentHeight);
-    close_button_->SetTranslate(
-        0, kContentVerticalOffset - (kContentHeight / 2) - 0.3f,
-        -kCloseButtonDistance);
-    close_button_->SetSize(kCloseButtonWidth, kCloseButtonHeight);
-  }
-
-  scene_->root_element().SetMode(mode());
-
-  webvr_url_toast_transient_parent_->SetVisible(started_for_autopresentation_ &&
-                                                !showing_web_vr_splash_screen_);
-
-  scene_->set_reticle_rendering_enabled(
-      !(web_vr_mode_ || exiting_ || showing_web_vr_splash_screen_));
-
-  ConfigureBackgroundColor();
-  scene_->set_dirty();
-}
-
-void UiSceneManager::ConfigureBackgroundColor() {
-  DCHECK(configuring_scene_);
-  for (Rect* panel : background_panels_) {
-    panel->SetColor(color_scheme().world_background);
-  }
-  ceiling_->SetCenterColor(color_scheme().ceiling);
-  ceiling_->SetEdgeColor(color_scheme().world_background);
-  floor_->SetCenterColor(color_scheme().floor);
-  floor_->SetEdgeColor(color_scheme().world_background);
-  floor_->SetGridColor(color_scheme().floor_grid);
-}
-
-void UiSceneManager::SetIncognito(bool incognito) {
-  if (incognito == incognito_)
-    return;
-  incognito_ = incognito;
-  ConfigureScene();
-}
-
-bool UiSceneManager::ShouldRenderWebVr() {
-  return scene_->web_vr_rendering_enabled();
-}
-
-void UiSceneManager::OnGlInitialized(
-    unsigned int content_texture_id,
-    UiElementRenderer::TextureLocation content_location,
-    SkiaSurfaceProvider* provider) {
-  main_content_->SetTexture(content_texture_id, content_location);
-  scene_->OnGlInitialized(provider);
-
-  ConfigureScene();
-}
-
-void UiSceneManager::OnAppButtonClicked() {
-  // App button clicks should be a no-op when auto-presenting WebVR.
-  if (started_for_autopresentation_)
-    return;
-
-  // If browsing mode is disabled, the app button should no-op.
-  if (browsing_disabled_)
-    return;
-
-  // App button click exits the WebVR presentation and fullscreen.
-  browser_->ExitPresent();
-  browser_->ExitFullscreen();
-}
-
-void UiSceneManager::OnAppButtonGesturePerformed(
-    PlatformController::SwipeDirection direction) {}
-
-void UiSceneManager::SetFullscreen(bool fullscreen) {
-  if (fullscreen_ == fullscreen)
-    return;
-  fullscreen_ = fullscreen;
-  ConfigureScene();
-}
-
-void UiSceneManager::OnBackButtonClicked() {
-  browser_->NavigateBack();
-}
-
-void UiSceneManager::OnSecurityIconClickedForTesting() {
-  OnSecurityIconClicked();
-}
-
-void UiSceneManager::OnExitPromptChoiceForTesting(bool chose_exit,
-                                                  UiUnsupportedMode reason) {
-  OnExitPromptChoice(chose_exit, reason);
-}
-
-void UiSceneManager::OnSecurityIconClicked() {
-  browser_->OnUnsupportedMode(UiUnsupportedMode::kUnhandledPageInfo);
-}
-
-void UiSceneManager::OnExitPromptBackplaneClicked(UiUnsupportedMode reason) {
-  browser_->OnExitVrPromptResult(reason, ExitVrPromptChoice::CHOICE_NONE);
-}
-
-void UiSceneManager::OnExitRecognizingSpeechClicked() {
-  browser_->SetVoiceSearchActive(false);
-}
-
-void UiSceneManager::OnExitPromptChoice(bool chose_exit,
-                                        UiUnsupportedMode reason) {
-  browser_->OnExitVrPromptResult(reason, chose_exit
-                                             ? ExitVrPromptChoice::CHOICE_EXIT
-                                             : ExitVrPromptChoice::CHOICE_STAY);
-}
-
-void UiSceneManager::SetIsExiting() {
-  if (exiting_)
-    return;
-  exiting_ = true;
-  ConfigureScene();
-}
-
-void UiSceneManager::SetHistoryButtonsEnabled(bool can_go_back,
-                                              bool can_go_forward) {
-  url_bar_->SetHistoryButtonsEnabled(can_go_back);
-}
-
-void UiSceneManager::OnCloseButtonClicked() {
-  if (fullscreen_) {
-    browser_->ExitFullscreen();
-  }
-  if (in_cct_) {
-    browser_->ExitCct();
-  }
-}
-
-void UiSceneManager::OnVoiceSearchButtonClicked() {
-  browser_->SetVoiceSearchActive(true);
-}
-
-void UiSceneManager::OnUnsupportedMode(UiUnsupportedMode mode) {
-  browser_->OnUnsupportedMode(mode);
-}
-
-ColorScheme::Mode UiSceneManager::mode() const {
-  if (incognito_)
-    return ColorScheme::kModeIncognito;
-  if (fullscreen_)
-    return ColorScheme::kModeFullscreen;
-  return ColorScheme::kModeNormal;
-}
-
-const ColorScheme& UiSceneManager::color_scheme() const {
-  return ColorScheme::GetColorScheme(mode());
-}
-
 }  // namespace vr
diff --git a/chrome/browser/vr/ui_scene_manager.h b/chrome/browser/vr/ui_scene_manager.h
index d23d6999..3f03d7b 100644
--- a/chrome/browser/vr/ui_scene_manager.h
+++ b/chrome/browser/vr/ui_scene_manager.h
@@ -6,230 +6,50 @@
 #define CHROME_BROWSER_VR_UI_SCENE_MANAGER_H_
 
 #include "base/macros.h"
-#include "base/values.h"
-#include "chrome/browser/vr/browser_ui_interface.h"
-#include "chrome/browser/vr/color_scheme.h"
-#include "chrome/browser/vr/elements/simple_textured_element.h"
-#include "chrome/browser/vr/platform_controller.h"
-#include "chrome/browser/vr/ui_element_renderer.h"
-#include "chrome/browser/vr/ui_unsupported_mode.h"
-#include "third_party/skia/include/core/SkBitmap.h"
+#include "chrome/browser/vr/elements/ui_element_name.h"
 
 namespace vr {
 
-class ContentElement;
 class ContentInputDelegate;
-class Grid;
-class Rect;
-class TransientElement;
-class WebVrUrlToast;
 class UiBrowserInterface;
-class UiElement;
 class UiScene;
-class UrlBar;
 struct Model;
-struct UiInitialState;
 
-// The scene manager creates and maintains a UiElement hierarchy.
-//
-// kRoot
-//   k2dBrowsingRoot
-//     k2dBrowsingBackground
-//       kBackgroundLeft
-//       kBackgroundRight
-//       kBackgroundTop
-//       kBackgroundBottom
-//       kBackgroundFront
-//       kBackgroundBack
-//       kFloor
-//       kCeiling
-//     k2dBrowsingForeground
-//       k2dBrowsingContentGroup
-//         kBackplane
-//         kContentQuad
-//         kIndicatorLayout
-//           kAudioCaptureIndicator
-//           kVideoCaptureIndicator
-//           kScreenCaptureIndicator
-//           kLocationAccessIndicator
-//           kBluetoothConnectedIndicator
-//       kExitPromptBackplane
-//         kExitPrompt
-//       (unnamed) a toggle element for hiding out of browser mode.
-//         kAudioPermissionPromptBackplane
-//           kAudioPermissounPromptShadow
-//             kAudioPermissionPrompt
-//       kExclusiveScreenToastTransientParent
-//         kExclusiveScreenToast
-//       kCloseButton
-//       kUrlBar
-//         kLoadingIndicator
-//         kExitButton
-//         kUnderDevelopmentNotice
-//         kVoiceSearchButton
-//         kSuggestionLayout
-//           (variable number of suggestions)
-//     kScreenDimmer
-//     k2dBrowsingViewportAwareRoot
-//       kExitWarning
-//     kSpeechRecognitionRoot
-//       kSpeechRecognitionResult
-//         kSpeechRecognitionResultText
-//         kSpeechRecognitionResultCircle
-//         kSpeechRecognitionResultMicrophoneIcon
-//         kSpeechRecognitionResultBackplane
-//       kSpeechRecognitionListening
-//         kSpeechRecognitionListeningGrowingCircle
-//         kSpeechRecognitionListeningInnerCircle
-//         kSpeechRecognitionListeningMicrophoneIcon
-//         kSpeechRecognitionListeningBackplane
-//   kWebVrRoot
-//     kWebVrViewportAwareRoot
-//       kExclusiveScreenToastTransientParent
-//         kExclusiveScreenToastViewportAware
-//       kWebVrPermanentHttpSecurityWarning
-//       kWebVrTransientHttpSecurityWarningTransientParent
-//         kWebVrTransientHttpSecurityWarning
-//       kWebVrUrlToastTransientParent
-//         kWebVrUrlToast
-//   kSplashScreenRoot
-//     kSplashScreenViewportAwareRoot
-//       kSplashScreenTransientParent
-//         kSplashScreenText
-//           kSplashScreenBackground
-//       kWebVrTimeoutSpinner
-//         kWebVrTimeoutSpinnerBackground
-//       kWebVrTimeoutMessage
-//         kWebVrTimeoutMessageLayout
-//           kWebVrTimeoutMessageIcon
-//           kWebVrTimeoutMessageText
-//           kWebVrTimeoutMessageButton
-//             kWebVrTimeoutMessageButtonText
-//   kControllerGroup
-//     kLaser
-//     kController
-//     kReticle
-//
-// TODO(vollick): The above hierarchy is complex, brittle, and would be easier
-// to manage if it were specified in a declarative format.
+// The scene manager creates our scene hierarchy.
 class UiSceneManager {
  public:
   UiSceneManager(UiBrowserInterface* browser,
                  UiScene* scene,
                  ContentInputDelegate* content_input_delegate,
-                 Model* model,
-                 const UiInitialState& ui_initial_state);
+                 Model* model);
   ~UiSceneManager();
 
-  // BrowserUiInterface support methods.
-  void SetFullscreen(bool fullscreen);
-  void SetIncognito(bool incognito);
-  void SetWebVrMode(bool web_vr, bool show_toast);
-  void SetIsExiting();
-  void SetHistoryButtonsEnabled(bool can_go_back, bool can_go_forward);
-
-  bool ShouldRenderWebVr();
-  void OnGlInitialized(unsigned int content_texture_id,
-                       UiElementRenderer::TextureLocation content_location,
-                       SkiaSurfaceProvider* provider);
-  void OnAppButtonClicked();
-  void OnAppButtonGesturePerformed(
-      PlatformController::SwipeDirection direction);
-  void OnProjMatrixChanged(const gfx::Transform& proj_matrix);
-  void OnWebVrFrameAvailable();
-  void OnWebVrTimedOut();
-
-  void OnSplashScreenHidden(TransientElementHideReason);
-  void OnSecurityIconClickedForTesting();
-  void OnExitPromptChoiceForTesting(bool chose_exit, UiUnsupportedMode reason);
-
-  // TODO(vollick): these should move to the model.
-  const ColorScheme& color_scheme() const;
-  bool web_vr_mode() const { return web_vr_mode_; }
-  bool web_vr_show_toast() const { return web_vr_show_toast_; }
-  bool showing_web_vr_splash_screen() const {
-    return showing_web_vr_splash_screen_;
-  }
-  bool browsing_mode() const {
-    return !web_vr_mode_ && !showing_web_vr_splash_screen_;
-  }
-  bool fullscreen() const { return fullscreen_; }
+  void CreateScene();
 
  private:
-  void Create2dBrowsingSubtreeRoots(Model* model);
+  void Create2dBrowsingSubtreeRoots();
   void CreateWebVrRoot();
-  void CreateScreenDimmer();
   void CreateWebVRExitWarning();
-  void CreateSystemIndicators(Model* model);
-  void CreateContentQuad(ContentInputDelegate* delegate);
-  void CreateSplashScreen(Model* model);
+  void CreateSystemIndicators();
+  void CreateContentQuad();
+  void CreateSplashScreen();
   void CreateUnderDevelopmentNotice();
   void CreateBackground();
   void CreateViewportAwareRoot();
-  void CreateUrlBar(Model* model);
-  void CreateSuggestionList(Model* model);
-  void CreateWebVrUrlToast(Model* model);
+  void CreateUrlBar();
+  void CreateSuggestionList();
+  void CreateWebVrUrlToast();
   void CreateCloseButton();
-  void CreateExitPrompt(Model* model);
-  void CreateAudioPermissionPrompt(Model* model);
-  void CreateToasts(Model* model);
-  void CreateVoiceSearchUiGroup(Model* model);
-  void CreateController(Model* model);
-
-  void ConfigureScene();
-  void ConfigureBackgroundColor();
-  void OnBackButtonClicked();
-  void OnSecurityIconClicked();
-  void OnExitPromptChoice(bool chose_exit, UiUnsupportedMode reason);
-  void OnExitPromptBackplaneClicked(UiUnsupportedMode reason);
-  void OnExitRecognizingSpeechClicked();
-  void OnCloseButtonClicked();
-  void OnUnsupportedMode(UiUnsupportedMode mode);
-  void OnVoiceSearchButtonClicked();
-  ColorScheme::Mode mode() const;
-
-  TransientElement* AddTransientParent(UiElementName name,
-                                       UiElementName parent_name,
-                                       int timeout_seconds,
-                                       bool animate_opacity);
+  void CreateExitPrompt();
+  void CreateAudioPermissionPrompt();
+  void CreateToasts();
+  void CreateVoiceSearchUiGroup();
+  void CreateController();
 
   UiBrowserInterface* browser_;
   UiScene* scene_;
-
-  // UI element pointers (not owned by the scene manager).
-  TransientElement* exclusive_screen_toast_transient_parent_ = nullptr;
-  TransientElement* exclusive_screen_toast_viewport_aware_transient_parent_ =
-      nullptr;
-  ShowUntilSignalTransientElement* splash_screen_transient_parent_ = nullptr;
-  UiElement* exit_warning_ = nullptr;
-  ContentElement* main_content_ = nullptr;
-  UiElement* screen_dimmer_ = nullptr;
-  Rect* ceiling_ = nullptr;
-  Grid* floor_ = nullptr;
-  UiElement* close_button_ = nullptr;
-  UrlBar* url_bar_ = nullptr;
-  TransientElement* webvr_url_toast_transient_parent_ = nullptr;
-  WebVrUrlToast* webvr_url_toast_ = nullptr;
-
-  bool in_cct_;
-  bool web_vr_mode_;
-  bool web_vr_show_toast_ = false;
-  bool started_for_autopresentation_ = false;
-  // Flag to indicate that we're waiting for the first WebVR frame to show up
-  // before we hide the splash screen. This is used in the case of WebVR
-  // auto-presentation.
-  bool showing_web_vr_splash_screen_ = false;
-  bool exiting_ = false;
-  bool browsing_disabled_ = false;
-  bool configuring_scene_ = false;
-
-  bool fullscreen_ = false;
-  bool incognito_ = false;
-
-  std::vector<Rect*> background_panels_;
-
-  gfx::SizeF last_content_screen_bounds_;
-  float last_content_aspect_ratio_ = 0.0f;
+  ContentInputDelegate* content_input_delegate_;
+  Model* model_;
 
   DISALLOW_COPY_AND_ASSIGN(UiSceneManager);
 };
diff --git a/chrome/browser/vr/ui_scene_manager_unittest.cc b/chrome/browser/vr/ui_scene_manager_unittest.cc
index 20ae9e25..15f79fe3 100644
--- a/chrome/browser/vr/ui_scene_manager_unittest.cc
+++ b/chrome/browser/vr/ui_scene_manager_unittest.cc
@@ -7,9 +7,9 @@
 #include "base/macros.h"
 #include "base/numerics/ranges.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/vr/color_scheme.h"
 #include "chrome/browser/vr/elements/button.h"
 #include "chrome/browser/vr/elements/content_element.h"
+#include "chrome/browser/vr/elements/exit_prompt.h"
 #include "chrome/browser/vr/elements/rect.h"
 #include "chrome/browser/vr/elements/ui_element.h"
 #include "chrome/browser/vr/elements/ui_element_name.h"
@@ -117,16 +117,6 @@
 
 }  // namespace
 
-TEST_F(UiSceneManagerTest, ExitPresentAndFullscreenOnAppButtonClick) {
-  MakeManager(kNotInCct, kInWebVr);
-
-  // Clicking app button should trigger to exit presentation.
-  EXPECT_CALL(*browser_, ExitPresent());
-  // And also trigger exit fullscreen.
-  EXPECT_CALL(*browser_, ExitFullscreen());
-  manager_->OnAppButtonClicked();
-}
-
 TEST_F(UiSceneManagerTest, ToastStateTransitions) {
   // Tests toast not showing when directly entering VR though WebVR
   // presentation.
@@ -138,27 +128,30 @@
   EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
   EXPECT_FALSE(IsVisible(kExclusiveScreenToastViewportAware));
 
-  manager_->SetFullscreen(true);
+  ui_->SetFullscreen(true);
   EXPECT_TRUE(IsVisible(kExclusiveScreenToast));
   EXPECT_FALSE(IsVisible(kExclusiveScreenToastViewportAware));
 
-  manager_->SetWebVrMode(true, true);
+  ui_->SetWebVrMode(true, true);
+  ui_->OnWebVrFrameAvailable();
   EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
   EXPECT_TRUE(IsVisible(kExclusiveScreenToastViewportAware));
 
-  manager_->SetWebVrMode(false, false);
+  ui_->SetWebVrMode(false, false);
+  // TODO(crbug.com/787582): we should not show the fullscreen toast again when
+  // returning to fullscreen mode after presenting webvr.
+  EXPECT_TRUE(IsVisible(kExclusiveScreenToast));
+  EXPECT_FALSE(IsVisible(kExclusiveScreenToastViewportAware));
+
+  ui_->SetFullscreen(false);
   EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
   EXPECT_FALSE(IsVisible(kExclusiveScreenToastViewportAware));
 
-  manager_->SetFullscreen(false);
+  ui_->SetWebVrMode(true, false);
   EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
   EXPECT_FALSE(IsVisible(kExclusiveScreenToastViewportAware));
 
-  manager_->SetWebVrMode(true, false);
-  EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
-  EXPECT_FALSE(IsVisible(kExclusiveScreenToastViewportAware));
-
-  manager_->SetWebVrMode(false, true);
+  ui_->SetWebVrMode(false, false);
   EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
   EXPECT_FALSE(IsVisible(kExclusiveScreenToastViewportAware));
 }
@@ -167,19 +160,20 @@
   MakeManager(kNotInCct, kNotInWebVr);
   EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
 
-  manager_->SetFullscreen(true);
+  ui_->SetFullscreen(true);
   EXPECT_TRUE(AnimateBy(MsToDelta(10)));
   EXPECT_TRUE(IsVisible(kExclusiveScreenToast));
   EXPECT_TRUE(AnimateBy(base::TimeDelta::FromSecondsD(kToastTimeoutSeconds)));
   EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
 
-  manager_->SetWebVrMode(true, true);
+  ui_->SetWebVrMode(true, true);
+  ui_->OnWebVrFrameAvailable();
   EXPECT_TRUE(AnimateBy(MsToDelta(10)));
   EXPECT_TRUE(IsVisible(kExclusiveScreenToastViewportAware));
   EXPECT_TRUE(AnimateBy(base::TimeDelta::FromSecondsD(kToastTimeoutSeconds)));
   EXPECT_FALSE(IsVisible(kExclusiveScreenToastViewportAware));
 
-  manager_->SetWebVrMode(false, false);
+  ui_->SetWebVrMode(false, false);
   EXPECT_FALSE(IsVisible(kExclusiveScreenToastViewportAware));
 }
 
@@ -193,23 +187,23 @@
   EXPECT_FALSE(IsVisible(kCloseButton));
 
   // Button should be visible in fullscreen and hidden when leaving fullscreen.
-  manager_->SetFullscreen(true);
+  ui_->SetFullscreen(true);
   EXPECT_TRUE(IsVisible(kCloseButton));
-  manager_->SetFullscreen(false);
+  ui_->SetFullscreen(false);
   EXPECT_FALSE(IsVisible(kCloseButton));
 
   // Button should not be visible when in WebVR.
   MakeManager(kInCct, kInWebVr);
   EXPECT_FALSE(IsVisible(kCloseButton));
-  manager_->SetWebVrMode(false, false);
+  ui_->SetWebVrMode(false, false);
   EXPECT_TRUE(IsVisible(kCloseButton));
 
   // Button should be visible in Cct across transistions in fullscreen.
   MakeManager(kInCct, kNotInWebVr);
   EXPECT_TRUE(IsVisible(kCloseButton));
-  manager_->SetFullscreen(true);
+  ui_->SetFullscreen(true);
   EXPECT_TRUE(IsVisible(kCloseButton));
-  manager_->SetFullscreen(false);
+  ui_->SetFullscreen(false);
   EXPECT_TRUE(IsVisible(kCloseButton));
 }
 
@@ -219,37 +213,42 @@
   // Hold onto the background color to make sure it changes.
   SkColor initial_background = SK_ColorBLACK;
   GetBackgroundColor(&initial_background);
-  manager_->SetFullscreen(true);
+  EXPECT_EQ(
+      ColorScheme::GetColorScheme(ColorScheme::kModeNormal).world_background,
+      initial_background);
+  ui_->SetFullscreen(true);
 
   // Make sure background has changed for fullscreen.
   SkColor fullscreen_background = SK_ColorBLACK;
   GetBackgroundColor(&fullscreen_background);
-  EXPECT_NE(initial_background, fullscreen_background);
+  EXPECT_EQ(ColorScheme::GetColorScheme(ColorScheme::kModeFullscreen)
+                .world_background,
+            fullscreen_background);
 
-  SetIncognito(true);
-
+  model_->incognito = true;
   // Make sure background has changed for incognito.
   SkColor incognito_background = SK_ColorBLACK;
   GetBackgroundColor(&incognito_background);
-  EXPECT_NE(fullscreen_background, incognito_background);
-  EXPECT_NE(initial_background, incognito_background);
+  EXPECT_EQ(
+      ColorScheme::GetColorScheme(ColorScheme::kModeIncognito).world_background,
+      incognito_background);
 
-  SetIncognito(false);
+  model_->incognito = false;
   SkColor no_longer_incognito_background = SK_ColorBLACK;
   GetBackgroundColor(&no_longer_incognito_background);
   EXPECT_EQ(fullscreen_background, no_longer_incognito_background);
 
-  manager_->SetFullscreen(false);
+  ui_->SetFullscreen(false);
   SkColor no_longer_fullscreen_background = SK_ColorBLACK;
   GetBackgroundColor(&no_longer_fullscreen_background);
   EXPECT_EQ(initial_background, no_longer_fullscreen_background);
 
-  SetIncognito(true);
+  model_->incognito = true;
   SkColor incognito_again_background = SK_ColorBLACK;
   GetBackgroundColor(&incognito_again_background);
   EXPECT_EQ(incognito_background, incognito_again_background);
 
-  SetIncognito(false);
+  model_->incognito = false;
   SkColor no_longer_incognito_again_background = SK_ColorBLACK;
   GetBackgroundColor(&no_longer_incognito_again_background);
   EXPECT_EQ(initial_background, no_longer_incognito_again_background);
@@ -261,7 +260,7 @@
   EXPECT_TRUE(OnBeginFrame());
   EXPECT_TRUE(IsVisible(kVoiceSearchButton));
 
-  SetIncognito(true);
+  model_->incognito = true;
   EXPECT_TRUE(OnBeginFrame());
   EXPECT_FALSE(IsVisible(kVoiceSearchButton));
 }
@@ -285,20 +284,21 @@
   auto initial_elements = std::set<UiElementName>();
   initial_elements.insert(kSplashScreenText);
   initial_elements.insert(kSplashScreenBackground);
+  AnimateBy(MsToDelta(1));
   VerifyElementsVisible("Initial", initial_elements);
 
   // Enter WebVR with autopresentation.
-  manager_->SetWebVrMode(true, false);
-  manager_->OnWebVrFrameAvailable();
+  ui_->SetWebVrMode(true, false);
+  model_->web_vr_timeout_state = kWebVrNoTimeoutPending;
   // The splash screen should go away.
-  AnimateBy(base::TimeDelta::FromSecondsD(kSplashScreenMinDurationSeconds +
-                                          kSmallDelaySeconds));
+  AnimateBy(
+      MsToDelta(1000 * (kSplashScreenMinDurationSeconds + kSmallDelaySeconds)));
   VerifyElementsVisible("Autopresented",
                         std::set<UiElementName>{kWebVrUrlToast});
 
   // Make sure the transient URL bar times out.
-  AnimateBy(base::TimeDelta::FromSeconds(kWebVrUrlToastTimeoutSeconds +
-                                         kSmallDelaySeconds));
+  AnimateBy(
+      MsToDelta(1000 * (kWebVrUrlToastTimeoutSeconds + kSmallDelaySeconds)));
   UiElement* transient_url_bar =
       scene_->GetUiElementByName(kWebVrUrlToastTransientParent);
   EXPECT_TRUE(IsAnimating(transient_url_bar, {OPACITY}));
@@ -314,7 +314,7 @@
   // Clicking app button should be a no-op.
   EXPECT_CALL(*browser_, ExitPresent()).Times(0);
   EXPECT_CALL(*browser_, ExitFullscreen()).Times(0);
-  manager_->OnAppButtonClicked();
+  ui_->OnAppButtonClicked();
 }
 
 TEST_F(UiSceneManagerTest, UiUpdatesForFullscreenChanges) {
@@ -338,12 +338,14 @@
 
   // In fullscreen mode, content elements should be visible, control elements
   // should be hidden.
-  manager_->SetFullscreen(true);
+  ui_->SetFullscreen(true);
   VerifyElementsVisible("In fullscreen", visible_in_fullscreen);
   // Make sure background has changed for fullscreen.
   SkColor fullscreen_background = SK_ColorBLACK;
   GetBackgroundColor(&fullscreen_background);
-  EXPECT_NE(initial_background, fullscreen_background);
+  EXPECT_EQ(ColorScheme::GetColorScheme(ColorScheme::kModeFullscreen)
+                .world_background,
+            fullscreen_background);
   // Should have started transition.
   EXPECT_TRUE(IsAnimating(content_quad, {BOUNDS}));
   EXPECT_TRUE(IsAnimating(content_group, {TRANSFORM}));
@@ -355,11 +357,13 @@
   EXPECT_NE(initial_position, content_group->LocalTransform());
 
   // Everything should return to original state after leaving fullscreen.
-  manager_->SetFullscreen(false);
+  ui_->SetFullscreen(false);
   VerifyElementsVisible("Restore initial", kElementsVisibleInBrowsing);
   SkColor no_longer_fullscreen_background = SK_ColorBLACK;
   GetBackgroundColor(&no_longer_fullscreen_background);
-  EXPECT_EQ(initial_background, no_longer_fullscreen_background);
+  EXPECT_EQ(
+      ColorScheme::GetColorScheme(ColorScheme::kModeNormal).world_background,
+      no_longer_fullscreen_background);
   // Should have started transition.
   EXPECT_TRUE(IsAnimating(content_quad, {BOUNDS}));
   EXPECT_TRUE(IsAnimating(content_group, {TRANSFORM}));
@@ -380,7 +384,7 @@
   // Clicking on security icon should trigger unsupported mode.
   EXPECT_CALL(*browser_,
               OnUnsupportedMode(UiUnsupportedMode::kUnhandledPageInfo));
-  manager_->OnSecurityIconClickedForTesting();
+  browser_->OnUnsupportedMode(UiUnsupportedMode::kUnhandledPageInfo);
   VerifyElementsVisible("Prompt invisible", kElementsVisibleInBrowsing);
 }
 
@@ -418,8 +422,8 @@
   // Click on backplane should trigger UI browser interface but not close
   // prompt.
   EXPECT_CALL(*browser_,
-              OnExitVrPromptResult(UiUnsupportedMode::kUnhandledPageInfo,
-                                   ExitVrPromptChoice::CHOICE_NONE));
+              OnExitVrPromptResult(ExitVrPromptChoice::CHOICE_NONE,
+                                   UiUnsupportedMode::kUnhandledPageInfo));
   scene_->GetUiElementByName(kExitPromptBackplane)->OnButtonUp(gfx::PointF());
   VerifyElementsVisible("Prompt still visible", kElementsVisibleWithExitPrompt);
 }
@@ -430,13 +434,14 @@
   // Initial state.
   VerifyElementsVisible("Initial", kElementsVisibleInBrowsing);
   model_->active_modal_prompt_type = kModalPromptTypeExitVRForSiteInfo;
+  OnBeginFrame();
 
   // Click on 'OK' should trigger UI browser interface but not close prompt.
   EXPECT_CALL(*browser_,
-              OnExitVrPromptResult(UiUnsupportedMode::kUnhandledPageInfo,
-                                   ExitVrPromptChoice::CHOICE_STAY));
-  manager_->OnExitPromptChoiceForTesting(false,
-                                         UiUnsupportedMode::kUnhandledPageInfo);
+              OnExitVrPromptResult(ExitVrPromptChoice::CHOICE_STAY,
+                                   UiUnsupportedMode::kUnhandledPageInfo));
+  static_cast<ExitPrompt*>(scene_->GetUiElementByName(kExitPrompt))
+      ->ClickPrimaryButtonForTesting();
   VerifyElementsVisible("Prompt still visible", kElementsVisibleWithExitPrompt);
 }
 
@@ -446,14 +451,16 @@
   // Initial state.
   VerifyElementsVisible("Initial", kElementsVisibleInBrowsing);
   model_->active_modal_prompt_type = kModalPromptTypeExitVRForSiteInfo;
+  OnBeginFrame();
 
   // Click on 'Exit VR' should trigger UI browser interface but not close
   // prompt.
   EXPECT_CALL(*browser_,
-              OnExitVrPromptResult(UiUnsupportedMode::kUnhandledPageInfo,
-                                   ExitVrPromptChoice::CHOICE_EXIT));
-  manager_->OnExitPromptChoiceForTesting(true,
-                                         UiUnsupportedMode::kUnhandledPageInfo);
+              OnExitVrPromptResult(ExitVrPromptChoice::CHOICE_EXIT,
+                                   UiUnsupportedMode::kUnhandledPageInfo));
+
+  static_cast<ExitPrompt*>(scene_->GetUiElementByName(kExitPrompt))
+      ->ClickSecondaryButtonForTesting();
   VerifyElementsVisible("Prompt still visible", kElementsVisibleWithExitPrompt);
 }
 
@@ -487,7 +494,7 @@
   model_->permissions.bluetooth_connected = true;
 
   // Transition to WebVR mode
-  manager_->SetWebVrMode(true, false);
+  ui_->SetWebVrMode(true, false);
 
   // All elements should be hidden.
   VerifyElementsVisible("Elements hidden", std::set<UiElementName>{});
@@ -513,12 +520,12 @@
   EXPECT_TRUE(VerifyRequiresLayout(indicators, true));
 
   // Go into non-browser modes and make sure all indicators are hidden.
-  manager_->SetWebVrMode(true, false);
+  ui_->SetWebVrMode(true, false);
   EXPECT_TRUE(VerifyVisibility(indicators, false));
-  manager_->SetWebVrMode(false, false);
-  manager_->SetFullscreen(true);
+  ui_->SetWebVrMode(false, false);
+  ui_->SetFullscreen(true);
   EXPECT_TRUE(VerifyVisibility(indicators, false));
-  manager_->SetFullscreen(false);
+  ui_->SetFullscreen(false);
 
   // Back to browser, make sure the indicators reappear.
   EXPECT_TRUE(AnimateBy(MsToDelta(500)));
@@ -537,31 +544,29 @@
 TEST_F(UiSceneManagerTest, PropagateContentBoundsOnStart) {
   MakeManager(kNotInCct, kNotInWebVr);
 
-  // Calculate the inheritable transforms.
-  EXPECT_TRUE(AnimateBy(MsToDelta(0)));
-
   gfx::SizeF expected_bounds(0.495922f, 0.330614f);
   EXPECT_CALL(*browser_,
               OnContentScreenBoundsChanged(
                   SizeFsAreApproximatelyEqual(expected_bounds, kTolerance)));
 
-  manager_->OnProjMatrixChanged(kPixelDaydreamProjMatrix);
+  ui_->OnProjMatrixChanged(kPixelDaydreamProjMatrix);
+  EXPECT_TRUE(AnimateBy(MsToDelta(500)));
 }
 
 TEST_F(UiSceneManagerTest, PropagateContentBoundsOnFullscreen) {
   MakeManager(kNotInCct, kNotInWebVr);
 
   EXPECT_TRUE(AnimateBy(MsToDelta(0)));
-  manager_->OnProjMatrixChanged(kPixelDaydreamProjMatrix);
-  manager_->SetFullscreen(true);
-  EXPECT_TRUE(AnimateBy(MsToDelta(0)));
+  ui_->OnProjMatrixChanged(kPixelDaydreamProjMatrix);
+  ui_->SetFullscreen(true);
 
   gfx::SizeF expected_bounds(0.587874f, 0.330614f);
   EXPECT_CALL(*browser_,
               OnContentScreenBoundsChanged(
                   SizeFsAreApproximatelyEqual(expected_bounds, kTolerance)));
 
-  manager_->OnProjMatrixChanged(kPixelDaydreamProjMatrix);
+  ui_->OnProjMatrixChanged(kPixelDaydreamProjMatrix);
+  EXPECT_TRUE(AnimateBy(MsToDelta(500)));
 }
 
 TEST_F(UiSceneManagerTest, HitTestableElements) {
@@ -574,7 +579,7 @@
   MakeManager(kNotInCct, kNotInWebVr);
 
   EXPECT_TRUE(AnimateBy(MsToDelta(0)));
-  manager_->OnProjMatrixChanged(kPixelDaydreamProjMatrix);
+  ui_->OnProjMatrixChanged(kPixelDaydreamProjMatrix);
 
   UiElement* content_quad = scene_->GetUiElementByName(kContentQuad);
   gfx::SizeF content_quad_size = content_quad->size();
@@ -584,7 +589,7 @@
 
   EXPECT_CALL(*browser_, OnContentScreenBoundsChanged(testing::_)).Times(0);
 
-  manager_->OnProjMatrixChanged(kPixelDaydreamProjMatrix);
+  ui_->OnProjMatrixChanged(kPixelDaydreamProjMatrix);
 }
 
 TEST_F(UiSceneManagerTest, RendererUsesCorrectOpacity) {
@@ -592,7 +597,8 @@
 
   ContentElement* content_element =
       static_cast<ContentElement*>(scene_->GetUiElementByName(kContentQuad));
-  content_element->SetTexture(0, vr::UiElementRenderer::kTextureLocationLocal);
+  content_element->SetTextureId(0);
+  content_element->SetTextureLocation(UiElementRenderer::kTextureLocationLocal);
   TexturedElement::SetInitializedForTesting();
 
   CheckRendererOpacityRecursive(&scene_->root_element());
@@ -615,40 +621,15 @@
 
 TEST_F(UiSceneManagerTest, ExitWarning) {
   MakeManager(kNotInCct, kNotInWebVr);
-  manager_->SetIsExiting();
+  ui_->SetIsExiting();
   EXPECT_TRUE(AnimateBy(MsToDelta(0)));
   EXPECT_TRUE(VerifyVisibility(kElementsVisibleWithExitWarning, true));
 }
 
-// This test ensures that we maintain a specific view hierarchy so that our UI
-// is not distorted based on a device's physical screen size. This test ensures
-// that we don't silently cause distoration by changing the hierarchy. The long
-// term solution is tracked by crbug.com/766318.
-TEST_F(UiSceneManagerTest, EnforceSceneHierarchyForProjMatrixChanges) {
-  MakeManager(kNotInCct, kNotInWebVr);
-  UiElement* browsing_content_group =
-      scene_->GetUiElementByName(k2dBrowsingContentGroup);
-  UiElement* browsing_foreground =
-      scene_->GetUiElementByName(k2dBrowsingForeground);
-  UiElement* browsing_root = scene_->GetUiElementByName(k2dBrowsingRoot);
-  UiElement* root = scene_->GetUiElementByName(kRoot);
-  EXPECT_EQ(browsing_content_group->parent(), browsing_foreground);
-  EXPECT_EQ(browsing_foreground->parent()->parent(), browsing_root);
-  EXPECT_EQ(browsing_root->parent(), root);
-  EXPECT_EQ(root->parent(), nullptr);
-  // Parents of k2dBrowsingContentGroup should not animate transform. Note that
-  // this test is not perfect because these could be animated anytime, but its
-  // better than having no test.
-  EXPECT_FALSE(
-      browsing_foreground->IsAnimatingProperty(TargetProperty::TRANSFORM));
-  EXPECT_FALSE(browsing_root->IsAnimatingProperty(TargetProperty::TRANSFORM));
-  EXPECT_FALSE(root->IsAnimatingProperty(TargetProperty::TRANSFORM));
-}
-
 TEST_F(UiSceneManagerTest, WebVrTimeout) {
   MakeManager(kNotInCct, kInWebVr);
 
-  manager_->SetWebVrMode(true, false);
+  ui_->SetWebVrMode(true, false);
   model_->web_vr_timeout_state = kWebVrAwaitingFirstFrame;
 
   AnimateBy(MsToDelta(500));
@@ -868,10 +849,10 @@
     ColorScheme::Mode mode = static_cast<ColorScheme::Mode>(i);
     SCOPED_TRACE(mode);
     if (mode == ColorScheme::kModeIncognito) {
-      manager_->SetIncognito(true);
+      ui_->SetIncognito(true);
     } else if (mode == ColorScheme::kModeFullscreen) {
-      manager_->SetIncognito(false);
-      manager_->SetFullscreen(true);
+      ui_->SetIncognito(false);
+      ui_->SetFullscreen(true);
     }
     ColorScheme scheme = ColorScheme::GetColorScheme(mode);
     EXPECT_TRUE(OnBeginFrame());
@@ -884,7 +865,7 @@
     button->hit_plane()->OnButtonDown(gfx::PointF(0.5f, 0.5f));
     EXPECT_TRUE(OnBeginFrame());
     VerifyButtonColor(button, scheme.button_colors.foreground,
-                      scheme.button_colors.background_press, "press");
+                      scheme.button_colors.background_down, "down");
     button->hit_plane()->OnMove(gfx::PointF());
     EXPECT_TRUE(OnBeginFrame());
     VerifyButtonColor(button, scheme.button_colors.foreground,
diff --git a/chrome/browser/vr/ui_scene_unittest.cc b/chrome/browser/vr/ui_scene_unittest.cc
index c8aeb2e3..4bac34c 100644
--- a/chrome/browser/vr/ui_scene_unittest.cc
+++ b/chrome/browser/vr/ui_scene_unittest.cc
@@ -106,7 +106,6 @@
   element->SetTranslate(6, 1, 0);
   element->SetRotate(0, 0, 1, 0.5f * base::kPiFloat);
   element->SetScale(3, 3, 1);
-  element->set_draw_phase(0);
   scene.AddUiElement(kRoot, std::move(element));
 
   // Add a child to the parent, with different transformations.
@@ -114,7 +113,6 @@
   element->SetTranslate(3, 0, 0);
   element->SetRotate(0, 0, 1, 0.5f * base::kPiFloat);
   element->SetScale(2, 2, 1);
-  element->set_draw_phase(0);
   UiElement* child = element.get();
   parent->AddChild(std::move(element));
 
@@ -134,13 +132,11 @@
   auto element = base::MakeUnique<UiElement>();
   UiElement* parent = element.get();
   element->SetOpacity(0.5);
-  element->set_draw_phase(0);
   scene.AddUiElement(kRoot, std::move(element));
 
   element = base::MakeUnique<UiElement>();
   UiElement* child = element.get();
   element->SetOpacity(0.5);
-  element->set_draw_phase(0);
   parent->AddChild(std::move(element));
 
   scene.OnBeginFrame(MsToTicks(0), kForwardVector);
@@ -153,12 +149,10 @@
   auto element = base::MakeUnique<UiElement>();
   UiElement* container = element.get();
   element->set_name(kWebVrRoot);
-  element->set_draw_phase(kPhaseNone);
   scene.AddUiElement(kRoot, std::move(element));
 
   auto root = base::MakeUnique<ViewportAwareRoot>();
   UiElement* viewport_aware_root = root.get();
-  root->set_draw_phase(kPhaseNone);
   container->AddChild(std::move(root));
 
   element = base::MakeUnique<UiElement>();
@@ -239,7 +233,6 @@
   UiElement* parent = element.get();
   element->SetSize(2, 2);
   element->SetScale(2, 2, 1);
-  element->set_draw_phase(0);
   scene.AddUiElement(kRoot, std::move(element));
 
   // Add a child to the parent, with anchoring.
@@ -249,7 +242,6 @@
   element->set_y_anchoring(GetParam().y_anchoring);
   element->set_x_centering(GetParam().x_centering);
   element->set_y_centering(GetParam().y_centering);
-  element->set_draw_phase(0);
   parent->AddChild(std::move(element));
 
   scene.OnBeginFrame(MsToTicks(0), kForwardVector);
diff --git a/chrome/browser/vr/ui_unittest.cc b/chrome/browser/vr/ui_unittest.cc
index 02ddbc3..b01a3fb 100644
--- a/chrome/browser/vr/ui_unittest.cc
+++ b/chrome/browser/vr/ui_unittest.cc
@@ -43,10 +43,19 @@
   // Initiating another exit VR prompt while a previous one was in flight should
   // result in a call to the UiBrowserInterface.
   EXPECT_CALL(*browser_,
-              OnExitVrPromptResult(UiUnsupportedMode::kUnhandledPageInfo,
-                                   ExitVrPromptChoice::CHOICE_NONE));
+              OnExitVrPromptResult(ExitVrPromptChoice::CHOICE_NONE,
+                                   UiUnsupportedMode::kUnhandledPageInfo));
   ui_->SetExitVrPromptEnabled(true,
                               UiUnsupportedMode::kAndroidPermissionNeeded);
 }
 
+TEST_F(UiTest, ExitPresentAndFullscreenOnAppButtonClick) {
+  ui_->SetWebVrMode(true, false);
+  // Clicking app button should trigger to exit presentation.
+  EXPECT_CALL(*browser_, ExitPresent());
+  // And also trigger exit fullscreen.
+  EXPECT_CALL(*browser_, ExitFullscreen());
+  ui_->OnAppButtonClicked();
+}
+
 }  // namespace vr
diff --git a/chrome/common/DEPS b/chrome/common/DEPS
index f3bced9..514be03c 100644
--- a/chrome/common/DEPS
+++ b/chrome/common/DEPS
@@ -27,6 +27,7 @@
   "+components/offline_pages/features",
   "+components/password_manager/core/common",
   "+components/policy/core/common",
+  "+components/prefs",
   "+components/printing/common",
   "+components/safe_browsing/proto/csd.pb.h",
   "+components/safe_browsing/web_ui/constants.h",
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index 7b4520d..8171be4 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -656,7 +656,7 @@
   // with them by third parties.
   schemes->secure_schemes.push_back(extensions::kExtensionScheme);
 
-  schemes->secure_origins = GetSecureOriginWhitelist();
+  schemes->secure_origins = secure_origin_whitelist::GetWhitelist();
 
   // chrome-native: is a scheme used for placeholder navigations that allow
   // UIs to be drawn with platform native widgets instead of HTML.  These pages
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 7712d48..78d4b4fd 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -238,6 +238,12 @@
 // Controls experimental rendering features for VR browsing.
 const base::Feature kVrBrowsingExperimentalRendering{
     "VrBrowsingExperimentalRendering", base::FEATURE_DISABLED_BY_DEFAULT};
+
+#if BUILDFLAG(ENABLE_OPENVR)
+// Controls OpenVR support.
+const base::Feature kOpenVR{"OpenVR", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif  // ENABLE_OPENVR
+
 #endif  // BUILDFLAG(ENABLE_VR)
 
 #if defined(OS_WIN)
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index f297182..c0407ec 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -121,7 +121,12 @@
 extern const base::Feature kVrBrowserKeyboard;
 extern const base::Feature kVrBrowsingExperimentalFeatures;
 extern const base::Feature kVrBrowsingExperimentalRendering;
-#endif
+
+#if BUILDFLAG(ENABLE_OPENVR)
+extern const base::Feature kOpenVR;
+#endif  // ENABLE_OPENVR
+
+#endif  // ENABLE_VR
 
 #if defined(OS_MACOSX)
 extern const base::Feature kFullscreenToolbarReveal;
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index fe75a8a..bbc67e3 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -2544,4 +2544,8 @@
 //  Timestamp of the last time the tab stats daily metrics have been reported.
 const char kTabStatsDailySample[] = "tab_stats.last_daily_sample";
 
+// A list of origins (URLs) to treat as "secure origins" for debugging purposes.
+const char kUnsafelyTreatInsecureOriginAsSecure[] =
+    "unsafely_treat_insecure_origin_as_secure";
+
 }  // namespace prefs
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 8537743..9ad8a87 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -904,6 +904,8 @@
 extern const char kTabStatsWindowCountMax[];
 extern const char kTabStatsDailySample[];
 
+extern const char kUnsafelyTreatInsecureOriginAsSecure[];
+
 }  // namespace prefs
 
 #endif  // CHROME_COMMON_PREF_NAMES_H_
diff --git a/chrome/common/secure_origin_whitelist.cc b/chrome/common/secure_origin_whitelist.cc
index 6d34b1e..10c0ca40 100644
--- a/chrome/common/secure_origin_whitelist.cc
+++ b/chrome/common/secure_origin_whitelist.cc
@@ -8,9 +8,13 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_split.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
 #include "extensions/common/constants.h"
 
-std::vector<GURL> GetSecureOriginWhitelist() {
+namespace secure_origin_whitelist {
+
+std::vector<GURL> GetWhitelist() {
   std::vector<GURL> origins;
   // If kUnsafelyTreatInsecureOriginAsSecure option is given, then treat the
   // value as a comma-separated list of origins:
@@ -30,8 +34,15 @@
   return origins;
 }
 
-std::set<std::string> GetSchemesBypassingSecureContextCheckWhitelist() {
+std::set<std::string> GetSchemesBypassingSecureContextCheck() {
   std::set<std::string> schemes;
   schemes.insert(extensions::kExtensionScheme);
   return schemes;
 }
+
+void RegisterProfilePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterStringPref(prefs::kUnsafelyTreatInsecureOriginAsSecure,
+                               /* default_value */ "");
+}
+
+}  // namespace secure_origin_whitelist
diff --git a/chrome/common/secure_origin_whitelist.h b/chrome/common/secure_origin_whitelist.h
index db0cd234..9476e8b 100644
--- a/chrome/common/secure_origin_whitelist.h
+++ b/chrome/common/secure_origin_whitelist.h
@@ -11,14 +11,23 @@
 
 #include "url/gurl.h"
 
+class PrefRegistrySimple;
+
+namespace secure_origin_whitelist {
+
 // Return a whitelist of origins that need to be considered trustworthy.
 // The whitelist is given by kUnsafelyTreatInsecureOriginAsSecure
 // command-line option. See
 // https://www.w3.org/TR/powerful-features/#is-origin-trustworthy.
-std::vector<GURL> GetSecureOriginWhitelist();
+std::vector<GURL> GetWhitelist();
 
 // Returns a whitelist of schemes that should bypass the Is Privileged Context
 // check. See http://www.w3.org/TR/powerful-features/#settings-privileged.
-std::set<std::string> GetSchemesBypassingSecureContextCheckWhitelist();
+std::set<std::string> GetSchemesBypassingSecureContextCheck();
+
+// Register preferences for Secure Origin Whitelists.
+void RegisterProfilePrefs(PrefRegistrySimple*);
+
+}  // namespace secure_origin_whitelist
 
 #endif  // CHROME_COMMON_SECURE_ORIGIN_WHITELIST_H_
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 6791c9e7..54169370 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -383,7 +383,7 @@
     kChromeUIInternetDetailDialogHost,
     kChromeUIVoiceSearchHost,
 #endif
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
     kChromeUIDiscardsHost,
 #endif
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 910ce92..a1a50fb5 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -511,12 +511,13 @@
   pdf::PepperPDFHost::SetPrintClient(pdf_print_client_.get());
 #endif
 
-  for (auto& origin : GetSecureOriginWhitelist()) {
+  for (auto& origin : secure_origin_whitelist::GetWhitelist()) {
     WebSecurityPolicy::AddOriginTrustworthyWhiteList(
         WebSecurityOrigin::Create(origin));
   }
 
-  for (auto& scheme : GetSchemesBypassingSecureContextCheckWhitelist()) {
+  for (auto& scheme :
+       secure_origin_whitelist::GetSchemesBypassingSecureContextCheck()) {
     WebSecurityPolicy::AddSchemeToBypassSecureContextWhitelist(
         WebString::FromASCII(scheme));
   }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index ff68cc2..1dff303 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -650,6 +650,7 @@
       "../browser/search/hotword_installer_browsertest.cc",
       "../browser/search/suggestions/image_fetcher_impl_browsertest.cc",
       "../browser/search_engines/template_url_scraper_browsertest.cc",
+      "../browser/secure_origin_whitelist_browsertest.cc",
       "../browser/service_process/service_process_control_browsertest.cc",
       "../browser/sessions/better_session_restore_browsertest.cc",
       "../browser/sessions/persistent_tab_restore_service_browsertest.cc",
@@ -3988,6 +3989,7 @@
       sources += [
         "../browser/ui/views/accelerator_table_unittest.cc",
         "../browser/ui/views/accelerator_table_unittest_mac.mm",
+        "../browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc",
         "../browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc",
         "../browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc",
         "../browser/ui/views/bookmarks/bookmark_context_menu_unittest.cc",
diff --git a/chrome/test/data/secure_origin_whitelist_browsertest.html b/chrome/test/data/secure_origin_whitelist_browsertest.html
new file mode 100644
index 0000000..cf6bd40
--- /dev/null
+++ b/chrome/test/data/secure_origin_whitelist_browsertest.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<!-- The page will replace the placeholder title with either "secure context"
+     or "insecure context", to make the window.isSecureContext observable to
+     the test driver.
+-->
+<title>bla</title>
+<script type="text/javascript">
+  document.title = isSecureContext ? "secure context" : "insecure context";
+</script>
+
diff --git a/chrome/test/data/session_restore/subdomain_cookies.html b/chrome/test/data/session_restore/subdomain_cookies.html
new file mode 100644
index 0000000..1975212
--- /dev/null
+++ b/chrome/test/data/session_restore/subdomain_cookies.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="common.js"></script>
+<script>
+function readData() {
+  return document.cookie;
+}
+function writeData() {
+  var exdate = new Date();
+  exdate.setDate(exdate.getDate() + 2);
+  document.cookie =
+      'permanentkey=permanentvalueT;path=/;domain=.test.com;expires=' + exdate.toUTCString();
+  return true;
+}
+</script>
+</head>
+<body onload="setTimeout(onLoad, 0);">
+</body>
+</html>
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 2232b19..86d671ba 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -109,6 +109,10 @@
 
   extra_js_files = [ "//chrome/browser/resources/md_downloads/constants.js" ]
 
+  if (is_win || is_mac || is_desktop_linux || is_chromeos) {
+    sources += [ "discards/discards_browsertest.js" ]
+  }
+
   if (is_chromeos) {
     sources += [
       "settings/easy_unlock_browsertest_chromeos.js",
diff --git a/chrome/test/data/webui/discards/OWNERS b/chrome/test/data/webui/discards/OWNERS
new file mode 100644
index 0000000..ba3619f
--- /dev/null
+++ b/chrome/test/data/webui/discards/OWNERS
@@ -0,0 +1 @@
+file://chrome/services/resource_coordinator/OWNERS
diff --git a/chrome/test/data/webui/discards/discards_browsertest.js b/chrome/test/data/webui/discards/discards_browsertest.js
new file mode 100644
index 0000000..7479c997
--- /dev/null
+++ b/chrome/test/data/webui/discards/discards_browsertest.js
@@ -0,0 +1,94 @@
+// 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.
+
+/** @const {string} Path to source root. */
+const ROOT_PATH = '../../../../../';
+
+/**
+ * TestFixture for Discards WebUI testing.
+ * @extends {testing.Test}
+ * @constructor
+ */
+function DiscardsTest() {}
+DiscardsTest.prototype = {
+  __proto__: testing.Test.prototype,
+  browsePreload: 'chrome://discards'
+};
+
+TEST_F('DiscardsTest', 'CompareTabDiscardsInfo', function() {
+  let dummy1 = {
+    title: 'title 1',
+    tabUrl: 'http://urlone.com',
+    isApp: false,
+    isInternal: false,
+    isMedia: false,
+    isPinned: false,
+    isDiscarded: false,
+    isAutoDiscardable: false,
+    discardCount: 0,
+    utilityRank: 0,
+    lastActiveSeconds: 0
+  };
+  let dummy2 = {
+    title: 'title 2',
+    tabUrl: 'http://urltwo.com',
+    isApp: true,
+    isInternal: true,
+    isMedia: true,
+    isPinned: true,
+    isDiscarded: true,
+    isAutoDiscardable: true,
+    discardCount: 1,
+    utilityRank: 1,
+    lastActiveSeconds: 1
+  };
+
+  ['title', 'tabUrl', 'isApp', 'isInternal', 'isMedia', 'isPinned',
+      'isDiscarded', 'isAutoDiscardable', 'discardCount', 'utilityRank',
+      'lastActiveSeconds'].forEach((sortKey) => {
+    assertTrue(
+        discards.compareTabDiscardsInfos(sortKey, dummy1, dummy2) < 0);
+    assertTrue(
+        discards.compareTabDiscardsInfos(sortKey, dummy2, dummy1) > 0);
+    assertTrue(
+        discards.compareTabDiscardsInfos(sortKey, dummy1, dummy1) == 0);
+    assertTrue(
+        discards.compareTabDiscardsInfos(sortKey, dummy2, dummy2) == 0);
+  });
+});
+
+TEST_F('DiscardsTest', 'LastActiveToString', function() {
+  // Test cases have the form [ 'expected output', input_in_seconds ].
+  [
+    [ 'just now', 0 ],
+    [ 'just now', 10 ],
+    [ 'just now', 59 ],
+    [ '1 minute ago', 60 ],
+    [ '10 minutes ago', 10 * 60 + 30 ],
+    [ '59 minutes ago', 59 * 60 + 59 ],
+    [ '1 hour ago', 60 * 60 ],
+    [ '1 hour and 1 minute ago', 61 * 60 ],
+    [ '1 hour and 10 minutes ago', 70 * 60 + 30 ],
+    [ '1 day ago', 24 * 60 * 60 ],
+    [ '2 days ago', 2.5 * 24 * 60 * 60 ],
+    [ '6 days ago', 6.9 * 24 * 60 * 60 ],
+    [ 'over 1 week ago', 7 * 24 * 60 * 60 ],
+    [ 'over 2 weeks ago', 2.5 * 7 * 24 * 60 * 60 ],
+    [ 'over 4 weeks ago', 30 * 24 * 60 * 60 ],
+    [ 'over 1 month ago', 30.5 * 24 * 60 * 60 ],
+    [ 'over 2 months ago', 2.5 * 30.5 * 24 * 60 * 60 ],
+    [ 'over 11 months ago', 364 * 24 * 60 * 60 ],
+    [ 'over 1 year ago', 365 * 24 * 60 * 60 ],
+    [ 'over 2 years ago', 2.3 * 365 * 24 * 60 * 60 ]
+  ].forEach((data) => {
+    assertEquals(data[0], discards.lastActiveToString(data[1]));
+  });
+});
+
+TEST_F('DiscardsTest', 'MaybeMakePlural', function() {
+  assertEquals('hours', discards.maybeMakePlural('hour', 0));
+  assertEquals('hour', discards.maybeMakePlural('hour', 1));
+  assertEquals('hours', discards.maybeMakePlural('hour', 2));
+  assertEquals('hours', discards.maybeMakePlural('hour', 10));
+});
diff --git a/chrome/test/media_router/media_router_integration_browsertest.cc b/chrome/test/media_router/media_router_integration_browsertest.cc
index 072c0e55..fecda826 100644
--- a/chrome/test/media_router/media_router_integration_browsertest.cc
+++ b/chrome/test/media_router/media_router_integration_browsertest.cc
@@ -262,9 +262,9 @@
   // Wait for the sinks to load.
   WaitUntilSinkDiscoveredOnUI();
   // Click on sink.
-  ChooseSink(GetActiveWebContents(), kTestSinkName);
-  // Give casting a second to go through.
-  Wait(base::TimeDelta::FromSeconds(1));
+  ChooseSink(GetActiveWebContents(), receiver_);
+  // Give casting a few seconds to go through.
+  Wait(base::TimeDelta::FromSeconds(3));
   // Expect that the current tab has the file open in it.
   ASSERT_EQ(file_url, GetActiveWebContents()->GetURL());
 }
@@ -707,6 +707,12 @@
 
   // Expect that no new tab has been opened.
   ASSERT_EQ(1, browser()->tab_strip_model()->count());
+
+  // Open the dialog again to check for a route.
+  OpenMRDialog(GetActiveWebContents());
+
+  // Wait for a route to be created.
+  WaitUntilRouteCreated();
 }
 
 // Tests that creating a route with a local file opens the file in a new tab.
@@ -722,9 +728,15 @@
 
   // Expect that a new tab has been opened.
   ASSERT_EQ(2, browser()->tab_strip_model()->count());
+
+  // Open the dialog again to check for a route.
+  OpenMRDialog(GetActiveWebContents());
+
+  // Wait for a route to be created.
+  WaitUntilRouteCreated();
 }
 
-// Tests that creating a route with a local file opens the file in a new tab.
+// Tests that failing to create a route with a local file shows an issue.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
                        MANUAL_OpenLocalMediaFileFailsAndShowsIssue) {
   OpenDialogAndCastFileFails();
diff --git a/chromeos/dbus/fake_cryptohome_client.cc b/chromeos/dbus/fake_cryptohome_client.cc
index 79fb1b85..ba632dc 100644
--- a/chromeos/dbus/fake_cryptohome_client.cc
+++ b/chromeos/dbus/fake_cryptohome_client.cc
@@ -24,10 +24,8 @@
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/cryptohome/key.pb.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
+#include "components/policy/proto/install_attributes.pb.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
-#include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
-#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h"
-#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
 
 namespace chromeos {
 
@@ -40,6 +38,9 @@
 constexpr int kDircryptoMigrationUpdateIntervalMs = 200;
 // The number of updates the MigrateToDircrypto will send before it completes.
 constexpr uint64_t kDircryptoMigrationMaxProgress = 15;
+// Buffer size for reading install attributes file. 16k should be plenty. The
+// file contains six attributes only (see InstallAttributes::LockDevice).
+constexpr size_t kInstallAttributesFileMaxSize = 16384;
 }  // namespace
 
 FakeCryptohomeClient::FakeCryptohomeClient()
@@ -51,6 +52,8 @@
   base::FilePath cache_path;
   locked_ = PathService::Get(chromeos::FILE_INSTALL_ATTRIBUTES, &cache_path) &&
             base::PathExists(cache_path);
+  if (locked_)
+    LoadInstallAttributes();
 }
 
 FakeCryptohomeClient::~FakeCryptohomeClient() {}
@@ -281,51 +284,24 @@
   // Persist the install attributes so that they can be reloaded if the
   // browser is restarted. This is used for ease of development when device
   // enrollment is required.
-  // The cryptohome::SerializedInstallAttributes protobuf lives in
-  // chrome/browser/chromeos, so it can't be used directly here; use the
-  // low-level protobuf API instead to just write the name-value pairs.
-  // The cache file is read by InstallAttributes::Init.
   base::FilePath cache_path;
   if (!PathService::Get(chromeos::FILE_INSTALL_ATTRIBUTES, &cache_path))
     return false;
 
-  std::string result;
-  {
-    // |result| can be used only after the StringOutputStream goes out of
-    // scope.
-    google::protobuf::io::StringOutputStream result_stream(&result);
-    google::protobuf::io::CodedOutputStream result_output(&result_stream);
-
-    // These tags encode a variable-length value on the wire, which can be
-    // used to encode strings, bytes and messages. We only needs constants
-    // for tag numbers 1 and 2 (see install_attributes.proto).
-    const int kVarLengthTag1 = (1 << 3) | 0x2;
-    const int kVarLengthTag2 = (2 << 3) | 0x2;
-
-    typedef std::map<std::string, std::vector<uint8_t>>::const_iterator Iter;
-    for (Iter it = install_attrs_.begin(); it != install_attrs_.end(); ++it) {
-      std::string attr;
-      {
-        google::protobuf::io::StringOutputStream attr_stream(&attr);
-        google::protobuf::io::CodedOutputStream attr_output(&attr_stream);
-
-        attr_output.WriteVarint32(kVarLengthTag1);
-        attr_output.WriteVarint32(it->first.size());
-        attr_output.WriteString(it->first);
-        attr_output.WriteVarint32(kVarLengthTag2);
-        attr_output.WriteVarint32(it->second.size());
-        attr_output.WriteRaw(it->second.data(), it->second.size());
-      }
-
-      // Two CodedOutputStreams are needed because inner messages must be
-      // prefixed by their total length, which can't be easily computed before
-      // writing their tags and values.
-      result_output.WriteVarint32(kVarLengthTag2);
-      result_output.WriteVarint32(attr.size());
-      result_output.WriteRaw(attr.data(), attr.size());
-    }
+  cryptohome::SerializedInstallAttributes install_attrs_proto;
+  for (const auto& it : install_attrs_) {
+    const std::string& name = it.first;
+    const std::vector<uint8_t>& value = it.second;
+    cryptohome::SerializedInstallAttributes::Attribute* attr_entry =
+        install_attrs_proto.add_attributes();
+    attr_entry->set_name(name);
+    attr_entry->mutable_value()->assign(value.data(),
+                                        value.data() + value.size());
   }
 
+  std::string result;
+  install_attrs_proto.SerializeToString(&result);
+
   // The real implementation does a blocking wait on the dbus call; the fake
   // implementation must have this file written before returning.
   base::ThreadRestrictions::ScopedAllowIO allow_io;
@@ -804,4 +780,32 @@
     observer.DircryptoMigrationProgress(status, current, total);
 }
 
+bool FakeCryptohomeClient::LoadInstallAttributes() {
+  base::FilePath cache_file;
+  const bool file_exists =
+      PathService::Get(FILE_INSTALL_ATTRIBUTES, &cache_file) &&
+      base::PathExists(cache_file);
+  DCHECK(file_exists);
+  // Mostly copied from chrome/browser/chromeos/settings/install_attributes.cc.
+  std::string file_blob;
+  if (!base::ReadFileToStringWithMaxSize(cache_file, &file_blob,
+                                         kInstallAttributesFileMaxSize)) {
+    PLOG(ERROR) << "Failed to read " << cache_file.value();
+    return false;
+  }
+
+  cryptohome::SerializedInstallAttributes install_attrs_proto;
+  if (!install_attrs_proto.ParseFromString(file_blob)) {
+    LOG(ERROR) << "Failed to parse install attributes cache.";
+    return false;
+  }
+
+  for (const auto& entry : install_attrs_proto.attributes()) {
+    install_attrs_[entry.name()].assign(
+        entry.value().data(), entry.value().data() + entry.value().size());
+  }
+
+  return true;
+}
+
 }  // namespace chromeos
diff --git a/chromeos/dbus/fake_cryptohome_client.h b/chromeos/dbus/fake_cryptohome_client.h
index 09a9674..d3b376c 100644
--- a/chromeos/dbus/fake_cryptohome_client.h
+++ b/chromeos/dbus/fake_cryptohome_client.h
@@ -301,6 +301,9 @@
   // Notifies LowDiskSpace() to Observer instances.
   void NotifyLowDiskSpace(uint64_t disk_free_bytes);
 
+  // Loads install attributes from the stub file.
+  bool LoadInstallAttributes();
+
   bool service_is_available_;
   base::ObserverList<Observer> observer_list_;
 
diff --git a/components/autofill/core/browser/autofill_experiments.cc b/components/autofill/core/browser/autofill_experiments.cc
index 379bf6b4..78935ae7 100644
--- a/components/autofill/core/browser/autofill_experiments.cc
+++ b/components/autofill/core/browser/autofill_experiments.cc
@@ -44,6 +44,8 @@
     "AutofillDeleteDisusedAddresses", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kAutofillDeleteDisusedCreditCards{
     "AutofillDeleteDisusedCreditCards", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillExpandedPopupViews{
+    "AutofillExpandedPopupViews", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kAutofillOfferLocalSaveIfServerCardManuallyEntered{
     "AutofillOfferLocalSaveIfServerCardManuallyEntered",
     base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/autofill/core/browser/autofill_experiments.h b/components/autofill/core/browser/autofill_experiments.h
index 6c2a20f..6221cf2 100644
--- a/components/autofill/core/browser/autofill_experiments.h
+++ b/components/autofill/core/browser/autofill_experiments.h
@@ -35,6 +35,7 @@
 extern const base::Feature kAutofillCreditCardLastUsedDateDisplay;
 extern const base::Feature kAutofillDeleteDisusedAddresses;
 extern const base::Feature kAutofillDeleteDisusedCreditCards;
+extern const base::Feature kAutofillExpandedPopupViews;
 extern const base::Feature kAutofillOfferLocalSaveIfServerCardManuallyEntered;
 extern const base::Feature kAutofillRationalizeFieldTypePredictions;
 extern const base::Feature kAutofillSendBillingCustomerNumber;
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc
index a46dfdce..bae77b9 100644
--- a/components/autofill/core/browser/payments/payments_client.cc
+++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -585,8 +585,7 @@
     case net::HTTP_OK: {
       std::string error_code;
       std::unique_ptr<base::Value> message_value = base::JSONReader::Read(data);
-      if (message_value.get() &&
-          message_value->IsType(base::Value::Type::DICTIONARY)) {
+      if (message_value.get() && message_value->is_dict()) {
         response_dict.reset(
             static_cast<base::DictionaryValue*>(message_value.release()));
         response_dict->GetString("error.code", &error_code);
diff --git a/components/autofill/ios/browser/resources/suggestion_controller.js b/components/autofill/ios/browser/resources/suggestion_controller.js
index 30ab3062..456e6ef 100644
--- a/components/autofill/ios/browser/resources/suggestion_controller.js
+++ b/components/autofill/ios/browser/resources/suggestion_controller.js
@@ -24,6 +24,26 @@
 // minification.
 __gCrWeb['suggestion'] = __gCrWeb.suggestion;
 
+ /**
+  * Returns the element with the specified name that is a child of the
+  * specified parent element.
+  * @param {Element} parent The parent of the desired element.
+  * @param {string} name The name of the desired element.
+  * @return {Element} The element if found, otherwise null;
+  */
+ var getElementByNameWithParent_ = function(parent, name) {
+   if (parent.name === name)
+     return parent;
+
+   var el;
+   for (var i = 0; i < parent.children.length; i++) {
+     el = getElementByNameWithParent_(parent.children[i], name);
+     if (el)
+       return el;
+   }
+   return null;
+ };
+
 /**
  * Returns the first element in |elements| that is later than |elementToCompare|
  * in tab order.
@@ -271,7 +291,7 @@
   var form = __gCrWeb.common.getFormElementFromIdentifier(formName);
   if (!form)
     return null;
-  return __gCrWeb.getElementByNameWithParent(form, fieldName);
+  return getElementByNameWithParent_(form, fieldName);
 };
 
 /**
diff --git a/components/bookmarks/browser/bookmark_codec.cc b/components/bookmarks/browser/bookmark_codec.cc
index 469641e..75735b9 100644
--- a/components/bookmarks/browser/bookmark_codec.cc
+++ b/components/bookmarks/browser/bookmark_codec.cc
@@ -177,7 +177,7 @@
 
   const base::Value* checksum_value;
   if (d_value->Get(kChecksumKey, &checksum_value)) {
-    if (checksum_value->type() != base::Value::Type::STRING)
+    if (!checksum_value->is_string())
       return false;
     if (!checksum_value->GetAsString(&stored_checksum_))
       return false;
@@ -395,7 +395,7 @@
 
   // Meta info used to be stored as a serialized dictionary, so attempt to
   // parse the value as one.
-  if (meta_info->IsType(base::Value::Type::STRING)) {
+  if (meta_info->is_string()) {
     std::string meta_info_str;
     meta_info->GetAsString(&meta_info_str);
     JSONStringValueDeserializer deserializer(meta_info_str);
@@ -438,11 +438,11 @@
     if (base::StartsWith(it.key(), "stars.", base::CompareCase::SENSITIVE))
       continue;
 
-    if (it.value().IsType(base::Value::Type::DICTIONARY)) {
+    if (it.value().is_dict()) {
       const base::DictionaryValue* subdict;
       it.value().GetAsDictionary(&subdict);
       DecodeMetaInfoHelper(*subdict, prefix + it.key() + ".", meta_info_map);
-    } else if (it.value().IsType(base::Value::Type::STRING)) {
+    } else if (it.value().is_string()) {
       it.value().GetAsString(&(*meta_info_map)[prefix + it.key()]);
     }
   }
diff --git a/components/content_settings/core/browser/content_settings_policy_provider.cc b/components/content_settings/core/browser/content_settings_policy_provider.cc
index 8081d76..cacfdf9 100644
--- a/components/content_settings/core/browser/content_settings_policy_provider.cc
+++ b/components/content_settings/core/browser/content_settings_policy_provider.cc
@@ -291,7 +291,7 @@
 
     std::unique_ptr<base::Value> value = base::JSONReader::Read(
         pattern_filter_json, base::JSON_ALLOW_TRAILING_COMMAS);
-    if (!value || !value->IsType(base::Value::Type::DICTIONARY)) {
+    if (!value || !value->is_dict()) {
       VLOG(1) << "Ignoring invalid certificate auto select setting. Reason:"
                  " Invalid JSON object: " << pattern_filter_json;
       continue;
diff --git a/components/content_settings/core/browser/cookie_settings.cc b/components/content_settings/core/browser/cookie_settings.cc
index 6dbac81c..0deb011 100644
--- a/components/content_settings/core/browser/cookie_settings.cc
+++ b/components/content_settings/core/browser/cookie_settings.cc
@@ -71,6 +71,14 @@
   return (setting == CONTENT_SETTING_SESSION_ONLY);
 }
 
+bool CookieSettings::IsCookieSessionOnlyOrBlocked(const GURL& origin) const {
+  ContentSetting setting;
+  GetCookieSetting(origin, origin, nullptr, &setting);
+  DCHECK(IsValidSetting(setting));
+  return (setting == CONTENT_SETTING_SESSION_ONLY) ||
+         (setting == CONTENT_SETTING_BLOCK);
+}
+
 void CookieSettings::GetCookieSettings(
     ContentSettingsForOneType* settings) const {
   host_content_settings_map_->GetSettingsForOneType(
diff --git a/components/content_settings/core/browser/cookie_settings.h b/components/content_settings/core/browser/cookie_settings.h
index 197882fd..f7f2b8b 100644
--- a/components/content_settings/core/browser/cookie_settings.h
+++ b/components/content_settings/core/browser/cookie_settings.h
@@ -59,6 +59,12 @@
   // This may be called on any thread.
   bool IsCookieSessionOnly(const GURL& url) const;
 
+  // Returns true if the cookie set by a page identified by |url| should be
+  // session only or blocked.
+  //
+  // This may be called on any thread.
+  bool IsCookieSessionOnlyOrBlocked(const GURL& url) const;
+
   // Returns all patterns with a non-default cookie setting, mapped to their
   // actual settings, in the precedence order of the setting rules. |settings|
   // must be a non-nullptr outparam.
diff --git a/components/content_settings/core/browser/website_settings_info.cc b/components/content_settings/core/browser/website_settings_info.cc
index e793208..9fbb132 100644
--- a/components/content_settings/core/browser/website_settings_info.cc
+++ b/components/content_settings/core/browser/website_settings_info.cc
@@ -47,8 +47,7 @@
   // For legacy reasons the default value is currently restricted to be an int.
   // TODO(raymes): We should migrate the underlying pref to be a dictionary
   // rather than an int.
-  DCHECK(!initial_default_value_ ||
-         initial_default_value_->IsType(base::Value::Type::INTEGER));
+  DCHECK(!initial_default_value_ || initial_default_value_->is_int());
 }
 
 WebsiteSettingsInfo::~WebsiteSettingsInfo() {}
diff --git a/components/cryptauth/wire_message.cc b/components/cryptauth/wire_message.cc
index ae52678d..d3bba84 100644
--- a/components/cryptauth/wire_message.cc
+++ b/components/cryptauth/wire_message.cc
@@ -97,7 +97,7 @@
 
   std::unique_ptr<base::Value> body_value =
       base::JSONReader::Read(serialized_message.substr(kHeaderLength));
-  if (!body_value || !body_value->IsType(base::Value::Type::DICTIONARY)) {
+  if (!body_value || !body_value->is_dict()) {
     PA_LOG(WARNING) << "Error: Unable to parse message as JSON.";
     return nullptr;
   }
diff --git a/components/dom_distiller/core/distiller_page.cc b/components/dom_distiller/core/distiller_page.cc
index eccdf82a..ad37b5f 100644
--- a/components/dom_distiller/core/distiller_page.cc
+++ b/components/dom_distiller/core/distiller_page.cc
@@ -94,7 +94,7 @@
   std::unique_ptr<dom_distiller::proto::DomDistillerResult> distiller_result(
       new dom_distiller::proto::DomDistillerResult());
   bool found_content;
-  if (value->IsType(base::Value::Type::NONE)) {
+  if (value->is_none()) {
     found_content = false;
   } else {
     found_content =
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 3a1baa5..a87eb105 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -483,7 +483,7 @@
 
     // No redirect case (one element means just the page itself).
     last_ids = AddPageVisit(request.url, request.time, last_ids.second, t,
-                            request.visit_source);
+                            request.hidden, request.visit_source);
 
     // Update the segment for this visit. KEYWORD_GENERATED visits should not
     // result in changing most visited, so we don't update segments (most
@@ -571,8 +571,10 @@
       // Record all redirect visits with the same timestamp. We don't display
       // them anyway, and if we ever decide to, we can reconstruct their order
       // from the redirect chain.
-      last_ids = AddPageVisit(redirects[redirect_index], request.time,
-                              last_ids.second, t, request.visit_source);
+      last_ids =
+          AddPageVisit(redirects[redirect_index], request.time, last_ids.second,
+                       t, request.hidden, request.visit_source);
+
       if (t & ui::PAGE_TRANSITION_CHAIN_START) {
         if (request.consider_for_ntp_most_visited) {
           UpdateSegments(redirects[redirect_index], from_visit_id,
@@ -765,10 +767,8 @@
     Time time,
     VisitID referring_visit,
     ui::PageTransition transition,
+    bool hidden,
     VisitSource visit_source) {
-  // Top-level frame navigations are visible, everything else is hidden
-  bool new_hidden = !ui::PageTransitionIsMainFrame(transition);
-
   // NOTE: This code must stay in sync with
   // ExpireHistoryBackend::ExpireURLsForVisits().
   int typed_increment = 0;
@@ -797,7 +797,7 @@
       url_info.set_last_visit(time);
 
     // Only allow un-hiding of pages, never hiding.
-    if (!new_hidden)
+    if (!hidden)
       url_info.set_hidden(false);
 
     db_->UpdateURLRow(url_id, url_info);
@@ -806,7 +806,7 @@
     url_info.set_visit_count(1);
     url_info.set_typed_count(typed_increment);
     url_info.set_last_visit(time);
-    url_info.set_hidden(new_hidden);
+    url_info.set_hidden(hidden);
 
     url_id = db_->AddURL(url_info);
     if (!url_id) {
@@ -1023,7 +1023,9 @@
   if (db_) {
     for (std::vector<VisitInfo>::const_iterator visit = visits.begin();
          visit != visits.end(); ++visit) {
-      if (!AddPageVisit(url, visit->first, 0, visit->second, visit_source)
+      if (!AddPageVisit(url, visit->first, 0, visit->second,
+                        !ui::PageTransitionIsMainFrame(visit->second),
+                        visit_source)
                .first) {
         return false;
       }
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h
index ddbac57f..5e16262 100644
--- a/components/history/core/browser/history_backend.h
+++ b/components/history/core/browser/history_backend.h
@@ -628,6 +628,7 @@
                                          base::Time time,
                                          VisitID referring_visit,
                                          ui::PageTransition transition,
+                                         bool hidden,
                                          VisitSource visit_source);
 
   // Returns a redirect chain in |redirects| for the VisitID
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc
index 9251a829..e740b1a9 100644
--- a/components/history/core/browser/history_backend_unittest.cc
+++ b/components/history/core/browser/history_backend_unittest.cc
@@ -360,9 +360,8 @@
 
     ContextID context_id = reinterpret_cast<ContextID>(1);
     history::HistoryAddPageArgs request(
-        redirects.back(), time, context_id, nav_entry_id, GURL(),
-        redirects, transition, history::SOURCE_BROWSED,
-        true, true);
+        redirects.back(), time, context_id, nav_entry_id, GURL(), redirects,
+        transition, false, history::SOURCE_BROWSED, true, true);
     backend_->AddPage(request);
   }
 
@@ -385,10 +384,9 @@
       redirects.push_back(url1);
     if (url2.is_valid())
       redirects.push_back(url2);
-    HistoryAddPageArgs request(
-        url2, time, dummy_context_id, 0, url1,
-        redirects, ui::PAGE_TRANSITION_CLIENT_REDIRECT,
-        history::SOURCE_BROWSED, did_replace, true);
+    HistoryAddPageArgs request(url2, time, dummy_context_id, 0, url1, redirects,
+                               ui::PAGE_TRANSITION_CLIENT_REDIRECT, false,
+                               history::SOURCE_BROWSED, did_replace, true);
     backend_->AddPage(request);
 
     if (transition1)
@@ -779,7 +777,7 @@
   GURL url("http://www.google.com/");
   HistoryAddPageArgs request(url, visit_time, nullptr, 0, GURL(),
                              history::RedirectList(),
-                             ui::PAGE_TRANSITION_KEYWORD_GENERATED,
+                             ui::PAGE_TRANSITION_KEYWORD_GENERATED, false,
                              history::SOURCE_BROWSED, false, true);
   backend_->AddPage(request);
 
@@ -912,7 +910,7 @@
   base::Time visit_time = base::Time::Now() - base::TimeDelta::FromDays(1);
   HistoryAddPageArgs request(url, visit_time, nullptr, 0, GURL(),
                              history::RedirectList(),
-                             ui::PAGE_TRANSITION_KEYWORD_GENERATED,
+                             ui::PAGE_TRANSITION_KEYWORD_GENERATED, false,
                              history::SOURCE_BROWSED, false, true);
   backend_->AddPage(request);
 
@@ -945,7 +943,7 @@
       ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FORWARD_BACK);
   HistoryAddPageArgs back_request(url, visit_time, nullptr, 0, GURL(),
                                   history::RedirectList(), back_transition,
-                                  history::SOURCE_BROWSED, false, true);
+                                  false, history::SOURCE_BROWSED, false, true);
   backend_->AddPage(back_request);
   url_id = backend_->db()->GetRowForURL(url, &row);
   ASSERT_NE(0, url_id);
@@ -1244,10 +1242,11 @@
   backend_->DeleteAllHistory();
 
   // Visit the url with username, password.
-  backend_->AddPageVisit(url, base::Time::Now(), 0,
+  backend_->AddPageVisit(
+      url, base::Time::Now(), 0,
       ui::PageTransitionFromInt(
           ui::PageTransitionGetQualifier(ui::PAGE_TRANSITION_TYPED)),
-      history::SOURCE_BROWSED);
+      false, history::SOURCE_BROWSED);
 
   // Fetch the row information about stripped url from history db.
   VisitVector visits;
@@ -1267,9 +1266,8 @@
   backend_->DeleteAllHistory();
 
   // Visit the url after typing it.
-  backend_->AddPageVisit(url, base::Time::Now(), 0,
-      ui::PAGE_TRANSITION_TYPED,
-      history::SOURCE_BROWSED);
+  backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_TYPED,
+                         false, history::SOURCE_BROWSED);
 
   // Ensure both the typed count and visit count are 1.
   VisitVector visits;
@@ -1280,10 +1278,11 @@
   EXPECT_EQ(1, row.visit_count());
 
   // Visit the url again via back/forward.
-  backend_->AddPageVisit(url, base::Time::Now(), 0,
-      ui::PageTransitionFromInt(
-          ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FORWARD_BACK),
-      history::SOURCE_BROWSED);
+  backend_->AddPageVisit(
+      url, base::Time::Now(), 0,
+      ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                ui::PAGE_TRANSITION_FORWARD_BACK),
+      false, history::SOURCE_BROWSED);
 
   // Ensure the typed count is still 1 but the visit count is 2.
   id = backend_->db()->GetRowForURL(url, &row);
@@ -1302,13 +1301,13 @@
   backend_->DeleteAllHistory();
 
   // Visit a typed URL with a redirect.
-  backend_->AddPageVisit(url1, base::Time::Now(), 0,
-      ui::PAGE_TRANSITION_TYPED,
-      history::SOURCE_BROWSED);
-  backend_->AddPageVisit(url2, base::Time::Now(), 0,
-      ui::PageTransitionFromInt(
-          ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_CLIENT_REDIRECT),
-      history::SOURCE_BROWSED);
+  backend_->AddPageVisit(url1, base::Time::Now(), 0, ui::PAGE_TRANSITION_TYPED,
+                         false, history::SOURCE_BROWSED);
+  backend_->AddPageVisit(
+      url2, base::Time::Now(), 0,
+      ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                ui::PAGE_TRANSITION_CLIENT_REDIRECT),
+      false, history::SOURCE_BROWSED);
 
   // Ensure the redirected URL does not count as typed.
   VisitVector visits;
@@ -1319,12 +1318,12 @@
   EXPECT_EQ(1, row.visit_count());
 
   // Visit the redirected url again via back/forward.
-  backend_->AddPageVisit(url2, base::Time::Now(), 0,
-      ui::PageTransitionFromInt(
-          ui::PAGE_TRANSITION_TYPED |
-          ui::PAGE_TRANSITION_FORWARD_BACK |
-          ui::PAGE_TRANSITION_CLIENT_REDIRECT),
-      history::SOURCE_BROWSED);
+  backend_->AddPageVisit(
+      url2, base::Time::Now(), 0,
+      ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                ui::PAGE_TRANSITION_FORWARD_BACK |
+                                ui::PAGE_TRANSITION_CLIENT_REDIRECT),
+      false, history::SOURCE_BROWSED);
 
   // Ensure the typed count is still 1 but the visit count is 2.
   id = backend_->db()->GetRowForURL(url2, &row);
@@ -1342,17 +1341,14 @@
   backend_->DeleteAllHistory();
 
   // Assume visiting the url from an externsion.
-  backend_->AddPageVisit(
-      url, base::Time::Now(), 0, ui::PAGE_TRANSITION_TYPED,
-      history::SOURCE_EXTENSION);
+  backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_TYPED,
+                         false, history::SOURCE_EXTENSION);
   // Assume the url is imported from Firefox.
-  backend_->AddPageVisit(url, base::Time::Now(), 0,
-                         ui::PAGE_TRANSITION_TYPED,
-                         history::SOURCE_FIREFOX_IMPORTED);
+  backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_TYPED,
+                         false, history::SOURCE_FIREFOX_IMPORTED);
   // Assume this url is also synced.
-  backend_->AddPageVisit(url, base::Time::Now(), 0,
-                         ui::PAGE_TRANSITION_TYPED,
-                         history::SOURCE_SYNCED);
+  backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_TYPED,
+                         false, history::SOURCE_SYNCED);
 
   // Fetch the row information about the url from history db.
   VisitVector visits;
@@ -1396,17 +1392,19 @@
   base::Time older_time = recent_time - visit_age;
 
   // Visit the url with recent time.
-  backend_->AddPageVisit(url, recent_time, 0,
+  backend_->AddPageVisit(
+      url, recent_time, 0,
       ui::PageTransitionFromInt(
           ui::PageTransitionGetQualifier(ui::PAGE_TRANSITION_TYPED)),
-      history::SOURCE_BROWSED);
+      false, history::SOURCE_BROWSED);
 
   // Add to the url a visit with older time (could be syncing from another
   // client, etc.).
-  backend_->AddPageVisit(url, older_time, 0,
+  backend_->AddPageVisit(
+      url, older_time, 0,
       ui::PageTransitionFromInt(
           ui::PageTransitionGetQualifier(ui::PAGE_TRANSITION_TYPED)),
-      history::SOURCE_SYNCED);
+      false, history::SOURCE_SYNCED);
 
   // Fetch the row information about url from history db.
   VisitVector visits;
@@ -1431,12 +1429,11 @@
   ClearBroadcastedNotifications();
 
   // Visit two distinct URLs, the second one twice.
-  backend_->AddPageVisit(url1, base::Time::Now(), 0,
-                         ui::PAGE_TRANSITION_LINK,
-                         history::SOURCE_BROWSED);
+  backend_->AddPageVisit(url1, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
+                         false, history::SOURCE_BROWSED);
   for (int i = 0; i < 2; ++i) {
     backend_->AddPageVisit(url2, base::Time::Now(), 0,
-                           ui::PAGE_TRANSITION_TYPED,
+                           ui::PAGE_TRANSITION_TYPED, false,
                            history::SOURCE_BROWSED);
   }
 
@@ -1471,18 +1468,18 @@
   // Assume this page is browsed by user.
   HistoryAddPageArgs request1(url, base::Time::Now(), nullptr, 0, GURL(),
                               history::RedirectList(),
-                              ui::PAGE_TRANSITION_KEYWORD_GENERATED,
+                              ui::PAGE_TRANSITION_KEYWORD_GENERATED, false,
                               history::SOURCE_BROWSED, false, true);
   backend_->AddPage(request1);
   // Assume this page is synced.
   HistoryAddPageArgs request2(url, base::Time::Now(), nullptr, 0, GURL(),
                               history::RedirectList(), ui::PAGE_TRANSITION_LINK,
-                              history::SOURCE_SYNCED, false, true);
+                              false, history::SOURCE_SYNCED, false, true);
   backend_->AddPage(request2);
   // Assume this page is browsed again.
   HistoryAddPageArgs request3(
       url, base::Time::Now(), nullptr, 0, GURL(), history::RedirectList(),
-      ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, false, true);
+      ui::PAGE_TRANSITION_TYPED, false, history::SOURCE_BROWSED, false, true);
   backend_->AddPage(request3);
 
   // Three visits should be added with proper sources.
@@ -1885,7 +1882,7 @@
   HistoryAddPageArgs request(
       client_redirect_url, base::Time::Now(), nullptr, 0, GURL(),
       /*redirects=*/{server_redirect_url, client_redirect_url},
-      ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, false, true);
+      ui::PAGE_TRANSITION_TYPED, false, history::SOURCE_BROWSED, false, true);
   backend_->AddPage(request);
 
   // Client redirect to page C (non-user initiated).
@@ -3260,7 +3257,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CHAIN_START |
                                   ui::PAGE_TRANSITION_CHAIN_END),
-        history::SOURCE_BROWSED);
+        false, history::SOURCE_BROWSED);
   }
 
   EXPECT_THAT(backend_->TopHosts(3),
@@ -3279,7 +3276,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CHAIN_START |
                                   ui::PAGE_TRANSITION_CHAIN_END),
-        history::SOURCE_BROWSED);
+        false, history::SOURCE_BROWSED);
   }
 
   EXPECT_THAT(backend_->TopHosts(3), ElementsAre(std::make_pair("cnn.com", 3)));
@@ -3296,7 +3293,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CHAIN_START |
                                   ui::PAGE_TRANSITION_CHAIN_END),
-        history::SOURCE_BROWSED);
+        false, history::SOURCE_BROWSED);
   }
 
   EXPECT_THAT(backend_->TopHosts(3),
@@ -3315,7 +3312,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CHAIN_START |
                                   ui::PAGE_TRANSITION_CHAIN_END),
-        history::SOURCE_BROWSED);
+        false, history::SOURCE_BROWSED);
   }
   backend_->AddPageVisit(
       GURL("http://www.oracle.com/"),
@@ -3323,7 +3320,7 @@
       ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                 ui::PAGE_TRANSITION_CHAIN_START |
                                 ui::PAGE_TRANSITION_CHAIN_END),
-      history::SOURCE_BROWSED);
+      false, history::SOURCE_BROWSED);
 
   EXPECT_THAT(backend_->TopHosts(3),
               ElementsAre(std::make_pair("cnn.com", 2),
@@ -3344,7 +3341,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CHAIN_START |
                                   ui::PAGE_TRANSITION_CHAIN_END),
-        history::SOURCE_BROWSED);
+        false, history::SOURCE_BROWSED);
   }
 
   EXPECT_THAT(backend_->TopHosts(2),
@@ -3369,7 +3366,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CHAIN_START |
                                   ui::PAGE_TRANSITION_CHAIN_END),
-        history::SOURCE_BROWSED);
+        false, history::SOURCE_BROWSED);
   }
 
   EXPECT_THAT(backend_->TopHosts(5), ElementsAre(std::make_pair("cnn.com", 3)));
@@ -3399,7 +3396,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CHAIN_START |
                                   ui::PAGE_TRANSITION_CHAIN_END),
-        history::SOURCE_BROWSED);
+        false, history::SOURCE_BROWSED);
   }
 
   EXPECT_EQ(kMaxTopHosts,
@@ -3427,7 +3424,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CHAIN_START |
                                   ui::PAGE_TRANSITION_CHAIN_END),
-        history::SOURCE_BROWSED);
+        false, history::SOURCE_BROWSED);
   }
 
   // Compute host_ranks_ for RecordTopHostsMetrics.
@@ -3441,7 +3438,7 @@
   urls.push_back(GURL("http://www.unipresse.com/"));
   for (const GURL& url : urls) {
     backend_->AddPageVisit(url, base::Time::Now(), 0,
-                           ui::PAGE_TRANSITION_CHAIN_END,
+                           ui::PAGE_TRANSITION_CHAIN_END, false,
                            history::SOURCE_BROWSED);
   }
 
@@ -3456,17 +3453,23 @@
   base::Time last_week = now - base::TimeDelta::FromDays(7);
 
   backend_->AddPageVisit(GURL("http://cnn.com/intl"), yesterday, 0,
-                         ui::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED);
+                         ui::PAGE_TRANSITION_LINK, false,
+                         history::SOURCE_BROWSED);
   backend_->AddPageVisit(GURL("http://cnn.com/us"), last_week, 0,
-                         ui::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED);
+                         ui::PAGE_TRANSITION_LINK, false,
+                         history::SOURCE_BROWSED);
   backend_->AddPageVisit(GURL("http://cnn.com/ny"), now, 0,
-                         ui::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED);
+                         ui::PAGE_TRANSITION_LINK, false,
+                         history::SOURCE_BROWSED);
   backend_->AddPageVisit(GURL("https://cnn.com/intl"), yesterday, 0,
-                         ui::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED);
+                         ui::PAGE_TRANSITION_LINK, false,
+                         history::SOURCE_BROWSED);
   backend_->AddPageVisit(GURL("http://cnn.com:8080/path"), yesterday, 0,
-                         ui::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED);
+                         ui::PAGE_TRANSITION_LINK, false,
+                         history::SOURCE_BROWSED);
   backend_->AddPageVisit(GURL("http://dogtopia.com/pups?q=poods"), now, 0,
-                         ui::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED);
+                         ui::PAGE_TRANSITION_LINK, false,
+                         history::SOURCE_BROWSED);
 
   std::set<GURL> origins;
   origins.insert(GURL("http://cnn.com/"));
@@ -3479,7 +3482,8 @@
   origins.insert(GURL("https://cnn.com/"));
   origins.insert(GURL("http://notpresent.com/"));
   backend_->AddPageVisit(GURL("http://cnn.com/"), tomorrow, 0,
-                         ui::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED);
+                         ui::PAGE_TRANSITION_LINK, false,
+                         history::SOURCE_BROWSED);
 
   EXPECT_THAT(
       backend_->GetCountsAndLastVisitForOrigins(origins),
diff --git a/components/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc
index 5144310..f613fe2 100644
--- a/components/history/core/browser/history_service.cc
+++ b/components/history/core/browser/history_service.cc
@@ -53,6 +53,7 @@
 #include "components/sync/model/sync_error_factory.h"
 #include "components/variations/variations_associated_data.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/page_transition_types.h"
 
 #if defined(OS_IOS)
 #include "base/critical_closure.h"
@@ -380,8 +381,9 @@
                              bool did_replace_entry) {
   DCHECK(thread_checker_.CalledOnValidThread());
   AddPage(HistoryAddPageArgs(url, time, context_id, nav_entry_id, referrer,
-                             redirects, transition, visit_source,
-                             did_replace_entry, true));
+                             redirects, transition,
+                             !ui::PageTransitionIsMainFrame(transition),
+                             visit_source, did_replace_entry, true));
 }
 
 void HistoryService::AddPage(const GURL& url,
@@ -389,8 +391,8 @@
                              VisitSource visit_source) {
   DCHECK(thread_checker_.CalledOnValidThread());
   AddPage(HistoryAddPageArgs(url, time, nullptr, 0, GURL(), RedirectList(),
-                             ui::PAGE_TRANSITION_LINK, visit_source, false,
-                             true));
+                             ui::PAGE_TRANSITION_LINK, false, visit_source,
+                             false, true));
 }
 
 void HistoryService::AddPage(const HistoryAddPageArgs& add_page_args) {
diff --git a/components/history/core/browser/history_types.cc b/components/history/core/browser/history_types.cc
index 76b4423..50ce78b 100644
--- a/components/history/core/browser/history_types.cc
+++ b/components/history/core/browser/history_types.cc
@@ -261,10 +261,10 @@
                          GURL(),
                          RedirectList(),
                          ui::PAGE_TRANSITION_LINK,
+                         false,
                          SOURCE_BROWSED,
                          false,
-                         true) {
-}
+                         true) {}
 
 HistoryAddPageArgs::HistoryAddPageArgs(const GURL& url,
                                        base::Time time,
@@ -273,6 +273,7 @@
                                        const GURL& referrer,
                                        const RedirectList& redirects,
                                        ui::PageTransition transition,
+                                       bool hidden,
                                        VisitSource source,
                                        bool did_replace_entry,
                                        bool consider_for_ntp_most_visited)
@@ -283,10 +284,10 @@
       referrer(referrer),
       redirects(redirects),
       transition(transition),
+      hidden(hidden),
       visit_source(source),
       did_replace_entry(did_replace_entry),
-      consider_for_ntp_most_visited(consider_for_ntp_most_visited) {
-}
+      consider_for_ntp_most_visited(consider_for_ntp_most_visited) {}
 
 HistoryAddPageArgs::HistoryAddPageArgs(const HistoryAddPageArgs& other) =
     default;
diff --git a/components/history/core/browser/history_types.h b/components/history/core/browser/history_types.h
index f8c020c..4f9c2cd 100644
--- a/components/history/core/browser/history_types.h
+++ b/components/history/core/browser/history_types.h
@@ -361,7 +361,7 @@
   //   HistoryAddPageArgs(
   //       GURL(), base::Time(), NULL, 0, GURL(),
   //       RedirectList(), ui::PAGE_TRANSITION_LINK,
-  //       SOURCE_BROWSED, false, true)
+  //       false, SOURCE_BROWSED, false, true)
   HistoryAddPageArgs();
   HistoryAddPageArgs(const GURL& url,
                      base::Time time,
@@ -370,6 +370,7 @@
                      const GURL& referrer,
                      const RedirectList& redirects,
                      ui::PageTransition transition,
+                     bool hidden,
                      VisitSource source,
                      bool did_replace_entry,
                      bool consider_for_ntp_most_visited);
@@ -383,6 +384,7 @@
   GURL referrer;
   RedirectList redirects;
   ui::PageTransition transition;
+  bool hidden;
   VisitSource visit_source;
   bool did_replace_entry;
   // Specifies whether a page visit should contribute to the Most Visited tiles
diff --git a/components/history/core/browser/web_history_service.cc b/components/history/core/browser/web_history_service.cc
index 199ed0e..f1a3937 100644
--- a/components/history/core/browser/web_history_service.cc
+++ b/components/history/core/browser/web_history_service.cc
@@ -391,7 +391,7 @@
   if (request->GetResponseCode() == net::HTTP_OK) {
     std::unique_ptr<base::Value> value =
         base::JSONReader::Read(request->GetResponseBody());
-    if (value.get() && value.get()->IsType(base::Value::Type::DICTIONARY))
+    if (value.get() && value.get()->is_dict())
       result.reset(static_cast<base::DictionaryValue*>(value.release()));
     else
       DLOG(WARNING) << "Non-JSON response received from history server.";
diff --git a/components/json_schema/json_schema_validator.cc b/components/json_schema/json_schema_validator.cc
index 080f4d7..c5f260fe 100644
--- a/components/json_schema/json_schema_validator.cc
+++ b/components/json_schema/json_schema_validator.cc
@@ -172,9 +172,8 @@
     }
 
     // Integer can be converted to double.
-    if (!(it.value().IsType(entry->type) ||
-          (it.value().IsType(base::Value::Type::INTEGER) &&
-           entry->type == base::Value::Type::DOUBLE))) {
+    if (!(it.value().type() == entry->type ||
+          (it.value().is_int() && entry->type == base::Value::Type::DOUBLE))) {
       *error = base::StringPrintf("Invalid value for %s attribute",
                                   it.key().c_str());
       return false;
@@ -182,7 +181,7 @@
 
     // base::Value::Type::INTEGER attributes must be >= 0.
     // This applies to "minItems", "maxItems", "minLength" and "maxLength".
-    if (it.value().IsType(base::Value::Type::INTEGER)) {
+    if (it.value().is_int()) {
       int integer_value;
       it.value().GetAsInteger(&integer_value);
       if (integer_value < 0) {
@@ -563,8 +562,7 @@
 
       case base::Value::Type::INTEGER:
       case base::Value::Type::DOUBLE:
-        if (instance->IsType(base::Value::Type::INTEGER) ||
-            instance->IsType(base::Value::Type::DOUBLE)) {
+        if (instance->is_int() || instance->is_double()) {
           if (GetNumberValue(choice) == GetNumberValue(instance))
             return;
         }
diff --git a/components/json_schema/json_schema_validator_unittest_base.cc b/components/json_schema/json_schema_validator_unittest_base.cc
index 15e6f76..a4097bf 100644
--- a/components/json_schema/json_schema_validator_unittest_base.cc
+++ b/components/json_schema/json_schema_validator_unittest_base.cc
@@ -49,7 +49,7 @@
   std::unique_ptr<base::Value> result(LoadValue(filename));
   if (!result.get())
     return nullptr;
-  if (!result->IsType(type)) {
+  if (result->type() != type) {
     ADD_FAILURE() << "Expected type " << type << ", got: " << result->type();
     return nullptr;
   }
diff --git a/components/nacl/renderer/json_manifest.cc b/components/nacl/renderer/json_manifest.cc
index dda3933..8b4e5b9 100644
--- a/components/nacl/renderer/json_manifest.cc
+++ b/components/nacl/renderer/json_manifest.cc
@@ -200,7 +200,7 @@
   // URL was already verified above by IsValidDictionary to be required.
   url_dict->GetWithoutPathExpansion(kUrlKey, &url);
   DCHECK(url);
-  if (!url->IsType(base::Value::Type::STRING)) {
+  if (!url->is_string()) {
     std::stringstream error_stream;
     error_stream << parent_key << " property '" << container_key
                  << "' has non-string value '" << *url << "' for key '"
@@ -212,7 +212,7 @@
     const base::Value* opt_level = nullptr;
     url_dict->GetWithoutPathExpansion(kOptLevelKey, &opt_level);
     DCHECK(opt_level);
-    if (!opt_level->IsType(base::Value::Type::INTEGER)) {
+    if (!opt_level->is_int()) {
       std::stringstream error_stream;
       error_stream << parent_key << " property '" << container_key
                    << "' has non-numeric value '" << *opt_level << "' for key '"
diff --git a/components/ntp_tiles/constants.cc b/components/ntp_tiles/constants.cc
index fa8303ca..e70d5d9 100644
--- a/components/ntp_tiles/constants.cc
+++ b/components/ntp_tiles/constants.cc
@@ -4,9 +4,7 @@
 
 #include "components/ntp_tiles/constants.h"
 
-#include "base/command_line.h"
 #include "base/feature_list.h"
-#include "components/ntp_tiles/switches.h"
 
 namespace ntp_tiles {
 
@@ -21,18 +19,4 @@
 const base::Feature kSiteExplorationUiFeature{
     "SiteExplorationUi", base::FEATURE_DISABLED_BY_DEFAULT};
 
-bool AreNtpMostLikelyFaviconsFromServerEnabled() {
-  // Check if the experimental flag is forced on or off.
-  base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
-  if (cmdline->HasSwitch(switches::kEnableNtpMostLikelyFaviconsFromServer)) {
-    return true;
-  }
-  if (cmdline->HasSwitch(switches::kDisableNtpMostLikelyFaviconsFromServer)) {
-    return false;
-  }
-
-  // Check if the finch experiment is turned on.
-  return base::FeatureList::IsEnabled(kNtpMostLikelyFaviconsFromServerFeature);
-}
-
 }  // namespace ntp_tiles
diff --git a/components/ntp_tiles/constants.h b/components/ntp_tiles/constants.h
index 2899e78..1789ba4 100644
--- a/components/ntp_tiles/constants.h
+++ b/components/ntp_tiles/constants.h
@@ -26,12 +26,6 @@
 // Feature to provide site exploration tiles in addition to personal tiles.
 extern const base::Feature kSiteExplorationUiFeature;
 
-// Use this to find out whether the kNtpMostLikelyFaviconsFromServerFeature is
-// enabled. This helper function abstracts iOS special way to override the
-// feature (via command-line params).
-// TODO(jkrcal): Remove once crbug.com/718926 is fixed.
-bool AreNtpMostLikelyFaviconsFromServerEnabled();
-
 }  // namespace ntp_tiles
 
 #endif  // COMPONENTS_NTP_TILES_CONSTANTS_H_
diff --git a/components/ntp_tiles/most_visited_sites.cc b/components/ntp_tiles/most_visited_sites.cc
index 8a564fc..2722ce9 100644
--- a/components/ntp_tiles/most_visited_sites.cc
+++ b/components/ntp_tiles/most_visited_sites.cc
@@ -354,11 +354,9 @@
     tile.favicon_url = GURL(suggestion_pb.favicon_url());
     tile.data_generation_time = profile_timestamp;
 
-    if (AreNtpMostLikelyFaviconsFromServerEnabled()) {
-      icon_cacher_->StartFetchMostLikely(
-          url, base::Bind(&MostVisitedSites::OnIconMadeAvailable,
-                          base::Unretained(this), url));
-    }
+    icon_cacher_->StartFetchMostLikely(
+        url, base::Bind(&MostVisitedSites::OnIconMadeAvailable,
+                        base::Unretained(this), url));
 
     tiles.push_back(std::move(tile));
   }
diff --git a/components/ntp_tiles/most_visited_sites_unittest.cc b/components/ntp_tiles/most_visited_sites_unittest.cc
index 0eb3012..f6f3e9b 100644
--- a/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -461,6 +461,8 @@
           .Times(AtLeast(0));
     }
 
+    EXPECT_CALL(*icon_cacher, StartFetchMostLikely(_, _)).Times(AtLeast(0));
+
     most_visited_sites_ = base::MakeUnique<MostVisitedSites>(
         &pref_service_, mock_top_sites_, &mock_suggestions_service_,
         popular_sites_factory_.New(), std::move(icon_cacher),
diff --git a/components/ntp_tiles/switches.cc b/components/ntp_tiles/switches.cc
index bd1ca44..9ae60506 100644
--- a/components/ntp_tiles/switches.cc
+++ b/components/ntp_tiles/switches.cc
@@ -18,15 +18,5 @@
 // Disables showing popular sites on the NTP.
 const char kDisableNTPPopularSites[] = "disable-ntp-popular-sites";
 
-// Enables the new Google favicon server for fetching favicons for Most Likely
-// tiles on the New Tab Page.
-const char kEnableNtpMostLikelyFaviconsFromServer[] =
-    "enable-ntp-most-likely-favicons-from-server";
-
-// Disables the new Google favicon server for fetching favicons for Most Likely
-// tiles on the New Tab Page.
-const char kDisableNtpMostLikelyFaviconsFromServer[] =
-    "disable-ntp-most-likely-favicons-from-server";
-
 }  // namespace switches
 }  // namespace ntp_tiles
diff --git a/components/ntp_tiles/switches.h b/components/ntp_tiles/switches.h
index 799d417..2405e7d1 100644
--- a/components/ntp_tiles/switches.h
+++ b/components/ntp_tiles/switches.h
@@ -13,11 +13,6 @@
 extern const char kEnableNTPPopularSites[];
 extern const char kDisableNTPPopularSites[];
 
-// These switches are only introduced to allow iOS to override a feature.
-// TODO(jkrcal): Remove once crbug.com/718926 is fixed.
-extern const char kEnableNtpMostLikelyFaviconsFromServer[];
-extern const char kDisableNtpMostLikelyFaviconsFromServer[];
-
 }  // namespace switches
 }  // namespace ntp_tiles
 
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/WebAppManifestSection.java b/components/payments/content/android/java/src/org/chromium/components/payments/WebAppManifestSection.java
index ccff536..e21c7ba 100644
--- a/components/payments/content/android/java/src/org/chromium/components/payments/WebAppManifestSection.java
+++ b/components/payments/content/android/java/src/org/chromium/components/payments/WebAppManifestSection.java
@@ -4,8 +4,6 @@
 
 package org.chromium.components.payments;
 
-import java.util.Arrays;
-
 /** Java equivalent of components/payments/content/web_app_manifest_section.h */
 public final class WebAppManifestSection {
     /**
@@ -19,7 +17,7 @@
     public WebAppManifestSection(String id, long minVersion, int numberOfFingerprints) {
         this.id = id;
         this.minVersion = minVersion;
-        fingerprints = new byte[numberOfFingerprints][];
+        this.fingerprints = new byte[numberOfFingerprints][];
     }
 
     /**
@@ -32,8 +30,7 @@
     public WebAppManifestSection(String id, long minVersion, byte[][] fingerprints) {
         this.id = id;
         this.minVersion = minVersion;
-        // Copy the array so FindBugs does not complain of exposing private data.
-        this.fingerprints = Arrays.copyOf(fingerprints, fingerprints.length);
+        this.fingerprints = fingerprints;
     }
 
     /** The {@link String} representing the package name of the app. */
diff --git a/components/policy/core/browser/configuration_policy_handler.cc b/components/policy/core/browser/configuration_policy_handler.cc
index 2af07c1..8ca7635 100644
--- a/components/policy/core/browser/configuration_policy_handler.cc
+++ b/components/policy/core/browser/configuration_policy_handler.cc
@@ -69,7 +69,7 @@
                                                  PolicyErrorMap* errors,
                                                  const base::Value** value) {
   *value = policies.GetValue(policy_name_);
-  if (*value && !(*value)->IsType(value_type_)) {
+  if (*value && (*value)->type() != value_type_) {
     errors->AddError(policy_name_, IDS_POLICY_TYPE_ERROR,
                      base::Value::GetTypeName(value_type_));
     return false;
diff --git a/components/policy/core/browser/proxy_policy_handler.cc b/components/policy/core/browser/proxy_policy_handler.cc
index 1cbfed4..09b39b3 100644
--- a/components/policy/core/browser/proxy_policy_handler.cc
+++ b/components/policy/core/browser/proxy_policy_handler.cc
@@ -222,10 +222,8 @@
 
   const base::Value* policy_value = nullptr;
   std::string tmp;
-  if (!settings->Get(policy_name, &policy_value) ||
-      policy_value->IsType(base::Value::Type::NONE) ||
-      (policy_value->IsType(base::Value::Type::STRING) &&
-       policy_value->GetAsString(&tmp) &&
+  if (!settings->Get(policy_name, &policy_value) || policy_value->is_none() ||
+      (policy_value->is_string() && policy_value->GetAsString(&tmp) &&
        tmp.empty())) {
     return nullptr;
   }
diff --git a/components/policy/core/browser/url_blacklist_policy_handler.cc b/components/policy/core/browser/url_blacklist_policy_handler.cc
index c8d0514..62d615c 100644
--- a/components/policy/core/browser/url_blacklist_policy_handler.cc
+++ b/components/policy/core/browser/url_blacklist_policy_handler.cc
@@ -27,12 +27,12 @@
       policies.GetValue(key::kDisabledSchemes);
   const base::Value* url_blacklist = policies.GetValue(key::kURLBlacklist);
 
-  if (disabled_schemes && !disabled_schemes->IsType(base::Value::Type::LIST)) {
+  if (disabled_schemes && !disabled_schemes->is_list()) {
     errors->AddError(key::kDisabledSchemes, IDS_POLICY_TYPE_ERROR,
                      base::Value::GetTypeName(base::Value::Type::LIST));
   }
 
-  if (url_blacklist && !url_blacklist->IsType(base::Value::Type::LIST)) {
+  if (url_blacklist && !url_blacklist->is_list()) {
     errors->AddError(key::kURLBlacklist, IDS_POLICY_TYPE_ERROR,
                      base::Value::GetTypeName(base::Value::Type::LIST));
   }
@@ -69,7 +69,7 @@
 
   if (url_blacklist) {
     for (const auto& entry : *url_blacklist) {
-      if (entry.IsType(base::Value::Type::STRING))
+      if (entry.is_string())
         merged_url_blacklist->Append(entry.CreateDeepCopy());
     }
   }
diff --git a/components/policy/core/common/registry_dict.cc b/components/policy/core/common/registry_dict.cc
index f591cb6..d2b1d6c9 100644
--- a/components/policy/core/common/registry_dict.cc
+++ b/components/policy/core/common/registry_dict.cc
@@ -42,7 +42,7 @@
     return value.CreateDeepCopy();
 
   // If the type is good already, go with it.
-  if (value.IsType(schema.type())) {
+  if (value.type() == schema.type()) {
     // Recurse for complex types.
     const base::DictionaryValue* dict = nullptr;
     const base::ListValue* list = nullptr;
@@ -129,7 +129,7 @@
       if (value.GetAsString(&string_value)) {
         std::unique_ptr<base::Value> result =
             base::JSONReader::Read(string_value);
-        if (result && result->IsType(schema.type()))
+        if (result && result->type() == schema.type())
           return result;
       }
       break;
diff --git a/components/policy/core/common/schema.cc b/components/policy/core/common/schema.cc
index 4cd6ed6..3f2e27e 100644
--- a/components/policy/core/common/schema.cc
+++ b/components/policy/core/common/schema.cc
@@ -782,11 +782,10 @@
     return false;
   }
 
-  if (!value.IsType(type())) {
+  if (value.type() != type()) {
     // Allow the integer to double promotion. Note that range restriction on
     // double is not supported now.
-    if (value.IsType(base::Value::Type::INTEGER) &&
-        type() == base::Value::Type::DOUBLE) {
+    if (value.is_int() && type() == base::Value::Type::DOUBLE) {
       return true;
     }
 
@@ -861,11 +860,10 @@
     return false;
   }
 
-  if (!value->IsType(type())) {
+  if (value->type() != type()) {
     // Allow the integer to double promotion. Note that range restriction on
     // double is not supported now.
-    if (value->IsType(base::Value::Type::INTEGER) &&
-        type() == base::Value::Type::DOUBLE) {
+    if (value->is_int() && type() == base::Value::Type::DOUBLE) {
       return true;
     }
 
diff --git a/components/policy/proto/BUILD.gn b/components/policy/proto/BUILD.gn
index 7d6cb62..a7039ac9 100644
--- a/components/policy/proto/BUILD.gn
+++ b/components/policy/proto/BUILD.gn
@@ -23,7 +23,10 @@
   ]
 
   if (is_chromeos) {
-    sources += [ "chrome_device_policy.proto" ]
+    sources += [
+      "chrome_device_policy.proto",
+      "install_attributes.proto",
+    ]
   }
 
   if (!is_android && !is_ios) {
diff --git a/chrome/browser/chromeos/policy/proto/install_attributes.proto b/components/policy/proto/install_attributes.proto
similarity index 100%
rename from chrome/browser/chromeos/policy/proto/install_attributes.proto
rename to components/policy/proto/install_attributes.proto
diff --git a/components/prefs/json_pref_store.cc b/components/prefs/json_pref_store.cc
index 31280be..1db24d2 100644
--- a/components/prefs/json_pref_store.cc
+++ b/components/prefs/json_pref_store.cc
@@ -90,7 +90,7 @@
                            : PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
     }
   }
-  if (!value->IsType(base::Value::Type::DICTIONARY))
+  if (!value->is_dict())
     return PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
   return PersistentPrefStore::PREF_READ_ERROR_NONE;
 }
diff --git a/components/prefs/overlay_user_pref_store_unittest.cc b/components/prefs/overlay_user_pref_store_unittest.cc
index 9dbb60cf..b5813b40 100644
--- a/components/prefs/overlay_user_pref_store_unittest.cc
+++ b/components/prefs/overlay_user_pref_store_unittest.cc
@@ -137,19 +137,19 @@
   Value* modify = nullptr;
   EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modify));
   ASSERT_TRUE(modify);
-  ASSERT_TRUE(modify->IsType(Value::Type::DICTIONARY));
+  ASSERT_TRUE(modify->is_dict());
   static_cast<DictionaryValue*>(modify)->SetInteger(overlay_key, 42);
 
   Value* original_in_underlay = nullptr;
   EXPECT_TRUE(underlay_->GetMutableValue(overlay_key, &original_in_underlay));
   ASSERT_TRUE(original_in_underlay);
-  ASSERT_TRUE(original_in_underlay->IsType(Value::Type::DICTIONARY));
+  ASSERT_TRUE(original_in_underlay->is_dict());
   EXPECT_TRUE(static_cast<DictionaryValue*>(original_in_underlay)->empty());
 
   Value* modified = nullptr;
   EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modified));
   ASSERT_TRUE(modified);
-  ASSERT_TRUE(modified->IsType(Value::Type::DICTIONARY));
+  ASSERT_TRUE(modified->is_dict());
   EXPECT_EQ(*modify, *modified);
 }
 
diff --git a/components/prefs/pref_member.cc b/components/prefs/pref_member.cc
index a66cbb2..59917510 100644
--- a/components/prefs/pref_member.cc
+++ b/components/prefs/pref_member.cc
@@ -128,7 +128,7 @@
 
 bool PrefMemberVectorStringUpdate(const base::Value& value,
                                   std::vector<std::string>* string_vector) {
-  if (!value.IsType(base::Value::Type::LIST))
+  if (!value.is_list())
     return false;
   const base::ListValue* list = static_cast<const base::ListValue*>(&value);
 
diff --git a/components/prefs/pref_registry.cc b/components/prefs/pref_registry.cc
index 57bce7a..ede32e0 100644
--- a/components/prefs/pref_registry.cc
+++ b/components/prefs/pref_registry.cc
@@ -42,7 +42,7 @@
   const base::Value* current_value = nullptr;
   DCHECK(defaults_->GetValue(pref_name, &current_value))
       << "Setting default for unregistered pref: " << pref_name;
-  DCHECK(value.IsType(current_value->type()))
+  DCHECK(value.type() == current_value->type())
       << "Wrong type for new default: " << pref_name;
 
   defaults_->ReplaceDefaultValue(
diff --git a/components/prefs/pref_service.cc b/components/prefs/pref_service.cc
index 3142af1..d14046b 100644
--- a/components/prefs/pref_service.cc
+++ b/components/prefs/pref_service.cc
@@ -317,7 +317,7 @@
   if (!user_pref_store_->GetMutableValue(path, &value))
     return nullptr;
 
-  if (!value->IsType(pref->GetType())) {
+  if (value->type() != pref->GetType()) {
     NOTREACHED() << "Pref value type doesn't match registered type.";
     return nullptr;
   }
@@ -489,7 +489,7 @@
   // exist or isn't the correct type, create a new user preference.
   base::Value* value = nullptr;
   if (!user_pref_store_->GetMutableValue(path, &value) ||
-      !value->IsType(type)) {
+      value->type() != type) {
     if (type == base::Value::Type::DICTIONARY) {
       value = new base::DictionaryValue;
     } else if (type == base::Value::Type::LIST) {
@@ -572,7 +572,7 @@
 
   const base::Value* found_value = nullptr;
   if (pref_value_store()->GetRecommendedValue(name_, type_, &found_value)) {
-    DCHECK(found_value->IsType(type_));
+    DCHECK(found_value->type() == type_);
     return found_value;
   }
 
@@ -636,7 +636,7 @@
     const base::Value* found_value = nullptr;
     base::Value::Type default_type = default_value->type();
     if (pref_value_store_->GetValue(path, default_type, &found_value)) {
-      DCHECK(found_value->IsType(default_type));
+      DCHECK(found_value->type() == default_type);
       return found_value;
     } else {
       // Every registered preference has at least a default value.
diff --git a/components/prefs/pref_value_store.cc b/components/prefs/pref_value_store.cc
index bf1c3dd7..3b80325 100644
--- a/components/prefs/pref_value_store.cc
+++ b/components/prefs/pref_value_store.cc
@@ -261,7 +261,7 @@
     PrefStoreType store,
     const base::Value** out_value) const {
   if (GetValueFromStore(name, store, out_value)) {
-    if ((*out_value)->IsType(type))
+    if ((*out_value)->type() == type)
       return true;
 
     LOG(WARNING) << "Expected type for " << name << " is " << type
diff --git a/components/printing/browser/BUILD.gn b/components/printing/browser/BUILD.gn
index 154e7736..d910171 100644
--- a/components/printing/browser/BUILD.gn
+++ b/components/printing/browser/BUILD.gn
@@ -20,7 +20,6 @@
     "//base",
     "//components/printing/common",
     "//components/printing/service/public/cpp:client",
-    "//mojo/public/cpp/system:system",
     "//printing",
     "//services/service_manager/public/cpp",
   ]
diff --git a/components/printing/browser/print_composite_client.cc b/components/printing/browser/print_composite_client.cc
index e105223..167cdee 100644
--- a/components/printing/browser/print_composite_client.cc
+++ b/components/printing/browser/print_composite_client.cc
@@ -10,7 +10,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/service_manager_connection.h"
-#include "mojo/public/cpp/system/platform_handle.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintCompositeClient);
@@ -42,38 +41,4 @@
             base::ThreadTaskRunnerHandle::Get());
 }
 
-std::unique_ptr<base::SharedMemory> PrintCompositeClient::GetShmFromMojoHandle(
-    mojo::ScopedSharedBufferHandle handle) {
-  base::SharedMemoryHandle memory_handle;
-  size_t memory_size = 0;
-  bool read_only_flag = false;
-
-  const MojoResult result = mojo::UnwrapSharedMemoryHandle(
-      std::move(handle), &memory_handle, &memory_size, &read_only_flag);
-  if (result != MOJO_RESULT_OK)
-    return nullptr;
-  DCHECK_GT(memory_size, 0u);
-
-  std::unique_ptr<base::SharedMemory> shm =
-      base::MakeUnique<base::SharedMemory>(memory_handle, true /* read_only */);
-  if (!shm->Map(memory_size)) {
-    DLOG(ERROR) << "Map shared memory failed.";
-    return nullptr;
-  }
-  return shm;
-}
-
-scoped_refptr<base::RefCountedBytes>
-PrintCompositeClient::GetDataFromMojoHandle(
-    mojo::ScopedSharedBufferHandle handle) {
-  std::unique_ptr<base::SharedMemory> shm =
-      GetShmFromMojoHandle(std::move(handle));
-  if (!shm)
-    return nullptr;
-
-  return base::MakeRefCounted<base::RefCountedBytes>(
-      reinterpret_cast<const unsigned char*>(shm->memory()),
-      shm->mapped_size());
-}
-
 }  // namespace printing
diff --git a/components/printing/browser/print_composite_client.h b/components/printing/browser/print_composite_client.h
index d63b341..e157eb3 100644
--- a/components/printing/browser/print_composite_client.h
+++ b/components/printing/browser/print_composite_client.h
@@ -5,9 +5,6 @@
 #ifndef COMPONENTS_PRINTING_BROWSER_PRINT_COMPOSITE_CLIENT_H_
 #define COMPONENTS_PRINTING_BROWSER_PRINT_COMPOSITE_CLIENT_H_
 
-#include "base/memory/ref_counted_memory.h"
-#include "base/memory/shared_memory.h"
-#include "base/memory/shared_memory_handle.h"
 #include "components/printing/service/public/cpp/pdf_compositor_client.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
@@ -28,12 +25,6 @@
   void set_for_preview(bool for_preview) { for_preview_ = for_preview; }
   bool for_preview() const { return for_preview_; }
 
-  // Utility functions.
-  static std::unique_ptr<base::SharedMemory> GetShmFromMojoHandle(
-      mojo::ScopedSharedBufferHandle handle);
-  static scoped_refptr<base::RefCountedBytes> GetDataFromMojoHandle(
-      mojo::ScopedSharedBufferHandle handle);
-
  private:
   void CreateConnectorRequest();
 
diff --git a/components/printing/service/BUILD.gn b/components/printing/service/BUILD.gn
index 32bdd44..4043453 100644
--- a/components/printing/service/BUILD.gn
+++ b/components/printing/service/BUILD.gn
@@ -27,6 +27,7 @@
   ]
 
   public_deps = [
+    "//components/printing/service/public/cpp:utils",
     "//components/printing/service/public/interfaces",
     "//services/service_manager/public/cpp",
   ]
diff --git a/components/printing/service/pdf_compositor_impl.cc b/components/printing/service/pdf_compositor_impl.cc
index c22998a..212514a 100644
--- a/components/printing/service/pdf_compositor_impl.cc
+++ b/components/printing/service/pdf_compositor_impl.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/memory/shared_memory.h"
 #include "base/memory/shared_memory_handle.h"
+#include "components/printing/service/public/cpp/pdf_service_mojo_utils.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "printing/common/pdf_metafile_utils.h"
 #include "third_party/skia/include/core/SkCanvas.h"
@@ -30,25 +31,10 @@
     mojom::PdfCompositor::CompositePdfCallback callback) {
   DCHECK(sk_handle.is_valid());
 
-  base::SharedMemoryHandle memory_handle;
-  size_t memory_size = 0;
-  bool read_only_flag = false;
-
-  const MojoResult result = mojo::UnwrapSharedMemoryHandle(
-      std::move(sk_handle), &memory_handle, &memory_size, &read_only_flag);
-  DCHECK_EQ(MOJO_RESULT_OK, result);
-  DCHECK_GT(memory_size, 0u);
-
   std::unique_ptr<base::SharedMemory> shm =
-      base::MakeUnique<base::SharedMemory>(memory_handle, true);
-  if (!shm->Map(memory_size)) {
-    DLOG(ERROR) << "CompositePdf: Shared memory map failed.";
-    std::move(callback).Run(mojom::PdfCompositor::Status::HANDLE_MAP_ERROR,
-                            mojo::ScopedSharedBufferHandle());
-    return;
-  }
+      GetShmFromMojoHandle(std::move(sk_handle));
 
-  SkMemoryStream stream(shm->memory(), memory_size);
+  SkMemoryStream stream(shm->memory(), shm->mapped_size());
   int page_count = SkMultiPictureDocumentReadPageCount(&stream);
   if (!page_count) {
     DLOG(ERROR) << "CompositePdf: No page is read.";
diff --git a/components/printing/service/pdf_compositor_service_unittest.cc b/components/printing/service/pdf_compositor_service_unittest.cc
index 0e16cea..3b15e55 100644
--- a/components/printing/service/pdf_compositor_service_unittest.cc
+++ b/components/printing/service/pdf_compositor_service_unittest.cc
@@ -161,19 +161,11 @@
 
 // Test callback is called on error conditions in service.
 TEST_F(PdfCompositorServiceTest, InvokeCallbackOnContentError) {
-  auto handle = LoadFileInSharedMemory();
-  ASSERT_TRUE(handle.IsValid());
-  mojo::ScopedSharedBufferHandle buffer_handle =
-      mojo::WrapSharedMemoryHandle(handle, 10, true);
-  // The size of mapped area is not equal to the original buffer,
-  // so the content is invalid.
-  ASSERT_LT(10u, handle.GetSize());
-  ASSERT_TRUE(buffer_handle->is_valid());
   EXPECT_CALL(*this, CallbackOnError(
                          mojom::PdfCompositor::Status::CONTENT_FORMAT_ERROR))
       .Times(1);
   compositor_->CompositePdf(
-      std::move(buffer_handle),
+      mojo::SharedBufferHandle::Create(10),
       base::BindOnce(&PdfCompositorServiceTest::OnCallback,
                      base::Unretained(this)));
   run_loop_->Run();
diff --git a/components/printing/service/public/cpp/BUILD.gn b/components/printing/service/public/cpp/BUILD.gn
index f0c9b84..83110a4 100644
--- a/components/printing/service/public/cpp/BUILD.gn
+++ b/components/printing/service/public/cpp/BUILD.gn
@@ -33,3 +33,14 @@
     "//services/service_manager/public/cpp",
   ]
 }
+
+source_set("utils") {
+  sources = [
+    "pdf_service_mojo_utils.cc",
+    "pdf_service_mojo_utils.h",
+  ]
+
+  public_deps = [
+    "//mojo/public/cpp/system:system",
+  ]
+}
diff --git a/components/printing/service/public/cpp/pdf_service_mojo_utils.cc b/components/printing/service/public/cpp/pdf_service_mojo_utils.cc
new file mode 100644
index 0000000..f5f6c89
--- /dev/null
+++ b/components/printing/service/public/cpp/pdf_service_mojo_utils.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 "components/printing/service/public/cpp/pdf_service_mojo_utils.h"
+
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/shared_memory.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace printing {
+
+std::unique_ptr<base::SharedMemory> GetShmFromMojoHandle(
+    mojo::ScopedSharedBufferHandle handle) {
+  base::SharedMemoryHandle memory_handle;
+  size_t memory_size = 0;
+  bool read_only_flag = false;
+
+  const MojoResult result = mojo::UnwrapSharedMemoryHandle(
+      std::move(handle), &memory_handle, &memory_size, &read_only_flag);
+  if (result != MOJO_RESULT_OK)
+    return nullptr;
+  DCHECK_GT(memory_size, 0u);
+
+  std::unique_ptr<base::SharedMemory> shm =
+      std::make_unique<base::SharedMemory>(memory_handle, read_only_flag);
+  if (!shm->Map(memory_size)) {
+    DLOG(ERROR) << "Map shared memory failed.";
+    return nullptr;
+  }
+  return shm;
+}
+
+scoped_refptr<base::RefCountedBytes> GetDataFromMojoHandle(
+    mojo::ScopedSharedBufferHandle handle) {
+  std::unique_ptr<base::SharedMemory> shm =
+      GetShmFromMojoHandle(std::move(handle));
+  if (!shm)
+    return nullptr;
+
+  return base::MakeRefCounted<base::RefCountedBytes>(
+      reinterpret_cast<const unsigned char*>(shm->memory()),
+      shm->mapped_size());
+}
+
+}  // namespace printing
diff --git a/components/printing/service/public/cpp/pdf_service_mojo_utils.h b/components/printing/service/public/cpp/pdf_service_mojo_utils.h
new file mode 100644
index 0000000..11a2ebe
--- /dev/null
+++ b/components/printing/service/public/cpp/pdf_service_mojo_utils.h
@@ -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.
+
+#ifndef COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_SERVICE_MOJO_UTILS_H_
+#define COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_SERVICE_MOJO_UTILS_H_
+
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
+#include "mojo/public/cpp/system/buffer.h"
+
+namespace base {
+class RefCountedBytes;
+class SharedMemory;
+}  // namespace base
+
+namespace printing {
+
+std::unique_ptr<base::SharedMemory> GetShmFromMojoHandle(
+    mojo::ScopedSharedBufferHandle handle);
+
+scoped_refptr<base::RefCountedBytes> GetDataFromMojoHandle(
+    mojo::ScopedSharedBufferHandle handle);
+
+}  // namespace printing
+
+#endif  // COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_SERVICE_MOJO_UTILS_H_
diff --git a/components/proximity_auth/messenger_impl.cc b/components/proximity_auth/messenger_impl.cc
index c3cc5c67..a4d88a2f 100644
--- a/components/proximity_auth/messenger_impl.cc
+++ b/components/proximity_auth/messenger_impl.cc
@@ -175,7 +175,7 @@
   // The decoded message should be a JSON string.
   std::unique_ptr<base::Value> message_value =
       base::JSONReader::Read(decoded_message);
-  if (!message_value || !message_value->IsType(base::Value::Type::DICTIONARY)) {
+  if (!message_value || !message_value->is_dict()) {
     PA_LOG(ERROR) << "Unable to parse message as JSON:\n" << decoded_message;
     return;
   }
diff --git a/components/safe_browsing/android/safe_browsing_api_handler_util.cc b/components/safe_browsing/android/safe_browsing_api_handler_util.cc
index 05664cb..9a9b1e85 100644
--- a/components/safe_browsing/android/safe_browsing_api_handler_util.cc
+++ b/components/safe_browsing/android/safe_browsing_api_handler_util.cc
@@ -204,7 +204,7 @@
   // Pick out the "matches" list.
   std::unique_ptr<base::Value> value = base::JSONReader::Read(metadata_str);
   const base::ListValue* matches = nullptr;
-  if (!value.get() || !value->IsType(base::Value::Type::DICTIONARY) ||
+  if (!value.get() || !value->is_dict() ||
       !(static_cast<base::DictionaryValue*>(value.get()))
            ->GetList(kJsonKeyMatches, &matches) ||
       !matches) {
diff --git a/components/search_engines/default_search_policy_handler.cc b/components/search_engines/default_search_policy_handler.cc
index 0436f6a..cee0cb28 100644
--- a/components/search_engines/default_search_policy_handler.cc
+++ b/components/search_engines/default_search_policy_handler.cc
@@ -209,7 +209,7 @@
     // It's important to check policy type for all policies and not just exit on
     // the first error, so we report all policy errors.
     const base::Value* value = policies.GetValue(policy_map_entry.policy_name);
-    if (value && !value->IsType(policy_map_entry.value_type)) {
+    if (value && value->type() != policy_map_entry.value_type) {
       errors->AddError(policy_map_entry.policy_name, IDS_POLICY_TYPE_ERROR,
                        base::Value::GetTypeName(policy_map_entry.value_type));
       all_ok = false;
diff --git a/components/spellcheck/browser/spelling_service_client.cc b/components/spellcheck/browser/spelling_service_client.cc
index ba69bdd..0556741 100644
--- a/components/spellcheck/browser/spelling_service_client.cc
+++ b/components/spellcheck/browser/spelling_service_client.cc
@@ -232,7 +232,7 @@
       static_cast<base::DictionaryValue*>(
           base::JSONReader::Read(data, base::JSON_ALLOW_TRAILING_COMMAS)
               .release()));
-  if (!value.get() || !value->IsType(base::Value::Type::DICTIONARY))
+  if (!value.get() || !value->is_dict())
     return false;
 
   // Check for errors from spelling service.
diff --git a/components/sync/syncable/model_type.cc b/components/sync/syncable/model_type.cc
index 1449f80e..e67fdac 100644
--- a/components/sync/syncable/model_type.cc
+++ b/components/sync/syncable/model_type.cc
@@ -496,12 +496,12 @@
 }
 
 ModelType ModelTypeFromValue(const base::Value& value) {
-  if (value.IsType(base::Value::Type::STRING)) {
+  if (value.is_string()) {
     std::string result;
     bool success = value.GetAsString(&result);
     DCHECK(success);
     return ModelTypeFromString(result);
-  } else if (value.IsType(base::Value::Type::INTEGER)) {
+  } else if (value.is_int()) {
     int result = 0;
     bool success = value.GetAsInteger(&result);
     DCHECK(success);
diff --git a/components/sync_preferences/pref_model_associator.cc b/components/sync_preferences/pref_model_associator.cc
index 44eac42f..89420a9 100644
--- a/components/sync_preferences/pref_model_associator.cc
+++ b/components/sync_preferences/pref_model_associator.cc
@@ -103,10 +103,10 @@
       // Update the local preference based on what we got from the
       // sync server. Note: this only updates the user value store, which is
       // ignored if the preference is policy controlled.
-      if (new_value->IsType(base::Value::Type::NONE)) {
+      if (new_value->is_none()) {
         LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str();
         pref_service_->ClearPref(pref_name);
-      } else if (!new_value->IsType(user_pref_value->type())) {
+      } else if (new_value->type() != user_pref_value->type()) {
         LOG(WARNING) << "Synced value for " << preference.name()
                      << " is of type " << new_value->type()
                      << " which doesn't match pref type "
@@ -126,7 +126,7 @@
         sync_changes->push_back(syncer::SyncChange(
             FROM_HERE, syncer::SyncChange::ACTION_UPDATE, sync_data));
       }
-    } else if (!sync_value->IsType(base::Value::Type::NONE)) {
+    } else if (!sync_value->is_none()) {
       // Only a server value exists. Just set the local user value.
       pref_service_->Set(pref_name, *sync_value);
     } else {
@@ -255,7 +255,7 @@
     const std::string& name,
     const base::Value& value,
     syncer::SyncData* sync_data) const {
-  if (value.IsType(base::Value::Type::NONE)) {
+  if (value.is_none()) {
     LOG(ERROR) << "Attempting to sync a null pref value for " << name;
     return false;
   }
@@ -282,9 +282,9 @@
 std::unique_ptr<base::Value> PrefModelAssociator::MergeListValues(
     const base::Value& from_value,
     const base::Value& to_value) {
-  if (from_value.type() == base::Value::Type::NONE)
+  if (from_value.is_none())
     return base::Value::ToUniquePtrValue(to_value.Clone());
-  if (to_value.type() == base::Value::Type::NONE)
+  if (to_value.is_none())
     return base::Value::ToUniquePtrValue(from_value.Clone());
 
   DCHECK(from_value.type() == base::Value::Type::LIST);
diff --git a/components/tracing/common/trace_config_file.cc b/components/tracing/common/trace_config_file.cc
index 993d68c..3193bb91 100644
--- a/components/tracing/common/trace_config_file.cc
+++ b/components/tracing/common/trace_config_file.cc
@@ -97,7 +97,7 @@
 
 bool TraceConfigFile::ParseTraceConfigFileContent(const std::string& content) {
   std::unique_ptr<base::Value> value(base::JSONReader::Read(content));
-  if (!value || !value->IsType(base::Value::Type::DICTIONARY))
+  if (!value || !value->is_dict())
     return false;
 
   std::unique_ptr<base::DictionaryValue> dict(
diff --git a/components/translate/core/browser/translate_language_list.cc b/components/translate/core/browser/translate_language_list.cc
index 20b9a51..45eaab8 100644
--- a/components/translate/core/browser/translate_language_list.cc
+++ b/components/translate/core/browser/translate_language_list.cc
@@ -294,8 +294,7 @@
   std::unique_ptr<base::Value> json_value =
       base::JSONReader::Read(language_list, base::JSON_ALLOW_TRAILING_COMMAS);
 
-  if (json_value == nullptr ||
-      !json_value->IsType(base::Value::Type::DICTIONARY)) {
+  if (!json_value || !json_value->is_dict()) {
     NotifyEvent(__LINE__, "Language list is invalid");
     NOTREACHED();
     return false;
diff --git a/components/update_client/component_patcher.cc b/components/update_client/component_patcher.cc
index e4ea386..81aa9f5 100644
--- a/components/update_client/component_patcher.cc
+++ b/components/update_client/component_patcher.cc
@@ -38,7 +38,7 @@
   std::unique_ptr<base::Value> root =
       deserializer.Deserialize(nullptr, nullptr);
 
-  return (root.get() && root->IsType(base::Value::Type::LIST))
+  return (root.get() && root->is_list())
              ? static_cast<base::ListValue*>(root.release())
              : nullptr;
 }
diff --git a/components/update_client/utils.cc b/components/update_client/utils.cc
index cd3321b..c200deff 100644
--- a/components/update_client/utils.cc
+++ b/components/update_client/utils.cc
@@ -245,7 +245,7 @@
   std::unique_ptr<base::Value> root = deserializer.Deserialize(nullptr, &error);
   if (!root.get())
     return std::unique_ptr<base::DictionaryValue>();
-  if (!root->IsType(base::Value::Type::DICTIONARY))
+  if (!root->is_dict())
     return std::unique_ptr<base::DictionaryValue>();
   return std::unique_ptr<base::DictionaryValue>(
       static_cast<base::DictionaryValue*>(root.release()));
diff --git a/components/viz/service/display/bsp_tree_perftest.cc b/components/viz/service/display/bsp_tree_perftest.cc
index 2fe59ae..6978507 100644
--- a/components/viz/service/display/bsp_tree_perftest.cc
+++ b/components/viz/service/display/bsp_tree_perftest.cc
@@ -145,41 +145,41 @@
 TEST_F(BspTreePerfTest, LayerSorterCubes) {
   SetTestName("layer_sort_cubes");
   ReadTestFile("layer_sort_cubes");
-  RunTest(cc::CompositorMode::SINGLE_THREADED, false);
+  RunTest(cc::CompositorMode::SINGLE_THREADED);
 }
 
 TEST_F(BspTreePerfTest, LayerSorterRubik) {
   SetTestName("layer_sort_rubik");
   ReadTestFile("layer_sort_rubik");
-  RunTest(cc::CompositorMode::SINGLE_THREADED, false);
+  RunTest(cc::CompositorMode::SINGLE_THREADED);
 }
 
 TEST_F(BspTreePerfTest, BspTreeCubes) {
   SetTestName("bsp_tree_cubes");
   SetNumberOfDuplicates(1);
   ReadTestFile("layer_sort_cubes");
-  RunTest(cc::CompositorMode::SINGLE_THREADED, false);
+  RunTest(cc::CompositorMode::SINGLE_THREADED);
 }
 
 TEST_F(BspTreePerfTest, BspTreeRubik) {
   SetTestName("bsp_tree_rubik");
   SetNumberOfDuplicates(1);
   ReadTestFile("layer_sort_rubik");
-  RunTest(cc::CompositorMode::SINGLE_THREADED, false);
+  RunTest(cc::CompositorMode::SINGLE_THREADED);
 }
 
 TEST_F(BspTreePerfTest, BspTreeCubes_2) {
   SetTestName("bsp_tree_cubes_2");
   SetNumberOfDuplicates(2);
   ReadTestFile("layer_sort_cubes");
-  RunTest(cc::CompositorMode::SINGLE_THREADED, false);
+  RunTest(cc::CompositorMode::SINGLE_THREADED);
 }
 
 TEST_F(BspTreePerfTest, BspTreeCubes_4) {
   SetTestName("bsp_tree_cubes_4");
   SetNumberOfDuplicates(4);
   ReadTestFile("layer_sort_cubes");
-  RunTest(cc::CompositorMode::SINGLE_THREADED, false);
+  RunTest(cc::CompositorMode::SINGLE_THREADED);
 }
 
 }  // namespace
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index 852e4c6..74121de 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -536,7 +536,8 @@
     if (pass != frame->render_pass_list.back())
       continue;
 
-    for (auto quad = pass->quad_list.begin(); quad != pass->quad_list.end();) {
+    auto last_quad = pass->quad_list.end();
+    for (auto quad = pass->quad_list.begin(); quad != last_quad;) {
       // RenderPassDrawQuad is a special type of DrawQuad where the visible_rect
       // of shared quad state is not entirely covered by draw quads in it.
       if (quad->material == ContentDrawQuadBase::Material::RENDER_PASS) {
diff --git a/components/webcrypto/algorithms/test_helpers.cc b/components/webcrypto/algorithms/test_helpers.cc
index 7bd4c40d..c3bdd2b 100644
--- a/components/webcrypto/algorithms/test_helpers.cc
+++ b/components/webcrypto/algorithms/test_helpers.cc
@@ -391,7 +391,7 @@
                                 json.size());
   std::unique_ptr<base::Value> value = base::JSONReader::Read(json_string);
   EXPECT_TRUE(value.get());
-  EXPECT_TRUE(value->IsType(base::Value::Type::DICTIONARY));
+  EXPECT_TRUE(value->is_dict());
 
   return std::unique_ptr<base::DictionaryValue>(
       static_cast<base::DictionaryValue*>(value.release()));
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc
index d5ec2e9..68c24b5 100644
--- a/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -82,31 +82,6 @@
   *called = true;
 }
 
-void DispatchSyncSuccessfulCallback(
-    int* count,
-    const scoped_refptr<ServiceWorkerVersion>& active_version,
-    const ServiceWorkerVersion::LegacyStatusCallback& callback) {
-  *count += 1;
-  callback.Run(SERVICE_WORKER_OK);
-}
-
-void DispatchSyncFailedCallback(
-    int* count,
-    const scoped_refptr<ServiceWorkerVersion>& active_version,
-    const ServiceWorkerVersion::LegacyStatusCallback& callback) {
-  *count += 1;
-  callback.Run(SERVICE_WORKER_ERROR_FAILED);
-}
-
-void DispatchSyncDelayedCallback(
-    int* count,
-    ServiceWorkerVersion::LegacyStatusCallback* out_callback,
-    const scoped_refptr<ServiceWorkerVersion>& active_version,
-    const ServiceWorkerVersion::LegacyStatusCallback& callback) {
-  *count += 1;
-  *out_callback = callback;
-}
-
 }  // namespace
 
 class BackgroundSyncManagerTest : public testing::Test {
@@ -380,32 +355,49 @@
     SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
   }
 
+  void DispatchSyncStatusCallback(
+      ServiceWorkerStatusCode status,
+      scoped_refptr<ServiceWorkerVersion> active_version,
+      ServiceWorkerVersion::StatusCallback callback) {
+    sync_events_called_++;
+    std::move(callback).Run(status);
+  }
+
   void InitSyncEventTest() {
-    SetupForSyncEvent(base::BindRepeating(DispatchSyncSuccessfulCallback,
-                                          &sync_events_called_));
+    SetupForSyncEvent(base::BindRepeating(
+        &BackgroundSyncManagerTest::DispatchSyncStatusCallback,
+        base::Unretained(this), SERVICE_WORKER_OK));
   }
 
   void InitFailedSyncEventTest() {
-    SetupForSyncEvent(
-        base::BindRepeating(DispatchSyncFailedCallback, &sync_events_called_));
+    SetupForSyncEvent(base::BindRepeating(
+        &BackgroundSyncManagerTest::DispatchSyncStatusCallback,
+        base::Unretained(this), SERVICE_WORKER_ERROR_FAILED));
+  }
+
+  void DispatchSyncDelayedCallback(
+      scoped_refptr<ServiceWorkerVersion> active_version,
+      ServiceWorkerVersion::StatusCallback callback) {
+    sync_events_called_++;
+    sync_fired_callback_ = std::move(callback);
   }
 
   void InitDelayedSyncEventTest() {
-    SetupForSyncEvent(base::BindRepeating(DispatchSyncDelayedCallback,
-                                          &sync_events_called_,
-                                          &sync_fired_callback_));
+    SetupForSyncEvent(base::BindRepeating(
+        &BackgroundSyncManagerTest::DispatchSyncDelayedCallback,
+        base::Unretained(this)));
   }
 
   void RegisterAndVerifySyncEventDelayed(
       const BackgroundSyncRegistrationOptions& sync_options) {
     int sync_events_called = sync_events_called_;
-    EXPECT_TRUE(sync_fired_callback_.is_null());
+    EXPECT_FALSE(sync_fired_callback_);
 
     EXPECT_TRUE(Register(sync_options));
 
     EXPECT_EQ(sync_events_called + 1, sync_events_called_);
     EXPECT_TRUE(GetRegistration(sync_options_1_));
-    EXPECT_FALSE(sync_fired_callback_.is_null());
+    EXPECT_TRUE(sync_fired_callback_);
   }
 
   void DeleteServiceWorkerAndStartOver() {
@@ -447,7 +439,7 @@
       callback_registrations_;
   ServiceWorkerStatusCode callback_sw_status_code_ = SERVICE_WORKER_OK;
   int sync_events_called_ = 0;
-  ServiceWorkerVersion::LegacyStatusCallback sync_fired_callback_;
+  ServiceWorkerVersion::StatusCallback sync_fired_callback_;
 };
 
 TEST_F(BackgroundSyncManagerTest, Register) {
@@ -832,12 +824,14 @@
   EXPECT_TRUE(Register(sync_options_1_));
 
   // The first sync attempt fails.
-  sync_fired_callback_.Run(SERVICE_WORKER_ERROR_FAILED);
+  ASSERT_TRUE(sync_fired_callback_);
+  std::move(sync_fired_callback_).Run(SERVICE_WORKER_ERROR_FAILED);
   base::RunLoop().RunUntilIdle();
 
   // It should fire again since it was reregistered mid-sync.
   EXPECT_TRUE(GetRegistration(sync_options_1_));
-  sync_fired_callback_.Run(SERVICE_WORKER_OK);
+  ASSERT_TRUE(sync_fired_callback_);
+  std::move(sync_fired_callback_).Run(SERVICE_WORKER_OK);
   EXPECT_FALSE(GetRegistration(sync_options_1_));
 }
 
@@ -849,12 +843,14 @@
   EXPECT_TRUE(Register(sync_options_1_));
 
   // The first sync event succeeds.
-  sync_fired_callback_.Run(SERVICE_WORKER_OK);
+  ASSERT_TRUE(sync_fired_callback_);
+  std::move(sync_fired_callback_).Run(SERVICE_WORKER_OK);
   base::RunLoop().RunUntilIdle();
 
   // It should fire again since it was reregistered mid-sync.
   EXPECT_TRUE(GetRegistration(sync_options_1_));
-  sync_fired_callback_.Run(SERVICE_WORKER_OK);
+  ASSERT_TRUE(sync_fired_callback_);
+  std::move(sync_fired_callback_).Run(SERVICE_WORKER_OK);
   EXPECT_FALSE(GetRegistration(sync_options_1_));
 }
 
@@ -907,7 +903,8 @@
 
   // Successfully complete the firing event. We can't verify that it actually
   // completed but at least we can test that it doesn't crash.
-  sync_fired_callback_.Run(SERVICE_WORKER_OK);
+  ASSERT_TRUE(sync_fired_callback_);
+  std::move(sync_fired_callback_).Run(SERVICE_WORKER_OK);
   base::RunLoop().RunUntilIdle();
 }
 
@@ -995,7 +992,8 @@
   RegisterAndVerifySyncEventDelayed(sync_options_1_);
 
   // Finish firing the event and verify that the registration is removed.
-  sync_fired_callback_.Run(SERVICE_WORKER_OK);
+  ASSERT_TRUE(sync_fired_callback_);
+  std::move(sync_fired_callback_).Run(SERVICE_WORKER_OK);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1, sync_events_called_);
   EXPECT_FALSE(GetRegistration(sync_options_1_));
@@ -1007,7 +1005,8 @@
   RegisterAndVerifySyncEventDelayed(sync_options_1_);
 
   test_background_sync_manager_->set_corrupt_backend(true);
-  sync_fired_callback_.Run(SERVICE_WORKER_OK);
+  ASSERT_TRUE(sync_fired_callback_);
+  std::move(sync_fired_callback_).Run(SERVICE_WORKER_OK);
   base::RunLoop().RunUntilIdle();
 
   // The backend should now be disabled because it couldn't unregister the
@@ -1023,7 +1022,8 @@
   RegisterAndVerifySyncEventDelayed(sync_options_1_);
   UnregisterServiceWorker(sw_registration_id_1_);
 
-  sync_fired_callback_.Run(SERVICE_WORKER_OK);
+  ASSERT_TRUE(sync_fired_callback_);
+  std::move(sync_fired_callback_).Run(SERVICE_WORKER_OK);
 
   // The backend isn't disabled, but the first service worker registration is
   // gone.
@@ -1161,7 +1161,8 @@
                 GetController()->run_in_background_min_ms()));
 
   // Finish the sync.
-  sync_fired_callback_.Run(SERVICE_WORKER_OK);
+  ASSERT_TRUE(sync_fired_callback_);
+  std::move(sync_fired_callback_).Run(SERVICE_WORKER_OK);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(GetController()->run_in_background_enabled());
 }
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc
index ba8c45a..f7ac86c 100644
--- a/content/browser/frame_host/frame_tree.cc
+++ b/content/browser/frame_host/frame_tree.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include <queue>
+#include <set>
 #include <utility>
 
 #include "base/bind.h"
@@ -109,6 +110,7 @@
                               blink::WebTreeScopeType::kDocument,
                               std::string(),
                               std::string(),
+                              false,
                               base::UnguessableToken::Create(),
                               FrameOwnerProperties())),
       focused_frame_tree_node_id_(FrameTreeNode::kFrameTreeNodeInvalidId),
@@ -179,6 +181,7 @@
     blink::WebTreeScopeType scope,
     const std::string& frame_name,
     const std::string& frame_unique_name,
+    bool is_created_by_script,
     const base::UnguessableToken& devtools_frame_token,
     const blink::FramePolicy& frame_policy,
     const FrameOwnerProperties& frame_owner_properties) {
@@ -194,7 +197,8 @@
   std::unique_ptr<FrameTreeNode> new_node = base::WrapUnique(new FrameTreeNode(
       this, parent->navigator(), render_frame_delegate_,
       render_widget_delegate_, manager_delegate_, parent, scope, frame_name,
-      frame_unique_name, devtools_frame_token, frame_owner_properties));
+      frame_unique_name, is_created_by_script, devtools_frame_token,
+      frame_owner_properties));
 
   // Set sandbox flags and container policy and make them effective immediately,
   // since initial sandbox flags and feature policy should apply to the initial
@@ -218,8 +222,10 @@
   // conflicts on future updates.
   NavigationEntryImpl* last_committed_entry = static_cast<NavigationEntryImpl*>(
       parent->navigator()->GetController()->GetLastCommittedEntry());
-  if (last_committed_entry)
-    last_committed_entry->ClearStaleFrameEntriesForNewFrame(added_node);
+  if (last_committed_entry) {
+    last_committed_entry->RemoveEntryForFrame(
+        added_node, /* only_if_different_position = */ true);
+  }
 
   // Now that the new node is part of the FrameTree and has a RenderFrameHost,
   // we can announce the creation of the initial RenderFrame which already
diff --git a/content/browser/frame_host/frame_tree.h b/content/browser/frame_host/frame_tree.h
index e7f3c4e4..889aa00 100644
--- a/content/browser/frame_host/frame_tree.h
+++ b/content/browser/frame_host/frame_tree.h
@@ -138,6 +138,7 @@
                 blink::WebTreeScopeType scope,
                 const std::string& frame_name,
                 const std::string& frame_unique_name,
+                bool is_created_by_script,
                 const base::UnguessableToken& devtools_frame_token,
                 const blink::FramePolicy& frame_policy,
                 const FrameOwnerProperties& frame_owner_properties);
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc
index bb8dc30..6e32f08 100644
--- a/content/browser/frame_host/frame_tree_node.cc
+++ b/content/browser/frame_host/frame_tree_node.cc
@@ -137,6 +137,7 @@
                              blink::WebTreeScopeType scope,
                              const std::string& name,
                              const std::string& unique_name,
+                             bool is_created_by_script,
                              const base::UnguessableToken& devtools_frame_token,
                              const FrameOwnerProperties& frame_owner_properties)
     : frame_tree_(frame_tree),
@@ -158,6 +159,7 @@
           false /* should enforce strict mixed content checking */,
           false /* is a potentially trustworthy unique origin */,
           false /* has received a user gesture */),
+      is_created_by_script_(is_created_by_script),
       devtools_frame_token_(devtools_frame_token),
       frame_owner_properties_(frame_owner_properties),
       loading_progress_(kLoadingProgressNotStarted),
@@ -174,7 +176,22 @@
 }
 
 FrameTreeNode::~FrameTreeNode() {
+  // Remove the children.  See https://crbug.com/612450 for explanation why we
+  // don't just call the std::vector::clear method.
   std::vector<std::unique_ptr<FrameTreeNode>>().swap(children_);
+
+  // If the removed frame was created by a script, then its history entry will
+  // never be reused - we can save some memory by removing the history entry.
+  // See also https://crbug.com/784356.
+  if (is_created_by_script_ && parent_) {
+    NavigationEntryImpl* nav_entry = static_cast<NavigationEntryImpl*>(
+        navigator()->GetController()->GetLastCommittedEntry());
+    if (nav_entry) {
+      nav_entry->RemoveEntryForFrame(this,
+                                     /* only_if_different_position = */ false);
+    }
+  }
+
   frame_tree_->FrameRemoved(this);
   for (auto& observer : observers_)
     observer.OnFrameTreeNodeDestroyed(this);
@@ -515,7 +532,6 @@
     current_frame_host()->Send(
         new FrameMsg_DroppedNavigation(current_frame_host()->GetRoutingID()));
   }
-
 }
 
 bool FrameTreeNode::has_started_loading() const {
diff --git a/content/browser/frame_host/frame_tree_node.h b/content/browser/frame_host/frame_tree_node.h
index 9fa966d..828822f 100644
--- a/content/browser/frame_host/frame_tree_node.h
+++ b/content/browser/frame_host/frame_tree_node.h
@@ -67,6 +67,7 @@
                 blink::WebTreeScopeType scope,
                 const std::string& name,
                 const std::string& unique_name,
+                bool is_created_by_script,
                 const base::UnguessableToken& devtools_frame_token,
                 const FrameOwnerProperties& frame_owner_properties);
 
@@ -418,6 +419,12 @@
   // they take effect on the next frame navigation.
   blink::FramePolicy pending_frame_policy_;
 
+  // Whether the frame was created by javascript.  This is useful to prune
+  // history entries when the frame is removed (because frames created by
+  // scripts are never recreated with the same unique name - see
+  // https://crbug.com/500260).
+  bool is_created_by_script_;
+
   // Used for devtools instrumentation and trace-ability. The token is
   // propagated to Blink's LocalFrame and both Blink and content/
   // can tag calls and requests with this token in order to attribute them
diff --git a/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc b/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
index ae92a09b..1d080003 100644
--- a/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
+++ b/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
@@ -4,6 +4,11 @@
 
 #include "content/browser/frame_host/frame_tree_node_blame_context.h"
 
+#include <algorithm>
+#include <memory>
+#include <set>
+#include <string>
+
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/test/trace_event_analyzer.h"
@@ -135,7 +140,7 @@
           node, process_id(), child_id,
           TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
           blink::WebTreeScopeType::kDocument, std::string(),
-          base::StringPrintf("uniqueName%d", child_id),
+          base::StringPrintf("uniqueName%d", child_id), false,
           base::UnguessableToken::Create(), blink::FramePolicy(),
           FrameOwnerProperties());
       FrameTreeNode* child = node->child_at(child_num - 1);
diff --git a/content/browser/frame_host/frame_tree_unittest.cc b/content/browser/frame_host/frame_tree_unittest.cc
index 8cd072a2..83fa660a 100644
--- a/content/browser/frame_host/frame_tree_unittest.cc
+++ b/content/browser/frame_host/frame_tree_unittest.cc
@@ -165,32 +165,32 @@
   frame_tree->AddFrame(root, process_id, 14,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName0", base::UnguessableToken::Create(),
+                       "uniqueName0", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(root, process_id, 15,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName1", base::UnguessableToken::Create(),
+                       "uniqueName1", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(root, process_id, 16,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName2", base::UnguessableToken::Create(),
+                       "uniqueName2", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(root->child_at(0), process_id, 244,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName3", base::UnguessableToken::Create(),
+                       "uniqueName3", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(root->child_at(1), process_id, 255,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, no_children_node,
-                       "uniqueName4", base::UnguessableToken::Create(),
+                       "uniqueName4", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(root->child_at(0), process_id, 245,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName5", base::UnguessableToken::Create(),
+                       "uniqueName5", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
 
   EXPECT_EQ(
@@ -203,49 +203,49 @@
   frame_tree->AddFrame(child_16, process_id, 264,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName6", base::UnguessableToken::Create(),
+                       "uniqueName6", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_16, process_id, 265,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName7", base::UnguessableToken::Create(),
+                       "uniqueName7", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_16, process_id, 266,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName8", base::UnguessableToken::Create(),
+                       "uniqueName8", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_16, process_id, 267,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, deep_subtree,
-                       "uniqueName9", base::UnguessableToken::Create(),
+                       "uniqueName9", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_16, process_id, 268,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName10", base::UnguessableToken::Create(),
+                       "uniqueName10", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
 
   FrameTreeNode* child_267 = child_16->child_at(3);
   frame_tree->AddFrame(child_267, process_id, 365,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName11", base::UnguessableToken::Create(),
+                       "uniqueName11", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_267->child_at(0), process_id, 455,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName12", base::UnguessableToken::Create(),
+                       "uniqueName12", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_267->child_at(0)->child_at(0), process_id, 555,
                        CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName13", base::UnguessableToken::Create(),
+                       "uniqueName13", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_267->child_at(0)->child_at(0)->child_at(0),
                        process_id, 655, CreateStubInterfaceProviderRequest(),
                        blink::WebTreeScopeType::kDocument, std::string(),
-                       "uniqueName14", base::UnguessableToken::Create(),
+                       "uniqueName14", false, base::UnguessableToken::Create(),
                        blink::FramePolicy(), FrameOwnerProperties());
 
   // Now that's it's fully built, verify the tree structure is as expected.
@@ -319,17 +319,17 @@
 
   main_test_rfh()->OnCreateChildFrame(
       22, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "child0", "uniqueName0",
+      blink::WebTreeScopeType::kDocument, "child0", "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       23, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "child1", "uniqueName1",
+      blink::WebTreeScopeType::kDocument, "child1", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       24, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName2",
+      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName2", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   FrameTreeNode* child0 = root->child_at(0);
@@ -339,7 +339,7 @@
   // Add one grandchild frame.
   child1->current_frame_host()->OnCreateChildFrame(
       33, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "grandchild", "uniqueName3",
+      blink::WebTreeScopeType::kDocument, "grandchild", "uniqueName3", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   FrameTreeNode* grandchild = child1->child_at(0);
@@ -379,17 +379,17 @@
   FrameTreeNode* root = frame_tree->root();
   main_test_rfh()->OnCreateChildFrame(
       22, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "child0", "uniqueName0",
+      blink::WebTreeScopeType::kDocument, "child0", "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       23, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "child1", "uniqueName1",
+      blink::WebTreeScopeType::kDocument, "child1", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       24, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "child2", "uniqueName2",
+      blink::WebTreeScopeType::kDocument, "child2", "uniqueName2", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   FrameTreeNode* child0 = root->child_at(0);
@@ -399,7 +399,7 @@
   // Add one grandchild frame.
   child1->current_frame_host()->OnCreateChildFrame(
       33, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "grandchild", "uniqueName3",
+      blink::WebTreeScopeType::kDocument, "grandchild", "uniqueName3", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   FrameTreeNode* grandchild = child1->child_at(0);
@@ -432,7 +432,7 @@
   // Simulate attaching a series of frames to build the frame tree.
   main_test_rfh()->OnCreateChildFrame(
       14, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0",
+      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   EXPECT_EQ(
@@ -441,7 +441,7 @@
       activity.GetLog());
   main_test_rfh()->OnCreateChildFrame(
       18, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1",
+      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   EXPECT_EQ(
@@ -463,7 +463,7 @@
 
   main_test_rfh()->OnCreateChildFrame(
       22, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0",
+      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   EXPECT_EQ(
@@ -472,7 +472,7 @@
       activity.GetLog());
   main_test_rfh()->OnCreateChildFrame(
       23, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1",
+      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   EXPECT_EQ(
@@ -503,7 +503,7 @@
   // Simulate attaching a frame from mismatched process id.
   ASSERT_FALSE(frame_tree->AddFrame(
       root, process_id + 1, 1, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0",
+      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties()));
   ASSERT_EQ("2: []", GetTreeState(frame_tree));
@@ -519,12 +519,12 @@
 
   main_test_rfh()->OnCreateChildFrame(
       22, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0",
+      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       23, CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1",
+      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
 
@@ -532,7 +532,7 @@
   RenderFrameHostImpl* child1_rfh = root->child_at(0)->current_frame_host();
   child1_rfh->OnCreateChildFrame(33, CreateStubInterfaceProviderRequest(),
                                  blink::WebTreeScopeType::kDocument,
-                                 std::string(), "uniqueName2",
+                                 std::string(), "uniqueName2", false,
                                  base::UnguessableToken::Create(),
                                  blink::FramePolicy(), FrameOwnerProperties());
 
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 2214e77..69cdeea0 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -3041,13 +3041,12 @@
   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   EXPECT_EQ(entry1, controller.GetLastCommittedEntry());
 
-  // The entry should have both the stale FrameNavigationEntry with the old
-  // name and the new FrameNavigationEntry for the fallback navigation.
-  ASSERT_EQ(2U, entry1->root_node()->children.size());
+  // There should be only 1 FNE, because when the child frame is dynamically
+  // created or recreated from javascript, it's FNE will be removed when the
+  // frame is removed.
+  ASSERT_EQ(1U, entry1->root_node()->children.size());
   EXPECT_EQ("data",
             entry1->root_node()->children[0]->frame_entry->url().scheme());
-  EXPECT_EQ("data",
-            entry1->root_node()->children[1]->frame_entry->url().scheme());
 
   // The iframe commit should have been classified AUTO_SUBFRAME and not
   // NEW_SUBFRAME, so we should still be able to go forward.
@@ -3198,19 +3197,16 @@
   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   EXPECT_EQ(entry, controller.GetLastCommittedEntry());
 
-  // There is only 1 child frame in the frame tree, but 2 FNEs, because when the
-  // child frame is dynamically created or recreated from javascript, it will
-  // each time get a fresh, random unique name.
+  // There is only 1 child frame in the frame tree and only 1 FNE, because when
+  // the child frame is dynamically created or recreated from javascript, it's
+  // FNE will be removed when the frame is removed.
   ASSERT_EQ(1U, root->child_count());
-  ASSERT_EQ(2U, entry->root_node()->children.size());
+  ASSERT_EQ(1U, entry->root_node()->children.size());
 
   // The entry should have FrameNavigationEntries for the subframes.
   EXPECT_EQ(blank_url, entry->root_node()->children[0]->frame_entry->url());
   EXPECT_EQ(inner_url,
             entry->root_node()->children[0]->children[0]->frame_entry->url());
-  EXPECT_EQ(blank_url, entry->root_node()->children[1]->frame_entry->url());
-  EXPECT_EQ(inner_url,
-            entry->root_node()->children[1]->children[0]->frame_entry->url());
 
   // With injected about:blank iframes, we never restore form values from
   // PageState.
@@ -3301,19 +3297,16 @@
   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   EXPECT_EQ(entry, controller.GetLastCommittedEntry());
 
-  // There is only 1 child frame in the frame tree, but 2 FNEs, because when the
-  // child frame is dynamically created or recreated from javascript, it will
-  // each time get a fresh, random unique name.
+  // There is only 1 child frame in the frame tree and only 1 FNE, because when
+  // the child frame is dynamically created or recreated from javascript, it's
+  // FNE will be removed when the frame is removed.
   ASSERT_EQ(1U, root->child_count());
-  ASSERT_EQ(2U, entry->root_node()->children.size());
+  ASSERT_EQ(1U, entry->root_node()->children.size());
 
   // The entry should have FrameNavigationEntries for the subframes.
   EXPECT_EQ(srcdoc_url, entry->root_node()->children[0]->frame_entry->url());
   EXPECT_EQ(inner_url,
             entry->root_node()->children[0]->children[0]->frame_entry->url());
-  EXPECT_EQ(srcdoc_url, entry->root_node()->children[1]->frame_entry->url());
-  EXPECT_EQ(inner_url,
-            entry->root_node()->children[1]->children[0]->frame_entry->url());
 
   // With *injected* iframe srcdoc pages, we don't restore form values from
   // PageState (because iframes injected by javascript always get a fresh,
@@ -6087,10 +6080,10 @@
     EXPECT_NE(nullptr, root_entry);
     EXPECT_EQ(3U, entry->root_node()->children.size());
 
-    // Both children of |entry->root_node()->children[0]| should be removed
-    // by NavigationEntryImpl::ClearStaleFrameEntriesForNewFrame, because
-    // both will have colliding unique names (the removed parent and the newly
-    // added frame both load '1-1.html' - which has 2 named framse).
+    // Both children of |entry->root_node()->children[0]| should be removed by
+    // NavigationEntryImpl::RemoveEntryForFrame, because both will have
+    // colliding unique names (the removed parent and the newly added frame both
+    // load '1-1.html' - which has 2 named framse).
     EXPECT_EQ(0U, entry->root_node()->children[0]->children.size());
   }
 }
@@ -6110,15 +6103,16 @@
       web_contents->GetController().GetLastCommittedEntry();
 
   // Add, then remove a named frame. It will create a FrameNavigationEntry
-  // for the name and leave it around.
+  // for the name and remove it (since this is a frame created by script).
   EXPECT_TRUE(ExecuteScript(root, kAddNamedFrameScript));
   EXPECT_EQ(1U, root->child_count());
   EXPECT_EQ(1U, nav_entry->root_node()->children.size());
+  // |tree_node| will becoma a dangling pointer when the frame is removed below.
   auto* tree_node = nav_entry->root_node()->children[0].get();
 
   EXPECT_TRUE(ExecuteScript(root, kRemoveFrameScript));
   EXPECT_EQ(0U, root->child_count());
-  EXPECT_EQ(1U, nav_entry->root_node()->children.size());
+  EXPECT_EQ(0U, nav_entry->root_node()->children.size());
 
   // Add another frame with the same name as before. The matching logic should
   // NOT consider them the same and should NOT result in the
@@ -6126,8 +6120,8 @@
   // will get a fresh, random unique name each time it is created or recreated).
   EXPECT_TRUE(ExecuteScript(root, kAddNamedFrameScript));
   EXPECT_EQ(1U, root->child_count());
-  EXPECT_EQ(2U, nav_entry->root_node()->children.size());
-  EXPECT_EQ(tree_node, nav_entry->root_node()->children[0].get());
+  EXPECT_EQ(1U, nav_entry->root_node()->children.size());
+  EXPECT_NE(tree_node, nav_entry->root_node()->children[0].get());
 
   EXPECT_TRUE(ExecuteScript(root, kRemoveFrameScript));
   EXPECT_EQ(0U, root->child_count());
@@ -7264,6 +7258,141 @@
   EXPECT_THAT(messages, testing::IsEmpty());
 }
 
+// This test helps verify that the browser does not retain history entries
+// for removed frames *if* the removed frame was created by a script.
+// Such frames get a fresh, random, unique name every time they are created
+// or recreated and therefore in such case will never match previous history
+// entries.  See also https://crbug.com/784356.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+                       PruningOfEntriesForDynamicFrames_ChildRemoved) {
+  GURL main_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  // Repeatedly create and remove a frame from a script.
+  std::string result;
+  std::string script = R"(
+        var iterations_left = 5;
+        function runOneIteration() {
+          if (iterations_left == 0) {
+            domAutomationController.send("done-with-test");
+            return;
+          }
+
+          var iframe = document.createElement("iframe");
+          document.body.appendChild(iframe);
+          document.body.removeChild(iframe);
+
+          iterations_left = iterations_left - 1;
+          setTimeout(runOneIteration, 0);
+        }
+        runOneIteration(); )";
+  EXPECT_TRUE(ExecuteScriptAndExtractString(shell(), script, &result));
+  EXPECT_EQ("done-with-test", result);
+
+  // Grab the last committed entry.
+  const NavigationControllerImpl& controller =
+      static_cast<const NavigationControllerImpl&>(
+          shell()->web_contents()->GetController());
+  EXPECT_EQ(1, controller.GetEntryCount());
+  NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(main_url, entry->GetURL());
+
+  // Verify that the number of FrameNavigationEntries stayed low (i.e. that we
+  // do not retain history entries for the 5 frames removed by the test).
+  EXPECT_EQ(0U, entry->root_node()->children.size());
+
+  // Sanity check - there are no children in the frame tree.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  ASSERT_EQ(0U, root->child_count());
+}
+
+// This test helps verify that the browser does not retain history entries
+// for removed frames *if* the removed frame was created by a script.
+// Such frames get a fresh, random, unique name every time they are created
+// or recreated and therefore in such case will never match previous history
+// entries.  See also https://crbug.com/784356.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+                       PruningOfEntriesForDynamicFrames_ParentNavigatedAway) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/navigation_controller/page_with_iframe_simple.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+  const NavigationControllerImpl& controller =
+      static_cast<const NavigationControllerImpl&>(
+          shell()->web_contents()->GetController());
+
+  // Add 5 dynamic subframes to |frame|.
+  RenderFrameHost* frame = shell()->web_contents()->GetAllFrames()[1];
+  std::string script = R"(
+        for (var i = 0; i < 5; i++) {
+          var iframe = document.createElement("iframe");
+          document.body.appendChild(iframe);
+        }; )";
+  EXPECT_TRUE(ExecuteScript(frame, script));
+
+  // Verify that now there are 5 FNEs for the dynamic frames.
+  EXPECT_EQ(1, controller.GetEntryCount());
+  NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(main_url, entry->GetURL());
+  EXPECT_EQ(1U, entry->root_node()->children.size());
+  EXPECT_EQ(5U, entry->root_node()->children[0]->children.size());
+
+  // Navigate |frame| (the parent of the dynamic frames) away.
+  // This will destroy the 5 dynamic children of |frame|.
+  GURL next_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
+  EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "frame", next_url));
+
+  // Verify that there are now 0 FNEs for the dynamic frames.
+  EXPECT_EQ(2, controller.GetEntryCount());
+  EXPECT_EQ(main_url, entry->GetURL());
+  EXPECT_EQ(1U, entry->root_node()->children.size());
+  EXPECT_EQ(0U, entry->root_node()->children[0]->children.size());
+}
+
+// This test helps verify that the browser does not retain history entries
+// for removed frames *if* the removed frame was created by a script.
+// Such frames get a fresh, random, unique name every time they are created
+// or recreated and therefore in such case will never match previous history
+// entries.  See also https://crbug.com/784356.
+IN_PROC_BROWSER_TEST_F(
+    NavigationControllerBrowserTest,
+    PruningOfEntriesForDynamicFrames_MainFrameNavigatedAway) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/navigation_controller/page_with_iframe_simple.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+  const NavigationControllerImpl& controller =
+      static_cast<const NavigationControllerImpl&>(
+          shell()->web_contents()->GetController());
+
+  // Add 5 dynamic subframes to |frame|.
+  RenderFrameHost* frame = shell()->web_contents()->GetAllFrames()[1];
+  std::string script = R"(
+        for (var i = 0; i < 5; i++) {
+          var iframe = document.createElement("iframe");
+          document.body.appendChild(iframe);
+        }; )";
+  EXPECT_TRUE(ExecuteScript(frame, script));
+
+  // Verify that now there are 5 FNEs for the dynamic frames.
+  EXPECT_EQ(1, controller.GetEntryCount());
+  NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(main_url, entry->GetURL());
+  EXPECT_EQ(1U, entry->root_node()->children.size());
+  EXPECT_EQ(5U, entry->root_node()->children[0]->children.size());
+
+  // Navigate the main frame (the grandparent of the dynamic frames) away.
+  // This will destroy the 5 dynamic children of |frame|.
+  GURL next_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), next_url));
+
+  // Verify that there are now 0 FNEs for the dynamic frames.
+  EXPECT_EQ(2, controller.GetEntryCount());
+  EXPECT_EQ(main_url, entry->GetURL());
+  EXPECT_EQ(1U, entry->root_node()->children.size());
+  EXPECT_EQ(0U, entry->root_node()->children[0]->children.size());
+}
+
 // This test reproduces issue 769645. It happens when the user reloads the page
 // and an "unload" event triggers a back navigation. If the reload navigation
 // has reached the ReadyToCommit stage but has not committed, the back
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 1b49409..7024ee4 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <memory>
+#include <string>
 #include <tuple>
 #include <utility>
 
@@ -271,9 +272,8 @@
 
 class TestWebContentsDelegate : public WebContentsDelegate {
  public:
-  explicit TestWebContentsDelegate() :
-      navigation_state_change_count_(0),
-      repost_form_warning_count_(0) {}
+  TestWebContentsDelegate()
+      : navigation_state_change_count_(0), repost_form_warning_count_(0) {}
 
   int navigation_state_change_count() {
     return navigation_state_change_count_;
@@ -675,7 +675,7 @@
 }
 
 void CheckNavigationEntryMatchLoadParams(
-    NavigationController::LoadURLParams& load_params,
+    const NavigationController::LoadURLParams& load_params,
     NavigationEntryImpl* entry) {
   EXPECT_EQ(load_params.url, entry->GetURL());
   EXPECT_EQ(load_params.referrer.url, entry->GetReferrer().url);
@@ -2224,7 +2224,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), unique_name,
+      blink::WebTreeScopeType::kDocument, std::string(), unique_name, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
@@ -2302,7 +2302,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), unique_name0,
+      blink::WebTreeScopeType::kDocument, std::string(), unique_name0, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
@@ -2348,7 +2348,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), unique_name1,
+      blink::WebTreeScopeType::kDocument, std::string(), unique_name1, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   TestRenderFrameHost* subframe2 = static_cast<TestRenderFrameHost*>(
@@ -2394,7 +2394,7 @@
   subframe->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), unique_name2,
+      blink::WebTreeScopeType::kDocument, std::string(), unique_name2, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   TestRenderFrameHost* subframe3 =
@@ -2458,7 +2458,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), unique_name,
+      blink::WebTreeScopeType::kDocument, std::string(), unique_name, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
@@ -2859,8 +2859,7 @@
   }
 }
 
-TEST_F(NavigationControllerTest, PushStateWithoutPreviousEntry)
-{
+TEST_F(NavigationControllerTest, PushStateWithoutPreviousEntry) {
   ASSERT_FALSE(controller_impl().GetLastCommittedEntry());
   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   GURL url("http://foo");
@@ -3867,7 +3866,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), unique_name,
+      blink::WebTreeScopeType::kDocument, std::string(), unique_name, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
@@ -4043,7 +4042,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), unique_name,
+      blink::WebTreeScopeType::kDocument, std::string(), unique_name, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc
index f4ba97c..aadd134 100644
--- a/content/browser/frame_host/navigation_entry_impl.cc
+++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -6,6 +6,9 @@
 
 #include <stddef.h>
 
+#include <algorithm>
+#include <map>
+#include <string>
 #include <utility>
 
 #include "base/containers/queue.h"
@@ -906,44 +909,28 @@
   return names;
 }
 
-void NavigationEntryImpl::ClearStaleFrameEntriesForNewFrame(
-    FrameTreeNode* frame_tree_node) {
+void NavigationEntryImpl::RemoveEntryForFrame(FrameTreeNode* frame_tree_node,
+                                              bool only_if_different_position) {
   DCHECK(!frame_tree_node->IsMainFrame());
 
-  NavigationEntryImpl::TreeNode* node = nullptr;
-  base::queue<NavigationEntryImpl::TreeNode*> work_queue;
-  int count = 0;
+  NavigationEntryImpl::TreeNode* node = GetTreeNode(frame_tree_node);
+  if (!node)
+    return;
 
-  work_queue.push(root_node());
-  while (!work_queue.empty()) {
-    node = work_queue.front();
-    work_queue.pop();
-
-    // Enqueue any children and keep looking if the current node doesn't match.
-    if (!node->MatchesFrame(frame_tree_node)) {
-      for (const auto& child : node->children) {
-        work_queue.push(child.get());
-      }
-      continue;
-    }
-
-    // Remove the node from the tree if it is not in the same position in the
-    // tree of FrameNavigationEntries and the FrameTree.
-    if (!InSameTreePosition(frame_tree_node, node)) {
-      NavigationEntryImpl::TreeNode* parent_node = node->parent;
-      auto it = std::find_if(
-          parent_node->children.begin(), parent_node->children.end(),
-          [node](const std::unique_ptr<NavigationEntryImpl::TreeNode>& item) {
-            return item.get() == node;
-          });
-      CHECK(it != parent_node->children.end());
-      parent_node->children.erase(it);
-    }
-    ++count;
+  // Remove the |node| from the tree if either 1) |only_if_different_position|
+  // was not asked for or 2) if it is not in the same position in the tree of
+  // FrameNavigationEntries and the FrameTree.
+  if (!only_if_different_position ||
+      !InSameTreePosition(frame_tree_node, node)) {
+    NavigationEntryImpl::TreeNode* parent_node = node->parent;
+    auto it = std::find_if(
+        parent_node->children.begin(), parent_node->children.end(),
+        [node](const std::unique_ptr<NavigationEntryImpl::TreeNode>& item) {
+          return item.get() == node;
+        });
+    CHECK(it != parent_node->children.end());
+    parent_node->children.erase(it);
   }
-
-  // At most one match is expected, since it is based on unique frame name.
-  DCHECK_LE(count, 1);
 }
 
 void NavigationEntryImpl::SetScreenshotPNGData(
diff --git a/content/browser/frame_host/navigation_entry_impl.h b/content/browser/frame_host/navigation_entry_impl.h
index ee3362e..fc75a4be 100644
--- a/content/browser/frame_host/navigation_entry_impl.h
+++ b/content/browser/frame_host/navigation_entry_impl.h
@@ -9,6 +9,7 @@
 
 #include <map>
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/macros.h"
@@ -256,7 +257,12 @@
   // |frame_tree_node|, and all of their children. There should be at most one,
   // since collisions are avoided but leave old FrameNavigationEntries in the
   // tree after their frame has been detached.
-  void ClearStaleFrameEntriesForNewFrame(FrameTreeNode* frame_tree_node);
+  //
+  // If |only_if_different_position| is specified, then the removal is only
+  // done if the found FNE is in a different tree position than the
+  // |frame_tree_node|.
+  void RemoveEntryForFrame(FrameTreeNode* frame_tree_node,
+                           bool only_if_different_position);
 
   void set_unique_id(int unique_id) {
     unique_id_ = unique_id;
@@ -413,7 +419,7 @@
     return has_user_gesture_;
   }
 
-  void set_has_user_gesture (bool has_user_gesture) {
+  void set_has_user_gesture(bool has_user_gesture) {
     has_user_gesture_ = has_user_gesture;
   }
 #endif
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 5573f1e..719a7f0 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1322,6 +1322,7 @@
     blink::WebTreeScopeType scope,
     const std::string& frame_name,
     const std::string& frame_unique_name,
+    bool is_created_by_script,
     const base::UnguessableToken& devtools_frame_token,
     const blink::FramePolicy& frame_policy,
     const FrameOwnerProperties& frame_owner_properties) {
@@ -1342,8 +1343,8 @@
   frame_tree_->AddFrame(frame_tree_node_, GetProcess()->GetID(), new_routing_id,
                         std::move(new_interface_provider_provider_request),
                         scope, frame_name, frame_unique_name,
-                        devtools_frame_token, frame_policy,
-                        frame_owner_properties);
+                        is_created_by_script, devtools_frame_token,
+                        frame_policy, frame_owner_properties);
 }
 
 void RenderFrameHostImpl::DidNavigate(
@@ -3108,7 +3109,8 @@
 #if !defined(OS_ANDROID)
   if (base::FeatureList::IsEnabled(features::kWebAuth)) {
     registry_->AddInterface(
-        base::Bind(&AuthenticatorImpl::Create, base::Unretained(this)));
+        base::Bind(&RenderFrameHostImpl::BindAuthenticatorRequest,
+                   base::Unretained(this)));
   }
 #endif  // !defined(OS_ANDROID)
 
@@ -4268,6 +4270,16 @@
   presentation_service_->Bind(std::move(request));
 }
 
+#if !defined(OS_ANDROID)
+void RenderFrameHostImpl::BindAuthenticatorRequest(
+    webauth::mojom::AuthenticatorRequest request) {
+  if (!authenticator_impl_)
+    authenticator_impl_.reset(new AuthenticatorImpl(this));
+
+  authenticator_impl_->Bind(std::move(request));
+}
+#endif
+
 void RenderFrameHostImpl::GetInterface(
     const std::string& interface_name,
     mojo::ScopedMessagePipeHandle interface_pipe) {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index aac32cd3..0995edf 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -59,6 +59,7 @@
 #include "third_party/WebKit/public/platform/WebSuddenTerminationDisablerType.h"
 #include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h"
 #include "third_party/WebKit/public/platform/modules/presentation/presentation.mojom.h"
+#include "third_party/WebKit/public/platform/modules/webauth/authenticator.mojom.h"
 #include "third_party/WebKit/public/web/WebTextDirection.h"
 #include "third_party/WebKit/public/web/WebTreeScopeType.h"
 #include "ui/accessibility/ax_modes.h"
@@ -99,6 +100,7 @@
 namespace content {
 class AssociatedInterfaceProviderImpl;
 class AssociatedInterfaceRegistryImpl;
+class AuthenticatorImpl;
 class LegacyIPCFrameInputHandler;
 class FrameTree;
 class FrameTreeNode;
@@ -288,6 +290,7 @@
                           blink::WebTreeScopeType scope,
                           const std::string& frame_name,
                           const std::string& frame_unique_name,
+                          bool is_created_by_script,
                           const base::UnguessableToken& devtools_frame_token,
                           const blink::FramePolicy& frame_policy,
                           const FrameOwnerProperties& frame_owner_properties);
@@ -978,6 +981,10 @@
   void BindPresentationServiceRequest(
       blink::mojom::PresentationServiceRequest request);
 
+#if !defined(OS_ANDROID)
+  void BindAuthenticatorRequest(webauth::mojom::AuthenticatorRequest request);
+#endif
+
   // service_manager::mojom::InterfaceProvider:
   void GetInterface(const std::string& interface_name,
                     mojo::ScopedMessagePipeHandle interface_pipe) override;
@@ -1320,6 +1327,10 @@
   // Hosts blink::mojom::PresentationService for the RenderFrame.
   std::unique_ptr<PresentationServiceImpl> presentation_service_;
 
+#if !defined(OS_ANDROID)
+  std::unique_ptr<AuthenticatorImpl> authenticator_impl_;
+#endif
+
   std::unique_ptr<AssociatedInterfaceProviderImpl>
       remote_associated_interfaces_;
 
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index 1c94dfaa..3a1a1378 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -6,8 +6,10 @@
 
 #include <stdint.h>
 
+#include <string>
 #include <tuple>
 #include <utility>
+#include <vector>
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -196,21 +198,20 @@
   bool is_closed() { return close_called_; }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(CloseWebContentsDelegate);
-
   bool close_called_;
+
+  DISALLOW_COPY_AND_ASSIGN(CloseWebContentsDelegate);
 };
 
 // This observer keeps track of the last deleted RenderViewHost to avoid
 // accessing it and causing use-after-free condition.
 class RenderViewHostDeletedObserver : public WebContentsObserver {
  public:
-  RenderViewHostDeletedObserver(RenderViewHost* rvh)
+  explicit RenderViewHostDeletedObserver(RenderViewHost* rvh)
       : WebContentsObserver(WebContents::FromRenderViewHost(rvh)),
         process_id_(rvh->GetProcess()->GetID()),
         routing_id_(rvh->GetRoutingID()),
-        deleted_(false) {
-  }
+        deleted_(false) {}
 
   void RenderViewDeleted(RenderViewHost* render_view_host) override {
     if (render_view_host->GetProcess()->GetID() == process_id_ &&
@@ -235,10 +236,8 @@
 // to ensure that no RenderFrameHost objects are created when not expected.
 class RenderFrameHostCreatedObserver : public WebContentsObserver {
  public:
-  RenderFrameHostCreatedObserver(WebContents* web_contents)
-      : WebContentsObserver(web_contents),
-        created_(false) {
-  }
+  explicit RenderFrameHostCreatedObserver(WebContents* web_contents)
+      : WebContentsObserver(web_contents), created_(false) {}
 
   void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
     created_ = true;
@@ -257,7 +256,7 @@
 // This WebContents observer keep track of its RVH change.
 class RenderViewHostChangedObserver : public WebContentsObserver {
  public:
-  RenderViewHostChangedObserver(WebContents* web_contents)
+  explicit RenderViewHostChangedObserver(WebContents* web_contents)
       : WebContentsObserver(web_contents), host_changed_(false) {}
 
   // WebContentsObserver.
@@ -286,10 +285,10 @@
 // See http://crbug.com/351815
 class PluginFaviconMessageObserver : public WebContentsObserver {
  public:
-  PluginFaviconMessageObserver(WebContents* web_contents)
+  explicit PluginFaviconMessageObserver(WebContents* web_contents)
       : WebContentsObserver(web_contents),
         plugin_crashed_(false),
-        favicon_received_(false) { }
+        favicon_received_(false) {}
 
   void PluginCrashed(const base::FilePath& plugin_path,
                      base::ProcessId plugin_pid) override {
@@ -1963,13 +1962,13 @@
   contents()->GetMainFrame()->OnCreateChildFrame(
       contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName1",
+      blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   contents()->GetMainFrame()->OnCreateChildFrame(
       contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName2",
+      blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName2", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   RenderFrameHostManager* root_manager =
@@ -2105,7 +2104,7 @@
   contents1->GetMainFrame()->OnCreateChildFrame(
       contents1->GetMainFrame()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName1",
+      blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   RenderFrameHostManager* iframe =
@@ -2156,7 +2155,7 @@
   main_rfh->OnCreateChildFrame(
       main_rfh->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1",
+      blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   RenderFrameHostManager* subframe_rfhm =
@@ -2317,12 +2316,12 @@
   tree1->AddFrame(root1, process_id, 12,
                   TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
                   blink::WebTreeScopeType::kDocument, std::string(),
-                  "uniqueName0", base::UnguessableToken::Create(),
+                  "uniqueName0", false, base::UnguessableToken::Create(),
                   blink::FramePolicy(), FrameOwnerProperties());
   tree1->AddFrame(root1, process_id, 13,
                   TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
                   blink::WebTreeScopeType::kDocument, std::string(),
-                  "uniqueName1", base::UnguessableToken::Create(),
+                  "uniqueName1", false, base::UnguessableToken::Create(),
                   blink::FramePolicy(), FrameOwnerProperties());
 
   std::unique_ptr<TestWebContents> tab2(
@@ -2334,12 +2333,12 @@
   tree2->AddFrame(root2, process_id, 22,
                   TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
                   blink::WebTreeScopeType::kDocument, std::string(),
-                  "uniqueName2", base::UnguessableToken::Create(),
+                  "uniqueName2", false, base::UnguessableToken::Create(),
                   blink::FramePolicy(), FrameOwnerProperties());
   tree2->AddFrame(root2, process_id, 23,
                   TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
                   blink::WebTreeScopeType::kDocument, std::string(),
-                  "uniqueName3", base::UnguessableToken::Create(),
+                  "uniqueName3", false, base::UnguessableToken::Create(),
                   blink::FramePolicy(), FrameOwnerProperties());
 
   std::unique_ptr<TestWebContents> tab3(
@@ -2356,7 +2355,7 @@
   tree4->AddFrame(root4, process_id, 42,
                   TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
                   blink::WebTreeScopeType::kDocument, std::string(),
-                  "uniqueName4", base::UnguessableToken::Create(),
+                  "uniqueName4", false, base::UnguessableToken::Create(),
                   blink::FramePolicy(), FrameOwnerProperties());
 
   root1->child_at(1)->SetOpener(root1->child_at(1));
@@ -2406,19 +2405,19 @@
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1",
+      blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "frame2", "uniqueName2",
+      blink::WebTreeScopeType::kDocument, "frame2", "uniqueName2", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "frame3", "uniqueName3",
+      blink::WebTreeScopeType::kDocument, "frame3", "uniqueName3", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
 
@@ -2511,7 +2510,7 @@
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1",
+      blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
 
@@ -3055,7 +3054,7 @@
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1",
+      blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
 
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index e0450549..65833e4 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -4,6 +4,11 @@
 
 #include "content/browser/frame_host/render_frame_message_filter.h"
 
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
 #include "base/command_line.h"
 #include "base/debug/alias.h"
 #include "base/macros.h"
@@ -70,6 +75,7 @@
     blink::WebTreeScopeType scope,
     const std::string& frame_name,
     const std::string& frame_unique_name,
+    bool is_created_by_script,
     const base::UnguessableToken& devtools_frame_token,
     const blink::FramePolicy& frame_policy,
     const FrameOwnerProperties& frame_owner_properties,
@@ -85,8 +91,8 @@
         new_routing_id,
         service_manager::mojom::InterfaceProviderRequest(
             std::move(interface_provider_request_handle)),
-        scope, frame_name, frame_unique_name, devtools_frame_token,
-        frame_policy, frame_owner_properties);
+        scope, frame_name, frame_unique_name, is_created_by_script,
+        devtools_frame_token, frame_policy, frame_owner_properties);
   }
 }
 
@@ -364,9 +370,9 @@
       BrowserThread::UI, FROM_HERE,
       base::BindOnce(&CreateChildFrameOnUI, render_process_id_,
                      params.parent_routing_id, params.scope, params.frame_name,
-                     params.frame_unique_name, *devtools_frame_token,
-                     params.frame_policy, params.frame_owner_properties,
-                     *new_routing_id,
+                     params.frame_unique_name, params.is_created_by_script,
+                     *devtools_frame_token, params.frame_policy,
+                     params.frame_owner_properties, *new_routing_id,
                      interface_provider_request.PassMessagePipe()));
 }
 
@@ -466,8 +472,8 @@
     return;
 
   if (base::FeatureList::IsEnabled(features::kNetworkService)) {
-    // TODO: modify GetRequestContextForURL to work with network service.
-    // TODO: merge this with code path below for non-network service.
+    // TODO(jam): modify GetRequestContextForURL to work with network service.
+    // Merge this with code path below for non-network service.
     cookie_manager_->SetCanonicalCookie(*cookie, url.SchemeIsCryptographic(),
                                         !options.exclude_httponly(),
                                         net::CookieStore::SetCookiesCallback());
@@ -508,8 +514,8 @@
   }
 
   if (base::FeatureList::IsEnabled(features::kNetworkService)) {
-    // TODO: modify GetRequestContextForURL to work with network service.
-    // TODO: merge this with code path below for non-network service.
+    // TODO(jam): modify GetRequestContextForURL to work with network service.
+    // Merge this with code path below for non-network service.
     cookie_manager_->GetCookieList(
         url, options,
         base::BindOnce(&RenderFrameMessageFilter::CheckPolicyForCookies, this,
diff --git a/content/browser/net/quota_policy_cookie_store.cc b/content/browser/net/quota_policy_cookie_store.cc
index ec7b4b8..4655760 100644
--- a/content/browser/net/quota_policy_cookie_store.cc
+++ b/content/browser/net/quota_policy_cookie_store.cc
@@ -46,7 +46,8 @@
     }
     const GURL url(net::cookie_util::CookieOriginToURL(cookie.first.first,
                                                        cookie.first.second));
-    if (!url.is_valid() || !special_storage_policy_->IsStorageSessionOnly(url))
+    if (!url.is_valid() ||
+        !special_storage_policy_->IsStorageSessionOnlyOrBlocked(url))
       continue;
 
     session_only_cookies.push_back(cookie.first);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 6027011..200663b 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2643,7 +2643,6 @@
     switches::kUseGpuInTests,
     switches::kUseMobileUserAgent,
     switches::kV,
-    switches::kV8CacheStrategiesForCacheStorage,
     switches::kVideoThreads,
     switches::kVideoUnderflowThresholdMs,
     switches::kVModule,
diff --git a/content/browser/renderer_host/render_process_host_unittest.cc b/content/browser/renderer_host/render_process_host_unittest.cc
index fd00d5ea..890330b7 100644
--- a/content/browser/renderer_host/render_process_host_unittest.cc
+++ b/content/browser/renderer_host/render_process_host_unittest.cc
@@ -132,7 +132,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      blink::WebTreeScopeType::kDocument, std::string(), unique_name,
+      blink::WebTreeScopeType::kDocument, std::string(), unique_name, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index d16a7cd..9d3ee73 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -2762,10 +2762,11 @@
   DISALLOW_COPY_AND_ASSIGN(CacheStorageSideDataSizeChecker);
 };
 
-class ServiceWorkerV8CacheStrategiesTest : public ServiceWorkerBrowserTest {
+class ServiceWorkerV8CodeCacheForCacheStorageTest
+    : public ServiceWorkerBrowserTest {
  public:
-  ServiceWorkerV8CacheStrategiesTest() {}
-  ~ServiceWorkerV8CacheStrategiesTest() override {}
+  ServiceWorkerV8CodeCacheForCacheStorageTest() = default;
+  ~ServiceWorkerV8CodeCacheForCacheStorageTest() override = default;
 
   void SetUpOnMainThread() override {
     ServiceWorkerBrowserTest::SetUpOnMainThread();
@@ -2773,59 +2774,6 @@
   }
 
  protected:
-  void CheckStrategyIsNone() {
-    RegisterAndActivateServiceWorker();
-
-    NavigateToTestPage();
-    WaitUntilSideDataSizeIs(0);
-
-    NavigateToTestPage();
-    WaitUntilSideDataSizeIs(0);
-
-    NavigateToTestPage();
-    WaitUntilSideDataSizeIs(0);
-  }
-
-  void CheckStrategyIsNormal() {
-    RegisterAndActivateServiceWorker();
-
-    NavigateToTestPage();
-    // fetch_event_response_via_cache.js returns |cloned_response| for the first
-    // load. So the V8 code cache should not be stored to the CacheStorage.
-    WaitUntilSideDataSizeIs(0);
-
-    NavigateToTestPage();
-    // V8ScriptRunner::setCacheTimeStamp() stores 12 byte data (tag +
-    // timestamp).
-    WaitUntilSideDataSizeIs(kV8CacheTimeStampDataSize);
-
-    NavigateToTestPage();
-    // The V8 code cache must be stored to the CacheStorage which must be bigger
-    // than 12 byte.
-    WaitUntilSideDataSizeIsBiggerThan(kV8CacheTimeStampDataSize);
-  }
-
-  void CheckStrategyIsAggressive() {
-    RegisterAndActivateServiceWorker();
-
-    NavigateToTestPage();
-    // fetch_event_response_via_cache.js returns |cloned_response| for the first
-    // load. So the V8 code cache should not be stored to the CacheStorage.
-    WaitUntilSideDataSizeIs(0);
-
-    NavigateToTestPage();
-    // The V8 code cache must be stored to the CacheStorage which must be bigger
-    // than 12 byte.
-    WaitUntilSideDataSizeIsBiggerThan(kV8CacheTimeStampDataSize);
-
-    NavigateToTestPage();
-    WaitUntilSideDataSizeIsBiggerThan(kV8CacheTimeStampDataSize);
-  }
-
- private:
-  static const char kPageUrl[];
-  static const char kWorkerUrl[];
-  static const char kScriptUrl[];
   static const int kV8CacheTimeStampDataSize;
 
   void RegisterAndActivateServiceWorker() {
@@ -2847,16 +2795,6 @@
     EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
   }
 
-  int GetSideDataSize() {
-    StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
-        shell()->web_contents()->GetBrowserContext());
-    return CacheStorageSideDataSizeChecker::GetSize(
-        static_cast<CacheStorageContextImpl*>(
-            partition->GetCacheStorageContext()),
-        partition->GetFileSystemContext(), embedded_test_server()->base_url(),
-        std::string("cache_name"), embedded_test_server()->GetURL(kScriptUrl));
-  }
-
   void WaitUntilSideDataSizeIs(int expected_size) {
     while (true) {
       if (GetSideDataSize() == expected_size)
@@ -2871,80 +2809,75 @@
     }
   }
 
-  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerV8CacheStrategiesTest);
+ private:
+  static const char kPageUrl[];
+  static const char kWorkerUrl[];
+  static const char kScriptUrl[];
+
+  int GetSideDataSize() {
+    StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
+        shell()->web_contents()->GetBrowserContext());
+    return CacheStorageSideDataSizeChecker::GetSize(
+        static_cast<CacheStorageContextImpl*>(
+            partition->GetCacheStorageContext()),
+        partition->GetFileSystemContext(), embedded_test_server()->base_url(),
+        std::string("cache_name"), embedded_test_server()->GetURL(kScriptUrl));
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerV8CodeCacheForCacheStorageTest);
 };
 
-const char ServiceWorkerV8CacheStrategiesTest::kPageUrl[] =
+const char ServiceWorkerV8CodeCacheForCacheStorageTest::kPageUrl[] =
     "/service_worker/v8_cache_test.html";
-const char ServiceWorkerV8CacheStrategiesTest::kWorkerUrl[] =
+const char ServiceWorkerV8CodeCacheForCacheStorageTest::kWorkerUrl[] =
     "/service_worker/fetch_event_response_via_cache.js";
-const char ServiceWorkerV8CacheStrategiesTest::kScriptUrl[] =
+const char ServiceWorkerV8CodeCacheForCacheStorageTest::kScriptUrl[] =
     "/service_worker/v8_cache_test.js";
 // V8ScriptRunner::setCacheTimeStamp() stores 12 byte data (tag + timestamp).
-const int ServiceWorkerV8CacheStrategiesTest::kV8CacheTimeStampDataSize =
-    sizeof(unsigned) + sizeof(double);
+const int
+    ServiceWorkerV8CodeCacheForCacheStorageTest::kV8CacheTimeStampDataSize =
+        sizeof(unsigned) + sizeof(double);
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerV8CacheStrategiesTest,
+IN_PROC_BROWSER_TEST_F(ServiceWorkerV8CodeCacheForCacheStorageTest,
                        V8CacheOnCacheStorage) {
-  // The strategy is "aggressive" on default.
-  CheckStrategyIsAggressive();
+  RegisterAndActivateServiceWorker();
+
+  // First load: fetch_event_response_via_cache.js returns |cloned_response|.
+  // The V8 code cache should not be stored in CacheStorage.
+  NavigateToTestPage();
+  WaitUntilSideDataSizeIs(0);
+
+  // Second load: The V8 code cache should be stored in CacheStorage. It must
+  // have size greater than 12 bytes.
+  NavigateToTestPage();
+  WaitUntilSideDataSizeIsBiggerThan(kV8CacheTimeStampDataSize);
 }
 
-class ServiceWorkerV8CacheStrategiesNoneTest
-    : public ServiceWorkerV8CacheStrategiesTest {
+class ServiceWorkerV8CodeCacheForCacheStorageNoneTest
+    : public ServiceWorkerV8CodeCacheForCacheStorageTest {
  public:
-  ServiceWorkerV8CacheStrategiesNoneTest() {}
-  ~ServiceWorkerV8CacheStrategiesNoneTest() override {}
+  ServiceWorkerV8CodeCacheForCacheStorageNoneTest() {}
+  ~ServiceWorkerV8CodeCacheForCacheStorageNoneTest() override {}
   void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitchASCII(switches::kV8CacheStrategiesForCacheStorage,
-                                    "none");
+    command_line->AppendSwitchASCII(switches::kV8CacheOptions, "none");
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerV8CacheStrategiesNoneTest);
+  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerV8CodeCacheForCacheStorageNoneTest);
 };
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerV8CacheStrategiesNoneTest,
+IN_PROC_BROWSER_TEST_F(ServiceWorkerV8CodeCacheForCacheStorageNoneTest,
                        V8CacheOnCacheStorage) {
-  CheckStrategyIsNone();
-}
+  RegisterAndActivateServiceWorker();
 
-class ServiceWorkerV8CacheStrategiesNormalTest
-    : public ServiceWorkerV8CacheStrategiesTest {
- public:
-  ServiceWorkerV8CacheStrategiesNormalTest() {}
-  ~ServiceWorkerV8CacheStrategiesNormalTest() override {}
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitchASCII(switches::kV8CacheStrategiesForCacheStorage,
-                                    "normal");
-  }
+  // First load.
+  NavigateToTestPage();
+  WaitUntilSideDataSizeIs(0);
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerV8CacheStrategiesNormalTest);
-};
-
-IN_PROC_BROWSER_TEST_F(ServiceWorkerV8CacheStrategiesNormalTest,
-                       V8CacheOnCacheStorage) {
-  CheckStrategyIsNormal();
-}
-
-class ServiceWorkerV8CacheStrategiesAggressiveTest
-    : public ServiceWorkerV8CacheStrategiesTest {
- public:
-  ServiceWorkerV8CacheStrategiesAggressiveTest() {}
-  ~ServiceWorkerV8CacheStrategiesAggressiveTest() override {}
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitchASCII(switches::kV8CacheStrategiesForCacheStorage,
-                                    "aggressive");
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerV8CacheStrategiesAggressiveTest);
-};
-
-IN_PROC_BROWSER_TEST_F(ServiceWorkerV8CacheStrategiesAggressiveTest,
-                       V8CacheOnCacheStorage) {
-  CheckStrategyIsAggressive();
+  // Second load: The V8 code cache must not be stored even after the second
+  // load when --v8-cache-options=none is set.
+  NavigateToTestPage();
+  WaitUntilSideDataSizeIs(0);
 }
 
 // ServiceWorkerDisableWebSecurityTests check the behavior when the web security
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc
index 91d4d2a..f290e38d 100644
--- a/content/browser/service_worker/service_worker_context_core.cc
+++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -66,22 +66,23 @@
           : ServiceWorkerCapability::SERVICE_WORKER_NO_FETCH_HANDLER);
 }
 
-void SuccessCollectorCallback(const base::Closure& done_closure,
+void SuccessCollectorCallback(base::OnceClosure done_closure,
                               bool* overall_success,
                               ServiceWorkerStatusCode status) {
   if (status != ServiceWorkerStatusCode::SERVICE_WORKER_OK) {
     *overall_success = false;
   }
-  done_closure.Run();
+  std::move(done_closure).Run();
 }
 
 void SuccessReportingCallback(
     const bool* success,
-    const ServiceWorkerContextCore::UnregistrationCallback& callback) {
+    base::OnceCallback<void(ServiceWorkerStatusCode)> callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   bool result = *success;
-  callback.Run(result ? ServiceWorkerStatusCode::SERVICE_WORKER_OK
-                      : ServiceWorkerStatusCode::SERVICE_WORKER_ERROR_FAILED);
+  std::move(callback).Run(
+      result ? ServiceWorkerStatusCode::SERVICE_WORKER_OK
+             : ServiceWorkerStatusCode::SERVICE_WORKER_ERROR_FAILED);
 }
 
 bool IsSameOriginClientProviderHost(const GURL& origin,
@@ -163,6 +164,35 @@
   DISALLOW_COPY_AND_ASSIGN(ClearAllServiceWorkersHelper);
 };
 
+class RegistrationDeletionListener
+    : public ServiceWorkerRegistration::Listener {
+ public:
+  // Wait until a |registration| is deleted and call |callback|.
+  static void WaitForDeletion(
+      scoped_refptr<ServiceWorkerRegistration> registration,
+      base::OnceClosure callback) {
+    DCHECK(!registration->is_deleted());
+    registration->AddListener(new RegistrationDeletionListener(
+        std::move(registration), std::move(callback)));
+  }
+
+  void OnRegistrationDeleted(ServiceWorkerRegistration* registration) override {
+    registration->RemoveListener(this);
+    std::move(callback_).Run();
+    delete this;
+  }
+
+ private:
+  RegistrationDeletionListener(
+      scoped_refptr<ServiceWorkerRegistration> registration,
+      base::OnceClosure callback)
+      : registration_(std::move(registration)),
+        callback_(std::move(callback)) {}
+  virtual ~RegistrationDeletionListener() = default;
+
+  scoped_refptr<ServiceWorkerRegistration> registration_;
+  base::OnceClosure callback_;
+};
 }  // namespace
 
 const base::FilePath::CharType
@@ -472,38 +502,43 @@
                  callback));
 }
 
-void ServiceWorkerContextCore::UnregisterServiceWorkers(
+void ServiceWorkerContextCore::DeleteForOrigin(
     const GURL& origin,
-    const UnregistrationCallback& callback) {
+    base::OnceCallback<void(ServiceWorkerStatusCode)> callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  storage()->GetAllRegistrationsInfos(base::Bind(
-      &ServiceWorkerContextCore::DidGetAllRegistrationsForUnregisterForOrigin,
-      AsWeakPtr(), callback, origin));
+  storage()->GetRegistrationsForOrigin(
+      origin,
+      AdaptCallbackForRepeating(base::BindOnce(
+          &ServiceWorkerContextCore::DidGetRegistrationsForDeleteForOrigin,
+          AsWeakPtr(), std::move(callback))));
 }
 
-void ServiceWorkerContextCore::DidGetAllRegistrationsForUnregisterForOrigin(
-    const UnregistrationCallback& result,
-    const GURL& origin,
+void ServiceWorkerContextCore::DidGetRegistrationsForDeleteForOrigin(
+    base::OnceCallback<void(ServiceWorkerStatusCode)> callback,
     ServiceWorkerStatusCode status,
-    const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
+    const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
+        registrations) {
   if (status != SERVICE_WORKER_OK) {
-    result.Run(status);
+    std::move(callback).Run(status);
     return;
   }
-  std::set<GURL> scopes;
-  for (const auto& registration_info : registrations) {
-    if (origin == registration_info.pattern.GetOrigin()) {
-      scopes.insert(registration_info.pattern);
-    }
-  }
   bool* overall_success = new bool(true);
-  base::Closure barrier = base::BarrierClosure(
-      scopes.size(), base::BindOnce(&SuccessReportingCallback,
-                                    base::Owned(overall_success), result));
-
-  for (const GURL& scope : scopes) {
+  // The barrier must be executed twice for each registration: once for
+  // unregistration and once for deletion.
+  base::RepeatingClosure barrier = base::BarrierClosure(
+      2 * registrations.size(),
+      base::BindOnce(&SuccessReportingCallback, base::Owned(overall_success),
+                     std::move(callback)));
+  for (const auto& registration : registrations) {
+    if (!registration->is_deleted()) {
+      RegistrationDeletionListener::WaitForDeletion(registration, barrier);
+    } else {
+      barrier.Run();
+    }
     UnregisterServiceWorker(
-        scope, base::Bind(&SuccessCollectorCallback, barrier, overall_success));
+        registration->pattern(),
+        AdaptCallbackForRepeating(base::BindOnce(&SuccessCollectorCallback,
+                                                 barrier, overall_success)));
   }
 }
 
diff --git a/content/browser/service_worker/service_worker_context_core.h b/content/browser/service_worker/service_worker_context_core.h
index afe5905..a5775b3 100644
--- a/content/browser/service_worker/service_worker_context_core.h
+++ b/content/browser/service_worker/service_worker_context_core.h
@@ -204,11 +204,12 @@
   void UnregisterServiceWorker(const GURL& pattern,
                                const UnregistrationCallback& callback);
 
-  // Callback is called issued after all unregistrations occur.  The Status
-  // is populated as SERVICE_WORKER_OK if all succeed, or SERVICE_WORKER_FAILED
+  // Callback is called after all deletions occured. The status code is
+  // SERVICE_WORKER_OK if all succeed, or SERVICE_WORKER_FAILED
   // if any did not succeed.
-  void UnregisterServiceWorkers(const GURL& origin,
-                                const UnregistrationCallback& callback);
+  void DeleteForOrigin(
+      const GURL& origin,
+      base::OnceCallback<void(ServiceWorkerStatusCode)> callback);
 
   // Updates the service worker. If |force_bypass_cache| is true or 24 hours
   // have passed since the last update, bypasses the browser cache.
@@ -335,11 +336,11 @@
                               int64_t registration_id,
                               ServiceWorkerStatusCode status);
 
-  void DidGetAllRegistrationsForUnregisterForOrigin(
-      const UnregistrationCallback& result,
-      const GURL& origin,
+  void DidGetRegistrationsForDeleteForOrigin(
+      base::OnceCallback<void(ServiceWorkerStatusCode)> callback,
       ServiceWorkerStatusCode status,
-      const std::vector<ServiceWorkerRegistrationInfo>& registrations);
+      const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
+          registrations);
 
   void DidFindRegistrationForCheckHasServiceWorker(
       const GURL& other_url,
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc
index ba1896a..293ed90 100644
--- a/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -453,8 +453,8 @@
             registration_id4);
 
   called = false;
-  context()->UnregisterServiceWorkers(origin1_p1.GetOrigin(),
-                                      MakeUnregisteredCallback(&called));
+  context()->DeleteForOrigin(origin1_p1.GetOrigin(),
+                             MakeUnregisteredCallback(&called));
 
   ASSERT_FALSE(called);
   base::RunLoop().RunUntilIdle();
@@ -506,11 +506,11 @@
   EXPECT_EQ(origin3_p1, notifications_[3].pattern);
   EXPECT_EQ(registration_id4, notifications_[3].registration_id);
   EXPECT_EQ(REGISTRATION_DELETED, notifications_[4].type);
-  EXPECT_EQ(origin1_p2, notifications_[4].pattern);
-  EXPECT_EQ(registration_id2, notifications_[4].registration_id);
+  EXPECT_EQ(origin1_p1, notifications_[4].pattern);
+  EXPECT_EQ(registration_id1, notifications_[4].registration_id);
   EXPECT_EQ(REGISTRATION_DELETED, notifications_[5].type);
-  EXPECT_EQ(origin1_p1, notifications_[5].pattern);
-  EXPECT_EQ(registration_id1, notifications_[5].registration_id);
+  EXPECT_EQ(origin1_p2, notifications_[5].pattern);
+  EXPECT_EQ(registration_id2, notifications_[5].registration_id);
 }
 
 // Make sure registering a new script shares an existing registration.
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index c66f364..6b7ccda 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -365,9 +365,9 @@
                             base::BindOnce(std::move(callback), false));
     return;
   }
-  context()->UnregisterServiceWorkers(
-      origin.GetOrigin(), base::Bind(&StatusCodeToBoolCallbackAdapter,
-                                     base::Passed(std::move(callback))));
+  context()->DeleteForOrigin(
+      origin.GetOrigin(),
+      base::BindOnce(&StatusCodeToBoolCallbackAdapter, std::move(callback)));
 }
 
 void ServiceWorkerContextWrapper::CheckHasServiceWorker(
diff --git a/content/browser/service_worker/service_worker_registration.cc b/content/browser/service_worker/service_worker_registration.cc
index 05f0087..80eb7c76 100644
--- a/content/browser/service_worker/service_worker_registration.cc
+++ b/content/browser/service_worker/service_worker_registration.cc
@@ -229,9 +229,9 @@
 
   context_->storage()->NotifyUninstallingRegistration(this);
   context_->storage()->DeleteRegistration(
-      id(),
-      pattern().GetOrigin(),
-      base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+      id(), pattern().GetOrigin(),
+      AdaptCallbackForRepeating(
+          base::BindOnce(&ServiceWorkerRegistration::OnDeleteFinished, this)));
 
   if (!active_version() || !active_version()->HasControllee())
     Clear();
@@ -512,8 +512,8 @@
 
 void ServiceWorkerRegistration::OnDeleteFinished(
     ServiceWorkerStatusCode status) {
-  // Intentionally empty completion callback, used to prevent
-  // |this| from being deleted until the storage method completes.
+  for (auto& listener : listeners_)
+    listener.OnRegistrationDeleted(this);
 }
 
 void ServiceWorkerRegistration::Clear() {
diff --git a/content/browser/service_worker/service_worker_registration.h b/content/browser/service_worker/service_worker_registration.h
index 444f1550..fea1bf1 100644
--- a/content/browser/service_worker/service_worker_registration.h
+++ b/content/browser/service_worker/service_worker_registration.h
@@ -46,6 +46,8 @@
         ServiceWorkerRegistration* registration) {}
     virtual void OnRegistrationFinishedUninstalling(
         ServiceWorkerRegistration* registration) {}
+    virtual void OnRegistrationDeleted(
+        ServiceWorkerRegistration* registration) {}
     virtual void OnUpdateFound(
         ServiceWorkerRegistration* registration) {}
     virtual void OnSkippedWaiting(ServiceWorkerRegistration* registation) {}
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 220e7d2c..dcb4ec5 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -672,9 +672,9 @@
     std::move(task).Run();
     return;
   }
-  StartWorker(purpose, base::AdaptCallbackForRepeating(base::BindOnce(
+  StartWorker(purpose, base::BindOnce(
                            &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
-                           std::move(error_callback), std::move(task))));
+                           std::move(error_callback), std::move(task)));
 }
 
 void ServiceWorkerVersion::AddControllee(
diff --git a/content/browser/top_document_isolation_browsertest.cc b/content/browser/top_document_isolation_browsertest.cc
index be1fa6e..cedc2f9 100644
--- a/content/browser/top_document_isolation_browsertest.cc
+++ b/content/browser/top_document_isolation_browsertest.cc
@@ -187,11 +187,11 @@
   NavigateToURL(shell(), ba_url);
 
   EXPECT_EQ(
-      " Site C ------------ proxies for B\n"
-      "   |--Site B ------- proxies for C\n"
-      "   +--Site B ------- proxies for C\n"
-      "Where B = default subframe process\n"
-      "      C = http://b.com/",
+      " Site C ------------ proxies for D\n"
+      "   |--Site D ------- proxies for C\n"
+      "   +--Site D ------- proxies for C\n"
+      "Where C = http://b.com/\n"
+      "      D = default subframe process",
       DepictFrameTree(root()));
 }
 
diff --git a/content/browser/webauth/authenticator_impl.cc b/content/browser/webauth/authenticator_impl.cc
index 6221918..44d4b385 100644
--- a/content/browser/webauth/authenticator_impl.cc
+++ b/content/browser/webauth/authenticator_impl.cc
@@ -47,20 +47,15 @@
 }
 }  // namespace
 
-// static
-void AuthenticatorImpl::Create(
-    RenderFrameHost* render_frame_host,
-    webauth::mojom::AuthenticatorRequest request) {
-  auto authenticator_impl =
-      std::make_unique<AuthenticatorImpl>(render_frame_host);
-  mojo::MakeStrongBinding(std::move(authenticator_impl), std::move(request));
+AuthenticatorImpl::AuthenticatorImpl(RenderFrameHost* render_frame_host)
+    : render_frame_host_(render_frame_host), weak_factory_(this) {
+  DCHECK(render_frame_host_);
 }
 
 AuthenticatorImpl::~AuthenticatorImpl() {}
 
-AuthenticatorImpl::AuthenticatorImpl(RenderFrameHost* render_frame_host)
-    : render_frame_host_(render_frame_host), weak_factory_(this) {
-  DCHECK(render_frame_host);
+void AuthenticatorImpl::Bind(webauth::mojom::AuthenticatorRequest request) {
+  bindings_.AddBinding(this, std::move(request));
 }
 
 // mojom::Authenticator
diff --git a/content/browser/webauth/authenticator_impl.h b/content/browser/webauth/authenticator_impl.h
index 5436b3a..c7d4eec 100644
--- a/content/browser/webauth/authenticator_impl.h
+++ b/content/browser/webauth/authenticator_impl.h
@@ -16,7 +16,7 @@
 #include "base/timer/timer.h"
 #include "content/browser/webauth/register_response_data.h"
 #include "content/common/content_export.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "third_party/WebKit/public/platform/modules/webauth/authenticator.mojom.h"
 #include "url/origin.h"
@@ -33,11 +33,14 @@
 // Implementation of the public Authenticator interface.
 class CONTENT_EXPORT AuthenticatorImpl : public webauth::mojom::Authenticator {
  public:
-  static void Create(RenderFrameHost* render_frame_host,
-                     webauth::mojom::AuthenticatorRequest request);
-  AuthenticatorImpl(RenderFrameHost* render_frame_host);
+  explicit AuthenticatorImpl(RenderFrameHost* render_frame_host);
   ~AuthenticatorImpl() override;
 
+  // Creates a binding between this object and |request|. Note that a
+  // AuthenticatorImpl instance can be bound to multiple requests (as happens in
+  // the case of simultaneous starting and finishing operations).
+  void Bind(webauth::mojom::AuthenticatorRequest request);
+
  private:
   // mojom:Authenticator
   void MakeCredential(webauth::mojom::MakeCredentialOptionsPtr options,
@@ -55,11 +58,11 @@
                               webauth::mojom::PublicKeyCredentialInfoPtr)>
           callback);
 
+  // Owns pipes to this Authenticator from |render_frame_host_|.
+  mojo::BindingSet<webauth::mojom::Authenticator> bindings_;
   std::unique_ptr<device::U2fRequest> u2f_request_;
   base::OneShotTimer timer_;
-
   RenderFrameHost* render_frame_host_;
-
   base::WeakPtrFactory<AuthenticatorImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AuthenticatorImpl);
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index fdef660..e77c07f 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -450,10 +450,14 @@
   }
 
   AuthenticatorPtr ConnectToAuthenticator() {
+    authenticator_impl_.reset(new AuthenticatorImpl(main_rfh()));
     AuthenticatorPtr authenticator;
-    AuthenticatorImpl::Create(main_rfh(), mojo::MakeRequest(&authenticator));
+    authenticator_impl_->Bind(mojo::MakeRequest(&authenticator));
     return authenticator;
   }
+
+ private:
+  std::unique_ptr<AuthenticatorImpl> authenticator_impl_;
 };
 
 class TestMakeCredentialCallback {
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index 1676cd91..38ba6e03 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -426,7 +426,8 @@
   channel_->Init(
       IPC::ChannelMojo::CreateClientFactory(
           std::move(handle), ChildProcess::current()->io_task_runner(),
-          base::ThreadTaskRunnerHandle::Get()),
+          ipc_task_runner_ ? ipc_task_runner_
+                           : base::ThreadTaskRunnerHandle::Get()),
       true /* create_pipe_now */);
 }
 
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index f1ab8b3..61b3818 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -593,6 +593,7 @@
   IPC_STRUCT_MEMBER(blink::WebTreeScopeType, scope)
   IPC_STRUCT_MEMBER(std::string, frame_name)
   IPC_STRUCT_MEMBER(std::string, frame_unique_name)
+  IPC_STRUCT_MEMBER(bool, is_created_by_script)
   IPC_STRUCT_MEMBER(blink::FramePolicy, frame_policy)
   IPC_STRUCT_MEMBER(content::FrameOwnerProperties, frame_owner_properties)
 IPC_STRUCT_END()
diff --git a/content/gpu/gpu_sandbox_hook_linux.cc b/content/gpu/gpu_sandbox_hook_linux.cc
index 1cef6ab..15f84bf 100644
--- a/content/gpu/gpu_sandbox_hook_linux.cc
+++ b/content/gpu/gpu_sandbox_hook_linux.cc
@@ -28,6 +28,10 @@
 #include "services/service_manager/sandbox/linux/bpf_gpu_policy_linux.h"
 #include "services/service_manager/sandbox/linux/sandbox_linux.h"
 
+#if BUILDFLAG(USE_VAAPI)
+#include <va/va_version.h>
+#endif
+
 using sandbox::bpf_dsl::Policy;
 using sandbox::syscall_broker::BrokerFilePermission;
 using sandbox::syscall_broker::BrokerProcess;
@@ -83,6 +87,14 @@
 #endif
 }
 
+inline bool IsLibVAVersion2() {
+#if BUILDFLAG(USE_VAAPI) && VA_MAJOR_VERSION == 1
+  return true;
+#else
+  return false;
+#endif
+}
+
 constexpr int dlopen_flag = RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE;
 
 void AddV4L2GpuWhitelist(
@@ -249,23 +261,40 @@
     // inside the sandbox, so preload them now.
     if (options.vaapi_accelerated_video_encode_enabled ||
         options.accelerated_video_decode_enabled) {
-      const char* I965DrvVideoPath = nullptr;
-      const char* I965HybridDrvVideoPath = nullptr;
-      if (IsArchitectureX86_64()) {
-        I965DrvVideoPath = "/usr/lib64/va/drivers/i965_drv_video.so";
-        I965HybridDrvVideoPath = "/usr/lib64/va/drivers/hybrid_drv_video.so";
-      } else if (IsArchitectureI386()) {
-        I965DrvVideoPath = "/usr/lib/va/drivers/i965_drv_video.so";
-      }
-      dlopen(I965DrvVideoPath, dlopen_flag);
-      if (I965HybridDrvVideoPath)
-        dlopen(I965HybridDrvVideoPath, dlopen_flag);
-      dlopen("libva.so.1", dlopen_flag);
+      if (IsLibVAVersion2()) {
+        if (IsArchitectureX86_64()) {
+          dlopen("/usr/lib64/va/drivers/i965_drv_video.so", dlopen_flag);
+          dlopen("/usr/lib64/va/drivers/hybrid_drv_video.so", dlopen_flag);
+        } else if (IsArchitectureI386()) {
+          dlopen("/usr/lib/va/drivers/i965_drv_video.so", dlopen_flag);
+        }
+        dlopen("libva.so.2", dlopen_flag);
 #if defined(USE_OZONE)
-      dlopen("libva-drm.so.1", dlopen_flag);
-#elif defined(USE_X11)
-      dlopen("libva-x11.so.1", dlopen_flag);
+        dlopen("libva-drm.so.2", dlopen_flag);
 #endif
+      } else {
+        // If we are linked against libva 1, we have two cases to handle:
+        // - the sysroot includes both libva 1 and 2, in which case the drivers
+        //   are in /usr/lib{64}/va1/
+        // - the sysroot only includes libva 1, in which case the drivers are
+        //   are in /usr/lib{64}/va/
+        // This is ugly, but temporary until all builds have switched to libva 2.
+        if (IsArchitectureX86_64()) {
+          if (!dlopen("/usr/lib64/va1/drivers/i965_drv_video.so", dlopen_flag))
+            dlopen("/usr/lib64/va/drivers/i965_drv_video.so", dlopen_flag);
+          if (!dlopen("/usr/lib64/va1/drivers/hybrid_drv_video.so", dlopen_flag))
+            dlopen("/usr/lib64/va/drivers/hybrid_drv_video.so", dlopen_flag);
+        } else if (IsArchitectureI386()) {
+          if (!dlopen("/usr/lib/va1/drivers/i965_drv_video.so", dlopen_flag))
+            dlopen("/usr/lib/va/drivers/i965_drv_video.so", dlopen_flag);
+        }
+        dlopen("libva.so.1", dlopen_flag);
+#if defined(USE_OZONE)
+        dlopen("libva-drm.so.1", dlopen_flag);
+#elif defined(USE_X11)
+        dlopen("libva-x11.so.1", dlopen_flag);
+#endif
+      }
     }
   }
 }
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index cfa357b2..0536839 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -425,10 +425,6 @@
 // Set options to cache V8 data. (off, preparse data, or code)
 const char kV8CacheOptions[] = "v8-cache-options";
 
-// Set strategies to cache V8 data in CacheStorage. (off, normal, or aggressive)
-const char kV8CacheStrategiesForCacheStorage[] =
-    "v8-cache-strategies-for-cache-storage";
-
 // Cause the OS X sandbox write to syslog every time an access to a resource
 // is denied by the sandbox.
 const char kEnableSandboxLogging[]          = "enable-sandbox-logging";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 5f27e8c..3c277af8 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -241,7 +241,6 @@
 extern const char kUtilityProcessAllowedDir[];
 CONTENT_EXPORT extern const char kUtilityStartupDialog[];
 CONTENT_EXPORT extern const char kV8CacheOptions[];
-CONTENT_EXPORT extern const char kV8CacheStrategiesForCacheStorage[];
 CONTENT_EXPORT extern const char kValidateInputEventStream[];
 CONTENT_EXPORT extern const char kWaitForDebuggerChildren[];
 CONTENT_EXPORT extern const char kZygoteCmdPrefix[];
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index 4934072..126d4a8 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -1483,9 +1483,13 @@
       FROM_HERE,
       base::BindOnce(
           &RunClosureWithTrace,
-          base::Bind(&webrtc::PeerConnectionInterface::SetRemoteDescription,
-                     native_peer_connection_, base::RetainedRef(set_request),
-                     base::Unretained(native_desc)),
+          base::Bind(
+              static_cast<void (webrtc::PeerConnectionInterface::*)(
+                  webrtc::SetSessionDescriptionObserver*,
+                  webrtc::SessionDescriptionInterface*)>(
+                  &webrtc::PeerConnectionInterface::SetRemoteDescription),
+              native_peer_connection_, base::RetainedRef(set_request),
+              base::Unretained(native_desc)),
           "SetRemoteDescription"));
 }
 
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_adapter.cc b/content/renderer/media/webrtc/webrtc_media_stream_adapter.cc
index d5b41c3..edf29991 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_adapter.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_adapter.cc
@@ -173,7 +173,7 @@
   }
 
   void InitializeOnMainThread(const std::string& label,
-                              RemoteAdapterRefMap adapter_refs,
+                              RemoteAdapterRefs adapter_refs,
                               size_t audio_track_count,
                               size_t video_track_count) {
     DCHECK(main_thread_->BelongsToCurrentThread());
@@ -203,15 +203,15 @@
 
   // |webrtc::ObserverInterface| implementation.
   void OnChanged() override {
-    RemoteAdapterRefMap new_adapter_refs =
-        RemoteWebRtcMediaStreamAdapter::GetRemoteAdapterRefMapFromWebRtcStream(
+    RemoteAdapterRefs new_adapter_refs =
+        RemoteWebRtcMediaStreamAdapter::GetRemoteAdapterRefsFromWebRtcStream(
             track_adapter_map_, webrtc_stream_.get());
     main_thread_->PostTask(
         FROM_HERE, base::BindOnce(&WebRtcStreamObserver::OnChangedOnMainThread,
                                   this, base::Passed(&new_adapter_refs)));
   }
 
-  void OnChangedOnMainThread(RemoteAdapterRefMap new_adapter_refs) {
+  void OnChangedOnMainThread(RemoteAdapterRefs new_adapter_refs) {
     DCHECK(main_thread_->BelongsToCurrentThread());
     if (adapter_)
       adapter_->OnChanged(std::move(new_adapter_refs));
@@ -224,24 +224,32 @@
 };
 
 // static
-RemoteWebRtcMediaStreamAdapter::RemoteAdapterRefMap
-RemoteWebRtcMediaStreamAdapter::GetRemoteAdapterRefMapFromWebRtcStream(
+bool RemoteWebRtcMediaStreamAdapter::RemoteAdapterRefsContainsTrack(
+    const RemoteAdapterRefs& adapter_refs,
+    webrtc::MediaStreamTrackInterface* webrtc_track) {
+  for (const auto& adapter_ref : adapter_refs) {
+    if (adapter_ref->webrtc_track() == webrtc_track)
+      return true;
+  }
+  return false;
+}
+
+// static
+RemoteWebRtcMediaStreamAdapter::RemoteAdapterRefs
+RemoteWebRtcMediaStreamAdapter::GetRemoteAdapterRefsFromWebRtcStream(
     const scoped_refptr<WebRtcMediaStreamTrackAdapterMap>& track_adapter_map,
     webrtc::MediaStreamInterface* webrtc_stream) {
-  RemoteAdapterRefMap adapter_refs;
+  // TODO(hbos): When adapter's |webrtc_track| can be called from any thread so
+  // can RemoteAdapterRefsContainsTrack and we can DCHECK here that we don't end
+  // up with duplicate entries. https://crbug.com/756436
+  RemoteAdapterRefs adapter_refs;
   for (auto& webrtc_audio_track : webrtc_stream->GetAudioTracks()) {
-    DCHECK(adapter_refs.find(webrtc_audio_track.get()) == adapter_refs.end());
-    adapter_refs.insert(
-        std::make_pair(webrtc_audio_track.get(),
-                       track_adapter_map->GetOrCreateRemoteTrackAdapter(
-                           webrtc_audio_track.get())));
+    adapter_refs.push_back(track_adapter_map->GetOrCreateRemoteTrackAdapter(
+        webrtc_audio_track.get()));
   }
   for (auto& webrtc_video_track : webrtc_stream->GetVideoTracks()) {
-    DCHECK(adapter_refs.find(webrtc_video_track.get()) == adapter_refs.end());
-    adapter_refs.insert(
-        std::make_pair(webrtc_video_track.get(),
-                       track_adapter_map->GetOrCreateRemoteTrackAdapter(
-                           webrtc_video_track.get())));
+    adapter_refs.push_back(track_adapter_map->GetOrCreateRemoteTrackAdapter(
+        webrtc_video_track.get()));
   }
   return adapter_refs;
 }
@@ -263,7 +271,7 @@
       weak_factory_.GetWeakPtr(), main_thread_, track_adapter_map_,
       webrtc_stream_);
 
-  RemoteAdapterRefMap adapter_refs = GetRemoteAdapterRefMapFromWebRtcStream(
+  RemoteAdapterRefs adapter_refs = GetRemoteAdapterRefsFromWebRtcStream(
       track_adapter_map_, webrtc_stream_.get());
   main_thread_->PostTask(
       FROM_HERE,
@@ -278,7 +286,7 @@
 RemoteWebRtcMediaStreamAdapter::~RemoteWebRtcMediaStreamAdapter() {
   DCHECK(main_thread_->BelongsToCurrentThread());
   observer_->Unregister();
-  OnChanged(RemoteAdapterRefMap());
+  OnChanged(RemoteAdapterRefs());
 }
 
 bool RemoteWebRtcMediaStreamAdapter::is_initialized() const {
@@ -302,7 +310,7 @@
 
 void RemoteWebRtcMediaStreamAdapter::InitializeOnMainThread(
     const std::string& label,
-    RemoteAdapterRefMap adapter_refs,
+    RemoteAdapterRefs adapter_refs,
     size_t audio_track_count,
     size_t video_track_count) {
   DCHECK(main_thread_->BelongsToCurrentThread());
@@ -315,8 +323,8 @@
       video_track_count);
   size_t audio_i = 0;
   size_t video_i = 0;
-  for (const auto& it : adapter_refs_) {
-    const blink::WebMediaStreamTrack& web_track = it.second->web_track();
+  for (const auto& adapter_ref : adapter_refs_) {
+    const blink::WebMediaStreamTrack& web_track = adapter_ref->web_track();
     if (web_track.Source().GetType() == blink::WebMediaStreamSource::kTypeAudio)
       web_audio_tracks[audio_i++] = web_track;
     else
@@ -332,23 +340,25 @@
 }
 
 void RemoteWebRtcMediaStreamAdapter::OnChanged(
-    RemoteAdapterRefMap new_adapter_refs) {
+    RemoteAdapterRefs new_adapter_refs) {
   DCHECK(main_thread_->BelongsToCurrentThread());
 
   // Find removed tracks.
   for (auto it = adapter_refs_.begin(); it != adapter_refs_.end();) {
-    if (new_adapter_refs.find(it->first) == new_adapter_refs.end()) {
-      web_stream_.RemoveTrack(it->second->web_track());
+    if (!RemoteAdapterRefsContainsTrack(new_adapter_refs,
+                                        (*it)->webrtc_track())) {
+      web_stream_.RemoveTrack((*it)->web_track());
       it = adapter_refs_.erase(it);
     } else {
       ++it;
     }
   }
   // Find added tracks.
-  for (auto& it : new_adapter_refs) {
-    if (adapter_refs_.find(it.first) == adapter_refs_.end()) {
-      web_stream_.AddTrack(it.second->web_track());
-      adapter_refs_.insert(std::make_pair(it.first, std::move(it.second)));
+  for (auto& new_adapter_ref : new_adapter_refs) {
+    if (!RemoteAdapterRefsContainsTrack(adapter_refs_,
+                                        new_adapter_ref->webrtc_track())) {
+      web_stream_.AddTrack(new_adapter_ref->web_track());
+      adapter_refs_.push_back(std::move(new_adapter_ref));
     }
   }
 }
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_adapter.h b/content/renderer/media/webrtc/webrtc_media_stream_adapter.h
index 9a4215a..cd5352fe 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_adapter.h
+++ b/content/renderer/media/webrtc/webrtc_media_stream_adapter.h
@@ -139,25 +139,28 @@
   const blink::WebMediaStream& web_stream() const override;
 
  private:
-  // A map between webrtc tracks and references to track adapters.
-  using RemoteAdapterRefMap =
-      std::map<webrtc::MediaStreamTrackInterface*,
-               std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>>;
+  // Track adapters for the remote webrtc tracks of a stream.
+  using RemoteAdapterRefs = std::vector<
+      std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>>;
+
+  static bool RemoteAdapterRefsContainsTrack(
+      const RemoteAdapterRefs& adapter_refs,
+      webrtc::MediaStreamTrackInterface* track);
 
   // Gets the adapters for the tracks that are members of the webrtc stream.
   // Invoke on webrtc signaling thread. New adapters are initialized in a post
   // to the main thread after which their |web_track| becomes available.
-  static RemoteAdapterRefMap GetRemoteAdapterRefMapFromWebRtcStream(
+  static RemoteAdapterRefs GetRemoteAdapterRefsFromWebRtcStream(
       const scoped_refptr<WebRtcMediaStreamTrackAdapterMap>& track_adapter_map,
       webrtc::MediaStreamInterface* webrtc_stream);
 
   class WebRtcStreamObserver;
 
   void InitializeOnMainThread(const std::string& label,
-                              RemoteAdapterRefMap track_adapter_refs,
+                              RemoteAdapterRefs track_adapter_refs,
                               size_t audio_track_count,
                               size_t video_track_count);
-  void OnChanged(RemoteAdapterRefMap new_adapter_refs);
+  void OnChanged(RemoteAdapterRefs new_adapter_refs);
 
   mutable base::Lock lock_;
   bool is_initialized_;
@@ -165,7 +168,7 @@
   // Track adapters belonging to this stream. Keeping adapter references alive
   // ensures the adapters are not disposed by the |track_adapter_map_| as long
   // as the webrtc layer track is in use by the webrtc layer stream.
-  RemoteAdapterRefMap adapter_refs_;
+  RemoteAdapterRefs adapter_refs_;
   base::WeakPtrFactory<RemoteWebRtcMediaStreamAdapter> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RemoteWebRtcMediaStreamAdapter);
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 1b4cbc25..191d033 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -3433,11 +3433,11 @@
   // Note that Blink can't be changed to just pass |fallback_name| as |name| in
   // the case |name| is empty: |fallback_name| should never affect the actual
   // browsing context name, only unique name generation.
-  bool is_new_subframe_created_by_script =
+  params.is_created_by_script =
       v8::Isolate::GetCurrent() && v8::Isolate::GetCurrent()->InContext();
   params.frame_unique_name = unique_name_helper_.GenerateNameForNewChildFrame(
       params.frame_name.empty() ? fallback_name.Utf8() : params.frame_name,
-      is_new_subframe_created_by_script);
+      params.is_created_by_script);
   params.frame_policy = {sandbox_flags, container_policy};
   params.frame_owner_properties =
       ConvertWebFrameOwnerPropertiesToFrameOwnerProperties(
@@ -3473,7 +3473,7 @@
       devtools_frame_token);
   child_render_frame->unique_name_helper_.set_propagated_name(
       params.frame_unique_name);
-  if (is_new_subframe_created_by_script)
+  if (params.is_created_by_script)
     child_render_frame->unique_name_helper_.Freeze();
   child_render_frame->InitializeBlameContext(this);
   blink::WebLocalFrame* web_frame = parent->CreateLocalChild(
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index b5597d44..8784a54 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -445,31 +445,6 @@
   }
 }
 
-WebSettings::V8CacheStrategiesForCacheStorage
-GetV8CacheStrategiesForCacheStorage() {
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  std::string v8_cache_strategies = command_line.GetSwitchValueASCII(
-      switches::kV8CacheStrategiesForCacheStorage);
-  if (v8_cache_strategies.empty()) {
-    v8_cache_strategies =
-        base::FieldTrialList::FindFullName("V8CacheStrategiesForCacheStorage");
-  }
-
-  if (base::StartsWith(v8_cache_strategies, "none",
-                       base::CompareCase::SENSITIVE)) {
-    return WebSettings::V8CacheStrategiesForCacheStorage::kNone;
-  } else if (base::StartsWith(v8_cache_strategies, "normal",
-                              base::CompareCase::SENSITIVE)) {
-    return WebSettings::V8CacheStrategiesForCacheStorage::kNormal;
-  } else if (base::StartsWith(v8_cache_strategies, "aggressive",
-                              base::CompareCase::SENSITIVE)) {
-    return WebSettings::V8CacheStrategiesForCacheStorage::kAggressive;
-  } else {
-    return WebSettings::V8CacheStrategiesForCacheStorage::kDefault;
-  }
-}
-
 // This class represents promise which is robust to (will not be broken by)
 // |DidNotSwapReason::SWAP_FAILS| events.
 class AlwaysDrawSwapPromise : public cc::SwapPromise {
@@ -890,9 +865,6 @@
   settings->SetV8CacheOptions(
       static_cast<WebSettings::V8CacheOptions>(prefs.v8_cache_options));
 
-  settings->SetV8CacheStrategiesForCacheStorage(
-      GetV8CacheStrategiesForCacheStorage());
-
   settings->SetImageAnimationPolicy(
       static_cast<WebSettings::ImageAnimationPolicy>(prefs.animation_policy));
 
diff --git a/content/renderer/webgraphicscontext3d_provider_impl.cc b/content/renderer/webgraphicscontext3d_provider_impl.cc
index 9f3d045e..c7acc980 100644
--- a/content/renderer/webgraphicscontext3d_provider_impl.cc
+++ b/content/renderer/webgraphicscontext3d_provider_impl.cc
@@ -71,10 +71,9 @@
   provider_->ContextSupport()->SetErrorMessageCallback(c);
 }
 
-void WebGraphicsContext3DProviderImpl::SignalQuery(
-    uint32_t query,
-    const base::Closure& callback) {
-  provider_->ContextSupport()->SignalQuery(query, callback);
+void WebGraphicsContext3DProviderImpl::SignalQuery(uint32_t query,
+                                                   base::OnceClosure callback) {
+  provider_->ContextSupport()->SignalQuery(query, std::move(callback));
 }
 
 void WebGraphicsContext3DProviderImpl::OnContextLost() {
diff --git a/content/renderer/webgraphicscontext3d_provider_impl.h b/content/renderer/webgraphicscontext3d_provider_impl.h
index ba4ef5f..c47c60a 100644
--- a/content/renderer/webgraphicscontext3d_provider_impl.h
+++ b/content/renderer/webgraphicscontext3d_provider_impl.h
@@ -48,7 +48,7 @@
   void SetLostContextCallback(const base::Closure&) override;
   void SetErrorMessageCallback(
       const base::Callback<void(const char*, int32_t)>&) override;
-  void SignalQuery(uint32_t, const base::Closure&) override;
+  void SignalQuery(uint32_t, base::OnceClosure) override;
 
   ui::ContextProviderCommandBuffer* context_provider() const {
     return provider_.get();
diff --git a/content/test/data/navigation_controller/page_with_iframe_simple.html b/content/test/data/navigation_controller/page_with_iframe_simple.html
index 7bc5b32..0cf74d6c 100644
--- a/content/test/data/navigation_controller/page_with_iframe_simple.html
+++ b/content/test/data/navigation_controller/page_with_iframe_simple.html
@@ -2,6 +2,6 @@
 <head></head>
 <body>
   <p>This page has an iframe.</p>
-  <p><iframe src="simple_page.html"></iframe>
+  <p><iframe id="frame" src="simple_page.html"></iframe>
 </body>
 </html>
diff --git a/content/test/test_background_sync_manager.cc b/content/test/test_background_sync_manager.cc
index 92fb542..8cd39c0 100644
--- a/content/test/test_background_sync_manager.cc
+++ b/content/test/test_background_sync_manager.cc
@@ -23,7 +23,7 @@
 }
 
 void TestBackgroundSyncManager::ResumeBackendOperation() {
-  ASSERT_FALSE(continuation_.is_null());
+  ASSERT_TRUE(continuation_);
   std::move(continuation_).Run();
 }
 
@@ -37,7 +37,7 @@
     const std::string& key,
     const std::string& data,
     const ServiceWorkerStorage::StatusCallback& callback) {
-  EXPECT_TRUE(continuation_.is_null());
+  EXPECT_FALSE(continuation_);
   if (corrupt_backend_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(callback, SERVICE_WORKER_ERROR_FAILED));
@@ -56,7 +56,7 @@
     const std::string& key,
     const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
         callback) {
-  EXPECT_TRUE(continuation_.is_null());
+  EXPECT_FALSE(continuation_);
   if (corrupt_backend_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
@@ -78,7 +78,7 @@
     scoped_refptr<ServiceWorkerVersion> active_version,
     blink::mojom::BackgroundSyncEventLastChance last_chance,
     const ServiceWorkerVersion::LegacyStatusCallback& callback) {
-  ASSERT_FALSE(dispatch_sync_callback_.is_null());
+  ASSERT_TRUE(dispatch_sync_callback_);
   last_chance_ = last_chance;
   dispatch_sync_callback_.Run(active_version, callback);
 }
diff --git a/content/test/test_background_sync_manager.h b/content/test/test_background_sync_manager.h
index c100e16..295c8e6 100644
--- a/content/test/test_background_sync_manager.h
+++ b/content/test/test_background_sync_manager.h
@@ -35,9 +35,9 @@
 //  - Setting the network state
 class TestBackgroundSyncManager : public BackgroundSyncManager {
  public:
-  using DispatchSyncCallback = base::RepeatingCallback<void(
-      const scoped_refptr<ServiceWorkerVersion>&,
-      const ServiceWorkerVersion::LegacyStatusCallback&)>;
+  using DispatchSyncCallback =
+      base::RepeatingCallback<void(scoped_refptr<ServiceWorkerVersion>,
+                                   ServiceWorkerVersion::StatusCallback)>;
 
   explicit TestBackgroundSyncManager(
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context);
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 159b4f4a..b8590d24 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -4,6 +4,9 @@
 
 #include "content/test/test_render_frame_host.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/guid.h"
 #include "base/run_loop.h"
 #include "content/browser/frame_host/frame_tree.h"
@@ -137,7 +140,7 @@
   OnCreateChildFrame(GetProcess()->GetNextRoutingID(),
                      CreateStubInterfaceProviderRequest(),
                      blink::WebTreeScopeType::kDocument, frame_name,
-                     frame_unique_name, base::UnguessableToken::Create(),
+                     frame_unique_name, false, base::UnguessableToken::Create(),
                      blink::FramePolicy(), FrameOwnerProperties());
   return static_cast<TestRenderFrameHost*>(
       child_creation_observer_.last_created_frame());
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn
index 38663e3..7f61975 100644
--- a/device/vr/BUILD.gn
+++ b/device/vr/BUILD.gn
@@ -70,6 +70,7 @@
     if (enable_openvr) {
       deps += [
         "//device/gamepad",
+        "//device/gamepad/public/cpp:shared_with_blink",
         "//third_party/openvr:openvr",
       ]
       sources += [
diff --git a/device/vr/features/features.gni b/device/vr/features/features.gni
index 2e3c76a7..5698cd850 100644
--- a/device/vr/features/features.gni
+++ b/device/vr/features/features.gni
@@ -9,13 +9,12 @@
   # support arm and arm64.
   enable_gvr_services = is_android && !is_chromecast &&
                         (current_cpu == "arm" || current_cpu == "arm64")
-  enable_openvr = false
+  enable_openvr = is_win
 }
 
 declare_args() {
-  # Enable VR device support whenever VR device SDK(s) are supported and
-  # on Windows for testing.
-  enable_vr = enable_gvr_services || enable_openvr || is_win
+  # Enable VR device support whenever VR device SDK(s) are supported.
+  enable_vr = enable_gvr_services || enable_openvr
 
   # Whether to include VR extras like test APKs in non-VR-specific targets
   include_vr_data = false
diff --git a/extensions/shell/browser/shell_special_storage_policy.cc b/extensions/shell/browser/shell_special_storage_policy.cc
index 26b9dc2..dc951c8 100644
--- a/extensions/shell/browser/shell_special_storage_policy.cc
+++ b/extensions/shell/browser/shell_special_storage_policy.cc
@@ -30,6 +30,11 @@
   return false;
 }
 
+bool ShellSpecialStoragePolicy::IsStorageSessionOnlyOrBlocked(
+    const GURL& origin) {
+  return false;
+}
+
 bool ShellSpecialStoragePolicy::HasSessionOnlyOrigins() {
   return false;
 }
diff --git a/extensions/shell/browser/shell_special_storage_policy.h b/extensions/shell/browser/shell_special_storage_policy.h
index 7a796ab..33f9850b 100644
--- a/extensions/shell/browser/shell_special_storage_policy.h
+++ b/extensions/shell/browser/shell_special_storage_policy.h
@@ -20,6 +20,7 @@
   bool IsStorageUnlimited(const GURL& origin) override;
   bool IsStorageDurable(const GURL& origin) override;
   bool IsStorageSessionOnly(const GURL& origin) override;
+  bool IsStorageSessionOnlyOrBlocked(const GURL& origin) override;
   bool HasIsolatedStorage(const GURL& origin) override;
   bool HasSessionOnlyOrigins() override;
 
diff --git a/gpu/command_buffer/client/context_support.h b/gpu/command_buffer/client/context_support.h
index a5fbe399..b0989373 100644
--- a/gpu/command_buffer/client/context_support.h
+++ b/gpu/command_buffer/client/context_support.h
@@ -28,7 +28,7 @@
   // Runs |callback| when the given sync token is signalled. The sync token may
   // belong to any context.
   virtual void SignalSyncToken(const SyncToken& sync_token,
-                               const base::Closure& callback) = 0;
+                               base::OnceClosure callback) = 0;
 
   // Returns true if the given sync token has been signaled. The sync token must
   // belong to this context. This may be called from any thread.
@@ -36,7 +36,7 @@
 
   // Runs |callback| when a query created via glCreateQueryEXT() has cleared
   // passed the glEndQueryEXT() point.
-  virtual void SignalQuery(uint32_t query, const base::Closure& callback) = 0;
+  virtual void SignalQuery(uint32_t query, base::OnceClosure callback) = 0;
 
   // Indicates whether the context should aggressively free allocated resources.
   // If set to true, the context will purge all temporary resources when
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 6c4aeb7..005b025 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -368,9 +368,9 @@
   mapped_memory_->FreePendingToken(mem, helper_->InsertToken());
 }
 
-void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
+void GLES2Implementation::RunIfContextNotLost(base::OnceClosure callback) {
   if (!lost_context_callback_run_)
-    callback.Run();
+    std::move(callback).Run();
 }
 
 void GLES2Implementation::FlushPendingWork() {
@@ -378,7 +378,7 @@
 }
 
 void GLES2Implementation::SignalSyncToken(const gpu::SyncToken& sync_token,
-                                          const base::Closure& callback) {
+                                          base::OnceClosure callback) {
   SyncToken verified_sync_token;
   if (sync_token.HasData() &&
       GetVerifiedSyncTokenForIPC(sync_token, &verified_sync_token)) {
@@ -386,10 +386,10 @@
     gpu_control_->SignalSyncToken(
         verified_sync_token,
         base::Bind(&GLES2Implementation::RunIfContextNotLost,
-                   weak_ptr_factory_.GetWeakPtr(), callback));
+                   weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
   } else {
     // Invalid sync token, just call the callback immediately.
-    callback.Run();
+    std::move(callback).Run();
   }
 }
 
@@ -404,15 +404,14 @@
 }
 
 void GLES2Implementation::SignalQuery(uint32_t query,
-                                      const base::Closure& callback) {
+                                      base::OnceClosure callback) {
   // Flush previously entered commands to ensure ordering with any
   // glBeginQueryEXT() calls that may have been put into the context.
   ShallowFlushCHROMIUM();
   gpu_control_->SignalQuery(
       query,
       base::Bind(&GLES2Implementation::RunIfContextNotLost,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback));
+                 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
 }
 
 void GLES2Implementation::SetAggressivelyFreeResources(
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 567453a..28ddf65 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -192,9 +192,9 @@
   // ContextSupport implementation.
   void FlushPendingWork() override;
   void SignalSyncToken(const gpu::SyncToken& sync_token,
-                       const base::Closure& callback) override;
+                       base::OnceClosure callback) override;
   bool IsSyncTokenSignaled(const gpu::SyncToken& sync_token) override;
-  void SignalQuery(uint32_t query, const base::Closure& callback) override;
+  void SignalQuery(uint32_t query, base::OnceClosure callback) override;
   void SetAggressivelyFreeResources(bool aggressively_free_resources) override;
   void Swap() override;
   void SwapWithBounds(const std::vector<gfx::Rect>& rects) override;
@@ -625,7 +625,7 @@
   void FinishHelper();
   void FlushHelper();
 
-  void RunIfContextNotLost(const base::Closure& callback);
+  void RunIfContextNotLost(base::OnceClosure callback);
 
   // Validate if an offset is valid, i.e., non-negative and fit into 32-bit.
   // If not, generate an approriate error, and return false.
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 30505b4d..ee15be2d 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -226,17 +226,6 @@
                                     web::BuildUserAgentFromProduct(product));
   }
 
-  // Populate command line flag for fetching missing favicons for NTP tiles.
-  NSString* enableMostLikelyFaviconsFromServer =
-      [defaults stringForKey:@"EnableNtpMostLikelyFaviconsFromServer"];
-  if ([enableMostLikelyFaviconsFromServer isEqualToString:@"Enabled"]) {
-    command_line->AppendSwitch(
-        ntp_tiles::switches::kEnableNtpMostLikelyFaviconsFromServer);
-  } else if ([enableMostLikelyFaviconsFromServer isEqualToString:@"Disabled"]) {
-    command_line->AppendSwitch(
-        ntp_tiles::switches::kDisableNtpMostLikelyFaviconsFromServer);
-  }
-
   // Freeform commandline flags.  These are added last, so that any flags added
   // earlier in this function take precedence.
   if ([defaults boolForKey:@"EnableFreeformCommandLineFlags"]) {
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 7975dd8c..f6b5131 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
@@ -181,6 +181,20 @@
     self.logoVendor.view.translatesAutoresizingMaskIntoConstraints = NO;
     self.fakeOmnibox.translatesAutoresizingMaskIntoConstraints = NO;
 
+    // -headerForView is regularly called before self.headerView has been added
+    // to the view hierarchy, so there's no simple way to get the correct
+    // safeAreaInsets.  Since this situation is universally called for the full
+    // screen new tab animation, it's safe to check the rootViewController's
+    // view instead.
+    UIView* insetsView = self.headerView;
+    if (!self.headerView.window) {
+      insetsView =
+          [[UIApplication sharedApplication] keyWindow].rootViewController.view;
+    }
+    UIEdgeInsets safeAreaInsets = SafeAreaInsetsForView(insetsView);
+    width = std::max<CGFloat>(
+        0, width - safeAreaInsets.left - safeAreaInsets.right);
+
     self.fakeOmniboxWidthConstraint = [self.fakeOmnibox.widthAnchor
         constraintEqualToConstant:content_suggestions::searchFieldWidth(width)];
     [self addConstraintsForLogoView:self.logoVendor.view
diff --git a/ios/chrome/browser/history/history_tab_helper.mm b/ios/chrome/browser/history/history_tab_helper.mm
index 9cbb594d..a0501e4 100644
--- a/ios/chrome/browser/history/history_tab_helper.mm
+++ b/ios/chrome/browser/history/history_tab_helper.mm
@@ -92,7 +92,7 @@
     return;
   }
 
-  DCHECK(web_state_->GetNavigationManager()->GetVisibleItem());
+  DCHECK(web_state->GetNavigationManager()->GetVisibleItem());
   web::NavigationItem* visible_item =
       web_state_->GetNavigationManager()->GetVisibleItem();
   DCHECK(!visible_item->GetTimestamp().is_null());
@@ -138,9 +138,21 @@
       referrer_url != kNewTabPageReferrerURL &&
       referrer_url != kReadingListReferrerURL;
 
+  // Top-level frame navigations are visible; everything else is hidden.
+  // Also hide top-level navigations that result in an error in order to
+  // prevent the omnibox from suggesting URLs that have never been navigated
+  // to successfully.  (If a top-level navigation to the URL succeeds at some
+  // point, the URL will be unhidden and thus eligible to be suggested by the
+  // omnibox.)
+  const bool hidden =
+      navigation_context->GetError() ||
+      (navigation_context->GetResponseHeaders() &&
+       navigation_context->GetResponseHeaders()->response_code() >= 400 &&
+       navigation_context->GetResponseHeaders()->response_code() > 600) ||
+      !ui::PageTransitionIsMainFrame(navigation_context->GetPageTransition());
   history::HistoryAddPageArgs add_page_args(
       url, visible_item->GetTimestamp(), this, visible_item->GetUniqueID(),
-      referrer_url, redirects, transition, history::SOURCE_BROWSED,
+      referrer_url, redirects, transition, hidden, history::SOURCE_BROWSED,
       /*did_replace_entry=*/false, consider_for_ntp_most_visited);
 
   if (delay_notification_) {
diff --git a/ios/chrome/browser/passwords/resources/password_controller.js b/ios/chrome/browser/passwords/resources/password_controller.js
index 209d148..6cb7cdd 100644
--- a/ios/chrome/browser/passwords/resources/password_controller.js
+++ b/ios/chrome/browser/passwords/resources/password_controller.js
@@ -187,33 +187,6 @@
   };
 
   /**
-   * Returns the element with the specified name that is a child of the
-   * specified parent element.
-   * @param {Element} parent The parent of the desired element.
-   * @param {string} name The name of the desired element.
-   * @param {boolen} isPassword Whether the field should be a password field;
-   *     if not supplied, |false| is assumed.
-   * @return {Element} The element if found, otherwise null;
-   */
-  __gCrWeb['getElementByNameWithParent'] = function(
-      parent, name, isPassword) {
-    isPassword = isPassword || false;
-    var parentType = parent.type || "";
-    var isParentPassword = parentType === "password";
-    if (parent.name === name && (isPassword === isParentPassword)) {
-      return parent;
-    }
-    for (var i = 0; i < parent.children.length; i++) {
-      var el = __gCrWeb.getElementByNameWithParent(
-          parent.children[i], name, isPassword);
-      if (el) {
-        return el;
-      }
-    }
-    return null;
-  };
-
-  /**
    * Given a description of a form (origin, action and input fields),
    * finds that form on the page and fills in the specified username
    * and password.
diff --git a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
index 256aab34c..9a91bb4 100644
--- a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
+++ b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
@@ -318,28 +318,6 @@
 			<key>AutocorrectionType</key>
 			<string>No</string>
 		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSMultiValueSpecifier</string>
-			<key>Title</key>
-			<string>Download missing favicons for NTP Most Likely Tiles from Google</string>
-			<key>Key</key>
-			<string>EnableNtpMostLikelyFaviconsFromServer</string>
-			<key>DefaultValue</key>
-			<string></string>
-			<key>Values</key>
-			<array>
-				<string></string>
-				<string>Enabled</string>
-				<string>Disabled</string>
-			</array>
-			<key>Titles</key>
-			<array>
-				<string>Default</string>
-				<string>Enabled</string>
-				<string>Disabled</string>
-			</array>
-		</dict>
 	</array>
 </dict>
 </plist>
diff --git a/ios/chrome/browser/ui/browser_view_controller_dependency_factory.mm b/ios/chrome/browser/ui/browser_view_controller_dependency_factory.mm
index fa213aa..50cdc82 100644
--- a/ios/chrome/browser/ui/browser_view_controller_dependency_factory.mm
+++ b/ios/chrome/browser/ui/browser_view_controller_dependency_factory.mm
@@ -68,7 +68,7 @@
                       dispatcher:
                           (id<ApplicationCommands, BrowserCommands>)dispatcher {
   id<Toolbar> toolbarController;
-  if (base::FeatureList::IsEnabled(kPropertyAnimationsToolbar)) {
+  if (base::FeatureList::IsEnabled(kCleanToolbar)) {
     ToolbarAdapter* adapter =
         [[ToolbarAdapter alloc] initWithDispatcher:dispatcher
                                       browserState:browserState_
diff --git a/ios/chrome/browser/ui/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
index 9690f0f..348efca4 100644
--- a/ios/chrome/browser/ui/browser_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
@@ -192,6 +192,9 @@
 - (void)setToolsMenuStateProvider:(id)provider {
   return;
 }
+- (void)start {
+  return;
+}
 @end
 
 #pragma mark -
diff --git a/ios/chrome/browser/ui/key_commands_provider.mm b/ios/chrome/browser/ui/key_commands_provider.mm
index 6c4514c2..63cfacc7 100644
--- a/ios/chrome/browser/ui/key_commands_provider.mm
+++ b/ios/chrome/browser/ui/key_commands_provider.mm
@@ -312,6 +312,20 @@
                           action:^{
                             [weakConsumer focusNextTab];
                           }],
+      [UIKeyCommand
+          cr_keyCommandWithInput:@"\t"
+                   modifierFlags:UIKeyModifierControl | UIKeyModifierShift
+                           title:nil
+                          action:^{
+                            [weakConsumer focusPreviousTab];
+                          }],
+      [UIKeyCommand
+          cr_keyCommandWithInput:@"\t"
+                   modifierFlags:UIKeyModifierControl
+                           title:nil
+                          action:^{
+                            [weakConsumer focusNextTab];
+                          }],
     ]];
   }
 
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h
index 9b5ac794..a03c6206 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h
@@ -5,7 +5,7 @@
 #ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_CLEAN_TOOLBAR_COORDINATOR_H_
 #define IOS_CHROME_BROWSER_UI_TOOLBAR_CLEAN_TOOLBAR_COORDINATOR_H_
 
-#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
 
 #include "ios/chrome/browser/ui/qr_scanner/requirements/qr_scanner_result_loading.h"
 #import "ios/chrome/browser/ui/toolbar/omnibox_focuser.h"
@@ -38,6 +38,8 @@
 @property(nonatomic, weak) id<ToolbarCoordinatorDelegate> delegate;
 // URL loader for the toolbar.
 @property(nonatomic, weak) id<UrlLoader> URLLoader;
+// UIViewController managed by this coordinator.
+@property(nonatomic, strong, readonly) UIViewController* viewController;
 
 // Start this coordinator.
 - (void)start;
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
index f5c524f..a3bfc79 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
@@ -20,6 +20,8 @@
 #include "ios/chrome/browser/ui/omnibox/location_bar_controller.h"
 #include "ios/chrome/browser/ui/omnibox/location_bar_controller_impl.h"
 #include "ios/chrome/browser/ui/omnibox/location_bar_delegate.h"
+#import "ios/chrome/browser/ui/omnibox/omnibox_popup_positioner.h"
+#include "ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator_delegate.h"
@@ -40,12 +42,13 @@
 #error "This file requires ARC support."
 #endif
 
-@interface ToolbarCoordinator ()<LocationBarDelegate> {
+@interface ToolbarCoordinator ()<LocationBarDelegate, OmniboxPopupPositioner> {
   std::unique_ptr<LocationBarControllerImpl> _locationBar;
+  std::unique_ptr<OmniboxPopupViewIOS> _popupView;
 }
 
 // The View Controller managed by this coordinator.
-@property(nonatomic, strong) ToolbarViewController* viewController;
+@property(nonatomic, strong) ToolbarViewController* toolbarViewController;
 // The mediator owned by this coordinator.
 @property(nonatomic, strong) ToolbarMediator* mediator;
 // LocationBarView containing the omnibox. At some point, this property and the
@@ -61,7 +64,7 @@
 @synthesize locationBarView = _locationBarView;
 @synthesize mediator = _mediator;
 @synthesize URLLoader = _URLLoader;
-@synthesize viewController = _viewController;
+@synthesize toolbarViewController = _toolbarViewController;
 @synthesize webStateList = _webStateList;
 
 - (instancetype)init {
@@ -71,6 +74,12 @@
   return self;
 }
 
+#pragma mark - Properties
+
+- (UIViewController*)viewController {
+  return self.toolbarViewController;
+}
+
 #pragma mark - BrowserCoordinator
 
 - (void)start {
@@ -89,22 +98,26 @@
                                    tintColor:tintColor];
   _locationBar = base::MakeUnique<LocationBarControllerImpl>(
       self.locationBarView, self.browserState, self, self.dispatcher);
+  _popupView = _locationBar->CreatePopupView(self);
   // End of TODO(crbug.com/785253):.
 
   ToolbarStyle style = isIncognito ? INCOGNITO : NORMAL;
   ToolbarButtonFactory* factory =
       [[ToolbarButtonFactory alloc] initWithStyle:style];
 
-  self.viewController =
+  self.toolbarViewController =
       [[ToolbarViewController alloc] initWithDispatcher:self.dispatcher
                                           buttonFactory:factory];
+  self.toolbarViewController.locationBarView = self.locationBarView;
 
-  self.mediator.consumer = self.viewController;
+  self.mediator.consumer = self.toolbarViewController;
   self.mediator.webStateList = self.webStateList;
 }
 
 - (void)stop {
   [self.mediator disconnect];
+  // The popup has to be destroyed before the location bar.
+  _popupView.reset();
   _locationBar.reset();
   self.locationBarView = nil;
 }
@@ -131,13 +144,45 @@
   self.viewController.view.hidden = NO;
   [_locationBarView setHidden:YES];
   [self.mediator updateConsumerForWebState:webState];
-  [self.viewController updateForSideSwipeSnapshotOnNTP:isNTP];
+  [self.toolbarViewController updateForSideSwipeSnapshotOnNTP:isNTP];
 }
 
 - (void)resetToolbarAfterSideSwipeSnapshot {
   [self.mediator updateConsumerForWebState:[self getWebState]];
   [_locationBarView setHidden:NO];
-  [self.viewController resetAfterSideSwipeSnapshot];
+  [self.toolbarViewController resetAfterSideSwipeSnapshot];
+}
+
+// TODO(crbug.com/786940): This protocol should move to the ViewController
+// owning the Toolbar. This can wait until the omnibox and toolbar refactoring
+// is more advanced.
+#pragma mark OmniboxPopupPositioner methods.
+
+- (UIView*)popupAnchorView {
+  return self.toolbarViewController.view;
+}
+
+- (CGRect)popupFrame:(CGFloat)height {
+  UIView* parent = [[self popupAnchorView] superview];
+  CGRect frame = [parent bounds];
+
+  if (IsIPadIdiom()) {
+    // For iPad, the omnibox is displayed between the location bar and the
+    // bottom of the toolbar.
+    CGRect fieldFrame = [parent convertRect:[_locationBarView bounds]
+                                   fromView:_locationBarView];
+    CGFloat maxY = CGRectGetMaxY(fieldFrame);
+    frame.origin.y = maxY + kiPadOmniboxPopupVerticalOffset;
+    frame.size.height = height;
+  } else {
+    // For iPhone place the popup just below the toolbar.
+    CGRect fieldFrame =
+        [parent convertRect:[self.toolbarViewController.view bounds]
+                   fromView:self.toolbarViewController.view];
+    frame.origin.y = CGRectGetMaxY(fieldFrame);
+    frame.size.height = CGRectGetMaxY([parent bounds]) - frame.origin.y;
+  }
+  return frame;
 }
 
 #pragma mark - LocationBarDelegate
@@ -175,14 +220,14 @@
 - (void)locationBarHasBecomeFirstResponder {
   [self.delegate locationBarDidBecomeFirstResponder];
   if (@available(iOS 10, *)) {
-    [self.viewController expandOmniboxAnimated:YES];
+    [self.toolbarViewController expandOmniboxAnimated:YES];
   }
 }
 
 - (void)locationBarHasResignedFirstResponder {
   [self.delegate locationBarDidResignFirstResponder];
   if (@available(iOS 10, *)) {
-    [self.viewController contractOmnibox];
+    [self.toolbarViewController contractOmnibox];
   }
 }
 
@@ -223,7 +268,7 @@
     model->OnSetFocus(false);
     model->SetCaretVisibility(false);
   } else {
-    [self.viewController expandOmniboxAnimated:NO];
+    [self.toolbarViewController expandOmniboxAnimated:NO];
   }
 
   [self focusOmnibox];
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h
index 91192c8..eb7d042 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h
@@ -38,7 +38,7 @@
 // The dispatcher for this view controller.
 @property(nonatomic, weak) id<ApplicationCommands, BrowserCommands> dispatcher;
 
-@property(nonatomic, strong) UIViewController* locationBarViewController;
+@property(nonatomic, strong) UIView* locationBarView;
 
 // Animates the toolbar so the omnibox is shrinking to its standard state.
 - (void)contractOmnibox;
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
index ba80428..83bcb022 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
@@ -16,6 +16,7 @@
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_constants.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
+#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
 #import "ios/third_party/material_components_ios/src/components/ProgressView/src/MaterialProgressView.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -40,7 +41,7 @@
 @implementation ToolbarViewController
 @synthesize buttonFactory = _buttonFactory;
 @synthesize dispatcher = _dispatcher;
-@synthesize locationBarViewController = _locationBarViewController;
+@synthesize locationBarView = _locationBarView;
 @synthesize stackView = _stackView;
 @synthesize locationBarContainer = _locationBarContainer;
 @synthesize backButton = _backButton;
@@ -90,9 +91,11 @@
 - (void)viewDidLoad {
   self.view.backgroundColor =
       [self.buttonFactory.toolbarConfiguration backgroundColor];
-  [self addChildViewController:self.locationBarViewController
-                     toSubview:self.locationBarContainer];
   [self setUpToolbarStackView];
+  if (self.locationBarView) {
+    [self.locationBarContainer addSubview:self.locationBarView];
+    AddSameConstraints(self.locationBarContainer, self.locationBarView);
+  }
   [self.view addSubview:self.stackView];
   [self.view addSubview:self.progressBar];
   [self setConstraints];
@@ -114,8 +117,7 @@
 }
 
 - (void)setConstraints {
-  [self.view setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
-                                 UIViewAutoresizingFlexibleHeight];
+  self.view.translatesAutoresizingMaskIntoConstraints = NO;
   NSArray* constraints = @[
     [self.stackView.topAnchor constraintEqualToAnchor:self.view.topAnchor
                                              constant:kVerticalMargin],
@@ -138,11 +140,19 @@
   ];
 
   // Constraint so Toolbar stackview never overlaps with the Status Bar.
-  NSLayoutConstraint* constraintTop = [self.stackView.topAnchor
-      constraintGreaterThanOrEqualToAnchor:self.topLayoutGuide.bottomAnchor
-                                  constant:kVerticalMargin];
-  constraintTop.priority = UILayoutPriorityRequired;
-  constraintTop.active = YES;
+  NSLayoutYAxisAnchor* topAnchor;
+  if (@available(iOS 11, *)) {
+    topAnchor = self.view.safeAreaLayoutGuide.topAnchor;
+  } else {
+    topAnchor = self.topLayoutGuide.topAnchor;
+  }
+  [self.stackView.topAnchor
+      constraintGreaterThanOrEqualToAnchor:topAnchor
+                                  constant:kVerticalMargin]
+      .active = YES;
+  [self.view.bottomAnchor constraintEqualToAnchor:topAnchor
+                                         constant:kToolbarHeight]
+      .active = YES;
 
   // Set the constraints priority to UILayoutPriorityDefaultHigh so these are
   // not broken when the views are hidden or the VC's view size is 0.
@@ -317,24 +327,18 @@
   [viewController didMoveToParentViewController:self];
 }
 
-- (void)setLocationBarViewController:(UIViewController*)controller {
-  if (self.locationBarViewController == controller) {
+- (void)setLocationBarView:(UIView*)view {
+  if (_locationBarView == view) {
     return;
   }
+  view.translatesAutoresizingMaskIntoConstraints = NO;
 
   if ([self isViewLoaded]) {
-    // Remove the old child view controller.
-    if (self.locationBarViewController) {
-      DCHECK_EQ(self, self.locationBarViewController.parentViewController);
-      [self.locationBarViewController willMoveToParentViewController:nil];
-      [self.locationBarViewController.view removeFromSuperview];
-      [self.locationBarViewController removeFromParentViewController];
-    }
-    // Add the new child view controller.
-    [self addChildViewController:controller
-                       toSubview:self.locationBarContainer];
+    [_locationBarView removeFromSuperview];
+    [self.locationBarContainer addSubview:view];
+    AddSameConstraints(self.locationBarContainer, view);
   }
-  _locationBarViewController = controller;
+  _locationBarView = view;
 }
 
 #pragma mark - Trait Collection Changes
diff --git a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h
index b3653d4..bbfb0e5 100644
--- a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h
+++ b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h
@@ -36,9 +36,12 @@
                   ActivityServicePositioner,
                   QRScannerResultLoading,
                   BubbleViewAnchorPointProvider>
+
 - (void)setToolsMenuStateProvider:
     (id<ToolsMenuPresentationStateProvider>)provider;
 - (void)setToolsMenuIsVisibleForToolsMenuButton:(BOOL)isVisible;
+- (void)start;
+
 @end
 
 @interface LegacyToolbarCoordinator
diff --git a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
index a15789ca..fa52d77f 100644
--- a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
@@ -95,6 +95,7 @@
     _toolsMenuCoordinator.presentationProvider =
         (id<ToolsMenuPresentationProvider>)_toolbarController;
   }
+  [toolbarController start];
 }
 
 - (void)setToolbarDelegate:(id<WebToolbarDelegate>)delegate {
@@ -213,16 +214,23 @@
 
 - (UIView*)snapshotForStackViewWithWidth:(CGFloat)width
                           safeAreaInsets:(UIEdgeInsets)safeAreaInsets {
-  CGRect oldFrame = self.toolbarViewController.view.frame;
+  // The snapshotted view must not be in the view hierarchy, because the code
+  // below temporarily changes the frames of views in order to take the snapshot
+  // in simulated target frame. The frames will be returned to normal after the
+  // snapshot is taken.
+  DCHECK(self.toolbarViewController.view.window == nil);
+
+  CGRect oldFrame = self.toolbarViewController.view.superview.frame;
   CGRect newFrame = oldFrame;
   newFrame.size.width = width;
 
-  self.toolbarViewController.view.frame = newFrame;
+  self.toolbarViewController.view.superview.frame = newFrame;
   [self.toolbarController activateFakeSafeAreaInsets:safeAreaInsets];
+  [self.toolbarViewController.view.superview layoutIfNeeded];
 
   UIView* toolbarSnapshotView = [self snapshotForTabSwitcher];
 
-  self.toolbarViewController.view.frame = oldFrame;
+  self.toolbarViewController.view.superview.frame = oldFrame;
   [self.toolbarController deactivateFakeSafeAreaInsets];
 
   return toolbarSnapshotView;
diff --git a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.h b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.h
index a90082b2..49372476 100644
--- a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.h
+++ b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.h
@@ -11,6 +11,9 @@
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 
+// Height of the toolbar.
+extern const CGFloat kToolbarHeight;
+
 // The time delay before non-initial button images are loaded.
 extern const int64_t kNonInitialImageAdditionDelayNanosec;
 
diff --git a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.mm b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.mm
index cff46cac..bf2cbb70 100644
--- a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.mm
+++ b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.mm
@@ -8,6 +8,8 @@
 #error "This file requires ARC support."
 #endif
 
+const CGFloat kToolbarHeight = 56;
+
 const int64_t kNonInitialImageAdditionDelayNanosec = 500000LL;
 
 NSString* const kToolbarIdentifier = @"kToolbarIdentifier";
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm b/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm
index c1455d55..e0cfdfda 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm
@@ -19,7 +19,6 @@
 @synthesize delegate = _delegate;
 @synthesize toolsPopupController = _toolsPopupController;
 @synthesize URLLoader = _URLLoader;
-@synthesize viewController = _viewController;
 
 - (instancetype)initWithDispatcher:
                     (id<ApplicationCommands, BrowserCommands>)dispatcher
@@ -47,6 +46,10 @@
   self.toolbarCoordinator.URLLoader = URLLoader;
 }
 
+- (UIViewController*)viewController {
+  return self.toolbarCoordinator.viewController;
+}
+
 #pragma mark - Abstract WebToolbar
 
 - (void)browserStateDestroyed {
@@ -124,6 +127,10 @@
   return;
 }
 
+- (void)start {
+  [self.toolbarCoordinator start];
+}
+
 #pragma mark - OmniboxFocuser
 
 - (void)focusOmnibox {
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
index 034dc437..1500a426 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
@@ -89,8 +89,17 @@
   API_AVAILABLE(ios(10.0)) UIViewPropertyAnimator* _omniboxContractorAnimator;
 }
 
+// Leading and trailing safe area constraint for faking a safe area. These
+// constraints are activated by calling activateFakeSafeAreaInsets and
+// deactivateFakeSafeAreaInsets.
 @property(nonatomic, strong) NSLayoutConstraint* leadingFakeSafeAreaConstraint;
 @property(nonatomic, strong) NSLayoutConstraint* trailingFakeSafeAreaConstraint;
+
+// These constraints pin the content view to the safe area. They are temporarily
+// disabled when a fake safe area is simulated by calling
+// activateFakeSafeAreaInsets.
+@property(nonatomic, strong) NSLayoutConstraint* leadingSafeAreaConstraint;
+@property(nonatomic, strong) NSLayoutConstraint* trailingSafeAreaConstraint;
 // Style of this toolbar.
 @property(nonatomic, readonly, assign) ToolbarControllerStyle style;
 // The view containing all the content of the toolbar. It respects the trailing
@@ -117,6 +126,8 @@
 @synthesize dispatcher = dispatcher_;
 @synthesize leadingFakeSafeAreaConstraint = _leadingFakeSafeAreaConstraint;
 @synthesize trailingFakeSafeAreaConstraint = _trailingFakeSafeAreaConstraint;
+@synthesize leadingSafeAreaConstraint = _leadingSafeAreaConstraint;
+@synthesize trailingSafeAreaConstraint = _trailingSafeAreaConstraint;
 @dynamic view;
 
 - (instancetype)initWithStyle:(ToolbarControllerStyle)style
@@ -176,12 +187,12 @@
       safeAreaTrailing = [contentView_.trailingAnchor
           constraintEqualToAnchor:self.view.trailingAnchor];
     }
-    self.leadingFakeSafeAreaConstraint = [contentView_.leadingAnchor
+    _leadingSafeAreaConstraint = safeAreaLeading;
+    _trailingSafeAreaConstraint = safeAreaTrailing;
+    _leadingFakeSafeAreaConstraint = [contentView_.leadingAnchor
         constraintEqualToAnchor:self.view.leadingAnchor];
-    self.trailingFakeSafeAreaConstraint = [contentView_.trailingAnchor
+    _trailingFakeSafeAreaConstraint = [contentView_.trailingAnchor
         constraintEqualToAnchor:self.view.trailingAnchor];
-    safeAreaLeading.priority = UILayoutPriorityDefaultHigh;
-    safeAreaTrailing.priority = UILayoutPriorityDefaultHigh;
     [NSLayoutConstraint activateConstraints:@[
       safeAreaLeading,
       safeAreaTrailing,
@@ -308,6 +319,8 @@
       UIEdgeInsetsGetLeading(fakeSafeAreaInsets);
   self.trailingFakeSafeAreaConstraint.constant =
       -UIEdgeInsetsGetTrailing(fakeSafeAreaInsets);
+  self.leadingSafeAreaConstraint.active = NO;
+  self.trailingSafeAreaConstraint.active = NO;
   self.leadingFakeSafeAreaConstraint.active = YES;
   self.trailingFakeSafeAreaConstraint.active = YES;
 }
@@ -315,6 +328,8 @@
 - (void)deactivateFakeSafeAreaInsets {
   self.leadingFakeSafeAreaConstraint.active = NO;
   self.trailingFakeSafeAreaConstraint.active = NO;
+  self.leadingSafeAreaConstraint.active = YES;
+  self.trailingSafeAreaConstraint.active = YES;
 }
 
 - (void)setToolsMenuIsVisibleForToolsMenuButton:(BOOL)isVisible {
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm b/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm
index 405631e..3fb5102 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm
@@ -271,11 +271,6 @@
 
 // Verifies that copying and pasting a URL includes the hidden protocol prefix.
 - (void)testCopyPasteURL {
-  // TODO(crbug.com/686069): Re-enable this test.  It is failing on iOS 9.
-  if (!base::ios::IsRunningOnIOS10OrLater()) {
-    EARL_GREY_TEST_DISABLED(@"Disabled on iOS 9.");
-  }
-
   // Clear generalPasteboard before and after the test.
   [UIPasteboard generalPasteboard].string = @"";
   [self setTearDownHandler:^{
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
index 64c6171e..bf08a7e 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -566,6 +566,9 @@
   return self;
 }
 
+- (void)start {
+}
+
 #pragma mark -
 #pragma mark Acessors
 
diff --git a/ios/chrome/browser/ui/ui_util.mm b/ios/chrome/browser/ui/ui_util.mm
index 28fe597..2526140 100644
--- a/ios/chrome/browser/ui/ui_util.mm
+++ b/ios/chrome/browser/ui/ui_util.mm
@@ -63,8 +63,9 @@
 }
 
 bool IsSafeAreaCompatibleToolbarEnabled() {
-  return IsIPhoneX() &&
-         base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar);
+  return (IsIPhoneX() &&
+          base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) ||
+         base::FeatureList::IsEnabled(kCleanToolbar);
 }
 
 CGFloat StatusBarHeight() {
@@ -73,8 +74,7 @@
 
   if (IsIPhoneX()) {
     if (IsSafeAreaCompatibleToolbarEnabled()) {
-      CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
-      return CGRectGetHeight(statusBarFrame);
+      return IsPortrait() ? 44 : 0;
     } else {
       // Return the height of the portrait status bar even in landscape because
       // the Toolbar does not properly layout itself if the status bar height
diff --git a/ios/chrome/browser/web/visible_url_egtest.mm b/ios/chrome/browser/web/visible_url_egtest.mm
index a93fc979..fb6d396 100644
--- a/ios/chrome/browser/web/visible_url_egtest.mm
+++ b/ios/chrome/browser/web/visible_url_egtest.mm
@@ -177,7 +177,13 @@
 
 // Tests that visible URL is always the same as last committed URL during
 // pending back and forward navigations.
-- (void)testBackForwardNavigation {
+// TODO(crbug.com/787872): Re-enable this test on devices.
+#if TARGET_IPHONE_SIMULATOR
+#define MAYBE_testBackForwardNavigation testBackForwardNavigation
+#else
+#define MAYBE_testBackForwardNavigation FLAKY_testBackForwardNavigation
+#endif
+- (void)MAYBE_testBackForwardNavigation {
   // Purge web view caches and pause the server to make sure that tests can
   // verify omnibox state before server starts responding.
   GREYAssert(PurgeCachedWebViewPages(), @"Pages were not purged");
@@ -503,7 +509,15 @@
 
 // Tests that visible URL is always the same as last committed URL if user
 // issues 2 go forward commands to WebUI page (crbug.com/711465).
-- (void)testDoubleForwardNavigationToWebUIPage {
+// TODO(crbug.com/787872): Re-enable this test on devices.
+#if TARGET_IPHONE_SIMULATOR
+#define MAYBE_testDoubleForwardNavigationToWebUIPage \
+  testDoubleForwardNavigationToWebUIPage
+#else
+#define MAYBE_testDoubleForwardNavigationToWebUIPage \
+  FLAKY_testDoubleForwardNavigationToWebUIPage
+#endif
+- (void)MAYBE_testDoubleForwardNavigationToWebUIPage {
   // Create 3rd entry in the history, to be able to go back twice.
   GURL URL(kChromeUIVersionURL);
   [ChromeEarlGrey loadURL:GURL(kChromeUIVersionURL)];
diff --git a/ios/web/public/test/web_test_with_web_state.mm b/ios/web/public/test/web_test_with_web_state.mm
index fed95692..cec7177 100644
--- a/ios/web/public/test/web_test_with_web_state.mm
+++ b/ios/web/public/test/web_test_with_web_state.mm
@@ -8,6 +8,7 @@
 #include "base/scoped_observer.h"
 #include "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
+#import "ios/testing/wait_util.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #import "ios/web/public/web_client.h"
 #include "ios/web/public/web_state/url_verification_constants.h"
@@ -19,6 +20,9 @@
 #error "This file requires ARC support."
 #endif
 
+using testing::WaitUntilConditionOrTimeout;
+using testing::kWaitForJSCompletionTimeout;
+
 namespace {
 // Returns CRWWebController for the given |web_state|.
 CRWWebController* GetWebController(web::WebState* web_state) {
@@ -163,18 +167,20 @@
 }
 
 id WebTestWithWebState::ExecuteJavaScript(NSString* script) {
-  __block id executionResult;
-  __block bool executionCompleted = false;
+  __block id execution_result = nil;
+  __block bool execution_completed = false;
+  SCOPED_TRACE(base::SysNSStringToUTF8(script));
   [GetWebController(web_state())
       executeJavaScript:script
       completionHandler:^(id result, NSError* error) {
-        executionResult = [result copy];
-        executionCompleted = true;
+        execution_result = [result copy];
+        execution_completed = true;
       }];
-  base::test::ios::WaitUntilCondition(^{
-    return executionCompleted;
-  });
-  return executionResult;
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return execution_completed;
+  }));
+
+  return execution_result;
 }
 
 void WebTestWithWebState::DestroyWebState() {
diff --git a/ios/web/web_state/js/common_js_unittest.mm b/ios/web/web_state/js/common_js_unittest.mm
index 96408cce..48d3f4b3 100644
--- a/ios/web/web_state/js/common_js_unittest.mm
+++ b/ios/web/web_state/js/common_js_unittest.mm
@@ -157,6 +157,9 @@
       {@"http://foo6.com/bar/#baz#blech", @"http://foo6.com/bar/"},
       // Poorly formed URLs are normalized.
       {@"http:///foo7.com//bar?baz", @"http://foo7.com//bar"},
+      // Non-http protocols.
+      {@"data:abc", @"data:abc"},
+      {@"javascript:login()", @"javascript:login()"},
   };
   for (size_t i = 0; i < arraysize(test_data); i++) {
     LoadHtml(@"<p>");
diff --git a/ios/web/web_state/js/resources/common.js b/ios/web/web_state/js/resources/common.js
index 7283c86..b69d0be 100644
--- a/ios/web/web_state/js/resources/common.js
+++ b/ios/web/web_state/js/resources/common.js
@@ -527,7 +527,10 @@
    */
   __gCrWeb.common.removeQueryAndReferenceFromURL = function(url) {
     var parsed = new URL(url);
-    return parsed.origin + parsed.pathname;
+    // For some protocols (eg. data:, javascript:) URL.origin is "null" so
+    // URL.protocol is used instead.
+    return (parsed.origin !== "null" ? parsed.origin : parsed.protocol)
+      + parsed.pathname;
   };
 
   /**
diff --git a/media/gpu/vaapi_wrapper.cc b/media/gpu/vaapi_wrapper.cc
index 618f9506..c229f9b3 100644
--- a/media/gpu/vaapi_wrapper.cc
+++ b/media/gpu/vaapi_wrapper.cc
@@ -205,12 +205,16 @@
 
 // static
 bool VADisplayState::PostSandboxInitialization() {
+  const std::string va_suffix(std::to_string(VA_MAJOR_VERSION + 1));
   StubPathMap paths;
-  paths[kModuleVa].push_back("libva.so.1");
+
+  paths[kModuleVa].push_back(std::string("libva.so.") + va_suffix);
 #if defined(USE_X11)
-  paths[kModuleVa_x11].push_back("libva-x11.so.1");
+  // libva-x11 does not exist on libva >= 2
+  if (VA_MAJOR_VERSION == 0)
+    paths[kModuleVa_x11].push_back("libva-x11.so.1");
 #elif defined(USE_OZONE)
-  paths[kModuleVa_drm].push_back("libva-drm.so.1");
+  paths[kModuleVa_drm].push_back(std::string("libva-drm.so.") + va_suffix);
 #endif
 
   const bool success = InitializeStubs(paths);
diff --git a/media/midi/midi_message_queue.h b/media/midi/midi_message_queue.h
index c351b33..804164f 100644
--- a/media/midi/midi_message_queue.h
+++ b/media/midi/midi_message_queue.h
@@ -8,9 +8,9 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <deque>
 #include <vector>
 
-#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "media/midi/midi_export.h"
 
@@ -64,7 +64,14 @@
   void Get(std::vector<uint8_t>* message);
 
  private:
-  base::circular_deque<uint8_t> queue_;
+  // While we should be using base::circular_deque here, the Chrome OS version
+  // hasn't been upreved to contain that implementation yet. Since for the
+  // purposes of this class the semantics of std::deque and
+  // base::circular_deque are the same, we can use the former.
+  // Once Chrome OS has upreved to a version of libchrome which includes
+  // base::circular_deque, we can switch back to it.
+  // TODO(pmalani): http://crbug.com/787643 tracking this.
+  std::deque<uint8_t> queue_;
   std::vector<uint8_t> next_message_;
   const bool allow_running_status_;
   DISALLOW_COPY_AND_ASSIGN(MidiMessageQueue);
diff --git a/printing/printing_context.cc b/printing/printing_context.cc
index 84f9a9c..26b7df3 100644
--- a/printing/printing_context.cc
+++ b/printing/printing_context.cc
@@ -23,7 +23,7 @@
     : delegate_(delegate),
       in_print_job_(false),
       abort_printing_(false) {
-  CHECK(delegate_);
+  DCHECK(delegate_);
 }
 
 PrintingContext::~PrintingContext() {
diff --git a/printing/printing_context.h b/printing/printing_context.h
index 03f940c..96934fb0 100644
--- a/printing/printing_context.h
+++ b/printing/printing_context.h
@@ -140,7 +140,7 @@
   PrintSettings settings_;
 
   // Printing context delegate.
-  Delegate* delegate_;
+  Delegate* const delegate_;
 
   // Is a print job being done.
   volatile bool in_print_job_;
diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn
index b9318813..17c2a7f 100644
--- a/services/network/public/cpp/BUILD.gn
+++ b/services/network/public/cpp/BUILD.gn
@@ -14,11 +14,14 @@
     "url_loader_completion_status.h",
   ]
 
+  public_deps = [
+    "//services/network/public/interfaces",
+  ]
+
   deps = [
     "//base",
     "//mojo/common",
     "//net",
-    "//services/network/public/interfaces",
   ]
 }
 
diff --git a/services/network/public/cpp/DEPS b/services/network/public/cpp/DEPS
new file mode 100644
index 0000000..d3acaa0
--- /dev/null
+++ b/services/network/public/cpp/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  # CORS related files will be included from Blink, and should use cors.mojom-shared.h.
+  "-services/network/public/interfaces/cors.mojom.h",
+]
diff --git a/services/network/public/cpp/cors_error_status.h b/services/network/public/cpp/cors_error_status.h
index 7214251..529d885 100644
--- a/services/network/public/cpp/cors_error_status.h
+++ b/services/network/public/cpp/cors_error_status.h
@@ -7,7 +7,7 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "net/http/http_response_headers.h"
-#include "services/network/public/interfaces/cors.mojom.h"
+#include "services/network/public/interfaces/cors.mojom-shared.h"
 
 namespace network {
 
diff --git a/services/network/public/cpp/url_loader_completion_status.h b/services/network/public/cpp/url_loader_completion_status.h
index 2c39f8c..5e5aed16 100644
--- a/services/network/public/cpp/url_loader_completion_status.h
+++ b/services/network/public/cpp/url_loader_completion_status.h
@@ -11,7 +11,7 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "services/network/public/cpp/cors_error_status.h"
-#include "services/network/public/interfaces/cors.mojom.h"
+#include "services/network/public/interfaces/cors.mojom-shared.h"
 
 namespace network {
 
diff --git a/services/ui/public/cpp/gpu/DEPS b/services/ui/public/cpp/gpu/DEPS
index 01136b5..446f64fa6 100644
--- a/services/ui/public/cpp/gpu/DEPS
+++ b/services/ui/public/cpp/gpu/DEPS
@@ -1,4 +1,3 @@
 include_rules = [
-  "+components/arc/common",
   "-services/ui/common",
 ]
diff --git a/services/ui/public/cpp/gpu/gpu.cc b/services/ui/public/cpp/gpu/gpu.cc
index 393fbb5..4329f3fb 100644
--- a/services/ui/public/cpp/gpu/gpu.cc
+++ b/services/ui/public/cpp/gpu/gpu.cc
@@ -182,12 +182,7 @@
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   GpuPtrFactory factory =
       base::BindRepeating(&DefaultFactory, connector, service_name);
-  auto gpu =
-      base::WrapUnique(new Gpu(std::move(factory), std::move(task_runner)));
-#if defined(OS_CHROMEOS)
-  gpu->InitializeArc(connector, service_name);
-#endif  // defined(OS_CHROMEOS)
-  return gpu;
+  return base::WrapUnique(new Gpu(std::move(factory), std::move(task_runner)));
 }
 
 scoped_refptr<viz::ContextProvider> Gpu::CreateContextProvider(
@@ -214,26 +209,6 @@
       shared_context_provider, command_buffer_metrics::MUS_CLIENT_CONTEXT);
 }
 
-#if defined(OS_CHROMEOS)
-void Gpu::CreateArcVideoDecodeAccelerator(
-    arc::mojom::VideoDecodeAcceleratorRequest vda_request) {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  arc_->CreateVideoDecodeAccelerator(std::move(vda_request));
-}
-
-void Gpu::CreateArcVideoEncodeAccelerator(
-    arc::mojom::VideoEncodeAcceleratorRequest vea_request) {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  arc_->CreateVideoEncodeAccelerator(std::move(vea_request));
-}
-
-void Gpu::CreateArcProtectedBufferManager(
-    arc::mojom::ProtectedBufferManagerRequest pbm_request) {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  arc_->CreateProtectedBufferManager(std::move(pbm_request));
-}
-#endif  // OS_CHROMEOS
-
 void Gpu::CreateJpegDecodeAccelerator(
     media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
@@ -356,12 +331,4 @@
   return std::make_unique<base::SharedMemory>(platform_handle, readonly);
 }
 
-#if defined(OS_CHROMEOS)
-void Gpu::InitializeArc(service_manager::Connector* connector,
-                        const std::string& service_name) {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  connector->BindInterface(service_name, &arc_);
-}
-#endif  // defined(OS_CHROMEOS)
-
 }  // namespace ui
diff --git a/services/ui/public/cpp/gpu/gpu.h b/services/ui/public/cpp/gpu/gpu.h
index 8589637..3aeff615 100644
--- a/services/ui/public/cpp/gpu/gpu.h
+++ b/services/ui/public/cpp/gpu/gpu.h
@@ -11,19 +11,11 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
-#include "build/build_config.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "services/ui/public/cpp/gpu/client_gpu_memory_buffer_manager.h"
 #include "services/ui/public/interfaces/gpu.mojom.h"
 
-#if defined(OS_CHROMEOS)
-#include "components/arc/common/protected_buffer_manager.mojom.h"  // nogncheck https://crbug.com/784179
-#include "components/arc/common/video_decode_accelerator.mojom.h"  // nogncheck https://crbug.com/784179
-#include "components/arc/common/video_encode_accelerator.mojom.h"  // nogncheck https://crbug.com/784179
-#include "services/ui/public/interfaces/arc.mojom.h"
-#endif  // defined(OS_CHROMEOS)
-
 namespace service_manager {
 class Connector;
 }
@@ -48,14 +40,7 @@
 
   scoped_refptr<viz::ContextProvider> CreateContextProvider(
       scoped_refptr<gpu::GpuChannelHost> gpu_channel);
-#if defined(OS_CHROMEOS)
-  void CreateArcVideoDecodeAccelerator(
-      arc::mojom::VideoDecodeAcceleratorRequest vda_request);
-  void CreateArcVideoEncodeAccelerator(
-      arc::mojom::VideoEncodeAcceleratorRequest vea_request);
-  void CreateArcProtectedBufferManager(
-      arc::mojom::ProtectedBufferManagerRequest pbm_request);
-#endif
+
   void CreateJpegDecodeAccelerator(
       media::mojom::GpuJpegDecodeAcceleratorRequest jda_request);
   void CreateVideoEncodeAcceleratorProvider(
@@ -93,11 +78,6 @@
   std::unique_ptr<base::SharedMemory> AllocateSharedMemory(
       size_t size) override;
 
-#if defined(OS_CHROMEOS)
-  void InitializeArc(service_manager::Connector* connector,
-                     const std::string& service_name);
-#endif  // defined(OS_CHROMEOS)
-
   scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
   std::unique_ptr<ClientGpuMemoryBufferManager> gpu_memory_buffer_manager_;
@@ -107,10 +87,6 @@
   scoped_refptr<gpu::GpuChannelHost> gpu_channel_;
   std::vector<gpu::GpuChannelEstablishedCallback> establish_callbacks_;
 
-#if defined(OS_CHROMEOS)
-  ui::mojom::ArcPtr arc_;
-#endif  // defined(OS_CHROMEOS)
-
   DISALLOW_COPY_AND_ASSIGN(Gpu);
 };
 
diff --git a/storage/browser/quota/special_storage_policy.h b/storage/browser/quota/special_storage_policy.h
index cac9f94..4b0763c9 100644
--- a/storage/browser/quota/special_storage_policy.h
+++ b/storage/browser/quota/special_storage_policy.h
@@ -58,6 +58,12 @@
   // when the session ends.
   virtual bool IsStorageSessionOnly(const GURL& origin) = 0;
 
+  // Cookies should also be deleted if the origin is blocked because it is
+  // possible to e.g. create an .example.com cookie from www.example.com. If
+  // www.example.com is SESSION_ONLY and example.com is BLOCKED, this cookie
+  // could be created but not deleted.
+  virtual bool IsStorageSessionOnlyOrBlocked(const GURL& origin) = 0;
+
   // Returns true if some origins are only allowed session-only storage.
   virtual bool HasSessionOnlyOrigins() = 0;
 
diff --git a/storage/browser/test/mock_special_storage_policy.cc b/storage/browser/test/mock_special_storage_policy.cc
index 3f1a198..3642c1d5 100644
--- a/storage/browser/test/mock_special_storage_policy.cc
+++ b/storage/browser/test/mock_special_storage_policy.cc
@@ -24,6 +24,11 @@
   return base::ContainsKey(session_only_, origin);
 }
 
+bool MockSpecialStoragePolicy::IsStorageSessionOnlyOrBlocked(
+    const GURL& origin) {
+  return base::ContainsKey(session_only_, origin);
+}
+
 bool MockSpecialStoragePolicy::HasIsolatedStorage(const GURL& origin) {
   return base::ContainsKey(isolated_, origin);
 }
diff --git a/storage/browser/test/mock_special_storage_policy.h b/storage/browser/test/mock_special_storage_policy.h
index 64528b65..0fd80734 100644
--- a/storage/browser/test/mock_special_storage_policy.h
+++ b/storage/browser/test/mock_special_storage_policy.h
@@ -22,6 +22,7 @@
   bool IsStorageProtected(const GURL& origin) override;
   bool IsStorageUnlimited(const GURL& origin) override;
   bool IsStorageSessionOnly(const GURL& origin) override;
+  bool IsStorageSessionOnlyOrBlocked(const GURL& origin) override;
   bool HasIsolatedStorage(const GURL& origin) override;
   bool HasSessionOnlyOrigins() override;
   bool IsStorageDurable(const GURL& origin) override;
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index 77352adb..39a520a 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -4016,68 +4016,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release_x64",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:22b1",
-              "id": "build146-b1",
-              "os": "Windows-10-10586",
-              "pool": "Chrome-perf-fyi"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:22b1",
-              "id": "build146-b1",
-              "os": "Windows-10-10586",
-              "pool": "Chrome-perf-fyi"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -7830,68 +7768,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release_x64",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:9874",
-              "id": "build210-b4",
-              "os": "Windows-10-10586",
-              "pool": "Chrome-perf-fyi"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:9874",
-              "id": "build210-b4",
-              "os": "Windows-10-10586",
-              "pool": "Chrome-perf-fyi"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 20d42f0..e29e3930 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -4538,66 +4538,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=android-chromium",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_mobile",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build14-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_mobile.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build14-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -9189,66 +9129,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=android-chromium",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_mobile",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build74-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_mobile.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build74-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -11503,36 +11383,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=android-webview",
-          "--output-format=chartjson",
-          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
-        ],
-        "isolate_name": "telemetry_perf_webview_tests",
-        "name": "v8.runtimestats.browsing_mobile",
-        "override_compile_targets": [
-          "telemetry_perf_webview_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build165-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -16094,66 +15944,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=android-chromium",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_mobile",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build16-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_mobile.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build16-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -18408,36 +18198,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=android-webview",
-          "--output-format=chartjson",
-          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
-        ],
-        "isolate_name": "telemetry_perf_webview_tests",
-        "name": "v8.runtimestats.browsing_mobile",
-        "override_compile_targets": [
-          "telemetry_perf_webview_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build113-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -22999,66 +22759,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=android-chromium",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_mobile",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build10-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_mobile.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build10-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -27610,66 +27310,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=android-chromium",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_mobile",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build18-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_mobile",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_mobile.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "id": "build18-b1--device1",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -31577,68 +31217,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3",
-              "id": "build30-a9",
-              "os": "Ubuntu-14.04",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3",
-              "id": "build30-a9",
-              "os": "Ubuntu-14.04",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -35536,68 +35114,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0166",
-              "id": "build105-b1",
-              "os": "Mac-10.11",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0166",
-              "id": "build105-b1",
-              "os": "Mac-10.11",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -39495,68 +39011,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "id": "build159-m1",
-              "os": "Mac-10.12",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "id": "build159-m1",
-              "os": "Mac-10.12",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -43454,68 +42908,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:1626",
-              "id": "build124-b1",
-              "os": "Mac-10.11",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:1626",
-              "id": "build124-b1",
-              "os": "Mac-10.11",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -47397,68 +46789,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a26",
-              "id": "build25-b1",
-              "os": "Mac-10.12",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a26",
-              "id": "build25-b1",
-              "os": "Mac-10.12",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -51356,68 +50686,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "id": "build131-b1",
-              "os": "Mac-10.11",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "id": "build131-b1",
-              "os": "Mac-10.11",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -55315,68 +54583,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0d26",
-              "id": "build5-b1",
-              "os": "Mac-10.11",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0d26",
-              "id": "build5-b1",
-              "os": "Mac-10.11",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -59129,68 +58335,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release_x64",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:1616",
-              "id": "build118-b1",
-              "os": "Windows-10-10240",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:1616",
-              "id": "build118-b1",
-              "os": "Windows-10-10240",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -62964,68 +62108,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release_x64",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "102b:0534",
-              "id": "build133-m1",
-              "os": "Windows-10-10240",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "102b:0534",
-              "id": "build133-m1",
-              "os": "Windows-10-10240",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -66841,68 +65923,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release_x64",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6613",
-              "id": "build102-m1",
-              "os": "Windows-2008ServerR2-SP1",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6613",
-              "id": "build102-m1",
-              "os": "Windows-2008ServerR2-SP1",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -70718,68 +69738,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release_x64",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:041a",
-              "id": "build165-m1",
-              "os": "Windows-2008ServerR2-SP1",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:041a",
-              "id": "build165-m1",
-              "os": "Windows-2008ServerR2-SP1",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -74619,68 +73577,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release_x64",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3",
-              "id": "build93-m1",
-              "os": "Windows-2008ServerR2-SP1",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3",
-              "id": "build93-m1",
-              "os": "Windows-2008ServerR2-SP1",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "--use-cmd-decoder=validating",
           "--use-stub"
         ],
@@ -78499,68 +77395,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "102b:0532",
-              "id": "build186-m1",
-              "os": "Windows-2008ServerR2-SP1",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "102b:0532",
-              "id": "build186-m1",
-              "os": "Windows-2008ServerR2-SP1",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -82355,68 +81189,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release_x64",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "102b:0532",
-              "id": "build141-m1",
-              "os": "Windows-2008ServerR2-SP1",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "102b:0532",
-              "id": "build141-m1",
-              "os": "Windows-2008ServerR2-SP1",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
@@ -86232,68 +85004,6 @@
       },
       {
         "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=release_x64",
-          "--output-format=chartjson"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "102b:0532",
-              "id": "build144-m1",
-              "os": "Windows-2012ServerR2-SP0",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
-          "v8.runtimestats.browsing_desktop",
-          "-v",
-          "--upload-results",
-          "--browser=reference",
-          "--output-format=chartjson",
-          "--max-failures=5",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "v8.runtimestats.browsing_desktop.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "102b:0532",
-              "id": "build144-m1",
-              "os": "Windows-2012ServerR2-SP0",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 36000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 600,
-          "upload_test_results": true
-        }
-      },
-      {
-        "args": [
           "webrtc",
           "-v",
           "--upload-results",
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 8936ad6..2ce76be6 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -21,11 +21,6 @@
 -BrowsingDataRemoverTransportSecurityStateBrowserTest.ClearTransportSecurityState
 -CaptivePortalBrowserTest.RequestFailsFastTimout
 -CertVerifierBrowserTest.MockCertVerifierSmokeTest
--ChromeResourceDispatcherHostDelegateBrowserTest.PolicyHeader
--ChromeResourceDispatcherHostDelegateBrowserTest.PolicyHeaderForRedirect
--ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToADownloads
--ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToLargeSniffedDownloads
--ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToTinySniffedDownloads
 -ChromeSecurityExploitBrowserTest.CreateFilesystemURLInExtensionOrigin
 -ChromeSitePerProcessTest.LaunchExternalProtocolFromSubframe
 -ContentFaviconDriverTest.ReloadBypassingCache
@@ -69,6 +64,7 @@
 # DnsProbeBrowserTests that are flaky.
 -DnsProbeBrowserTest.CorrectionsLoadStopped
 -DnsProbeBrowserTest.CorrectionsLoadStoppedSlowProbe
+-DnsProbeBrowserTest.NoInternetProbeResultWithSlowBrokenCorrections
 -DomainReliabilityBrowserTest.Upload
 -DoNotTrackTest.Redirect
 -DoNotTrackTest.Simple
@@ -349,7 +345,6 @@
 -CaptivePortalBrowserTest.RequestFails
 -CaptivePortalBrowserTest.Status511
 -CaptivePortalBrowserTest.TwoBrokenTabs
--ChromeResourceDispatcherHostDelegateBrowserTest.MirrorRequestHeader
 -ClientHintsBrowserTest.ClientHintsLifetimeNotAttachedCookiesBlocked
 -CommonNameMismatchBrowserTest.CheckWWWSubdomainMismatchInverse
 -CommonNameMismatchBrowserTest.ShouldShowWWWSubdomainMismatchInterstitial
@@ -410,6 +405,7 @@
 -NoSessionRestoreTest.SessionCookiesBrowserCloseWithPopupOpen
 -NoSessionRestoreTest.SessionCookiesCloseAllBrowsers
 -NoSessionRestoreTest.SessionStorage
+-NoSessionRestoreTest.SubdomainCookiesClearedOnCloseAllBrowsers
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.AppCacheHtmlUninitialized/0
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.IssuesIdlePriorityRequests/0
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.Jpeg/0
@@ -938,3 +934,11 @@
 # for frame requests and send IPCs from the renderer for subresources.
 # http://crbug.com/783981
 -ClientSideDetectionHostBrowserTest.VerifyIPAddressCollection
+
+# http://crbug.com/787614
+-ChromeResourceDispatcherHostDelegateBrowserTest.PolicyHeader
+-ChromeResourceDispatcherHostDelegateBrowserTest.PolicyHeaderForRedirect
+-ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToADownloads
+-ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToLargeSniffedDownloads
+-ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToTinySniffedDownloads
+-ChromeResourceDispatcherHostDelegateBrowserTest.MirrorRequestHeader
diff --git a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
index 1488ef61..0556cad2 100644
--- a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
@@ -8,7 +8,7 @@
 -ServiceWorkerNavigationPreloadTest.RespondWithNavigationPreloadWithMimeSniffing
 -ServiceWorkerV8CacheStrategiesAggressiveTest.V8CacheOnCacheStorage
 -ServiceWorkerV8CacheStrategiesNormalTest.V8CacheOnCacheStorage
--ServiceWorkerV8CacheStrategiesTest.V8CacheOnCacheStorage
+-ServiceWorkerV8CodeCacheForCacheStorageTest.V8CacheOnCacheStorage
 -ServiceWorkerVersionBrowserTest.ServiceWorkerScriptHeader
 
 # ServiceWorker restart needs to read installed scripts.
@@ -83,17 +83,6 @@
 -RequestDataResourceDispatcherHostBrowserTest.LinkRelPrefetchReferrerPolicy
 -RequestDataResourceDispatcherHostBrowserTest.SameOriginAuxiliary
 -RequestDataResourceDispatcherHostBrowserTest.SameOriginNested
--ResourceDispatcherHostBrowserTest.ContentDispositionEmpty
--ResourceDispatcherHostBrowserTest.ContentDispositionInline
--ResourceDispatcherHostBrowserTest.CrossOriginRedirectBlocked
--ResourceDispatcherHostBrowserTest.CrossSiteAfterCrash
--ResourceDispatcherHostBrowserTest.CrossSiteNavigationNonBuffered
--ResourceDispatcherHostBrowserTest.DoNotSniffHTMLFromImageGIF
--ResourceDispatcherHostBrowserTest.DoNotSniffHTMLFromTextPlain
--ResourceDispatcherHostBrowserTest.PageTransitionClientRedirect
--ResourceDispatcherHostBrowserTest.RespectNoSniffDirective
--ResourceDispatcherHostBrowserTest.SniffHTMLWithNoContentType
--ResourceDispatcherHostBrowserTest.SniffNoContentTypeNoData
 -SitePerProcessIgnoreCertErrorsBrowserTest.SubresourceWithCertificateErrors
 -WebContentsImplBrowserTest.ClearNonVisiblePendingOnFail
 -WebContentsImplBrowserTest.DownloadImage_Deny_FileImage
@@ -130,3 +119,16 @@
 -WorkerFetchTest.SharedWorkerHttpAuth/1
 -WorkerFetchTest.WorkerHttpAuth/0
 -WorkerFetchTest.WorkerHttpAuth/1
+
+# http://crbug.com/787614
+-ResourceDispatcherHostBrowserTest.ContentDispositionEmpty
+-ResourceDispatcherHostBrowserTest.ContentDispositionInline
+-ResourceDispatcherHostBrowserTest.CrossOriginRedirectBlocked
+-ResourceDispatcherHostBrowserTest.CrossSiteAfterCrash
+-ResourceDispatcherHostBrowserTest.CrossSiteNavigationNonBuffered
+-ResourceDispatcherHostBrowserTest.DoNotSniffHTMLFromImageGIF
+-ResourceDispatcherHostBrowserTest.DoNotSniffHTMLFromTextPlain
+-ResourceDispatcherHostBrowserTest.PageTransitionClientRedirect
+-ResourceDispatcherHostBrowserTest.RespectNoSniffDirective
+-ResourceDispatcherHostBrowserTest.SniffHTMLWithNoContentType
+-ResourceDispatcherHostBrowserTest.SniffNoContentTypeNoData
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 5beefb5..1a3eeab 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2105,6 +2105,24 @@
             ]
         }
     ],
+    "NTPUseGoogleLocalNtp": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "UseGoogleLocalNtp"
+                    ]
+                }
+            ]
+        }
+    ],
     "NetAdaptiveProxyConnectionTimeout": [
         {
             "platforms": [
@@ -3942,31 +3960,6 @@
             ]
         }
     ],
-    "V8CacheStrategiesForCacheStorage": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "linux",
-                "mac",
-                "win"
-            ],
-            "experiments": [
-                {
-                    "name": "default"
-                },
-                {
-                    "name": "none"
-                },
-                {
-                    "name": "normal"
-                },
-                {
-                    "name": "aggressive"
-                }
-            ]
-        }
-    ],
     "V8ContextSnapshot": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 7660a8e..02dd116 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -6184,9 +6184,9 @@
 crbug.com/591099 http/tests/devtools/extensions/extensions-sidebar.html [ Failure ]
 crbug.com/591099 http/tests/devtools/extensions/extensions-timeline-api.html [ Failure ]
 crbug.com/591099 http/tests/devtools/indexeddb/resources-panel.js [ Failure Timeout ]
-crbug.com/591099 http/tests/devtools/layers/layer-canvas-log.html [ Failure ]
-crbug.com/591099 http/tests/devtools/layers/layer-replay-scale.html [ Failure ]
-crbug.com/591099 http/tests/devtools/layers/layer-sticky-position-constraint-get.html [ Failure ]
+crbug.com/591099 http/tests/devtools/layers/layer-canvas-log.js [ Failure ]
+crbug.com/591099 http/tests/devtools/layers/layer-replay-scale.js [ Failure ]
+crbug.com/591099 http/tests/devtools/layers/layer-sticky-position-constraint-get.js [ Failure ]
 crbug.com/591099 http/tests/devtools/network/network-columns-visible.js [ Failure ]
 crbug.com/591099 http/tests/devtools/network/network-datareceived.js [ Failure ]
 crbug.com/591099 http/tests/devtools/network/network-disable-cache-preloads.php [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls b/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls
index abaef65..8d71d080 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls
@@ -44,10 +44,10 @@
 crbug.com/417782 [ Linux ] fast/spatial-navigation/snav-unit-overflow-and-scroll-in-direction.html [ Failure ]
 crbug.com/417782 html/dialog/form-method-dialog.html [ Crash ]
 crbug.com/417782 http/tests/devtools/device-mode/default-background-color.html [ Failure ]
-crbug.com/417782 http/tests/devtools/layers/layer-compositing-reasons.html [ Failure ]
-crbug.com/417782 http/tests/devtools/layers/layer-scroll-rects-get.html [ Failure ]
-crbug.com/417782 http/tests/devtools/layers/layer-tree-model.html [ Failure ]
-crbug.com/417782 http/tests/devtools/layers/layers-3d-view-hit-testing.html [ Failure ]
+crbug.com/417782 http/tests/devtools/layers/layer-compositing-reasons.js [ Failure ]
+crbug.com/417782 http/tests/devtools/layers/layer-scroll-rects-get.js [ Failure ]
+crbug.com/417782 http/tests/devtools/layers/layer-tree-model.js [ Failure ]
+crbug.com/417782 http/tests/devtools/layers/layers-3d-view-hit-testing.js [ Failure ]
 crbug.com/417782 [ Linux ] http/tests/devtools/sources/autocomplete-hide-on-smart-brace.js [ Timeout ]
 crbug.com/417782 http/tests/devtools/tracing/scroll-invalidations.html [ Failure ]
 crbug.com/417782 http/tests/devtools/tracing/timeline-paint/layer-tree.js [ Failure ]
@@ -84,10 +84,10 @@
 crbug.com/417782 [ Linux ] virtual/android/fullscreen/video-controls-timeline.html [ Failure ]
 crbug.com/417782 [ Linux ] virtual/android/fullscreen/video-scrolled-iframe.html [ Failure ]
 crbug.com/417782 virtual/mojo-loading/http/tests/devtools/device-mode/default-background-color.html [ Failure ]
-crbug.com/417782 virtual/mojo-loading/http/tests/devtools/layers/layer-compositing-reasons.html [ Failure ]
-crbug.com/417782 virtual/mojo-loading/http/tests/devtools/layers/layer-scroll-rects-get.html [ Failure ]
-crbug.com/417782 virtual/mojo-loading/http/tests/devtools/layers/layer-tree-model.html [ Failure ]
-crbug.com/417782 virtual/mojo-loading/http/tests/devtools/layers/layers-3d-view-hit-testing.html [ Failure ]
+crbug.com/417782 virtual/mojo-loading/http/tests/devtools/layers/layer-compositing-reasons.js [ Failure ]
+crbug.com/417782 virtual/mojo-loading/http/tests/devtools/layers/layer-scroll-rects-get.js [ Failure ]
+crbug.com/417782 virtual/mojo-loading/http/tests/devtools/layers/layer-tree-model.js [ Failure ]
+crbug.com/417782 virtual/mojo-loading/http/tests/devtools/layers/layers-3d-view-hit-testing.js [ Failure ]
 crbug.com/417782 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/layer-tree.js [ Failure ]
 crbug.com/417782 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Timeout ]
 crbug.com/417782 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.js [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
index d358cf7..37fbd03 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -74,8 +74,9 @@
 crbug.com/601584 virtual/mojo-loading/http/tests/bluetooth/https/requestDevice/cross-origin-iframe.html [ Failure ]
 
 # https://crbug.com/606594 - UaF of delegate_ in WebFrameTestClient::willSendRequest
-crbug.com/606594 http/tests/local/serviceworker/fetch-request-body-file.html [ Failure Crash ]
-crbug.com/606594 virtual/mojo-loading/http/tests/local/serviceworker/fetch-request-body-file.html [ Crash ]
+# https://crbug.com/786510 - test tries to access cross-origin document body
+crbug.com/606594 http/tests/local/serviceworker/fetch-request-body-file.html [ Skip ]
+crbug.com/606594 virtual/mojo-loading/http/tests/local/serviceworker/fetch-request-body-file.html [ Skip ]
 
 # https://crbug.com/607991 - MockWebClipboardImpl not replicated across OOPIFs.
 crbug.com/607991 http/tests/misc/copy-resolves-urls.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index 9bed552..2d5e112e 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -153,8 +153,8 @@
 crbug.com/451577 [ Mac ] http/tests/devtools/extensions/extensions-reload.html [ Slow ]
 crbug.com/451577 [ Mac ] http/tests/devtools/extensions/extensions-resources.html [ Slow ]
 crbug.com/451577 [ Win10 ] http/tests/devtools/extensions/extensions-sidebar.html [ Slow ]
-crbug.com/451577 [ Mac ] http/tests/devtools/layers/layer-canvas-log.html [ Slow ]
-crbug.com/667560 [ Mac ] virtual/mojo-loading/http/tests/devtools/layers/layer-canvas-log.html [ Slow ]
+crbug.com/451577 [ Mac ] http/tests/devtools/layers/layer-canvas-log.js [ Slow ]
+crbug.com/667560 [ Mac ] virtual/mojo-loading/http/tests/devtools/layers/layer-canvas-log.js [ Slow ]
 crbug.com/451577 [ Mac ] http/tests/devtools/network/network-domain-filter.html [ Slow ]
 crbug.com/667560 [ Mac ] virtual/mojo-loading/http/tests/devtools/network/network-domain-filter.html [ Slow ]
 
@@ -471,8 +471,8 @@
 # These tests were previously marked Slow in ASANExpectations.
 crbug.com/451577 [ Linux ] http/tests/devtools/elements/user-properties.js [ Slow ]
 crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/elements/user-properties.js [ Slow ]
-crbug.com/451577 [ Linux ] http/tests/devtools/layers/layer-canvas-log.html [ Slow ]
-crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/layers/layer-canvas-log.html [ Slow ]
+crbug.com/451577 [ Linux ] http/tests/devtools/layers/layer-canvas-log.js [ Slow ]
+crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/layers/layer-canvas-log.js [ Slow ]
 
 # These imported tests exercise tens of thousands of code points and generate large results.
 crbug.com/736056 external/wpt/encoding/legacy-mb-japanese [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 316d7f34..bc075ae 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -428,7 +428,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-bfc-003-right-table.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-bfc-004.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-bfc-006.xht [ Failure ]
-crbug.com/723135 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-zero-height-wrap-001.xht [ Failure ]
 crbug.com/723135 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-zero-height-wrap-002.xht [ Failure ]
 
 ### virtual/layout_ng/external/wpt/css/CSS2/floats-clear
@@ -451,12 +450,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-137.xht [ Skip ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-143.xht [ Failure ]
 
-# Regressions while changing zero-block-size float behaviour.
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/001.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/005.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/001.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/005.html [ Failure ]
-
 ### virtual/layout_ng/external/wpt/css/CSS2/linebox
 
 # 1px glyph position diff at box boundary. Check if they need fix.
@@ -629,12 +622,6 @@
 ### virtual/layout_ng/fast/block/margin-collapse
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/103.html [ Failure ]
 
-### virtual/layout_ng/fast/block/margin-collapse/block-inside-inline
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/010.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/011.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/012.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/015.html [ Failure ]
-
 ### virtual/layout_ng/fast/block/margin-collapse
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/clear-nested-float-more-than-one-previous-sibling-away.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/webkit-margin-collapse-container.html [ Failure ]
@@ -645,6 +632,16 @@
 crbug.com/724701 virtual/layout_ng/overflow/overflow-basic-004.html [ Failure ]
 crbug.com/728378 virtual/layout_ng/overflow/overflow-position-003.html [ Failure ]
 
+### single pixel underline Mac failures
+crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/margin-collapse/001.html [ Failure ]
+crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/margin-collapse/005.html [ Failure ]
+crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/001.html [ Failure ]
+crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/005.html [ Failure ]
+crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/010.html [ Failure ]
+crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/011.html [ Failure ]
+crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/012.html [ Failure ]
+crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/015.html [ Failure ]
+
 # ====== LayoutNG,LayoutNGPaintFragments ======
 
 ### Crash site: ContainerNode.cpp
@@ -760,6 +757,7 @@
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation.html [ Failure Crash ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/host-pseudo-elements.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/layout.html [ Failure ]
+# Solving crbug.com/787717 would fix the crash of nodetree-radio-node-list.html
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/nodetree-radio-node-list.html [ Failure Crash ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/offsetParent.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/slots-1.html [ Failure ]
@@ -2058,7 +2056,6 @@
 
 # ====== New tests from wpt-importer added here ======
 crbug.com/626703 [ Retina ] external/wpt/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.https.html [ Timeout ]
-crbug.com/626703 external/wpt/css/css-display/display-contents-dynamic-pseudo-insertion-001.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1i.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1j.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1k.html [ Failure ]
@@ -3285,17 +3282,6 @@
 # module script lacks XHTML support
 crbug.com/717643 external/wpt/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml [ Failure ]
 
-crbug.com/778796 http/tests/devtools/console/console-custom-formatters.js [ Skip ]
-crbug.com/778796 http/tests/devtools/console/console-uncaught-promise-in-worker.js [ Skip ]
-crbug.com/778796 http/tests/devtools/sources/debugger-async/async-callstack-promises.js [ Skip ]
-crbug.com/778796 http/tests/devtools/sources/debugger-step/debugger-step-through-promises.js [ Skip ]
-crbug.com/778796 http/tests/devtools/sources/debugger/async-callstack-fetch.js [ Skip ]
-crbug.com/778796 virtual/mojo-loading/http/tests/devtools/console/console-custom-formatters.js [ Skip ]
-crbug.com/778796 virtual/mojo-loading/http/tests/devtools/console/console-uncaught-promise-in-worker.js [ Skip ]
-crbug.com/778796 virtual/mojo-loading/http/tests/devtools/sources/debugger-async/async-callstack-promises.js [ Skip ]
-crbug.com/778796 virtual/mojo-loading/http/tests/devtools/sources/debugger-step/debugger-step-through-promises.js [ Skip ]
-crbug.com/778796 virtual/mojo-loading/http/tests/devtools/sources/debugger/async-callstack-fetch.js [ Skip ]
-
 # known bug: import() inside set{Timeout,Interval}
 crbug.com/773622 external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-classic.html [ Failure ]
 crbug.com/773622 external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-module.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/animations/resources/animation-test-helpers.js b/third_party/WebKit/LayoutTests/animations/resources/animation-test-helpers.js
index 7164a1b0..eed57ca3 100644
--- a/third_party/WebKit/LayoutTests/animations/resources/animation-test-helpers.js
+++ b/third_party/WebKit/LayoutTests/animations/resources/animation-test-helpers.js
@@ -246,7 +246,7 @@
     if (document.getAnimations().length > 0) {
         callback();
     } else {
-        setTimeout(waitForAnimationsToStart.bind(this, callback), 0);
+        requestAnimationFrame(waitForAnimationsToStart.bind(this, callback));
     }
 }
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-dynamic-pseudo-insertion-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-dynamic-pseudo-insertion-001-ref.html
index 9c59597..38dd74a7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-dynamic-pseudo-insertion-001-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-dynamic-pseudo-insertion-001-ref.html
@@ -2,4 +2,4 @@
 <meta charset="utf-8">
 <title>CSS Test Reference</title>
 <link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
-PASS
+P<span>A</span>SS
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html
new file mode 100644
index 0000000..e50c7b52
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrer with the no-referrer policy</title>
+<meta name="referrer" content="no-referrer">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+
+// "name" parameter is necessary for bypassing the module map.
+
+import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same";
+
+import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote";
+
+import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same";
+
+import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote";
+
+import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote";
+
+test(t => {
+  assert_equals(
+      referrerSame, "",
+      "Referrer should not be sent for the same-origin top-level script.");
+}, "Importing a same-origin top-level script with the no-referrer policy.");
+
+test(t => {
+  assert_equals(
+      referrerRemote, "",
+      "Referrer should not be sent for the remote-origin top-level script.");
+}, "Importing a remote-origin top-level script with the no-referrer policy.");
+
+test(t => {
+  assert_equals(
+      referrerSameSame, "",
+      "Referrer should not be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a same-origin top-level " +
+   "script with the no-referrer policy.");
+
+test(t => {
+  assert_equals(
+      referrerSameRemote, "",
+      "Referrer should not be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a same-origin top-level " +
+   "script with the no-referrer policy.");
+
+test(t => {
+  assert_equals(
+      referrerRemoteRemote, "",
+      "Referrer should not be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a remote-origin " +
+   "top-level script with the no-referrer policy.");
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub-expected.txt
new file mode 100644
index 0000000..cd990f90
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS Importing a same-origin top-level script with the origin-when-cross-origin policy.
+PASS Importing a remote-origin top-level script with the origin-when-cross-origin policy.
+PASS Importing a same-origin descendant script from a same-origin top-level script with the origin-when-cross-origin policy.
+PASS Importing a remote-origin descendant script from a same-origin top-level script with the origin-when-cross-origin policy.
+FAIL Importing a remote-origin descendant script from a remote-origin top-level script with the origin-when-cross-origin policy. assert_equals: Referrer should be sent for the remote-origin descendant script. expected "http://www1.web-platform.test:8001/" but got "http://www1.web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html
new file mode 100644
index 0000000..3623ac2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrer with the origin-when-cross-origin policy</title>
+<meta name="referrer" content="origin-when-cross-origin">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+
+// "name" parameter is necessary for bypassing the module map.
+
+import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same";
+
+import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote";
+
+import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same";
+
+import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote";
+
+import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote";
+
+const origin = (new URL(location.href)).origin + "/";
+const remoteOrigin = "http://{{domains[www1]}}:{{ports[http][0]}}/";
+
+test(t => {
+  assert_equals(
+      referrerSame, location.href,
+      "Referrer should be sent for the same-origin top-level script.");
+}, "Importing a same-origin top-level script with the " +
+   "origin-when-cross-origin policy.");
+
+test(t => {
+  assert_equals(
+      referrerRemote, origin,
+      "Referrer should be sent for the remote-origin top-level script.");
+}, "Importing a remote-origin top-level script with the " +
+   "origin-when-cross-origin policy.");
+
+test(t => {
+  const scriptURL =
+      new URL("resources/import-referrer-checker.sub.js", location.href)
+  assert_equals(
+      referrerSameSame, scriptURL + "?name=same_same",
+      "Referrer should be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a same-origin top-level " +
+   "script with the origin-when-cross-origin policy.");
+
+test(t => {
+  assert_equals(
+      referrerSameRemote, origin,
+      "Referrer should be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a same-origin top-level " +
+   "script with the origin-when-cross-origin policy.");
+
+test(t => {
+  assert_equals(
+      referrerRemoteRemote, remoteOrigin,
+      "Referrer should be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a remote-origin " +
+   "top-level script with the origin-when-cross-origin policy.");
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html
new file mode 100644
index 0000000..f512982a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrer with the origin policy</title>
+<meta name="referrer" content="origin">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+
+// "name" parameter is necessary for bypassing the module map.
+
+import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same";
+
+import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote";
+
+import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same";
+
+import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote";
+
+import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote";
+
+const origin = (new URL(location.href)).origin + "/";
+const remoteOrigin = "http://{{domains[www1]}}:{{ports[http][0]}}/";
+
+test(t => {
+  assert_equals(
+      referrerSame, origin,
+      "Referrer should be sent for the same-origin top-level script.");
+}, "Importing a same-origin top-level script with the origin policy.");
+
+test(t => {
+  assert_equals(
+      referrerRemote, origin,
+      "Referrer should be sent for the remote-origin top-level script.");
+}, "Importing a remote-origin top-level script with the origin policy.");
+
+test(t => {
+  assert_equals(
+      referrerSameSame, origin,
+      "Referrer should be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a same-origin top-level " +
+   "script with the origin policy.");
+
+test(t => {
+  assert_equals(
+      referrerSameRemote, origin,
+      "Referrer should be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a same-origin top-level " +
+   "script with the origin policy.");
+
+test(t => {
+  assert_equals(
+      referrerRemoteRemote, remoteOrigin,
+      "Referrer should be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a remote-origin " +
+   "top-level script with the origin policy.");
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub-expected.txt
new file mode 100644
index 0000000..6720439b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS Importing a same-origin top-level script with the same-origin policy.
+PASS Importing a remote-origin top-level script with the same-origin policy.
+PASS Importing a same-origin descendant script from a same-origin top-level script with the same-origin policy.
+PASS Importing a remote-origin descendant script from a same-origin top-level script with the same-origin policy.
+FAIL Importing a remote-origin descendant script from a remote-origin top-level script with the same-origin policy. assert_equals: Referrer should not be sent for the remote-origin descendant script even if it is imported from the script in the same remote-origin. expected "" but got "http://www1.web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html
new file mode 100644
index 0000000..67b055c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrer with the same-origin policy</title>
+<meta name="referrer" content="same-origin">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+
+// "name" parameter is necessary for bypassing the module map.
+
+import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same";
+
+import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote";
+
+import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same";
+
+import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote";
+
+import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote";
+
+test(t => {
+  assert_equals(
+      referrerSame, location.href,
+      "Referrer should be sent for the same-origin top-level script.");
+}, "Importing a same-origin top-level script with the same-origin policy.");
+
+test(t => {
+  assert_equals(
+      referrerRemote, "",
+      "Referrer should not be sent for the remote-origin top-level script.");
+}, "Importing a remote-origin top-level script with the same-origin policy.");
+
+test(t => {
+  const path =
+      new URL("resources/import-referrer-checker.sub.js", location.href);
+  assert_equals(
+      referrerSameSame, path + `?name=same_same`,
+      "Referrer should be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a same-origin top-level " +
+   "script with the same-origin policy.");
+
+test(t => {
+  assert_equals(
+      referrerSameRemote, "",
+      "Referrer should not be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a same-origin top-level " +
+   "script with the same-origin policy.");
+
+test(t => {
+  assert_equals(
+      referrerRemoteRemote, "",
+      "Referrer should not be sent for the remote-origin descendant script " +
+      "even if it is imported from the script in the same remote-origin.");
+}, "Importing a remote-origin descendant script from a remote-origin " +
+   "top-level script with the same-origin policy.");
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html
new file mode 100644
index 0000000..11f60c0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrer with the unsafe-url policy</title>
+<meta name="referrer" content="unsafe-url">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+
+// "name" parameter is necessary for bypassing the module map.
+
+import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same";
+
+import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote";
+
+import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same";
+
+import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote";
+
+import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote";
+
+test(t => {
+  assert_equals(
+      referrerSame, location.href,
+      "Referrer should be sent for the same-origin top-level script.");
+}, "Importing a same-origin top-level script with the unsafe-url policy.");
+
+test(t => {
+  assert_equals(
+      referrerRemote, location.href,
+      "Referrer should be sent for the remote-origin top-level script.");
+}, "Importing a remote-origin top-level script with the unsafe-url policy.");
+
+test(t => {
+  const scriptURL =
+      new URL("resources/import-referrer-checker.sub.js", location.href)
+  assert_equals(
+      referrerSameSame, scriptURL + "?name=same_same",
+      "Referrer should be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a same-origin top-level " +
+   "script with the unsafe-url policy.");
+
+test(t => {
+  const scriptURL =
+      new URL("resources/import-remote-origin-referrer-checker.sub.js",
+              location.href)
+  assert_equals(
+      referrerSameRemote, scriptURL + "?name=same_remote",
+      "Referrer should be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a same-origin top-level " +
+   "script with the unsafe-url policy.");
+
+test(t => {
+  const scriptURL =
+      "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/" +
+      "scripting-1/the-script-element/module/resources/" +
+      "import-referrer-checker.sub.js";
+  assert_equals(
+      referrerRemoteRemote, scriptURL + "?name=remote_remote",
+      "Referrer should be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a remote-origin " +
+   "top-level script with the unsafe-url policy.");
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js
new file mode 100644
index 0000000..2c7dce9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js
@@ -0,0 +1,2 @@
+import { referrer as referrerImport } from './referrer-checker.py?name={{GET[name]}}';
+export const referrer = referrerImport;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers
new file mode 100644
index 0000000..cb762eff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js
new file mode 100644
index 0000000..45a2520
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js
@@ -0,0 +1,2 @@
+import { referrer as referrerImport } from 'http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name={{GET[name]}}';
+export const referrer = referrerImport;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py
new file mode 100644
index 0000000..b652cbe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py
@@ -0,0 +1,6 @@
+def main(request, response):
+    referrer = request.headers.get("referer", "")
+    response_headers = [("Content-Type", "text/javascript"),
+                        ("Access-Control-Allow-Origin", "*")];
+    return (200, response_headers,
+            "export const referrer = '" + referrer + "';")
diff --git a/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/idlharness.html
index ab8fd74..6c2d488d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/idlharness.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/idlharness.html
@@ -19,11 +19,6 @@
 <pre id='untested_idl' style='display:none'>
 typedef double DOMHighResTimeStamp;
 
-interface Window {
-    [Replaceable]
-    readonly attribute Performance performance;
-};
-
 [Exposed=(Window,Worker)]
 interface Performance {
 };
@@ -140,7 +135,8 @@
   idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
   idl_array.add_idls(document.getElementById("idl").textContent);
 
-  idl_array.add_objects({PerformanceNavigation: ["window.performance.navigation"],
+  idl_array.add_objects({Performance: ["window.performance"],
+                         PerformanceNavigation: ["window.performance.navigation"],
                          PerformanceTiming: ["window.performance.timing"],
                          PerformanceNavigationTiming: ["window.performance.getEntriesByType('navigation')[0]"] });
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-tests.js b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-tests.js
index 366bb9b..2fee0169 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-tests.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-tests.js
@@ -9,88 +9,71 @@
     });
 }
 
+// Run a referrer policy test with the given settings.
+//
+// Example:
+// settings = {
+//   workletType: 'paint',
+//   referrerPolicy: 'no-referrer',
+//   isCrossOrigin: false
+// };
+function runReferrerTest(settings) {
+  const kWindowURL =
+      'resources/referrer-window.html' +
+      `?pipe=header(Referrer-Policy, ${settings.referrerPolicy})`;
+  return openWindow(kWindowURL).then(win => {
+    const promise = new Promise(resolve => window.onmessage = resolve);
+    win.postMessage(settings, '*');
+    return promise;
+  }).then(msg_event => assert_equals(msg_event.data, 'RESOLVED'));
+}
+
 // Runs a series of tests related to the referrer policy on a worklet.
 //
 // Usage:
 // runReferrerTests("paint");
-function runReferrerTests(worklet_type) {
-  const worklet = get_worklet(worklet_type);
+function runReferrerTests(workletType) {
+  const worklet = get_worklet(workletType);
 
   promise_test(() => {
-      const kWindowURL = "resources/referrer-window.html" +
-                         "?pipe=header(Referrer-Policy,no-referrer)";
-      return openWindow(kWindowURL).then(win => {
-          const promise = new Promise(resolve => window.onmessage = resolve);
-          win.postMessage({ type: worklet_type,
-                            referrer_policy: 'no-referrer',
-                            is_cross_origin: false }, '*');
-          return promise;
-      }).then(msg_event => assert_equals(msg_event.data, 'RESOLVED'));
+      return runReferrerTest({ workletType: workletType,
+                               referrerPolicy: 'no-referrer',
+                               isCrossOrigin: false });
   }, 'Importing a same-origin script from a page that has "no-referrer" ' +
      'referrer policy should not send referrer.');
 
   promise_test(() => {
-      const kWindowURL = "resources/referrer-window.html" +
-                         "?pipe=header(Referrer-Policy,no-referrer)";
-      return openWindow(kWindowURL).then(win => {
-          const promise = new Promise(resolve => window.onmessage = resolve);
-          win.postMessage({ type: worklet_type,
-                            referrer_policy: 'no-referrer',
-                            is_cross_origin: true }, '*');
-          return promise;
-      }).then(msg_event => assert_equals(msg_event.data, 'RESOLVED'));
+      return runReferrerTest({ workletType: workletType,
+                               referrerPolicy: 'no-referrer',
+                               isCrossOrigin: true });
   }, 'Importing a remote-origin script from a page that has "no-referrer" ' +
      'referrer policy should not send referrer.');
 
   promise_test(() => {
-      const kWindowURL = 'resources/referrer-window.html' +
-                         '?pipe=header(Referrer-Policy,origin)';
-      return openWindow(kWindowURL).then(win => {
-          const promise = new Promise(resolve => window.onmessage = resolve);
-          win.postMessage({ type: worklet_type,
-                            referrer_policy: 'origin',
-                            is_cross_origin: false }, '*');
-          return promise;
-      }).then(msg_event => assert_equals(msg_event.data, 'RESOLVED'));
+      return runReferrerTest({ workletType: workletType,
+                               referrerPolicy: 'origin',
+                               isCrossOrigin: false });
   }, 'Importing a same-origin script from a page that has "origin" ' +
      'referrer policy should send only an origin as referrer.');
 
   promise_test(() => {
-      const kWindowURL = 'resources/referrer-window.html' +
-                         '?pipe=header(Referrer-Policy,origin)';
-      return openWindow(kWindowURL).then(win => {
-          const promise = new Promise(resolve => window.onmessage = resolve);
-          win.postMessage({ type: worklet_type,
-                            referrer_policy: 'origin',
-                            is_cross_origin: true }, '*');
-          return promise;
-      }).then(msg_event => assert_equals(msg_event.data, 'RESOLVED'));
+      return runReferrerTest({ workletType: workletType,
+                               referrerPolicy: 'origin',
+                               isCrossOrigin: true });
   }, 'Importing a remote-origin script from a page that has "origin" ' +
      'referrer policy should send only an origin as referrer.');
 
   promise_test(() => {
-      const kWindowURL = 'resources/referrer-window.html' +
-                         '?pipe=header(Referrer-Policy,same-origin)';
-      return openWindow(kWindowURL).then(win => {
-          const promise = new Promise(resolve => window.onmessage = resolve);
-          win.postMessage({ type: worklet_type,
-                            referrer_policy: 'same-origin',
-                            is_cross_origin: false }, '*');
-          return promise;
-      }).then(msg_event => assert_equals(msg_event.data, 'RESOLVED'));
+      return runReferrerTest({ workletType: workletType,
+                               referrerPolicy: 'same-origin',
+                               isCrossOrigin: false });
   }, 'Importing a same-origin script from a page that has "same-origin" ' +
      'referrer policy should send referrer.');
 
   promise_test(() => {
-      const kWindowURL = 'resources/referrer-window.html' +
-                         '?pipe=header(Referrer-Policy,same-origin)';
-      return openWindow(kWindowURL).then(win => {
-          const promise = new Promise(resolve => window.onmessage = resolve);
-          win.postMessage({ type: worklet_type,
-                            referrer_policy: 'same-origin',
-                            is_cross_origin: true }, '*');
-          return promise;
-      }).then(msg_event => assert_equals(msg_event.data, 'RESOLVED'));
+      return runReferrerTest({ workletType: workletType,
+                               referrerPolicy: 'same-origin',
+                               isCrossOrigin: true });
   }, 'Importing a remote-origin script from a page that has "same-origin" ' +
      'referrer policy should not send referrer.');
 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-window.html b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-window.html
index 49f46db2..773bb3b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-window.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-window.html
@@ -9,22 +9,24 @@
 </head>
 <body>
 <script>
+function createScriptURL(isCrossOrigin, params) {
+  if (isCrossOrigin) {
+    return get_host_info().HTTPS_REMOTE_ORIGIN +
+           '/worklets/resources/referrer.py?' + params;
+  }
+  return 'referrer.py?' + params;
+}
+
 window.onmessage = e => {
-  const worklet_type = e.data.type;
-  const is_cross_origin = e.data.is_cross_origin;
+  const isCrossOrigin = e.data.isCrossOrigin;
 
   const params = new URLSearchParams;
-  params.append('referrer_policy', e.data.referrer_policy)
+  params.append('referrer_policy', e.data.referrerPolicy)
   params.append('source_origin', get_host_info().HTTPS_ORIGIN);
+  params.append('is_cross_origin', isCrossOrigin ? 'true' : 'false')
 
-  let script_url = '';
-  if (is_cross_origin) {
-    params.append('is_cross_origin', 'true')
-    script_url = get_host_info().HTTPS_REMOTE_ORIGIN + '/worklets/resources/';
-  }
-  script_url += 'referrer.py?' + params;
-
-  get_worklet(worklet_type).addModule(script_url)
+  const scriptURL = createScriptURL(isCrossOrigin, params);
+  get_worklet(e.data.workletType).addModule(scriptURL)
       .then(() => window.opener.postMessage('RESOLVED', '*'))
       .catch(e => window.opener.postMessage(e.message, '*'));
 };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer.py b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer.py
index 62dd4a1..475845c9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer.py
+++ b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer.py
@@ -3,7 +3,7 @@
     referrer = request.headers.get("referer", None)
     referrer_policy = request.GET.first("referrer_policy")
     source_origin = request.GET.first("source_origin")
-    is_cross_origin = request.GET.first("is_cross_origin", False)
+    is_cross_origin = request.GET.first("is_cross_origin")
 
     response_headers = [("Content-Type", "text/javascript"),
                         ("Access-Control-Allow-Origin", source_origin)];
@@ -22,9 +22,9 @@
     # When the referrer policy is "same-origin", the referrer header should be
     # sent only for a same-origin request.
     if referrer_policy == "same-origin":
-        if is_cross_origin and not referrer:
+        if is_cross_origin == "true" and not referrer:
             return (200, response_headers, "")
-        if not is_cross_origin and referrer:
+        if is_cross_origin == "false" and referrer:
             return (200, response_headers, "")
 
     return (404)
diff --git a/third_party/WebKit/LayoutTests/fast/history/history-length-append-subframe-no-hash-expected.txt b/third_party/WebKit/LayoutTests/fast/history/history-length-append-subframe-no-hash-expected.txt
index 8eaea86f..e722c72 100644
--- a/third_party/WebKit/LayoutTests/fast/history/history-length-append-subframe-no-hash-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/history/history-length-append-subframe-no-hash-expected.txt
@@ -11,6 +11,5 @@
 ============== Back Forward List ==============
 curr->  (file test):fast/history/history-length-append-subframe-no-hash.html#wentBack
             about:blank (in frame "<!--framePath //<!--frame0-->-->")
-            about:blank (in frame "<!--framePath //<!--frame0-->-->")
         (file test):fast/history/resources/back-on-load.html
 ===============================================
diff --git a/third_party/WebKit/LayoutTests/fast/history/history-length-append-subframe-with-hash-expected.txt b/third_party/WebKit/LayoutTests/fast/history/history-length-append-subframe-with-hash-expected.txt
index c01110e..ffbea6b 100644
--- a/third_party/WebKit/LayoutTests/fast/history/history-length-append-subframe-with-hash-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/history/history-length-append-subframe-with-hash-expected.txt
@@ -10,7 +10,6 @@
 
 ============== Back Forward List ==============
 curr->  (file test):fast/history/history-length-append-subframe-with-hash.html#wentBack
-            about:blank/#identifier (in frame "<!--framePath //<!--frame0-->-->")
             about:blank (in frame "<!--framePath //<!--frame0-->-->")
         (file test):fast/history/resources/back-on-load.html
 ===============================================
diff --git a/third_party/WebKit/LayoutTests/fast/history/redirect-via-iframe-expected.txt b/third_party/WebKit/LayoutTests/fast/history/redirect-via-iframe-expected.txt
index a58a5bb..31b0bf49 100644
--- a/third_party/WebKit/LayoutTests/fast/history/redirect-via-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/history/redirect-via-iframe-expected.txt
@@ -5,6 +5,5 @@
 
 ============== Back Forward List ==============
         (file test):fast/history/redirect-via-iframe.html
-            (file test):fast/history/resources/iframe-redirect.html#2 (in frame "<!--framePath //<!--frame0-->-->")
 curr->  (file test):fast/history/resources/redirect-target.html#2
 ===============================================
diff --git a/third_party/WebKit/LayoutTests/fast/loader/frame-location-change-not-added-to-history-expected.txt b/third_party/WebKit/LayoutTests/fast/loader/frame-location-change-not-added-to-history-expected.txt
index bd73696..6aa4b9c 100644
--- a/third_party/WebKit/LayoutTests/fast/loader/frame-location-change-not-added-to-history-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/loader/frame-location-change-not-added-to-history-expected.txt
@@ -2,5 +2,4 @@
 
 ============== Back Forward List ==============
 curr->  (file test):fast/loader/frame-location-change-not-added-to-history.html
-            data:,hello (in frame "<!--framePath //<!--frame0-->-->")
 ===============================================
diff --git a/third_party/WebKit/LayoutTests/fast/loader/frame-src-change-not-added-to-history-expected.txt b/third_party/WebKit/LayoutTests/fast/loader/frame-src-change-not-added-to-history-expected.txt
index 5a44276e..c1e45b30 100644
--- a/third_party/WebKit/LayoutTests/fast/loader/frame-src-change-not-added-to-history-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/loader/frame-src-change-not-added-to-history-expected.txt
@@ -2,5 +2,4 @@
 
 ============== Back Forward List ==============
 curr->  (file test):fast/loader/frame-src-change-not-added-to-history.html
-            data:,hello (in frame "<!--framePath //<!--frame0-->-->")
 ===============================================
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-canvas-log-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-canvas-log-expected.txt
index 2e1a134..24b91a45 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-canvas-log-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-canvas-log-expected.txt
@@ -1,3 +1,4 @@
+Tests layer command log
 
 Canvas log:
 {
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-canvas-log.html b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-canvas-log.html
deleted file mode 100644
index 6e5f153..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-canvas-log.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/layers-test.js"></script>
-<script>
-function test() {
-  LayersTestRunner.requestLayers(onGotLayers);
-
-  function onGotLayers() {
-    var layer = LayersTestRunner.findLayerByNodeIdAttribute('a');
-    layer.snapshots()[0].then(snapshotWithRect => snapshotWithRect.snapshot.commandLog()).then(onHistoryReceived);
-  }
-
-  function onHistoryReceived(items) {
-    TestRunner.addResult('Canvas log:');
-    TestRunner.addObject(items, {'uniqueID': 'skip'});
-    TestRunner.completeTest();
-  }
-}
-</script>
-</head>
-<body onload="runTest()">
-<div id="a" style="transform: translateZ(0px); background-color:blue; width:100px; height:100px;">
-    <div style="width:50px; height:50px; background-color:red;"></div>
-    <img src="resources/test.png">
-    <svg>
-        <rect x="0" y="0" width="10" height="10" style="opacity:0.5"/>
-    </svg>
-  </div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-canvas-log.js b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-canvas-log.js
new file mode 100644
index 0000000..398d3fa7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-canvas-log.js
@@ -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.
+
+(async function() {
+  TestRunner.addResult(`Tests layer command log\n`);
+  await TestRunner.loadModule('layers_test_runner');
+  await TestRunner.loadHTML(`
+      <div id="a" style="transform: translateZ(0px); background-color:blue; width:100px; height:100px;">
+          <div style="width:50px; height:50px; background-color:red;"></div>
+          <img src="resources/test.png">
+          <svg>
+              <rect x="0" y="0" width="10" height="10" style="opacity:0.5"/>
+          </svg>
+      </div>
+  `);
+
+  await LayersTestRunner.requestLayers();
+
+  var layer = LayersTestRunner.findLayerByNodeIdAttribute('a');
+  layer.snapshots()[0].then(snapshotWithRect => snapshotWithRect.snapshot.commandLog()).then(onHistoryReceived);
+
+  function onHistoryReceived(items) {
+    TestRunner.addResult('Canvas log:');
+    TestRunner.addObject(items, {'uniqueID': 'skip'});
+    TestRunner.completeTest();
+  }
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-compositing-reasons-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-compositing-reasons-expected.txt
index 0bddd6a..e0cd974 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-compositing-reasons-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-compositing-reasons-expected.txt
@@ -1,13 +1,4 @@
-translated
-translated individual
-
-backface hidden
-animated
-animated individual
-opacity
-reflected
-perspective
-preserve3d
+Tests layer compositing reasons in Layers Panel
 Compositing reasons for #document: root
 Compositing reasons for div#transform3d: assumedOverlap,inlineTransform,transform3D
 Compositing reasons for div#transform3d-individual: assumedOverlap,inlineTransform,transform3D
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-compositing-reasons.html b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-compositing-reasons.html
deleted file mode 100644
index 4e984e4..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-compositing-reasons.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<html>
-<head>
-<style>
-@-webkit-keyframes rotate {
-        0%  { transform: rotate(0deg); }
-        50%  { transform: rotate(180deg); }
-        100%  { transform: rotate(360deg); }
-}
-
-@keyframes rotate-individual {
-        0%  { rotate: 0deg; }
-        50%  { rotate: 180deg; }
-        100%  { rotate: 360deg; }
-}
-</style>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/layers-test.js"></script>
-<script>
-if (window.testRunner)
-    testRunner.waitUntilDone();
-
-if (window.internals) {
-    document.addEventListener('webkitAnimationStart', function() {
-        internals.pauseAnimations(0);
-    });
-}
-
-function test() {
-  async function dumpCompositingReasons(layer) {
-    var reasons = await layer.requestCompositingReasons();
-    var node = layer.nodeForSelfOrAncestor();
-    var label = Components.DOMPresentationUtils.fullQualifiedSelector(node, false);
-    TestRunner.addResult(`Compositing reasons for ${label}: ` + reasons.sort().join(','));
-  }
-
-  var idsToTest = [
-    'transform3d', 'transform3d-individual', 'iframe', 'backface-visibility', 'animation', 'animation-individual',
-    'transformWithCompositedDescendants', 'transformWithCompositedDescendants-individual',
-    'opacityWithCompositedDescendants', 'reflectionWithCompositedDescendants', 'perspective', 'preserve3d'
-  ];
-
-  async function onGotLayers() {
-    dumpCompositingReasons(LayersTestRunner.layerTreeModel().layerTree().contentRoot());
-    for (var i = 0; i < idsToTest.length - 1; ++i)
-      dumpCompositingReasons(LayersTestRunner.findLayerByNodeIdAttribute(idsToTest[i]));
-    await dumpCompositingReasons(LayersTestRunner.findLayerByNodeIdAttribute(idsToTest[idsToTest.length - 1]));
-    TestRunner.completeTest();
-  }
-  LayersTestRunner.requestLayers(onGotLayers);
-}
-
-</script>
-</head>
-<body onload="runTest()">
-<div id="transform3d" style="transform: translateZ(100px);">translated</div>
-<div id="transform3d-individual" style="translate: 0px 0px 100px;">translated individual</div>
-<iframe id="iframe" src="resources/composited-iframe.html"></iframe>
-<div id="backface-visibility" style="backface-visibility: hidden">backface hidden</div>
-<div id="animation" style="width: 50px; height: 50px; -webkit-animation-name: rotate; -webkit-animation-iteration-count: infinite; -webkit-animation-duration: 5s;">animated</div>
-<div id="animation-individual" style="width: 50px; height: 50px; animation-name: rotate-individual; animation-iteration-count: infinite; animation-duration: 5s;">animated individual</div>
-<div id="transformWithCompositedDescendants" style="transform: rotate(10deg)">
-    <div style="transform: scale3d(2, 3, 4);">
-    </div>
-</div>
-<div id="transformWithCompositedDescendants-individual" style="rotate: 10deg">
-    <div style="scale: 2 3 4;">
-    </div>
-</div>
-<div id="opacityWithCompositedDescendants" style="opacity: 0.5">
-    <div style="transform: translateZ(100px);">opacity
-    </div>
-</div>
-<div id="reflectionWithCompositedDescendants" style="-webkit-box-reflect: below">
-    <div style="transform: translateZ(100px);">reflected
-    </div>
-</div>
-<div id="perspective" style="-webkit-perspective: 500;">
-    <div style="transform: translateZ(100px);">perspective
-    </div>
-</div>
-<div id="preserve3d" style="-webkit-transform-style: preserve-3d;">
-    <div style="transform: translateZ(100px);">preserve3d
-    </div>
-</div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-compositing-reasons.js b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-compositing-reasons.js
new file mode 100644
index 0000000..da77c6ed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-compositing-reasons.js
@@ -0,0 +1,42 @@
+// 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.
+
+(async function() {
+  TestRunner.addResult(`Tests layer compositing reasons in Layers Panel`);
+  await TestRunner.loadModule('layers_test_runner');
+  await TestRunner.navigatePromise(TestRunner.url('resources/compositing-reasons.html'));
+
+  await TestRunner.evaluateInPageAsync(`
+    (function() {
+      return new Promise(fulfill => {
+        var iframe = document.getElementById('iframe');
+        iframe.onload = fulfill;
+        iframe.src = "composited-iframe.html";
+      });
+    })()`);
+
+  await TestRunner.evaluateInPagePromise(`
+    document.addEventListener('webkitAnimationStart', () => internals.pauseAnimations(0));
+  `);
+
+  async function dumpCompositingReasons(layer) {
+    var reasons = await layer.requestCompositingReasons();
+    var node = layer.nodeForSelfOrAncestor();
+    var label = Components.DOMPresentationUtils.fullQualifiedSelector(node, false);
+    TestRunner.addResult(`Compositing reasons for ${label}: ` + reasons.sort().join(','));
+  }
+
+  var idsToTest = [
+    'transform3d', 'transform3d-individual', 'iframe', 'backface-visibility', 'animation', 'animation-individual',
+    'transformWithCompositedDescendants', 'transformWithCompositedDescendants-individual',
+    'opacityWithCompositedDescendants', 'reflectionWithCompositedDescendants', 'perspective', 'preserve3d'
+  ];
+
+  await LayersTestRunner.requestLayers();
+  dumpCompositingReasons(LayersTestRunner.layerTreeModel().layerTree().contentRoot());
+  for (var i = 0; i < idsToTest.length - 1; ++i)
+    dumpCompositingReasons(LayersTestRunner.findLayerByNodeIdAttribute(idsToTest[i]));
+  await dumpCompositingReasons(LayersTestRunner.findLayerByNodeIdAttribute(idsToTest[idsToTest.length - 1]));
+  TestRunner.completeTest();
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-replay-scale-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-replay-scale-expected.txt
index 0277d78..3c20c5d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-replay-scale-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-replay-scale-expected.txt
@@ -1,6 +1,5 @@
 Tests that when layer snapshots are replayed with scaling applied the image dimensions are properly scaled.
 
-
 Image dimensions at scale undefined: 180 x 180
 Image dimensions at scale 0.5: 90 x 90
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-replay-scale.html b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-replay-scale.html
deleted file mode 100644
index 96fb271..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-replay-scale.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/layers-test.js"></script>
-<script>
-function test() {
-  LayersTestRunner.requestLayers(onGotLayers);
-
-  async function onGotLayers() {
-    var layer = LayersTestRunner.findLayerByNodeIdAttribute('a');
-    var snapshotWithRect = await layer.snapshots()[0];
-    await testImageForSnapshot(snapshotWithRect.snapshot, undefined);
-    await testImageForSnapshot(snapshotWithRect.snapshot, 0.5);
-    TestRunner.completeTest();
-  }
-
-  async function testImageForSnapshot(snapshot, scale) {
-    var imageURL = await snapshot.replay(scale);
-    var image = await new Promise(fulfill => {
-      var image = new Image();
-      image.addEventListener('load', () => fulfill(image), false);
-      image.src = imageURL;
-    });
-    TestRunner.addResult(`Image dimensions at scale ${scale}: ${image.naturalWidth} x ${image.naturalHeight}`);
-  }
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>
-Tests that when layer snapshots are replayed with scaling applied the image dimensions are properly scaled.
-</p>
-<div id="a" style="background-color:blue; transform: translateZ(0px); overflow: hidden;">
-    <script>
-(function()
-{
-    var a = document.getElementById("a");
-    var size = (180 / window.devicePixelRatio) + "px";
-    a.style.width = size;
-    a.style.height = size;
-})();
-    </script>
-    <div style="width:50px; height:50px; background-color:red;"></div>
-    <img src="../tracing/resources/test.png">
-    <svg>
-        <rect x="0" y="0" width="10" height="10" style="opacity:0.5"/>
-    </svg>
-  </div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-replay-scale.js b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-replay-scale.js
new file mode 100644
index 0000000..10f5903
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-replay-scale.js
@@ -0,0 +1,45 @@
+// 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.
+
+(async function() {
+  TestRunner.addResult(
+      `Tests that when layer snapshots are replayed with scaling applied the image dimensions are properly scaled.\n`);
+  await TestRunner.loadModule('layers_test_runner');
+  await TestRunner.loadHTML(`
+      <div id="a" style="background-color:blue; transform: translateZ(0px); overflow: hidden;">
+
+          <div style="width:50px; height:50px; background-color:red;"></div>
+          <img src="../tracing/resources/test.png">
+          <svg>
+              <rect x="0" y="0" width="10" height="10" style="opacity:0.5"/>
+          </svg>
+        </div>
+    `);
+  await TestRunner.evaluateInPagePromise(`
+      (function() {
+          var a = document.getElementById("a");
+          var size = (180 / window.devicePixelRatio) + "px";
+          a.style.width = size;
+          a.style.height = size;
+      })();
+    `);
+
+  await LayersTestRunner.requestLayers();
+
+  var layer = LayersTestRunner.findLayerByNodeIdAttribute('a');
+  var snapshotWithRect = await layer.snapshots()[0];
+  await testImageForSnapshot(snapshotWithRect.snapshot, undefined);
+  await testImageForSnapshot(snapshotWithRect.snapshot, 0.5);
+  TestRunner.completeTest();
+
+  async function testImageForSnapshot(snapshot, scale) {
+    var imageURL = await snapshot.replay(scale);
+    var image = await new Promise(fulfill => {
+      var image = new Image();
+      image.addEventListener('load', () => fulfill(image), false);
+      image.src = imageURL;
+    });
+    TestRunner.addResult(`Image dimensions at scale ${scale}: ${image.naturalWidth} x ${image.naturalHeight}`);
+  }
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-scroll-rects-get-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-scroll-rects-get-expected.txt
index 05c891a..ccbec06 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-scroll-rects-get-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-scroll-rects-get-expected.txt
@@ -1,5 +1,6 @@
+Tests scroll rectangles support in in Layers3DViewxScroll rectangles
+
 Scroll rectangles
-Model elements dump
 {
     0 : {
         rect : {
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-scroll-rects-get.html b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-scroll-rects-get.html
deleted file mode 100644
index 292f922e..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-scroll-rects-get.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/layers-test.js"></script>
-<script>
-function test() {
-  function onGotLayers() {
-    TestRunner.addResult('Scroll rectangles');
-    LayersTestRunner.dumpModelScrollRects();
-    TestRunner.completeTest();
-  }
-
-  LayersTestRunner.requestLayers(onGotLayers);
-}
-</script>
-</head>
-<body onload="runTest()">
-<div style="transform: translateZ(100px);" onmousewheel=""></div>
-<div id="touchable" style="transform:translateZ(100px);height:20px;width:20px;overflow:scroll;">
-    <div style="height:40px;width:40px;"></div>
-</div>
-<script type="text/javascript">
-    var element = document.getElementById('touchable');
-    element.addEventListener("touchstart", function(evt) {}, false);
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-scroll-rects-get.js b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-scroll-rects-get.js
new file mode 100644
index 0000000..ac00eed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-scroll-rects-get.js
@@ -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.
+
+(async function() {
+  TestRunner.addResult(`Tests scroll rectangles support in in Layers3DViewxScroll rectangles\n`);
+  await TestRunner.loadModule('layers_test_runner');
+  await TestRunner.loadHTML(`
+      <div style="transform: translateZ(100px);" onmousewheel=""></div>
+      <div id="touchable" style="transform:translateZ(100px);height:20px;width:20px;overflow:scroll;">
+          <div style="height:40px;width:40px;"></div>
+      </div>
+    `);
+  await TestRunner.evaluateInPagePromise(`
+          var element = document.getElementById('touchable');
+          element.addEventListener("touchstart", () => {}, false);
+    `);
+
+  await LayersTestRunner.requestLayers();
+
+  TestRunner.addResult('Scroll rectangles');
+  LayersTestRunner.layerTreeModel().layerTree().forEachLayer(layer => {
+    if (layer._scrollRects.length > 0)
+      TestRunner.addObject(layer._scrollRects);
+  });
+  TestRunner.completeTest();
+
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-sticky-position-constraint-get-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-sticky-position-constraint-get-expected.txt
index 69dde5ab..953cdee5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-sticky-position-constraint-get-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-sticky-position-constraint-get-expected.txt
@@ -1,5 +1,6 @@
- Sticky position constraint
-Model elements dump
+Tests sticky position constraints in Layers panel
+
+Sticky position constraint
 {
     _containingBlockRect : {
         height : 400
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-sticky-position-constraint-get.html b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-sticky-position-constraint-get.html
deleted file mode 100644
index a5fae626..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-sticky-position-constraint-get.html
+++ /dev/null
@@ -1,74 +0,0 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/layers-test.js"></script>
-<script>
-function test() {
-  function onGotLayers() {
-    TestRunner.addResult('Sticky position constraint');
-    LayersTestRunner.dumpModelStickyPositionConstraint();
-    TestRunner.completeTest();
-  }
-
-  LayersTestRunner.requestLayers(onGotLayers);
-}
-</script>
-<style>
-.scroller {
-  height: 100px;
-  width: 100px;
-  overflow-y: scroll;
-  overflow-x: hidden;
-}
-
-.composited {
-  will-change: transform;
-}
-
-.inline {
-  display: inline;
-}
-
-.sticky {
-  position: sticky;
-  top: 10px;
-}
-
-.large-box {
-  height: 50px;
-  width: 50px;
-  background-color: green;
-}
-
-.small-box {
-  height: 25px;
-  width: 25px;
-  background-color: blue;
-}
-
-.padding {
-  height: 350px;
-  width: 100px;
-}
-</style>
-</head>
-<body onload="runTest()">
-
-<!-- General stickyPositionConstraint test. -->
-<div class="composited scroller">
-  <div class="composited sticky large-box">
-    <div class="composited sticky small-box" style="top: 20px;"></div>
-  </div>
-  <div class="padding"></div>
-</div>
-
-<!-- Test _nearestLayerShiftingStickyBox is filled correctly. -->
-<div class="composited scroller">
-  <div class="composited inline sticky">
-    <div class="composited inline sticky" style="top: 20px;">
-    </div>
-  </div>
-  <div class="padding"></div>
-</div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-sticky-position-constraint-get.js b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-sticky-position-constraint-get.js
new file mode 100644
index 0000000..d8f6ebb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-sticky-position-constraint-get.js
@@ -0,0 +1,79 @@
+// 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.
+
+(async function() {
+  TestRunner.addResult(`Tests sticky position constraints in Layers panel\n`);
+  await TestRunner.loadModule('layers_test_runner');
+  await TestRunner.loadHTML(`
+      <style>
+      .scroller {
+        height: 100px;
+        width: 100px;
+        overflow-y: scroll;
+        overflow-x: hidden;
+      }
+
+      .composited {
+        will-change: transform;
+      }
+
+      .inline {
+        display: inline;
+      }
+
+      .sticky {
+        position: sticky;
+        top: 10px;
+      }
+
+      .large-box {
+        height: 50px;
+        width: 50px;
+        background-color: green;
+      }
+
+      .small-box {
+        height: 25px;
+        width: 25px;
+        background-color: blue;
+      }
+
+      .padding {
+        height: 350px;
+        width: 100px;
+      }
+      </style>
+      <!-- General stickyPositionConstraint test. -->
+      <div class="composited scroller">
+        <div class="composited sticky large-box">
+          <div class="composited sticky small-box" style="top: 20px;"></div>
+        </div>
+        <div class="padding"></div>
+      </div>
+
+      <!-- Test _nearestLayerShiftingStickyBox is filled correctly. -->
+      <div class="composited scroller">
+        <div class="composited inline sticky">
+          <div class="composited inline sticky" style="top: 20px;">
+          </div>
+        </div>
+        <div class="padding"></div>
+      </div>
+    `);
+
+  await LayersTestRunner.requestLayers();
+  TestRunner.addResult('Sticky position constraint');
+
+  var stickyFormatters = {
+    '_nearestLayerShiftingContainingBlock': 'formatAsTypeNameOrNull',
+    '_nearestLayerShiftingStickyBox': 'formatAsTypeNameOrNull'
+  };
+
+  LayersTestRunner.layerTreeModel().layerTree().forEachLayer(layer => {
+    if (layer._stickyPositionConstraint)
+      TestRunner.addObject(layer._stickyPositionConstraint, stickyFormatters);
+  });
+
+  TestRunner.completeTest();
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-tree-model-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-tree-model-expected.txt
index df0d5ed..0ce7d91 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-tree-model-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-tree-model-expected.txt
@@ -1,4 +1,4 @@
-
+Tests general layer tree model functionality
 Initial layer tree
 #document (9)
     iframe#frame (10)
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-tree-model.html b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-tree-model.html
deleted file mode 100644
index 72f758f..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-tree-model.html
+++ /dev/null
@@ -1,69 +0,0 @@
-<html>
-<head>
-<style>
-.layer {
-    transform: translateZ(10px);
-    opacity: 0.8;
-}
-</style>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/layers-test.js"></script>
-<script>
-
-function updateTree()
-{
-    document.getElementById("c").appendChild(document.getElementById("b1"));
-    var b3 = document.getElementById("b3");
-    b3.parentElement.removeChild(b3);
-    var b4 = document.createElement("div");
-    b4.id = "b4";
-    b4.className = "layer";
-    document.getElementById("a").appendChild(b4);
-}
-
-function updateGeometry()
-{
-    document.getElementById("c").style.width = "80px";
-}
-
-function test() {
-  function addDepthMarker(layer) {
-    layer.__extraData = layer.parent() ? layer.parent().__extraData + 1 : 0;
-  }
-
-  LayersTestRunner.requestLayers(step1);
-
-  function step1() {
-    // Assure layer objects are not re-created during updates.
-    LayersTestRunner.layerTreeModel().layerTree().forEachLayer(addDepthMarker);
-    TestRunner.addResult('Initial layer tree');
-    LayersTestRunner.dumpLayerTree();
-    LayersTestRunner.evaluateAndRunWhenTreeChanges('requestAnimationFrame(updateTree)', step2);
-  }
-
-  function step2() {
-    TestRunner.addResult('Updated layer tree');
-    LayersTestRunner.dumpLayerTree();
-    LayersTestRunner.evaluateAndRunWhenTreeChanges('requestAnimationFrame(updateGeometry)', step3);
-  }
-
-  function step3() {
-    TestRunner.addResult('Updated layer geometry');
-    LayersTestRunner.dumpLayerTree();
-    TestRunner.completeTest();
-  }
-}
-
-</script>
-</head>
-<body onload="runTest()">
-<div id="a" style="width: 200px; height: 200px" class="layer">
-    <div class="layer" id="b1" style="width: 150px; height: 100px"></div>
-    <div id="b2" class="layer" style="width: 140px; height: 110px">
-        <div id="c" class="layer" style="width: 100px; height: 90px"></div>
-    </div>
-    <div id="b3" class="layer" style="width: 140px; height: 110px"></div>
-</div>
-<iframe id="frame" src="resources/composited-iframe.html" width="200" height="200"></div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-tree-model.js b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-tree-model.js
new file mode 100644
index 0000000..63e48dc2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layer-tree-model.js
@@ -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.
+
+(async function() {
+  TestRunner.addResult(`Tests general layer tree model functionality`);
+  await TestRunner.loadModule('layers_test_runner');
+  await TestRunner.loadHTML(`
+      <style>
+      .layer {
+          transform: translateZ(10px);
+          opacity: 0.8;
+      }
+      #frame {
+        width: 200px;
+        height: 200px;
+      }
+      </style>
+      <div id="a" style="width: 200px; height: 200px" class="layer">    <div class="layer" id="b1" style="width: 150px; height: 100px"></div>
+          <div id="b2" class="layer" style="width: 140px; height: 110px">
+              <div id="c" class="layer" style="width: 100px; height: 90px"></div>
+          </div>
+          <div id="b3" class="layer" style="width: 140px; height: 110px"></div>
+      </div>
+    `);
+  await TestRunner.addIframe('resources/composited-iframe.html', {id: 'frame'});
+  await TestRunner.evaluateInPagePromise(`
+      function updateTree()
+      {
+          document.getElementById("c").appendChild(document.getElementById("b1"));
+          var b3 = document.getElementById("b3");
+          b3.parentElement.removeChild(b3);
+          var b4 = document.createElement("div");
+          b4.id = "b4";
+          b4.className = "layer";
+          document.getElementById("a").appendChild(b4);
+      }
+
+      function updateGeometry()
+      {
+          document.getElementById("c").style.width = "80px";
+      }
+  `);
+
+  await LayersTestRunner.requestLayers();
+
+  // Assure layer objects are not re-created during updates.
+  LayersTestRunner.layerTreeModel().layerTree().forEachLayer(layer => {
+    layer.__extraData = layer.parent() ? layer.parent().__extraData + 1 : 0;
+  });
+
+  TestRunner.addResult('Initial layer tree');
+  LayersTestRunner.dumpLayerTree();
+  await LayersTestRunner.evaluateAndWaitForTreeChange('requestAnimationFrame(updateTree)');
+
+  TestRunner.addResult('Updated layer tree');
+  LayersTestRunner.dumpLayerTree();
+  await LayersTestRunner.evaluateAndWaitForTreeChange('requestAnimationFrame(updateGeometry)');
+
+  TestRunner.addResult('Updated layer geometry');
+  LayersTestRunner.dumpLayerTree();
+  TestRunner.completeTest();
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-3d-view-hit-testing-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-3d-view-hit-testing-expected.txt
index 3a0c928..2839b22 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-3d-view-hit-testing-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-3d-view-hit-testing-expected.txt
@@ -1,3 +1,5 @@
+Tests hit testing in Layers3DView
+
 Initial state
 State of layers:
 hovered layer: none
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-3d-view-hit-testing.html b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-3d-view-hit-testing.js
similarity index 60%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-3d-view-hit-testing.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-3d-view-hit-testing.js
index 4e0881a..3432e75 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-3d-view-hit-testing.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-3d-view-hit-testing.js
@@ -1,15 +1,51 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/layers-test.js"></script>
-<script>
-function test() {
+// 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.
+
+(async function() {
+  TestRunner.addResult(`Tests hit testing in Layers3DView\n`);
+  await TestRunner.loadModule('layers_test_runner');
+  await TestRunner.loadHTML(`
+      <div id="a" style="transform:translateZ(0px) translateY(60px) rotateZ(45deg);width:300px;height:300px;margin-left:100px; border: 1px solid black;">
+          <div id="b" style="transform:translateX(0px) translateY(0px) translateZ(0px) rotateX(45deg) rotateY(45deg);width:300px;height:300px; border: 1px solid black;"></div>
+      </div>
+  `);
+
   var contentRoot;
   var layers;
   var rootOffsetXInPixels, rootOffsetYInPixels, rootHeightInPixels, rootWidthInPixels;
   var canvas;
   const ButtonByEventType = {mousemove: -1, mousedown: 0, mouseup: 0};
 
+  await LayersTestRunner.requestLayers();
+  await TestRunner.showPanel('layers');
+
+  initLayers();
+  initSizes();
+
+  TestRunner.addResult('Initial state');
+  dumpOutlinedStateForLayers();
+
+  TestRunner.addResult('\nHovering content root');
+  dispatchMouseEventOnCanvas('mousemove', 0.1237135833164431, 0.11536508236291274);
+  dumpOutlinedStateForLayers();
+
+  TestRunner.addResult('\nSelecting layer b');
+  dispatchMouseEventOnCanvas('mousedown', 0.5, 0.5);
+  dispatchMouseEventOnCanvas('mouseup', 0.5, 0.5);
+  dumpOutlinedStateForLayers();
+
+  TestRunner.addResult('\nHovering layer a');
+  dispatchMouseEventOnCanvas('mousemove', 0.4, 0.2);
+  dumpOutlinedStateForLayers();
+
+  TestRunner.addResult('\nSelecting content root');
+  dispatchMouseEventOnCanvas('mousedown', 0.5, 0.001);
+  dispatchMouseEventOnCanvas('mouseup', 0.5, 0.001);
+  dumpOutlinedStateForLayers();
+
+  TestRunner.completeTest();
+
   function initLayers() {
     layerA = LayersTestRunner.findLayerByNodeIdAttribute('a');
     layerB = LayersTestRunner.findLayerByNodeIdAttribute('b');
@@ -66,41 +102,4 @@
     dumpStateForOutlineType(LayerViewer.Layers3DView.OutlineType.Selected);
   }
 
-  function onGotLayers() {
-    initLayers();
-    initSizes();
-
-    TestRunner.addResult('Initial state');
-    dumpOutlinedStateForLayers();
-
-    TestRunner.addResult('\nHovering content root');
-    dispatchMouseEventOnCanvas('mousemove', 0.1237135833164431, 0.11536508236291274);
-    dumpOutlinedStateForLayers();
-
-    TestRunner.addResult('\nSelecting layer b');
-    dispatchMouseEventOnCanvas('mousedown', 0.5, 0.5);
-    dispatchMouseEventOnCanvas('mouseup', 0.5, 0.5);
-    dumpOutlinedStateForLayers();
-
-    TestRunner.addResult('\nHovering layer a');
-    dispatchMouseEventOnCanvas('mousemove', 0.4, 0.2);
-    dumpOutlinedStateForLayers();
-
-    TestRunner.addResult('\nSelecting content root');
-    dispatchMouseEventOnCanvas('mousedown', 0.5, 0.001);
-    dispatchMouseEventOnCanvas('mouseup', 0.5, 0.001);
-    dumpOutlinedStateForLayers();
-
-    TestRunner.completeTest();
-  }
-
-  LayersTestRunner.requestLayers(onGotLayers);
-}
-</script>
-</head>
-<body onload="runTest()" style="height:500px;width:500px;">
-<div id="a" style="transform:translateZ(0px) translateY(60px) rotateZ(45deg);width:300px;height:300px;margin-left:100px; border: 1px solid black;">
-    <div id="b" style="transform:translateX(0px) translateY(0px) translateZ(0px) rotateX(45deg) rotateY(45deg);width:300px;height:300px; border: 1px solid black;"></div>
-</div>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-panel-mouse-events-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-panel-mouse-events-expected.txt
index 5c858562..c35ec648 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-panel-mouse-events-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-panel-mouse-events-expected.txt
@@ -1,3 +1,5 @@
+Tests moust hover/select events handling in the Layers panel
+
 Hovering b1 in tree
 Layer b1 in tree: hovered
 Layer b3 in tree: 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-panel-mouse-events.html b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-panel-mouse-events.html
deleted file mode 100644
index b8ec6ad..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-panel-mouse-events.html
+++ /dev/null
@@ -1,96 +0,0 @@
-<html>
-<head>
-<style>
-.layer {
-    position: absolute;
-    transform: translateZ(10px);
-    opacity: 0.8;
-    left: 20px;
-    top: 20px;
-    background-color: #eee;
-    border-color: black;
-}
-</style>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/layers-test.js"></script>
-<script>
-function initialize_LayersPanelnMouseEvents()
-{
-
-InspectorTest.findLayerTreeElement = function(layer)
-{
-    var layerTree = UI.panels.layers._layerTreeOutline._treeOutline;
-    var element = layer[LayerViewer.LayerTreeElement._symbol];
-    element.reveal();
-    return element.listItemElement;
-}
-
-InspectorTest.dispatchMouseEventToLayerTree = function(eventType, button, layer)
-{
-    var element = InspectorTest.findLayerTreeElement(layer);
-    TestRunner.assertTrue(!!element);
-    LayersTestRunner.dispatchMouseEvent(eventType, button, element, element.clientWidth >> 1, element.clientHeight >> 1);
-}
-
-InspectorTest.dumpSelectedStyles = function(message, element)
-{
-    var classes = [];
-    if (element.classList.contains("selected"))
-        classes.push("selected");
-    if (element.classList.contains("hovered"))
-        classes.push("hovered");
-
-    TestRunner.addResult(message + ": " + classes.join(", "));
-}
-
-}
-
-function test() {
-  function step1() {
-    UI.panels.layers._update();
-    var layerB1 = LayersTestRunner.findLayerByNodeIdAttribute('b1');
-    var treeElementB1 = InspectorTest.findLayerTreeElement(layerB1);
-
-    var layerB3 = LayersTestRunner.findLayerByNodeIdAttribute('b3');
-    var treeElementB3 = InspectorTest.findLayerTreeElement(layerB3);
-
-    function dumpElementSelectionState() {
-      UI.panels.layers._update();
-      InspectorTest.dumpSelectedStyles('Layer b1 in tree', treeElementB1);
-      InspectorTest.dumpSelectedStyles('Layer b3 in tree', treeElementB3);
-    }
-    TestRunner.addResult('Hovering b1 in tree');
-    InspectorTest.dispatchMouseEventToLayerTree('mousemove', -1, layerB1);
-    dumpElementSelectionState();
-
-    TestRunner.addResult('Hovering b3 in tree');
-    InspectorTest.dispatchMouseEventToLayerTree('mousemove', -1, layerB3);
-    dumpElementSelectionState();
-
-    TestRunner.addResult('Hovering away from tree');
-    InspectorTest.dispatchMouseEventToLayerTree('mouseout', -1, layerB3);
-    dumpElementSelectionState();
-
-    TestRunner.addResult('Selecting b1 in tree');
-    InspectorTest.dispatchMouseEventToLayerTree('mousedown', 0, layerB1);
-    dumpElementSelectionState();
-
-    TestRunner.addResult('Selecting b3 in tree');
-    InspectorTest.dispatchMouseEventToLayerTree('mousedown', 0, layerB3);
-    dumpElementSelectionState();
-
-    TestRunner.completeTest();
-  }
-  LayersTestRunner.requestLayers(TestRunner.safeWrap(step1));
-}
-</script>
-
-<body onload="runTest()">
-<div id="a" style="width: 200px; height: 200px" class="layer">
-  <div class="layer" id="b1" style="width: 150px; height: 100px"></div>
-  <div id="b2" class="layer" style="width: 140px; height: 110px">
-    <div id="b3" class="layer" style="width: 140px; height: 110px;"></div>
-    <div id="c" class="layer" style="width: 100px; height: 90px"></div>
-  </div>
-</div>
-</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-panel-mouse-events.js b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-panel-mouse-events.js
new file mode 100644
index 0000000..9cc0b5f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/layers-panel-mouse-events.js
@@ -0,0 +1,65 @@
+// 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.
+
+(async function() {
+  TestRunner.addResult(`Tests moust hover/select events handling in the Layers panel\n`);
+  await TestRunner.loadModule('layers_test_runner');
+  await TestRunner.loadHTML(`
+      <style>
+      .layer {
+          position: absolute;
+          transform: translateZ(10px);
+          opacity: 0.8;
+          left: 20px;
+          top: 20px;
+          background-color: #eee;
+          border-color: black;
+      }
+      </style>
+      <div id="a" style="width: 200px; height: 200px" class="layer">
+        <div class="layer" id="b1" style="width: 150px; height: 100px"></div>
+        <div id="b2" class="layer" style="width: 140px; height: 110px">
+          <div id="b3" class="layer" style="width: 140px; height: 110px;"></div>
+          <div id="c" class="layer" style="width: 100px; height: 90px"></div>
+        </div>
+      </div>
+    `);
+
+  await TestRunner.showPanel('layers');
+  await LayersTestRunner.requestLayers();
+
+  UI.panels.layers._update();
+  var layerB1 = LayersTestRunner.findLayerByNodeIdAttribute('b1');
+  var treeElementB1 = LayersTestRunner.findLayerTreeElement(layerB1);
+
+  var layerB3 = LayersTestRunner.findLayerByNodeIdAttribute('b3');
+  var treeElementB3 = LayersTestRunner.findLayerTreeElement(layerB3);
+
+  function dumpElementSelectionState() {
+    UI.panels.layers._update();
+    LayersTestRunner.dumpSelectedStyles('Layer b1 in tree', treeElementB1);
+    LayersTestRunner.dumpSelectedStyles('Layer b3 in tree', treeElementB3);
+  }
+  TestRunner.addResult('Hovering b1 in tree');
+  LayersTestRunner.dispatchMouseEventToLayerTree('mousemove', -1, layerB1);
+  dumpElementSelectionState();
+
+  TestRunner.addResult('Hovering b3 in tree');
+  LayersTestRunner.dispatchMouseEventToLayerTree('mousemove', -1, layerB3);
+  dumpElementSelectionState();
+
+  TestRunner.addResult('Hovering away from tree');
+  LayersTestRunner.dispatchMouseEventToLayerTree('mouseout', -1, layerB3);
+  dumpElementSelectionState();
+
+  TestRunner.addResult('Selecting b1 in tree');
+  LayersTestRunner.dispatchMouseEventToLayerTree('mousedown', 0, layerB1);
+  dumpElementSelectionState();
+
+  TestRunner.addResult('Selecting b3 in tree');
+  LayersTestRunner.dispatchMouseEventToLayerTree('mousedown', 0, layerB3);
+  dumpElementSelectionState();
+
+  TestRunner.completeTest();
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/no-overlay-layers-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/no-overlay-layers-expected.txt
index 2dbe5d5c..c0b48b61 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/no-overlay-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/no-overlay-layers-expected.txt
@@ -1,2 +1,3 @@
+Tests overlay layers are not present in the layer tree
 DONE
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/no-overlay-layers.html b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/no-overlay-layers.html
deleted file mode 100644
index 525f175..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/no-overlay-layers.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<html>
-<head>
-<style>
-.layer {
-    transform: translateZ(10px);
-    opacity: 0.8;
-}
-</style>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/layers-test.js"></script>
-<script>
-
-function updateGeometry()
-{
-    document.getElementById("a").style.width = "300px";
-}
-
-function test() {
-  var layersBeforeHighlight = [];
-
-  LayersTestRunner.requestLayers(step1);
-
-  function step1() {
-    // Assure layer objects are not re-created during updates.
-    LayersTestRunner.layerTreeModel().layerTree().forEachLayer(function(layer) {
-      layersBeforeHighlight.push(layer.id());
-    });
-    TestRunner.OverlayAgent.highlightRect(0, 0, 200, 200, {r: 255, g: 0, b: 0});
-    LayersTestRunner.evaluateAndRunWhenTreeChanges('requestAnimationFrame(updateGeometry)', step2);
-  }
-
-  function step2() {
-    var layersAfterHighlight = [];
-    LayersTestRunner.layerTreeModel().layerTree().forEachLayer(function(layer) {
-      layersAfterHighlight.push(layer.id());
-    });
-    layersBeforeHighlight.sort();
-    layersAfterHighlight.sort();
-    TestRunner.assertEquals(JSON.stringify(layersBeforeHighlight), JSON.stringify(layersAfterHighlight));
-    TestRunner.addResult('DONE');
-    TestRunner.completeTest();
-  }
-}
-
-</script>
-</head>
-<body onload="runTest()">
-<div id="a" style="width: 200px; height: 200px" class="layer">
-</div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/no-overlay-layers.js b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/no-overlay-layers.js
new file mode 100644
index 0000000..a90133f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/no-overlay-layers.js
@@ -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.
+
+(async function() {
+  TestRunner.addResult(`Tests overlay layers are not present in the layer tree`);
+
+  await TestRunner.loadModule('layers_test_runner');
+  await TestRunner.loadHTML(`
+      <style>
+      .layer {
+          transform: translateZ(10px);
+          opacity: 0.8;
+      }
+      </style>
+      <div id="a" style="width: 200px; height: 200px" class="layer">
+        CONTENT
+      </div>
+    `);
+  await TestRunner.evaluateInPagePromise(`
+      function updateGeometry()
+      {
+          document.getElementById("a").style.width = "300px";
+      }
+  `);
+
+  await LayersTestRunner.requestLayers();
+
+  var layersBeforeHighlight = [];
+  LayersTestRunner.layerTreeModel().layerTree().forEachLayer(function(layer) {
+    layersBeforeHighlight.push(layer.id());
+  });
+  TestRunner.OverlayAgent.highlightRect(0, 0, 200, 200, {r: 255, g: 0, b: 0});
+
+  await LayersTestRunner.evaluateAndWaitForTreeChange('updateGeometry()');
+
+  var layersAfterHighlight = [];
+  LayersTestRunner.layerTreeModel().layerTree().forEachLayer(function(layer) {
+    layersAfterHighlight.push(layer.id());
+  });
+
+  layersBeforeHighlight.sort();
+  layersAfterHighlight.sort();
+
+  TestRunner.assertEquals(JSON.stringify(layersBeforeHighlight), JSON.stringify(layersAfterHighlight));
+  TestRunner.addResult('DONE');
+  TestRunner.completeTest();
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/layers/resources/compositing-reasons.html b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/resources/compositing-reasons.html
new file mode 100644
index 0000000..7744500a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/layers/resources/compositing-reasons.html
@@ -0,0 +1,43 @@
+<style>
+@-webkit-keyframes rotate {
+    0%  { transform: rotate(0deg); }
+    50%  { transform: rotate(180deg); }
+    100%  { transform: rotate(360deg); }
+}
+
+@keyframes rotate-individual {
+    0%  { rotate: 0deg; }
+    50%  { rotate: 180deg; }
+    100%  { rotate: 360deg; }
+}
+</style>
+<div id="transform3d" style="transform: translateZ(100px);"></div>
+<div id="transform3d-individual" style="translate: 0px 0px 100px;">translated individual</div>
+<iframe id="iframe"></iframe>
+<div id="backface-visibility" style="backface-visibility: hidden">backface hidden</div>
+<div id="animation" style="width: 50px; height: 50px; -webkit-animation-name: rotate; -webkit-animation-iteration-count: infinite; -webkit-animation-duration: 5s;">animated</div>
+<div id="animation-individual" style="width: 50px; height: 50px; animation-name: rotate-individual; animation-iteration-count: infinite; animation-duration: 5s;">animated individual</div>
+<div id="transformWithCompositedDescendants" style="transform: rotate(10deg)">
+    <div style="transform: scale3d(2, 3, 4);">
+    </div>
+</div>
+<div id="transformWithCompositedDescendants-individual" style="rotate: 10deg">
+    <div style="scale: 2 3 4;">
+    </div>
+</div>
+<div id="opacityWithCompositedDescendants" style="opacity: 0.5">
+    <div style="transform: translateZ(100px);">opacity
+    </div>
+</div>
+<div id="reflectionWithCompositedDescendants" style="-webkit-box-reflect: below">
+    <div style="transform: translateZ(100px);">reflected
+    </div>
+</div>
+<div id="perspective" style="-webkit-perspective: 500;">
+    <div style="transform: translateZ(100px);">perspective</div>
+</div>
+<div id="preserve3d" style="-webkit-transform-style: preserve-3d;">
+    <div style="transform: translateZ(100px);">preserve3d
+    </div>
+</div>
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/back-to-dynamic-iframe-expected.txt b/third_party/WebKit/LayoutTests/http/tests/navigation/back-to-dynamic-iframe-expected.txt
index 79356831..ef6edca 100644
--- a/third_party/WebKit/LayoutTests/http/tests/navigation/back-to-dynamic-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/back-to-dynamic-iframe-expected.txt
@@ -2,7 +2,6 @@
 
 ============== Back Forward List ==============
 curr->  http://127.0.0.1:8000/navigation/back-to-dynamic-iframe.html
-            http://127.0.0.1:8000/navigation/resources/back-to-dynamic-iframe-iframe.html#FAIL (in frame "<!--framePath //<!--frame0-->-->")
             http://127.0.0.1:8000/navigation/resources/back-to-dynamic-iframe-iframe.html#PASS (in frame "<!--framePath //<!--frame0-->-->")
         http://127.0.0.1:8000/navigation/resources/go-back.html
 ===============================================
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/idlharness-expected.txt b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/idlharness-expected.txt
deleted file mode 100644
index 7086811c..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/idlharness-expected.txt
+++ /dev/null
@@ -1,88 +0,0 @@
-This is a testharness.js-based test.
-FAIL Window interface: attribute performance assert_true: The prototype object must have a property "performance" expected true got false
-FAIL Window interface: window must inherit property "performance" with the proper type assert_inherits: property "performance" found on object expected in prototype chain
-PASS PerformanceTiming interface: existence and properties of interface object
-PASS PerformanceTiming interface object length
-PASS PerformanceTiming interface object name
-PASS PerformanceTiming interface: existence and properties of interface prototype object
-PASS PerformanceTiming interface: existence and properties of interface prototype object's "constructor" property
-PASS PerformanceTiming interface: attribute navigationStart
-PASS PerformanceTiming interface: attribute unloadEventStart
-PASS PerformanceTiming interface: attribute unloadEventEnd
-PASS PerformanceTiming interface: attribute redirectStart
-PASS PerformanceTiming interface: attribute redirectEnd
-PASS PerformanceTiming interface: attribute fetchStart
-PASS PerformanceTiming interface: attribute domainLookupStart
-PASS PerformanceTiming interface: attribute domainLookupEnd
-PASS PerformanceTiming interface: attribute connectStart
-PASS PerformanceTiming interface: attribute connectEnd
-PASS PerformanceTiming interface: attribute secureConnectionStart
-PASS PerformanceTiming interface: attribute requestStart
-PASS PerformanceTiming interface: attribute responseStart
-PASS PerformanceTiming interface: attribute responseEnd
-PASS PerformanceTiming interface: attribute domLoading
-PASS PerformanceTiming interface: attribute domInteractive
-PASS PerformanceTiming interface: attribute domContentLoadedEventStart
-PASS PerformanceTiming interface: attribute domContentLoadedEventEnd
-PASS PerformanceTiming interface: attribute domComplete
-PASS PerformanceTiming interface: attribute loadEventStart
-PASS PerformanceTiming interface: attribute loadEventEnd
-PASS PerformanceTiming must be primary interface of window.performance.timing
-PASS Stringification of window.performance.timing
-PASS PerformanceTiming interface: window.performance.timing must inherit property "navigationStart" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "unloadEventStart" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "unloadEventEnd" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "redirectStart" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "redirectEnd" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "fetchStart" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "domainLookupStart" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "domainLookupEnd" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "connectStart" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "connectEnd" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "secureConnectionStart" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "requestStart" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "responseStart" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "responseEnd" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "domLoading" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "domInteractive" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "domContentLoadedEventStart" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "domContentLoadedEventEnd" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "domComplete" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "loadEventStart" with the proper type
-PASS PerformanceTiming interface: window.performance.timing must inherit property "loadEventEnd" with the proper type
-PASS PerformanceNavigation interface: existence and properties of interface object
-PASS PerformanceNavigation interface object length
-PASS PerformanceNavigation interface object name
-PASS PerformanceNavigation interface: existence and properties of interface prototype object
-PASS PerformanceNavigation interface: existence and properties of interface prototype object's "constructor" property
-PASS PerformanceNavigation interface: constant TYPE_NAVIGATE on interface object
-PASS PerformanceNavigation interface: constant TYPE_NAVIGATE on interface prototype object
-PASS PerformanceNavigation interface: constant TYPE_RELOAD on interface object
-PASS PerformanceNavigation interface: constant TYPE_RELOAD on interface prototype object
-PASS PerformanceNavigation interface: constant TYPE_BACK_FORWARD on interface object
-PASS PerformanceNavigation interface: constant TYPE_BACK_FORWARD on interface prototype object
-PASS PerformanceNavigation interface: constant TYPE_RESERVED on interface object
-PASS PerformanceNavigation interface: constant TYPE_RESERVED on interface prototype object
-PASS PerformanceNavigation interface: attribute type
-PASS PerformanceNavigation interface: attribute redirectCount
-PASS PerformanceNavigation must be primary interface of window.performance.navigation
-PASS Stringification of window.performance.navigation
-PASS PerformanceNavigation interface: window.performance.navigation must inherit property "TYPE_NAVIGATE" with the proper type
-PASS PerformanceNavigation interface: window.performance.navigation must inherit property "TYPE_RELOAD" with the proper type
-PASS PerformanceNavigation interface: window.performance.navigation must inherit property "TYPE_BACK_FORWARD" with the proper type
-PASS PerformanceNavigation interface: window.performance.navigation must inherit property "TYPE_RESERVED" with the proper type
-PASS PerformanceNavigation interface: window.performance.navigation must inherit property "type" with the proper type
-PASS PerformanceNavigation interface: window.performance.navigation must inherit property "redirectCount" with the proper type
-FAIL Performance interface: existence and properties of interface object assert_equals: prototype of self's property "Performance" is not Function.prototype expected function "function () { [native code] }" but got function "function EventTarget() { [native code] }"
-PASS Performance interface object length
-PASS Performance interface object name
-FAIL Performance interface: existence and properties of interface prototype object assert_equals: prototype of Performance.prototype is not Object.prototype expected object "[object Object]" but got object "[object EventTarget]"
-PASS Performance interface: existence and properties of interface prototype object's "constructor" property
-PASS Performance interface: attribute timing
-PASS Performance interface: attribute navigation
-PASS Performance must be primary interface of window.performance
-PASS Stringification of window.performance
-PASS Performance interface: window.performance must inherit property "timing" with the proper type
-PASS Performance interface: window.performance must inherit property "navigation" with the proper type
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/idlharness.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/idlharness.html
deleted file mode 100644
index 7ccd14f7..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/idlharness.html
+++ /dev/null
@@ -1,89 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8" />
-<title>idlharness test</title>
-<link rel="author" title="W3C" href="http://www.w3.org/" />
-<link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-<link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"/>
-<link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute"/>
-<script src="/w3c/resources/testharness.js"></script>
-<script src="/w3c/resources/testharnessreport.js"></script>
-<script src="/w3c/resources/WebIDLParser.js"></script>
-<script src="/w3c/resources/idlharness.js"></script>
-</head>
-<body>
-<h1>idlharness test</h1>
-<p>This test validates the WebIDL included in the Navigation Timing specification.</p>
-
-<pre id='untested_idl' style='display:none'>
-
-interface Window {
-};
-
-</pre>
-
-<pre id='idl'>
-interface PerformanceTiming {
-  readonly attribute unsigned long long navigationStart;
-  readonly attribute unsigned long long unloadEventStart;
-  readonly attribute unsigned long long unloadEventEnd;
-  readonly attribute unsigned long long redirectStart;
-  readonly attribute unsigned long long redirectEnd;
-  readonly attribute unsigned long long fetchStart;
-  readonly attribute unsigned long long domainLookupStart;
-  readonly attribute unsigned long long domainLookupEnd;
-  readonly attribute unsigned long long connectStart;
-  readonly attribute unsigned long long connectEnd;
-  readonly attribute unsigned long long secureConnectionStart;
-  readonly attribute unsigned long long requestStart;
-  readonly attribute unsigned long long responseStart;
-  readonly attribute unsigned long long responseEnd;
-  readonly attribute unsigned long long domLoading;
-  readonly attribute unsigned long long domInteractive;
-  readonly attribute unsigned long long domContentLoadedEventStart;
-  readonly attribute unsigned long long domContentLoadedEventEnd;
-  readonly attribute unsigned long long domComplete;
-  readonly attribute unsigned long long loadEventStart;
-  readonly attribute unsigned long long loadEventEnd;
-};
-
-interface PerformanceNavigation {
-  const unsigned short TYPE_NAVIGATE = 0;
-  const unsigned short TYPE_RELOAD = 1;
-  const unsigned short TYPE_BACK_FORWARD = 2;
-  const unsigned short TYPE_RESERVED = 255;
-  readonly attribute unsigned short type;
-  readonly attribute unsigned short redirectCount;
-};
-
-interface Performance {
-  readonly attribute PerformanceTiming timing;
-  readonly attribute PerformanceNavigation navigation;
-};
-
-partial interface Window {
-  [Replaceable] readonly attribute Performance performance;
-};
-</pre>
-
-<script>
-(function() {
-  var idl_array = new IdlArray();
-
-  idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
-  idl_array.add_idls(document.getElementById("idl").textContent);
-
-  idl_array.add_objects({Window: ["window"],
-                         Performance: ["window.performance"],
-                         PerformanceNavigation: ["window.performance.navigation"],
-                         PerformanceTiming: ["window.performance.timing"]});
-
-  idl_array.test();
-})();
-</script>
-
-<div id="log"></div>
-
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_document_open.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_document_open.html
deleted file mode 100644
index 45961d1..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_document_open.html
+++ /dev/null
@@ -1,112 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8" />
-<title>window.performance.timing for dynamically created documents</title>
-<link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-<link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-<script src="/w3c/resources/testharness.js"></script>
-<script src="/w3c/resources/testharnessreport.js"></script>
-<script src="/w3c/webperf/resources/webperftestharness.js"></script>
-<link rel="stylesheet" href="/w3c/resources/testharness.css" />
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "connectEnd is the same after document open.": {},
-  "connectStart is the same after document open.": {},
-  "domComplete is the same after document open.": {},
-  "domContentLoadedEventEnd is the same after document open.": {},
-  "domContentLoadedEventStart is the same after document open.": {},
-  "domInteractive is the same after document open.": {},
-  "domLoading is the same after document open.": {},
-  "domainLookupEnd is the same after document open.": {},
-  "domainLookupStart is the same after document open.": {},
-  "fetchStart is the same after document open.": {},
-  "loadEventEnd is the same after document open.": {},
-  "loadEventStart is the same after document open.": {},
-  "navigationStart is the same after document open.": {},
-  "redirectEnd is the same after document open.": {},
-  "redirectStart is the same after document open.": {},
-  "requestStart is the same after document open.": {},
-  "responseEnd is the same after document open.": {},
-  "responseStart is the same after document open.": {},
-  "unloadEventEnd is the same after document open.": {},
-  "unloadEventStart is the same after document open.": {}
-}
-*/</script>
-<script>
-setup({explicit_done: true});
-
-// explicitly test the namespace before we start testing
-test_namespace();
-
-var originalTiming = {};
-var didOpen = false;
-
-function onload_test() {
-  if (!didOpen) {
-    setTimeout(testTimingWithDocumentOpen, 0);
-    didOpen = true;
-  }
-}
-
-function testTimingWithDocumentOpen() {
-  var subcontentWindow = document.getElementById("frameContext").contentWindow;
-
-  if (subcontentWindow.performance === undefined)
-  {
-    // avoid script errors
-    done();
-    return;
-  }
-
-  var timing = subcontentWindow.performance.timing;
-  for (i in timingAttributes) {
-    originalTiming[timingAttributes[i]] = timing[timingAttributes[i]];
-  }
-
-  var subdocument = subcontentWindow.document;
-  subdocument.open();
-  subdocument.write('<!DOCTYPE HTML>');
-  subdocument.write('<html>');
-  subdocument.write('<head>');
-  subdocument.write('<meta charset="utf-8" />');
-  subdocument.write('<title><Green Test Page</title>');
-  subdocument.write('</head>');
-  subdocument.write('<body style="background-color:#00FF00;">');
-  subdocument.write('</body>');
-  subdocument.write('</html>');
-  subdocument.close();
-
-  setTimeout(function() {
-    var timing = subcontentWindow.performance.timing;
-    for (var i in timingAttributes) {
-      test_equals(timing[timingAttributes[i]],
-                  originalTiming[timingAttributes[i]],
-                  timingAttributes[i] + " is the same after document open.");
-    }
-    done();
-  }, 0);
-}
-</script>
-</head>
-<body>
-<h1>Description</h1>
-<p>This test validates window.performance.timing remains constant when a
-document is replaced using document.open.</p>
-
-<p>This page should be loaded with a yellow frame below. It then replaces the
-document in that frame with a green document.</p>
-
-<p>The test passes if all of the checks to performance.timing are correct and
-the frame below ends with a green background.</p>
-
-<div id="log"></div>
-<br />
-<iframe id="frameContext" onload="onload_test();" src="/w3c/webperf/resources/blank_page_yellow.htm" style="width: 250px; height: 250px;"></iframe>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_document_readiness_exist.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_document_readiness_exist.html
deleted file mode 100644
index 46e76436..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_document_readiness_exist.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <meta charset="utf-8" />
-    <title>document.readyState values exist during a navigation</title>
-    <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-    <link rel="help" href="http://www.w3.org/TR/html5/dom.html#resource-metadata-management"/>
-    <script src="/w3c/resources/testharness.js"></script>
-    <script src="/w3c/resources/testharnessreport.js"></script>
-    <link rel="stylesheet" href="/w3c/resources/testharness.css" />
- <script id="metadata_cache">/*
-{
-  "Document readiness has loading state.": {},
-  "Document readiness has interactive state.": {},
-  "Document readiness has complete state.": {}
-}
-*/</script>
-    <script>
-        setup({ explicit_done: true });
-        var has_loading = (document.readyState == "loading");
-        var has_interactive = (document.readyState == "interactive");
-        var has_complete = (document.readyState == "complete");
-
-        document.onreadystatechange = function()
-        {
-            if (document.readyState == "loading")
-            {
-                has_loading = true;
-            }
-            if (document.readyState == "interactive")
-            {
-                has_interactive = true;
-            }
-            if (document.readyState = "complete")
-            {
-                has_complete = true;
-            }
-        };
-
-        function onload_test()
-        {
-            test(function () { assert_true(has_loading); }, "Document readiness has loading state.");
-            test(function () { assert_true(has_interactive); }, "Document readiness has interactive state.");
-            test(function () { assert_true(has_complete); }, "Document readiness has complete state.");
-            done();
-        }
-    </script>
-
-</head>
-<body onload="onload_test();">
-    <h1>Description</h1>
-    <p>This test validates that the "loading", "interactive" and "complete"
-       document.readyState states are available during a navigation.</p>
-    <p>Refresh this page to guarantee all readyState phases.</p>
-    <div id="log"></div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigate_within_document.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigate_within_document.html
deleted file mode 100644
index bdf8f2d..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigate_within_document.html
+++ /dev/null
@@ -1,100 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" >
-        <title>window.performance.timing in document navigation</title>
-        <link rel="author" title="Google" href="http://www.google.com/" />
-         <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.timing is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "connectEnd is the same after in document navigation.": {},
-  "connectStart is the same after in document navigation.": {},
-  "domComplete is the same after in document navigation.": {},
-  "domContentLoadedEventEnd is the same after in document navigation.": {},
-  "domContentLoadedEventStart is the same after in document navigation.": {},
-  "domInteractive is the same after in document navigation.": {},
-  "domLoading is the same after in document navigation.": {},
-  "domainLookupEnd is the same after in document navigation.": {},
-  "domainLookupStart is the same after in document navigation.": {},
-  "fetchStart is the same after in document navigation.": {},
-  "loadEventEnd is the same after in document navigation.": {},
-  "loadEventStart is the same after in document navigation.": {},
-  "navigationStart is the same after in document navigation.": {},
-  "redirectEnd is the same after in document navigation.": {},
-  "redirectStart is the same after in document navigation.": {},
-  "requestStart is the same after in document navigation.": {},
-  "responseEnd is the same after in document navigation.": {},
-  "responseStart is the same after in document navigation.": {},
-  "unloadEventEnd is the same after in document navigation.": {},
-  "unloadEventStart is the same after in document navigation.": {}
-}
-*/</script>
-    </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates that all of the window.performance.timing attributes remain unchanged after an in document navigation (URL fragment change).</p>
-
-        <div id="log"></div>
-        <script>
-            setup({explicit_done: true});
-
-            // explicitly test the namespace before we start testing
-            test_namespace('timing');
-
-            var timing;
-
-            function check_timing_not_changed()
-            {
-                for (var i = 0; i < timingAttributes.length; ++i)
-                {
-                    var property = timingAttributes[i];
-                    test_equals(timing[property], initial_timing[property],
-                                property + " is the same after in document navigation.");
-                }
-                done();
-            }
-
-            var initial_timing = {};
-            function save_timing_after_load()
-            {
-                for (var i = 0; i < timingAttributes.length; ++i)
-                {
-                    var property = timingAttributes[i];
-                    initial_timing[property] = timing[property];
-                }
-                window.location.href = "#1";
-                setTimeout("check_timing_not_changed()", 0);
-            }
-
-            function load_handler()
-            {
-                if (performanceNamespace === undefined)
-                {
-                    // avoid script errors
-                    done();
-                    return;
-                }
-
-                timing = performanceNamespace.timing;
-
-                window.removeEventListener("load", load_handler);
-                setTimeout("save_timing_after_load()", 0);
-            }
-
-            window.addEventListener("load", load_handler, false);
-        </script>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_attributes_exist.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_attributes_exist.html
deleted file mode 100644
index d0d93e9..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_attributes_exist.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8">
-        <title>window.performance.navigation attributes</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation.type is defined.": {},
-  "window.performance.navigation.redirectCount is defined.": {}
-}
-*/</script>
-    </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates that all of the window.performance.navigation attributes exist (but does not validate that their values are correct).</p>
-
-        <div id="log"></div>
-
-        <script>
-        test_namespace('navigation');
-
-        test_attribute_exists('navigation', 'type');
-        test_attribute_exists('navigation', 'redirectCount');
-        </script>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_redirectCount_none.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_redirectCount_none.html
deleted file mode 100644
index 8a4619bc..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_redirectCount_none.html
+++ /dev/null
@@ -1,46 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance.navigation.redirectCount on a non-redirected navigation</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "timing.redirectStart on an non-redirected navigation": {},
-  "timing.redirectEnd on an non-redirected navigation": {},
-  "navigation.redirectCount on an non-redirected navigation": { "help": "http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface" }
-}
-*/</script>
-    </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates that the value of the window.performance.navigation.redirectCount attribute, as well as the window.performance.timing.redirectStart and redirectEnd attributes on a non-redirected navigation.</p>
-
-        <div id="log"></div>
-
-        <script>
-        test_namespace('navigation');
-
-        if (performanceNamespace !== undefined)
-        {
-            test_equals(performanceNamespace.timing.redirectStart, 0, 'timing.redirectStart on an non-redirected navigation');
-            test_equals(performanceNamespace.timing.redirectEnd, 0, 'timing.redirectEnd on an non-redirected navigation');
-            test_equals(performanceNamespace.navigation.redirectCount, 0, 'navigation.redirectCount on an non-redirected navigation',{help:"http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"});
-        }
-        </script>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_type_backforward.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_type_backforward.html
deleted file mode 100644
index 2b30fe9..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_type_backforward.html
+++ /dev/null
@@ -1,113 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.navigation.type for back and forward navigations</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-        <link rel="stylesheet" href="/w3c/resources/testharness.css" />
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation.type == TYPE_NAVIGATE": {},
-  "window.performance.navigation.type == TYPE_BACK_FORWARD after history.back()": {},
-  "window.performance.navigation.type == TYPE_BACK_FORWARD after history.forward()": {}
-}
-*/</script>
-        <script>
-            setup({explicit_done: true});
-
-            // explicitly test the namespace before we start testing
-            test_namespace('navigation');
-
-            function onload_test()
-            {
-                if (performanceNamespace === undefined)
-                {
-                    // avoid script errors
-                    done();
-                    return;
-                }
-
-                // do this with a timeout to see the visuals of the navigations.
-                setTimeout("nav_frame();", 100);
-            }
-
-            var step = 1;
-            function nav_frame()
-            {
-                var navigation_frame = document.getElementById("frameContext").contentWindow;
-                switch (step)
-                {
-                    case 1:
-                    {
-                        navigation_frame.location.href = '/w3c/webperf/resources/blank_page_green_with_onunload.htm';
-                        step++;
-                        break;
-                    }
-                    case 2:
-                    {
-                        test_equals(navigation_frame.performance.navigation.type,
-                                performanceNamespace.navigation.TYPE_NAVIGATE,
-                                'window.performance.navigation.type == TYPE_NAVIGATE');
-                        navigation_frame.history.back();
-                        step++;
-                        break;
-                    }
-                    case 3:
-                    {
-                        test_equals(navigation_frame.performance.navigation.type,
-                                performanceNamespace.navigation.TYPE_BACK_FORWARD,
-                                'window.performance.navigation.type == TYPE_BACK_FORWARD after history.back()');
-                        step++;
-                        navigation_frame.history.forward();
-                        break;
-                    }
-                    case 4:
-                    {
-                        test_equals(navigation_frame.performance.navigation.type,
-                                performanceNamespace.navigation.TYPE_BACK_FORWARD,
-                                'window.performance.navigation.type == TYPE_BACK_FORWARD after history.forward()');
-                        done();
-                        step++;
-                        break;
-                    }
-                    default:
-                        break;
-                }
-            }
-        </script>
-
-    </head>
-    <body>
-        <h1>
-            Description</h1>
-        <p>
-            This test validates the value of window.performance.navigation.type with a forward
-            and back navigation.</p>
-
-        <p>This page should be loaded with a yellow background frame below.  It should turn green for a starting
-            navigation, back to yellow for a back navigation and then back to green again for a forward navigation.</p>
-
-        <p>Along the navigation timeline the frame.window.performance.type is checked for TYPE_BACK_FORWARD.</p>
-
-        <p>This test passes if all of the checks to the navigation.type are correct throughout the navigation
-            scenario and the frame below ends with a green background.  Otherwise, this test fails.</p>
-
-        <div id="log"></div>
-        <br />
-        <iframe id="frameContext" onload="onload_test();" src="/w3c/webperf/resources/blank_page_yellow_with_onunload.htm" style="width: 250px; height: 250px;"></iframe>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_type_enums.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_type_enums.html
deleted file mode 100644
index 3ac6575..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_type_enums.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance.navigation enums</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
- <script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation.TYPE_NAVIGATE is defined.": {},
-  "window.performance.navigation.TYPE_NAVIGATE = 0": {},
-  "window.performance.navigation.TYPE_RELOAD is defined.": {},
-  "window.performance.navigation.TYPE_RELOAD = 1": {},
-  "window.performance.navigation.TYPE_BACK_FORWARD is defined.": {},
-  "window.performance.navigation.TYPE_BACK_FORWARD = 2": {},
-  "window.performance.navigation.TYPE_RESERVED is defined.": {},
-  "window.performance.navigation.TYPE_RESERVED = 255": {}
-}
-*/</script>
-   </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates that the TYPE_* enumerations of window.performance.navigation exist and their values are correct.</p>
-
-        <div id="log"></div>
-
-        <script>
-        test_namespace('navigation');
-
-        test_enum('navigation', 'TYPE_NAVIGATE', 0);
-        test_enum('navigation', 'TYPE_RELOAD', 1);
-        test_enum('navigation', 'TYPE_BACK_FORWARD', 2);
-        test_enum('navigation', 'TYPE_RESERVED', 255);
-        </script>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_type_reload.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_type_reload.html
deleted file mode 100644
index 56e715d..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_navigation_type_reload.html
+++ /dev/null
@@ -1,144 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance.navigation.type with a reloaded navigation</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-        <link rel="stylesheet" href="/w3c/resources/testharness.css" />
- <script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation.type == TYPE_RELOAD,{help:"http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"}": {},
-  "Reload connectEnd(1340376070295) > Original connectEnd(1340376070163)": {},
-  "Reload connectStart(1340376070295) > Original connectStart(1340376070163)": {},
-  "Reload domComplete(1340376070300) > Original domComplete(1340376070179)": {},
-  "Reload domContentLoadedEventEnd(1340376070300) > Original domContentLoadedEventEnd(1340376070179)": {},
-  "Reload domContentLoadedEventStart(1340376070300) > Original domContentLoadedEventStart(1340376070179)": {},
-  "Reload domInteractive(1340376070300) > Original domInteractive(1340376070179)": {},
-  "Reload domLoading(1340376070299) > Original domLoading(1340376070178)": {},
-  "Reload domainLookupEnd(1340376070295) > Original domainLookupEnd(1340376070163)": {},
-  "Reload domainLookupStart(1340376070295) > Original domainLookupStart(1340376070163)": {},
-  "Reload fetchStart(1340376070290) > Original fetchStart(1340376070163)": {},
-  "Reload loadEventEnd(1340376070300) > Original loadEventEnd(1340376070179)": {},
-  "Reload loadEventStart(1340376070300) > Original loadEventStart(1340376070179)": {},
-  "Reload navigationStart(1340376070290) > Original navigationStart(1340376070163)": {},
-  "Reload redirectEnd(0) == Original redirectEnd(0)": {},
-  "Reload redirectStart(0) == Original redirectStart(0)": {},
-  "Reload requestStart(1340376070295) > Original requestStart(1340376070164)": {},
-  "Reload responseEnd(1340376070296) > Original responseEnd(1340376070174)": {},
-  "Reload responseStart(1340376070296) > Original responseStart(1340376070164)": {},
-  "Reload unloadEventEnd(1340376070296) > Original unloadEventEnd(0)": {},
-  "Reload unloadEventStart(1340376070296) > Original unloadEventStart(0)": {}
-}
-*/</script>
-        <script>
-            setup({explicit_done: true});
-
-            // explicitly test the namespace before we start testing
-            test_namespace('navigation');
-            var reload_frame;
-            var startingTime;
-
-            function deepCopy(p, c)
-            {
-                var c = c || {};
-                for (var i in p)
-                {
-                    if (typeof p[i] === 'object')
-                    {
-                        c[i] = (p[i].constructor === Array) ? [] : {};
-                        deepCopy(p[i], c[i]);
-                    } else c[i] = p[i];
-                }
-                return c;
-            }
-
-
-            function onload_test()
-            {
-                reload_frame = document.getElementById("frameContext");
-                reload_frame.onload = function() {
-                  /* Need to make sure we don't examine loadEventEnd
-                     until after the load event has finished firing */
-                    setTimeout(do_test, 0);
-                }
-                setTimeout("reload_the_frame();", 100);
-            }
-
-            function reload_the_frame()
-            {
-                //Before reloading, save the current timing
-                startingTime = deepCopy(reload_frame.contentWindow.performance.timing);
-                reload_frame.contentWindow.location.reload(true);
-            }
-
-            function do_test()
-            {
-                reload_frame.onload = null;
-                if (performanceNamespace)
-                {
-                    //Verify that the navigation type has updated to reload
-                    test_equals(reload_frame.contentWindow.performance.navigation.type,
-                            performanceNamespace.navigation.TYPE_RELOAD,
-                            'window.performance.navigation.type == TYPE_RELOAD,{help:"http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"}');
-
-                    //Verify that the timing data has been updated into the future
-                    var reloadTime = reload_frame.contentWindow.performance.timing;
-                    for (attribute in timingAttributes)
-                    {
-                        var time = timingAttributes[attribute];
-                        if (reloadTime[time] === 0)
-                        {
-                            test_equals(reloadTime[time],
-                                        startingTime[time],
-                                        "Reload " + time  +
-                                        " == " +
-                                        "Original " + time );
-                        }
-                        else
-                        {
-                            test_greater_than(reloadTime[time],
-                                              startingTime[time],
-                                              "Reload " + time  +
-                                              " > " +
-                                              "Original " + time );
-                        }
-                    }
-                }
-
-                done();
-            }
-        </script>
-    </head>
-    <body onload="onload_test();">
-        <h1>Description</h1>
-        <p>This test validates the value of window.performance.navigation.type and the values of
-            window.performance.timing.* with a reloaded navigation.</p>
-
-        <p>This page should be loaded with a green background frame below.  The frame will be automatically reloaded
-        and then verified that
-        <ul>
-            <li>The window.performance.navigation.type = TYPE_RELOAD</li>
-            <li>All of the widow.performance.timing.* values after reload are > all of the window.performance.timing.* values
-                prior to reload.</li>
-        </ul>
-        </p>
-
-        <div id="log"></div>
-        <br />
-        <iframe id="frameContext" src="/w3c/webperf/resources/blank_page_green.htm" style="width: 250px; height: 250px;"></iframe>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_no_previous_document.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_no_previous_document.html
deleted file mode 100644
index 008932d..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_no_previous_document.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance.timing attributes on an initial navigation</title>
-        <link rel="author" title="Google" href="http://www.google.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "timing.navigation.type is TYPE_NAVIGATE": { "help": "http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface" },
-  "timing.unloadEventStart == 0 on navigation with no previous document": {},
-  "timing.unloadEventEnd == 0 navigation with no previous document": {}
-}
-*/</script>
-        <link rel="stylesheet" href="/w3c/resources/testharness.css" />
-
-        <script>
-            setup({explicit_done: true});
-
-            var frame;
-            function onload_test()
-            {
-                frame = document.getElementById("frameContext");
-                test_namespace('navigation');
-                if (performanceNamespace)
-                {
-                    test_true(frame.contentWindow.performance.navigation.type == performanceNamespace.navigation.TYPE_NAVIGATE,
-                              'timing.navigation.type is TYPE_NAVIGATE',{help:"http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"});
-
-                    test_equals(frame.contentWindow.performance.timing.unloadEventStart, 0, 'timing.unloadEventStart == 0 on navigation with no previous document');
-                    test_equals(frame.contentWindow.performance.timing.unloadEventEnd, 0, 'timing.unloadEventEnd == 0 navigation with no previous document');
-                }
-                done();
-            }
-        </script>
-
-    </head>
-    <body onload="onload_test();">
-        <h1>Description</h1>
-        <p>This test validates the unload event times are 0 when there is no previous document.</p>
-
-        <div id="log"></div><br />
-        <iframe id="frameContext" src="/w3c/webperf/resources/blank_page_green.htm" style="width: 250px; height: 250px;"></iframe>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_performance_attributes_exist.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_performance_attributes_exist.html
deleted file mode 100644
index ef14c4e..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_performance_attributes_exist.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance attributes</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
- <script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.timing is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  }
-}
-*/</script>
-       <link rel="stylesheet" href="/w3c/resources/testharness.css" />
-    </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates that the navigation and timing attributes exist for window.performance
-        (but does not validate that their values are correct).</p>
-        <div id="log"></div>
-        <script>
-            test_namespace('navigation');
-            test_namespace('timing', true);
-        </script>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_performance_attributes_exist_in_object.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_performance_attributes_exist_in_object.html
deleted file mode 100644
index 2635f3f..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_performance_attributes_exist_in_object.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance attribute exists in an object</title>
-        <link rel="author" title="Google" href="http://www.google.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.timing is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  }
-}
-*/</script>
-        <link rel="stylesheet" href="/w3c/resources/testharness.css" />
-        <script>
-          function onload_test() {
-            var objWindow =
-                document.getElementById("objectContext").contentDocument.defaultView;
-            performanceNamespace = objWindow.performance;
-            test_namespace('timing');
-            test_namespace('navigation', true);
-          }
-        </script>
-    </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates that the window.performance object exists in an
-        object element (but does not validate that their values are correct).</p>
-        <object id="objectContext" onload="onload_test();" data="/w3c/webperf/resources/blank_page_green.htm"></object>
-        <div id="log"></div>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_readwrite.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_readwrite.html
deleted file mode 100644
index adde89e1..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_readwrite.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance is read/write</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute"/>
-        <meta name="assert" content="The window.performance attribute provides a hosting area for performance related attributes. "/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance is read/write": {},
-  "var performance is read/write": {}
-}
-*/</script>
-        <link rel="stylesheet" href="/w3c/resources/testharness.css" />
-    </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates that the window.performance object is read/write.</p>
-        <div id="log"></div>
-        <script>
-            test_namespace();
-
-            window.performance = 'foo';
-            test_equals(window.performance, 'foo', 'window.performance is read/write');
-
-            var performance = 'bar';
-            test_equals(performance, 'bar', 'var performance is read/write');
-        </script>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_attributes_exist.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_attributes_exist.html
deleted file mode 100644
index 78d9371..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_attributes_exist.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance.timing attributes</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.timing is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.timing.connectEnd is defined.": {},
-  "window.performance.timing.connectStart is defined.": {},
-  "window.performance.timing.domComplete is defined.": {},
-  "window.performance.timing.domContentLoadedEventEnd is defined.": {},
-  "window.performance.timing.domContentLoadedEventStart is defined.": {},
-  "window.performance.timing.domInteractive is defined.": {},
-  "window.performance.timing.domLoading is defined.": {},
-  "window.performance.timing.domainLookupEnd is defined.": {},
-  "window.performance.timing.domainLookupStart is defined.": {},
-  "window.performance.timing.fetchStart is defined.": {},
-  "window.performance.timing.loadEventEnd is defined.": {},
-  "window.performance.timing.loadEventStart is defined.": {},
-  "window.performance.timing.navigationStart is defined.": {},
-  "window.performance.timing.redirectEnd is defined.": {},
-  "window.performance.timing.redirectStart is defined.": {},
-  "window.performance.timing.requestStart is defined.": {},
-  "window.performance.timing.responseEnd is defined.": {},
-  "window.performance.timing.responseStart is defined.": {},
-  "window.performance.timing.unloadEventEnd is defined.": {},
-  "window.performance.timing.unloadEventStart is defined.": {}
-}
-*/</script>
-    </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates that all of the window.performance.timing attributes exist (but does not validate that their values are correct).</p>
-
-        <div id="log"></div>
-
-        <script>
-        test_namespace('timing');
-
-        for (var i = 0; i < timingAttributes.length; ++i)
-        {
-            test_attribute_exists('timing', timingAttributes[i]);
-        }
-        </script>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_attributes_order.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_attributes_order.html
deleted file mode 100644
index 41bdbee..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_attributes_order.html
+++ /dev/null
@@ -1,167 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance.timing attribute ordering on a simple navigation</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-        <link rel="stylesheet" href="/w3c/resources/testharness.css" />
- <script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.timing is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation.type == TYPE_NAVIGATE": { "help": "http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface" },
-  "window.performance.timing.navigationStart > 0": {},
-  "window.performance.timing.redirectStart == 0": {},
-  "window.performance.timing.redirectEnd == 0": {},
-  "window.performance.timing.fetchStart > 0": {},
-  "window.performance.timing.fetchStart >= window.performance.timing.navigationStart": {},
-  "window.performance.timing.domainLookupStart > 0": {},
-  "window.performance.timing.domainLookupStart >= window.performance.timing.fetchStart": {},
-  "window.performance.timing.domainLookupEnd > 0": {},
-  "window.performance.timing.domainLookupEnd >= window.performance.timing.domainLookupStart": {},
-  "window.performance.timing.connectStart > 0": {},
-  "window.performance.timing.connectStart >= window.performance.timing.domainLookupEnd": {},
-  "window.performance.timing.connectEnd > 0": {},
-  "window.performance.timing.connectEnd >= window.performance.timing.connectStart": {},
-  "window.performance.timing.requestStart > 0": {},
-  "window.performance.timing.requestStart >= window.performance.timing.connectEnd": {},
-  "window.performance.timing.responseStart > 0": {},
-  "window.performance.timing.responseStart >= window.performance.timing.requestStart": {},
-  "window.performance.timing.responseEnd > 0": {},
-  "window.performance.timing.responseEnd >= window.performance.timing.responseStart": {},
-  "window.performance.timing.domLoading > 0": {},
-  "window.performance.timing.domLoading >= window.performance.timing.fetchStart": {},
-  "window.performance.timing.domInteractive > 0": {},
-  "window.performance.timing.domInteractive >= window.performance.timing.responseEnd": {},
-  "window.performance.timing.domContentLoadedEventStart > 0": {},
-  "window.performance.timing.domContentLoadedEventStart >= window.performance.timing.domInteractive": {},
-  "window.performance.timing.domContentLoadedEventEnd > 0": {},
-  "window.performance.timing.domContentLoadedEventEnd >= window.performance.timing.domContentLoadedEventStart": {},
-  "window.performance.timing.domComplete > 0": {},
-  "window.performance.timing.domComplete >= window.performance.timing.domContentLoadedEventEnd": {},
-  "window.performance.timing.loadEventStart > 0": {},
-  "window.performance.timing.loadEventStart >= window.performance.timing.domContentLoadedEventEnd": {},
-  "window.performance.timing.loadEventEnd > 0": {},
-  "window.performance.timing.loadEventEnd >= window.performance.timing.loadEventStart": {},
-  "window.performance.timing.unloadEventStart > 0": {},
-  "window.performance.timing.unloadEventStart >= window.performance.timing.navigationStart": {},
-  "window.performance.timing.unloadEventEnd > 0": {},
-  "window.performance.timing.unloadEventEnd >= window.performance.timing.unloadEventStart": {}
-}
-*/</script>
-        <script>
-            setup({explicit_done: true});
-
-            test_namespace('timing');
-
-            var step = 1;
-            function onload_test()
-            {
-                if (step === 1 && window.performance === undefined)
-                {
-                    // avoid script errors
-                    done();
-                    return;
-                }
-
-                var navigation_frame = document.getElementById("frameContext").contentWindow;
-                performanceNamespace = navigation_frame.performance;
-                switch (step)
-                {
-                    case 1:
-                    {
-                        navigation_frame.location.href = '/w3c/webperf/resources/blank_page_green.htm';
-                        step++;
-                        break;
-                    }
-                case 2:
-                    {
-                        test_namespace('navigation', true);
-
-                        //
-                        // Tests
-                        //
-                        test_equals(performanceNamespace.navigation.type,
-                                performanceNamespace.navigation.TYPE_NAVIGATE,
-                                'window.performance.navigation.type == TYPE_NAVIGATE',{help:"http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"});
-
-                        // navigiation must be non-0
-                        test_timing_greater_than('navigationStart', 0);
-
-                        // must be no redirection for this test case
-                        test_timing_equals('redirectStart', 0);
-                        test_timing_equals('redirectEnd', 0);
-
-                        // validate attribute ordering
-                        test_timing_order('fetchStart', 'navigationStart');
-                        test_timing_order('domainLookupStart', 'fetchStart');
-                        test_timing_order('domainLookupEnd', 'domainLookupStart');
-                        test_timing_order('connectStart', 'domainLookupEnd');
-                        test_timing_order('connectEnd', 'connectStart');
-                        test_timing_order('requestStart', 'connectEnd');
-                        test_timing_order('responseStart', 'requestStart');
-                        test_timing_order('responseEnd', 'responseStart');
-                        test_timing_order('domLoading', 'fetchStart');
-                        test_timing_order('domInteractive', 'responseEnd');
-                        test_timing_order('domContentLoadedEventStart', 'domInteractive');
-                        test_timing_order('domContentLoadedEventEnd', 'domContentLoadedEventStart');
-                        test_timing_order('domComplete', 'domContentLoadedEventEnd');
-                        test_timing_order('loadEventStart', 'domContentLoadedEventEnd');
-                        test_timing_order('loadEventEnd', 'loadEventStart');
-
-                        // setup requires the frame to have a previous page with an onunload event handler.
-                        test_timing_order('unloadEventStart', 'navigationStart');
-                        test_timing_order('unloadEventEnd', 'unloadEventStart');
-
-                        step++;
-                        done();
-                        break;
-                    }
-                    default:
-                        break;
-                }
-            }
-        </script>
-    </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates the ordering of the window.performance.timing attributes.</p>
-
-        <p>This page should be loaded with a yellow background frame below which contains an unload event
-           handler.</p>
-
-        <p>After the page loads, the frame is navigated to a new blank page with a green background.  At this point, the navigation timeline is verified</p>
-
-        <p>This test passes if all of the checks to the frame.window.performance.timing attributes are
-           correct throughout the navigation scenario and the frame below ends with a green background.
-           Otherwise, this test fails.</p>
-
-        <h1>Setup</h1>
-
-        <div id="log"></div>
-        <br />
-        <iframe id="frameContext"
-                onload="/* Need to make sure we don't examine loadEventEnd
-                           until after the load event has finished firing */
-                        setTimeout(onload_test, 0);"
-                src="/w3c/webperf/resources/blank_page_unload.htm"
-                style="width: 250px; height: 250px;"></iframe>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_client_redirect.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_client_redirect.html
deleted file mode 100644
index 864214e..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_client_redirect.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance.timing.redirect attributes on a client redirect navigation</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-        <link rel="stylesheet" href="/w3c/resources/testharness.css" />
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.timing is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "timing.navigation.type is TYPE_NAVIGATE": { "help": "http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface" },
-  "navigation.redirectCount == 0 on an client redirected navigation": { "help": "http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface" },
-  "timing.redirectStart == 0 on an client redirected navigation": {},
-  "timing.redirectEnd == 0 on an client redirected navigation": {}
-}
-*/</script>
-        <script>
-            setup({explicit_done: true});
-
-            test_namespace('navigation');
-            test_namespace('timing', true);
-
-            var redirect_frame;
-            function onload_test()
-            {
-                if (performanceNamespace === undefined)
-                {
-                    // avoid script errors
-                    done();
-                    return;
-                }
-
-                redirect_frame = document.getElementById("frameContext");
-                redirect_frame.onload = do_test;
-            }
-
-            function do_test()
-            {
-                redirect_frame.onload = "";
-                test_true(redirect_frame.contentWindow.performance.navigation.type == performanceNamespace.navigation.TYPE_NAVIGATE,
-                          'timing.navigation.type is TYPE_NAVIGATE',{help:"http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"});
-
-                test_equals(redirect_frame.contentWindow.performance.navigation.redirectCount, 0, 'navigation.redirectCount == 0 on an client redirected navigation',{help:"http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"});
-                test_equals(redirect_frame.contentWindow.performance.timing.redirectStart, 0, 'timing.redirectStart == 0 on an client redirected navigation');
-                test_equals(redirect_frame.contentWindow.performance.timing.redirectEnd, 0, 'timing.redirectEnd == 0 on an client redirected navigation');
-
-                done();
-            }
-        </script>
-
-    </head>
-    <body onload="onload_test();">
-        <h1>Description</h1>
-        <p>This test validates the values of the window.navigation.redirectCount and the
-           window.performance.timing.redirectStart/End times on a client side redirect.</p>
-
-        <div id="log"></div><br />
-        <iframe id="frameContext" src="/w3c/webperf/resources/blank_page_meta_redirect.htm" style="width: 250px; height: 250px;"></iframe>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_reload.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_reload.html
deleted file mode 100644
index ec9f7512..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_reload.html
+++ /dev/null
@@ -1,122 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance.timing attributes after a reloaded navigation</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-        <link rel="stylesheet" href="/w3c/resources/testharness.css" />
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation.type == TYPE_RELOAD": { "help": "http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface" },
-  "connectEnd is different after the reload.": {},
-  "connectStart is different after the reload.": {},
-  "domComplete is different after the reload.": {},
-  "domContentLoadedEventEnd is different after the reload.": {},
-  "domContentLoadedEventStart is different after the reload.": {},
-  "domInteractive is different after the reload.": {},
-  "domLoading is different after the reload.": {},
-  "domainLookupEnd is different after the reload.": {},
-  "domainLookupStart is different after the reload.": {},
-  "fetchStart is different after the reload.": {},
-  "loadEventEnd is different after the reload.": {},
-  "loadEventStart is different after the reload.": {},
-  "navigationStart is different after the reload.": {},
-  "requestStart is different after the reload.": {},
-  "responseEnd is different after the reload.": {},
-  "responseStart is different after the reload.": {}
-}
-*/</script>
-        <script>
-            setup({explicit_done: true});
-
-            // explicitly test the namespace before we start testing
-            test_namespace('navigation');
-
-            var reload_frame;
-            var initial_timing;
-
-            function onload_test()
-            {
-                reload_frame = document.getElementById("frameContext");
-
-                if (reload_frame.contentWindow.performance === undefined)
-                {
-                    // avoid script errors
-                    done();
-                    return;
-                }
-
-                reload_frame.onload = do_test;
-
-                // save frame's initial timings
-                initial_timing = {};
-                var timing = reload_frame.contentWindow.performance.timing;
-
-                for (var i = 0; i < timingAttributes.length; ++i)
-                {
-                    var property = timingAttributes[i];
-                    initial_timing[property] = timing[property];
-                }
-
-                setTimeout("reload_the_frame();", 100);
-            }
-
-            function reload_the_frame()
-            {
-                reload_frame.contentWindow.location.reload(true);
-            }
-
-            function do_test()
-            {
-                reload_frame.onload = "";
-
-                // ensure the frame reloaded
-                test_equals(reload_frame.contentWindow.performance.navigation.type,
-                            performanceNamespace.navigation.TYPE_RELOAD,
-                            "window.performance.navigation.type == TYPE_RELOAD", {help:"http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"});
-
-                // ensure reload timings changed
-                var timing = reload_frame.contentWindow.performance.timing;
-                for (var i = 0; i < timingAttributes.length; ++i)
-                {
-                    var property = timingAttributes[i];
-
-                    // ignore any timings that were zero initially
-                    if (initial_timing[property] !== 0)
-                    {
-                        test_not_equals(timing[property], initial_timing[property],
-                                property + " is different after the reload.");
-                    }
-                }
-
-                done();
-            }
-        </script>
-    </head>
-    <body onload="onload_test();">
-        <h1>Description</h1>
-        <p>This test validates that the window.performance.timing attributes change when a page is reloaded.</p>
-
-        <p>This page should be loaded with a green background frame below.  The frame will be automatically reloaded
-        and then verified that the window.performance.timing attributes have been updated to the new reloaded navigation timings.</p>
-
-        <div id="log"></div>
-        <br />
-        <iframe id="frameContext" src="/w3c/webperf/resources/blank_page_green.htm" style="width: 250px; height: 250px;"></iframe>
-
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_server_redirect.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_server_redirect.html
deleted file mode 100644
index daa6959..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_server_redirect.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance.timing.redirect attributes on a same-origin server redirected navigation</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-
-        <script>
-            function onload_test()
-            {
-                test_namespace('navigation');
-                if (performanceNamespace === undefined)
-                {
-                    // avoid script errors
-                    done();
-                    return;
-                }
-
-                performanceNamespace = document.getElementById("frameContext").contentWindow.performance;
-                test_equals(performanceNamespace.navigation.type,
-                        performanceNamespace.navigation.TYPE_NAVIGATE,
-                        'timing.navigation.type is TYPE_NAVIGATE');
-                test_equals(performanceNamespace.navigation.redirectCount, 1, 'navigation.redirectCount == 1 on an server redirected navigation');
-
-                test_timing_greater_than('navigationStart', 0);
-
-                test_timing_order('redirectStart', 'navigationStart');
-                test_timing_order('redirectEnd', 'redirectStart');
-                test_timing_order('fetchStart', 'redirectEnd');
-            }
-        </script>
-
-    </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates the values of the window.performance.redirectCount and the
-           window.performance.timing.redirectStart/End times for a same-origin server side redirect navigation.</p>
-
-        <div id="log"></div>
-        <br />
-        <iframe id="frameContext" onload="onload_test();" src="/w3c/webperf/resources/redirect.php?location=/w3c/webperf/resources/blank_page_green.htm" style="width: 250px; height: 250px;"></iframe>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_xserver_redirect-expected.txt b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_xserver_redirect-expected.txt
deleted file mode 100644
index 2b437b9..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_xserver_redirect-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This is a testharness.js-based test.
-FAIL Starting document.location.hostname is correct (127.0.0.1:8000) assert_equals: Starting document.location.hostname is correct (127.0.0.1:8000) expected "127.0.0.1:8000" but got "127.0.0.1"
-PASS window.performance is defined
-PASS window.performance.navigation is defined
-PASS timing.navigation.type is TYPE_NAVIGATE
-PASS navigation.redirectCount == 0 on a cross-origin server redirected navigation
-PASS window.performance.timing.navigationStart > 0
-PASS timing.redirectStart == 0 on a server redirected navigation from another domain
-PASS timing.redirectEnd == 0 on a server redirected navigation from another domain
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_xserver_redirect.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_xserver_redirect.html
deleted file mode 100644
index 65d2214..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_timing_xserver_redirect.html
+++ /dev/null
@@ -1,89 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>window.performance.timing.redirect attributes on a cross-origin server redirected navigation</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface"/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-<script id="metadata_cache">/*
-{
-  "Starting document.location.hostname is correct (127.0.0.1:8000)": {},
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.navigation is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  }
-}
-*/</script>
-        <script>
-            setup({explicit_done: true});
-
-            //
-            // Test configuration
-            //
-
-            // the current page's origin
-            var pageOrigin = '127.0.0.1:8000';
-
-            // the origin to redirect through
-            var redirectOrigin = 'localhost:8000';
-
-            //
-            // Tests
-            //
-            function onload_test()
-            {
-                test_namespace('navigation');
-                if (performanceNamespace === undefined)
-                {
-                    // avoid script errors
-                    done();
-                    return;
-                }
-
-                performanceNamespace = document.getElementById("frameContext").contentWindow.performance;
-                test_equals(performanceNamespace.navigation.type,
-                        performanceNamespace.navigation.TYPE_NAVIGATE,
-                        'timing.navigation.type is TYPE_NAVIGATE',{help:"http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"});
-                test_equals(performanceNamespace.navigation.redirectCount, 0, 'navigation.redirectCount == 0 on a cross-origin server redirected navigation', {help:"http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface"});
-
-                test_timing_greater_than('navigationStart', 0);
-
-                test_equals(performanceNamespace.timing.redirectStart, 0, 'timing.redirectStart == 0 on a server redirected navigation from another domain');
-                test_equals(performanceNamespace.timing.redirectEnd, 0, 'timing.redirectEnd == 0 on a server redirected navigation from another domain');
-
-                done();
-            }
-        </script>
-
-    </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates the values of the window.performance.redirectCount and the
-           window.performance.timing.redirectStart/End times for a cross-origin server side redirect navigation.</p>
-
-        <div id="log"></div>
-        <br />
-        <iframe id="frameContext" src="" style="width: 250px; height: 250px;"></iframe>
-        <script>
-            // ensure we're starting at the right origin
-            test_equals(document.location.hostname, pageOrigin, 'Starting document.location.hostname is correct (' + pageOrigin + ')');
-
-            // combine the page origin and redirect origin into the IFRAME's src URL
-            var destUrl = 'http://' + redirectOrigin + '/w3c/webperf/resources/redirect.php';
-            destUrl    += '?location=http://' + pageOrigin + '/w3c/webperf/resources/blank_page_green.htm';
-
-            var frameContext = document.getElementById("frameContext");
-            frameContext.onload = onload_test;
-            frameContext.src = destUrl;
-        </script>
-    </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_unique_performance_objects.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_unique_performance_objects.html
deleted file mode 100644
index 3d6d4ac..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/approved/navigation-timing/html/test_unique_performance_objects.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <title>Each window object has a unique performance object</title>
-        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
-        <link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute" />
-        <meta name="assert" content="Each browsing context must have a unique window.performance.timing attribute."/>
-        <script src="/w3c/resources/testharness.js"></script>
-        <script src="/w3c/resources/testharnessreport.js"></script>
-        <script src="/w3c/webperf/resources/webperftestharness.js"></script>
-        <link rel="stylesheet" href="/w3c/resources/testharness.css" />
-<script id="metadata_cache">/*
-{
-  "window.performance is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "window.performance.timing is defined": {
-    "help": "http://www.w3.org/TR/navigation-timing/#sec-window.performance-attribute",
-    "assert": "The window.performance attribute provides a hosting area for performance related attributes. ",
-    "author": "W3C http://www.w3.org/"
-  },
-  "Different window objects have unique performance objects": {}
-}
-*/</script>
-    </head>
-    <body>
-        <h1>Description</h1>
-        <p>This test validates that each window has a unique window.performance object.</p>
-        <iframe id="frameContext" src="/w3c/webperf/resources/blank_page_green.htm" style="display:none;";></iframe>
-        <div id="log"></div>
-        <script>
-            test_namespace('timing');
-
-            if (performanceNamespace !== undefined)
-            {
-                test_not_equals(performanceNamespace.timing,
-                                document.getElementById("frameContext").contentWindow.performance.timing,
-                                "Different window objects have unique performance objects");
-            }
-        </script>
-    </body>
-</html>
diff --git a/third_party/WebKit/Source/bindings/bindings.gni b/third_party/WebKit/Source/bindings/bindings.gni
index d2bf3dc..1e41cd0 100644
--- a/third_party/WebKit/Source/bindings/bindings.gni
+++ b/third_party/WebKit/Source/bindings/bindings.gni
@@ -111,7 +111,6 @@
                     "core/v8/V8BindingForCore.cpp",
                     "core/v8/V8BindingForCore.h",
                     "core/v8/V8CacheOptions.h",
-                    "core/v8/V8CacheStrategiesForCacheStorage.h",
                     "core/v8/V8CrossOriginSetterInfo.h",
                     "core/v8/V8DOMConfiguration.cpp",
                     "core/v8/V8DOMConfiguration.h",
diff --git a/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp b/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp
index 93ae250..e7a4de1 100644
--- a/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp
@@ -145,8 +145,6 @@
   }
 
   SetupWindowPrototypeChain();
-  V8ContextSnapshot::InstallConditionalFeatures(context,
-                                                GetFrame()->GetDocument());
 
   SecurityOrigin* origin = nullptr;
   if (world_->IsMainWorld()) {
@@ -173,20 +171,12 @@
     MainThreadDebugger::Instance()->ContextCreated(script_state_.get(),
                                                    GetFrame(), origin);
     GetFrame()->Client()->DidCreateScriptContext(context, world_->GetWorldId());
+  }
 
-    InstallOriginTrialFeaturesOnGlobal(&V8Window::wrapperTypeInfo,
-                                       script_state_.get());
+  InstallConditionalFeatures();
 
-    if (world_->IsMainWorld()) {
-      // For the main world, install any remaining conditional bindings (i.e.
-      // for origin trials, which do not apply to extensions). Some conditional
-      // bindings cannot be enabled until the execution context is available
-      // (e.g. parsing the document, inspecting HTTP headers).
-      InstallOriginTrialFeatures(&V8Window::wrapperTypeInfo,
-                                 script_state_.get(), v8::Local<v8::Object>(),
-                                 v8::Local<v8::Function>());
-      GetFrame()->Loader().DispatchDidClearWindowObjectInMainWorld();
-    }
+  if (world_->IsMainWorld()) {
+    GetFrame()->Loader().DispatchDidClearWindowObjectInMainWorld();
   }
 }
 
@@ -232,7 +222,7 @@
     // in some cases, e.g. loading XML files.
     if (context.IsEmpty()) {
       v8::Local<v8::ObjectTemplate> global_template =
-          V8Window::domTemplate(isolate, *world_)->InstanceTemplate();
+          V8Window::domTemplate(isolate, World())->InstanceTemplate();
       CHECK(!global_template.IsEmpty());
       context = v8::Context::New(isolate, &extension_configuration,
                                  global_template, global_proxy);
@@ -253,6 +243,41 @@
   DCHECK(script_state_->ContextIsValid());
 }
 
+void LocalWindowProxy::InstallConditionalFeatures() {
+  TRACE_EVENT1("v8", "InstallConditionalFeatures", "IsMainFrame",
+               GetFrame()->IsMainFrame());
+
+  v8::Local<v8::Context> context = script_state_->GetContext();
+  const WrapperTypeInfo* wrapper_type_info =
+      GetFrame()->DomWindow()->GetWrapperTypeInfo();
+
+  InstallOriginTrialFeaturesOnGlobal(wrapper_type_info, script_state_.get());
+
+  // If the context was created from snapshot, all remained conditionally
+  // enabled features are installed in
+  // V8ContextSnapshot::InstallConditionalFeatures().
+  if (V8ContextSnapshot::InstallConditionalFeatures(
+          context, GetFrame()->GetDocument())) {
+    return;
+  }
+
+  v8::Local<v8::Object> global_proxy = context->Global();
+  wrapper_type_info->InstallConditionalFeatures(
+      context, World(), global_proxy, v8::Local<v8::Object>(),
+      v8::Local<v8::Function>(),
+      wrapper_type_info->domTemplate(GetIsolate(), World()));
+
+  if (world_->IsMainWorld()) {
+    // For the main world, install any remaining conditional bindings (i.e.
+    // for origin trials, which do not apply to extensions). Some conditional
+    // bindings cannot be enabled until the execution context is available
+    // (e.g. parsing the document, inspecting HTTP headers).
+    InstallOriginTrialFeatures(wrapper_type_info, script_state_.get(),
+                               v8::Local<v8::Object>(),
+                               v8::Local<v8::Function>());
+  }
+}
+
 void LocalWindowProxy::SetupWindowPrototypeChain() {
   TRACE_EVENT1("v8", "LocalWindowProxy::SetupWindowPrototypeChain",
                "IsMainFrame", GetFrame()->IsMainFrame());
diff --git a/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.h b/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.h
index 3845ed3..605139d9 100644
--- a/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.h
+++ b/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.h
@@ -82,6 +82,9 @@
   // wrapper is not yet associated with the native DOMWindow object.
   void CreateContext();
 
+  // Installs conditionally enabled features, if necessary.
+  void InstallConditionalFeatures();
+
   // Associates the window wrapper and its prototype chain with the native
   // DOMWindow object. Also does some more Window-specific initialization.
   void SetupWindowPrototypeChain();
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp
index 3988b5f..e7563293 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp
@@ -87,22 +87,15 @@
 V8CacheOptions CacheOptions(const ScriptResource* resource,
                             const Settings* settings) {
   V8CacheOptions v8_cache_options(kV8CacheOptionsDefault);
-  if (settings)
+  if (settings) {
     v8_cache_options = settings->GetV8CacheOptions();
-  if (resource && !resource->GetResponse().CacheStorageCacheName().IsNull()) {
-    switch (settings->GetV8CacheStrategiesForCacheStorage()) {
-      case V8CacheStrategiesForCacheStorage::kNone:
-        v8_cache_options = kV8CacheOptionsNone;
-        break;
-      case V8CacheStrategiesForCacheStorage::kNormal:
-        v8_cache_options = kV8CacheOptionsCode;
-        break;
-      case V8CacheStrategiesForCacheStorage::kDefault:
-      case V8CacheStrategiesForCacheStorage::kAggressive:
-        v8_cache_options = kV8CacheOptionsAlways;
-        break;
-    }
+    if (v8_cache_options == kV8CacheOptionsNone)
+      return kV8CacheOptionsNone;
   }
+  // If the resource is served from CacheStorage, generate the V8 code cache in
+  // the first load.
+  if (resource && !resource->GetResponse().CacheStorageCacheName().IsNull())
+    return kV8CacheOptionsAlways;
   return v8_cache_options;
 }
 
@@ -392,13 +385,4 @@
   return world;
 }
 
-STATIC_ASSERT_ENUM(WebSettings::V8CacheStrategiesForCacheStorage::kDefault,
-                   V8CacheStrategiesForCacheStorage::kDefault);
-STATIC_ASSERT_ENUM(WebSettings::V8CacheStrategiesForCacheStorage::kNone,
-                   V8CacheStrategiesForCacheStorage::kNone);
-STATIC_ASSERT_ENUM(WebSettings::V8CacheStrategiesForCacheStorage::kNormal,
-                   V8CacheStrategiesForCacheStorage::kNormal);
-STATIC_ASSERT_ENUM(WebSettings::V8CacheStrategiesForCacheStorage::kAggressive,
-                   V8CacheStrategiesForCacheStorage::kAggressive);
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8CacheStrategiesForCacheStorage.h b/third_party/WebKit/Source/bindings/core/v8/V8CacheStrategiesForCacheStorage.h
deleted file mode 100644
index a65be5b..0000000
--- a/third_party/WebKit/Source/bindings/core/v8/V8CacheStrategiesForCacheStorage.h
+++ /dev/null
@@ -1,19 +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 V8CacheStrategiesForCacheStorage_h
-#define V8CacheStrategiesForCacheStorage_h
-
-namespace blink {
-
-enum class V8CacheStrategiesForCacheStorage {
-  kDefault,
-  kNone,
-  kNormal,
-  kAggressive,
-};
-
-}  // namespace blink
-
-#endif  // V8CacheStrategiesForCacheStorage_h
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ContextSnapshot.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ContextSnapshot.cpp
index 0c99dbef..ac6523bd 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ContextSnapshot.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ContextSnapshot.cpp
@@ -168,14 +168,14 @@
   return context;
 }
 
-void V8ContextSnapshot::InstallConditionalFeatures(
+bool V8ContextSnapshot::InstallConditionalFeatures(
     v8::Local<v8::Context> context,
     Document* document) {
   ScriptState* script_state = ScriptState::From(context);
   v8::Isolate* isolate = script_state->GetIsolate();
   const DOMWrapperWorld& world = script_state->World();
   if (!CanCreateContextFromSnapshot(isolate, world, document)) {
-    return;
+    return false;
   }
 
   TRACE_EVENT1("v8", "V8ContextSnapshot::InstallRuntimeEnabled", "IsMainFrame",
@@ -215,7 +215,7 @@
   }
 
   if (!world.IsMainWorld()) {
-    return;
+    return true;
   }
 
   // The below code handles window.document on the main world.
@@ -263,6 +263,8 @@
                                      type->domTemplate(isolate, world));
     InstallOriginTrialFeatures(type, script_state, prototype, interface);
   }
+
+  return true;
 }
 
 void V8ContextSnapshot::EnsureInterfaceTemplates(v8::Isolate* isolate) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ContextSnapshot.h b/third_party/WebKit/Source/bindings/core/v8/V8ContextSnapshot.h
index e9dd19d..d5cf6522 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ContextSnapshot.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ContextSnapshot.h
@@ -44,9 +44,10 @@
       v8::Local<v8::Object> global_proxy,
       Document*);
 
-  // Install conditionally enabled features on some v8::Object's in a context
-  // created from a snapshot.
-  static void InstallConditionalFeatures(v8::Local<v8::Context>, Document*);
+  // If the context was created from the snapshot, installs conditionally
+  // enabled features on some v8::Object's in the context and returns true.
+  // Otherwise, does nothing and returns false.
+  static bool InstallConditionalFeatures(v8::Local<v8::Context>, Document*);
 
   static void EnsureInterfaceTemplates(v8::Isolate*);
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverDelegate.cpp b/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverDelegate.cpp
index b2e4ab6..e68a8823 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverDelegate.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverDelegate.cpp
@@ -25,7 +25,7 @@
 void V8IntersectionObserverDelegate::Deliver(
     const HeapVector<Member<IntersectionObserverEntry>>& entries,
     IntersectionObserver& observer) {
-  callback_->call(&observer, entries, &observer);
+  callback_->InvokeAndReportException(&observer, entries, &observer);
 }
 
 ExecutionContext* V8IntersectionObserverDelegate::GetExecutionContext() const {
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 07279c9..b53f494 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_callback_function.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_callback_function.py
@@ -44,19 +44,19 @@
         'forward_declarations': sorted(forward_declarations(callback_function)),
         'header_includes': sorted(CALLBACK_FUNCTION_H_INCLUDES),
         'idl_type': idl_type_str,
+        'return_cpp_type': idl_type.cpp_type,
         'this_include_header_name': to_snake_case('V8%s' % callback_function.name),
     }
 
     if idl_type_str != 'void':
         context.update({
-            'return_cpp_type': idl_type.cpp_type + '&',
             'return_value_conversion': idl_type.v8_value_to_local_cpp_value(
                 callback_function.extended_attributes,
                 'call_result', 'native_result', isolate='GetIsolate()',
-                bailout_return_value='false'),
+                bailout_return_value='v8::Nothing<%s>()' % context['return_cpp_type']),
         })
 
-    context.update(arguments_context(callback_function.arguments, context.get('return_cpp_type')))
+    context.update(arguments_context(callback_function.arguments))
     return context
 
 
@@ -76,7 +76,7 @@
     return declarations
 
 
-def arguments_context(arguments, return_cpp_type):
+def arguments_context(arguments):
     def argument_context(argument):
         idl_type = argument.idl_type
         return {
@@ -95,8 +95,6 @@
     argument_declarations.extend(
         '%s %s' % (argument.idl_type.callback_cpp_type, argument.name)
         for argument in arguments)
-    if return_cpp_type:
-        argument_declarations.append('%s return_value' % return_cpp_type)
     return {
         'argument_declarations': argument_declarations,
         'arguments': [argument_context(argument) for argument in arguments],
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 2f1a164f..9d473d79 100644
--- a/third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+++ b/third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
@@ -11,7 +11,7 @@
 
 namespace blink {
 
-bool {{cpp_class}}::call({{argument_declarations | join(', ')}}) {
+v8::Maybe<{{return_cpp_type}}> {{cpp_class}}::Invoke({{argument_declarations | join(', ')}}) {
   // This function implements "invoke" steps in
   // "3.10. Invoking callback functions".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
@@ -21,7 +21,19 @@
      into a rejected promise. See also step 14.4. to 14.6. #}
 
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
-    return false;
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Context::Scope context_scope(
+        CallbackRelevantScriptState()->GetContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "{{callback_function_name}}",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<{{return_cpp_type}}>();
   }
 
   // step 4. If ! IsCallable(F) is false:
@@ -42,14 +54,17 @@
   {# TODO(yukishiino): Callback function type value must make the incumbent
      environment alive, i.e. the reference to v8::Context must be strong. #}
   if (IncumbentScriptState()->GetContext().IsEmpty()) {
-    return false;
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "{{callback_function_name}}",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<{{return_cpp_type}}>();
   }
   v8::Context::BackupIncumbentScope backup_incumbent_scope(
       IncumbentScriptState()->GetContext());
 
-  v8::TryCatch try_catch(GetIsolate());
-  try_catch.SetVerbose(true);
-
   v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
                                        CallbackRelevantScriptState());
 
@@ -65,7 +80,7 @@
                                    "invoke");
     if (!IsValidEnum({{argument.name}}, {{valid_enum_variables}}, WTF_ARRAY_LENGTH({{valid_enum_variables}}), "{{argument.enum_type}}", exception_state)) {
       NOTREACHED();
-      return false;
+      return v8::Nothing<{{return_cpp_type}}>();
     }
   }
 #endif
@@ -100,13 +115,13 @@
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
     //   callResult and jump to the step labeled return.
-    return false;
+    return v8::Nothing<{{return_cpp_type}}>();
   }
 
   // step 13. Set completion to the result of converting callResult.[[Value]] to
   //   an IDL value of the same type as the operation's return type.
   {% if idl_type == 'void' %}
-  return true;
+  return v8::JustVoid();
   {% else %}
   {
     ExceptionState exceptionState(GetIsolate(),
@@ -114,12 +129,27 @@
                                   "{{callback_function_name}}",
                                   "invoke");
     {{v8_value_to_local_cpp_value(return_value_conversion) | indent(4)}}
-    return_value = native_result;
-    return true;
+    return v8::Just<{{return_cpp_type}}>(native_result);
   }
   {% endif %}
 }
 
+{% if idl_type == 'void' %}
+void {{cpp_class}}::InvokeAndReportException({{argument_declarations | join(', ')}}) {
+  v8::TryCatch try_catch(GetIsolate());
+  try_catch.SetVerbose(true);
+
+  v8::Maybe<void> maybe_result =
+      Invoke({{
+                 (['callback_this_value'] +
+                  (arguments|map(attribute='name')|list)
+                 )|join(', ')
+             }});
+  // An exception if any is killed with the v8::TryCatch above.
+  ALLOW_UNUSED_LOCAL(maybe_result);
+}
+{% endif %}
+
 }  // namespace blink
 
 {% endfilter %}{# format_blink_cpp_source_code #}
diff --git a/third_party/WebKit/Source/bindings/templates/callback_function.h.tmpl b/third_party/WebKit/Source/bindings/templates/callback_function.h.tmpl
index 0c73f3d7..1f768fff 100644
--- a/third_party/WebKit/Source/bindings/templates/callback_function.h.tmpl
+++ b/third_party/WebKit/Source/bindings/templates/callback_function.h.tmpl
@@ -23,11 +23,15 @@
 
   ~{{cpp_class}}() override = default;
 
-  {# TODO(yukishiino): Change the return type to v8::Maybe<T> so that the
-     function returns a return value or throws an exception. #}
   // Performs "invoke".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
-  bool call({{argument_declarations | join(', ')}});
+  v8::Maybe<{{return_cpp_type}}> Invoke({{argument_declarations | join(', ')}}) WARN_UNUSED_RESULT;
+
+{% if idl_type == 'void' %}
+  // Performs "invoke", and then reports an exception, if any, to the global
+  // error handler such as DevTools' console.
+  void InvokeAndReportException({{argument_declarations | join(', ')}});
+{% endif %}
 
  private:
   explicit {{cpp_class}}(v8::Local<v8::Function> callback_function)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
index ea7a156f..51b52ca 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
@@ -21,13 +21,25 @@
 
 namespace blink {
 
-bool V8AnyCallbackFunctionOptionalAnyArg::call(ScriptWrappable* callback_this_value, ScriptValue optionalAnyArg, ScriptValue& return_value) {
+v8::Maybe<ScriptValue> V8AnyCallbackFunctionOptionalAnyArg::Invoke(ScriptWrappable* callback_this_value, ScriptValue optionalAnyArg) {
   // This function implements "invoke" steps in
   // "3.10. Invoking callback functions".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
 
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
-    return false;
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Context::Scope context_scope(
+        CallbackRelevantScriptState()->GetContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "AnyCallbackFunctionOptionalAnyArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<ScriptValue>();
   }
 
   // step 4. If ! IsCallable(F) is false:
@@ -46,14 +58,17 @@
       CallbackRelevantScriptState());
   // step 9. Prepare to run a callback with stored settings.
   if (IncumbentScriptState()->GetContext().IsEmpty()) {
-    return false;
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "AnyCallbackFunctionOptionalAnyArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<ScriptValue>();
   }
   v8::Context::BackupIncumbentScope backup_incumbent_scope(
       IncumbentScriptState()->GetContext());
 
-  v8::TryCatch try_catch(GetIsolate());
-  try_catch.SetVerbose(true);
-
   v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
                                        CallbackRelevantScriptState());
 
@@ -78,7 +93,7 @@
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
     //   callResult and jump to the step labeled return.
-    return false;
+    return v8::Nothing<ScriptValue>();
   }
 
   // step 13. Set completion to the result of converting callResult.[[Value]] to
@@ -89,8 +104,7 @@
                                   "AnyCallbackFunctionOptionalAnyArg",
                                   "invoke");
     ScriptValue native_result = ScriptValue(ScriptState::Current(GetIsolate()), call_result);
-    return_value = native_result;
-    return true;
+    return v8::Just<ScriptValue>(native_result);
   }
 }
 
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.h b/third_party/WebKit/Source/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.h
index b5f40af..98434e4 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.h
@@ -29,7 +29,7 @@
 
   // Performs "invoke".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
-  bool call(ScriptWrappable* callback_this_value, ScriptValue optionalAnyArg, ScriptValue& return_value);
+  v8::Maybe<ScriptValue> Invoke(ScriptWrappable* callback_this_value, ScriptValue optionalAnyArg) WARN_UNUSED_RESULT;
 
  private:
   explicit V8AnyCallbackFunctionOptionalAnyArg(v8::Local<v8::Function> callback_function)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_long_callback_function.cc b/third_party/WebKit/Source/bindings/tests/results/core/v8_long_callback_function.cc
index 933eec8..c015a451 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_long_callback_function.cc
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_long_callback_function.cc
@@ -21,13 +21,25 @@
 
 namespace blink {
 
-bool V8LongCallbackFunction::call(ScriptWrappable* callback_this_value, int32_t num1, int32_t num2, int32_t& return_value) {
+v8::Maybe<int32_t> V8LongCallbackFunction::Invoke(ScriptWrappable* callback_this_value, int32_t num1, int32_t num2) {
   // This function implements "invoke" steps in
   // "3.10. Invoking callback functions".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
 
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
-    return false;
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Context::Scope context_scope(
+        CallbackRelevantScriptState()->GetContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "LongCallbackFunction",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<int32_t>();
   }
 
   // step 4. If ! IsCallable(F) is false:
@@ -46,14 +58,17 @@
       CallbackRelevantScriptState());
   // step 9. Prepare to run a callback with stored settings.
   if (IncumbentScriptState()->GetContext().IsEmpty()) {
-    return false;
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "LongCallbackFunction",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<int32_t>();
   }
   v8::Context::BackupIncumbentScope backup_incumbent_scope(
       IncumbentScriptState()->GetContext());
 
-  v8::TryCatch try_catch(GetIsolate());
-  try_catch.SetVerbose(true);
-
   v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
                                        CallbackRelevantScriptState());
 
@@ -79,7 +94,7 @@
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
     //   callResult and jump to the step labeled return.
-    return false;
+    return v8::Nothing<int32_t>();
   }
 
   // step 13. Set completion to the result of converting callResult.[[Value]] to
@@ -91,9 +106,8 @@
                                   "invoke");
     int32_t native_result = NativeValueTraits<IDLLong>::NativeValue(GetIsolate(), call_result, exceptionState, kNormalConversion);
     if (exceptionState.HadException())
-      return false;
-    return_value = native_result;
-    return true;
+      return v8::Nothing<int32_t>();
+    return v8::Just<int32_t>(native_result);
   }
 }
 
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_long_callback_function.h b/third_party/WebKit/Source/bindings/tests/results/core/v8_long_callback_function.h
index 3a0e5767..eec69f3 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_long_callback_function.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_long_callback_function.h
@@ -29,7 +29,7 @@
 
   // Performs "invoke".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
-  bool call(ScriptWrappable* callback_this_value, int32_t num1, int32_t num2, int32_t& return_value);
+  v8::Maybe<int32_t> Invoke(ScriptWrappable* callback_this_value, int32_t num1, int32_t num2) WARN_UNUSED_RESULT;
 
  private:
   explicit V8LongCallbackFunction(v8::Local<v8::Function> callback_function)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
index 40b5438..b78f0b6 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
@@ -21,13 +21,25 @@
 
 namespace blink {
 
-bool V8StringSequenceCallbackFunctionLongSequenceArg::call(ScriptWrappable* callback_this_value, const Vector<int32_t>& arg, Vector<String>& return_value) {
+v8::Maybe<Vector<String>> V8StringSequenceCallbackFunctionLongSequenceArg::Invoke(ScriptWrappable* callback_this_value, const Vector<int32_t>& arg) {
   // This function implements "invoke" steps in
   // "3.10. Invoking callback functions".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
 
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
-    return false;
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Context::Scope context_scope(
+        CallbackRelevantScriptState()->GetContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "StringSequenceCallbackFunctionLongSequenceArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<Vector<String>>();
   }
 
   // step 4. If ! IsCallable(F) is false:
@@ -46,14 +58,17 @@
       CallbackRelevantScriptState());
   // step 9. Prepare to run a callback with stored settings.
   if (IncumbentScriptState()->GetContext().IsEmpty()) {
-    return false;
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "StringSequenceCallbackFunctionLongSequenceArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<Vector<String>>();
   }
   v8::Context::BackupIncumbentScope backup_incumbent_scope(
       IncumbentScriptState()->GetContext());
 
-  v8::TryCatch try_catch(GetIsolate());
-  try_catch.SetVerbose(true);
-
   v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
                                        CallbackRelevantScriptState());
 
@@ -78,7 +93,7 @@
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
     //   callResult and jump to the step labeled return.
-    return false;
+    return v8::Nothing<Vector<String>>();
   }
 
   // step 13. Set completion to the result of converting callResult.[[Value]] to
@@ -90,9 +105,8 @@
                                   "invoke");
     Vector<String> native_result = NativeValueTraits<IDLSequence<IDLString>>::NativeValue(GetIsolate(), call_result, exceptionState);
     if (exceptionState.HadException())
-      return false;
-    return_value = native_result;
-    return true;
+      return v8::Nothing<Vector<String>>();
+    return v8::Just<Vector<String>>(native_result);
   }
 }
 
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.h b/third_party/WebKit/Source/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.h
index da13e44..34dc31d0 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.h
@@ -29,7 +29,7 @@
 
   // Performs "invoke".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
-  bool call(ScriptWrappable* callback_this_value, const Vector<int32_t>& arg, Vector<String>& return_value);
+  v8::Maybe<Vector<String>> Invoke(ScriptWrappable* callback_this_value, const Vector<int32_t>& arg) WARN_UNUSED_RESULT;
 
  private:
   explicit V8StringSequenceCallbackFunctionLongSequenceArg(v8::Local<v8::Function> callback_function)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function.cc b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function.cc
index 086d222..6ebddaf 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function.cc
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function.cc
@@ -20,13 +20,25 @@
 
 namespace blink {
 
-bool V8VoidCallbackFunction::call(ScriptWrappable* callback_this_value) {
+v8::Maybe<void> V8VoidCallbackFunction::Invoke(ScriptWrappable* callback_this_value) {
   // This function implements "invoke" steps in
   // "3.10. Invoking callback functions".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
 
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
-    return false;
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Context::Scope context_scope(
+        CallbackRelevantScriptState()->GetContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunction",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
 
   // step 4. If ! IsCallable(F) is false:
@@ -45,14 +57,17 @@
       CallbackRelevantScriptState());
   // step 9. Prepare to run a callback with stored settings.
   if (IncumbentScriptState()->GetContext().IsEmpty()) {
-    return false;
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunction",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
   v8::Context::BackupIncumbentScope backup_incumbent_scope(
       IncumbentScriptState()->GetContext());
 
-  v8::TryCatch try_catch(GetIsolate());
-  try_catch.SetVerbose(true);
-
   v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
                                        CallbackRelevantScriptState());
 
@@ -76,12 +91,22 @@
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
     //   callResult and jump to the step labeled return.
-    return false;
+    return v8::Nothing<void>();
   }
 
   // step 13. Set completion to the result of converting callResult.[[Value]] to
   //   an IDL value of the same type as the operation's return type.
-  return true;
+  return v8::JustVoid();
+}
+
+void V8VoidCallbackFunction::InvokeAndReportException(ScriptWrappable* callback_this_value) {
+  v8::TryCatch try_catch(GetIsolate());
+  try_catch.SetVerbose(true);
+
+  v8::Maybe<void> maybe_result =
+      Invoke(callback_this_value);
+  // An exception if any is killed with the v8::TryCatch above.
+  ALLOW_UNUSED_LOCAL(maybe_result);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function.h b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function.h
index 8bbcba6..16ba1130 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function.h
@@ -29,7 +29,11 @@
 
   // Performs "invoke".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
-  bool call(ScriptWrappable* callback_this_value);
+  v8::Maybe<void> Invoke(ScriptWrappable* callback_this_value) WARN_UNUSED_RESULT;
+
+  // Performs "invoke", and then reports an exception, if any, to the global
+  // error handler such as DevTools' console.
+  void InvokeAndReportException(ScriptWrappable* callback_this_value);
 
  private:
   explicit V8VoidCallbackFunction(v8::Local<v8::Function> callback_function)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
index 449f32e6..3a3f0aa 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
@@ -21,13 +21,25 @@
 
 namespace blink {
 
-bool V8VoidCallbackFunctionDictionaryArg::call(ScriptWrappable* callback_this_value, const TestDictionary& arg) {
+v8::Maybe<void> V8VoidCallbackFunctionDictionaryArg::Invoke(ScriptWrappable* callback_this_value, const TestDictionary& arg) {
   // This function implements "invoke" steps in
   // "3.10. Invoking callback functions".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
 
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
-    return false;
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Context::Scope context_scope(
+        CallbackRelevantScriptState()->GetContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionDictionaryArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
 
   // step 4. If ! IsCallable(F) is false:
@@ -46,14 +58,17 @@
       CallbackRelevantScriptState());
   // step 9. Prepare to run a callback with stored settings.
   if (IncumbentScriptState()->GetContext().IsEmpty()) {
-    return false;
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionDictionaryArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
   v8::Context::BackupIncumbentScope backup_incumbent_scope(
       IncumbentScriptState()->GetContext());
 
-  v8::TryCatch try_catch(GetIsolate());
-  try_catch.SetVerbose(true);
-
   v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
                                        CallbackRelevantScriptState());
 
@@ -78,12 +93,22 @@
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
     //   callResult and jump to the step labeled return.
-    return false;
+    return v8::Nothing<void>();
   }
 
   // step 13. Set completion to the result of converting callResult.[[Value]] to
   //   an IDL value of the same type as the operation's return type.
-  return true;
+  return v8::JustVoid();
+}
+
+void V8VoidCallbackFunctionDictionaryArg::InvokeAndReportException(ScriptWrappable* callback_this_value, const TestDictionary& arg) {
+  v8::TryCatch try_catch(GetIsolate());
+  try_catch.SetVerbose(true);
+
+  v8::Maybe<void> maybe_result =
+      Invoke(callback_this_value, arg);
+  // An exception if any is killed with the v8::TryCatch above.
+  ALLOW_UNUSED_LOCAL(maybe_result);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.h b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.h
index 50404a3..c1189020 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.h
@@ -30,7 +30,11 @@
 
   // Performs "invoke".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
-  bool call(ScriptWrappable* callback_this_value, const TestDictionary& arg);
+  v8::Maybe<void> Invoke(ScriptWrappable* callback_this_value, const TestDictionary& arg) WARN_UNUSED_RESULT;
+
+  // Performs "invoke", and then reports an exception, if any, to the global
+  // error handler such as DevTools' console.
+  void InvokeAndReportException(ScriptWrappable* callback_this_value, const TestDictionary& arg);
 
  private:
   explicit V8VoidCallbackFunctionDictionaryArg(v8::Local<v8::Function> callback_function)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
index e57ff41..597a0945 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
@@ -21,13 +21,25 @@
 
 namespace blink {
 
-bool V8VoidCallbackFunctionEnumArg::call(ScriptWrappable* callback_this_value, const String& arg) {
+v8::Maybe<void> V8VoidCallbackFunctionEnumArg::Invoke(ScriptWrappable* callback_this_value, const String& arg) {
   // This function implements "invoke" steps in
   // "3.10. Invoking callback functions".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
 
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
-    return false;
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Context::Scope context_scope(
+        CallbackRelevantScriptState()->GetContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionEnumArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
 
   // step 4. If ! IsCallable(F) is false:
@@ -46,14 +58,17 @@
       CallbackRelevantScriptState());
   // step 9. Prepare to run a callback with stored settings.
   if (IncumbentScriptState()->GetContext().IsEmpty()) {
-    return false;
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionEnumArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
   v8::Context::BackupIncumbentScope backup_incumbent_scope(
       IncumbentScriptState()->GetContext());
 
-  v8::TryCatch try_catch(GetIsolate());
-  try_catch.SetVerbose(true);
-
   v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
                                        CallbackRelevantScriptState());
 
@@ -72,7 +87,7 @@
                                    "invoke");
     if (!IsValidEnum(arg, valid_arg_values, WTF_ARRAY_LENGTH(valid_arg_values), "TestEnum", exception_state)) {
       NOTREACHED();
-      return false;
+      return v8::Nothing<void>();
     }
   }
 #endif
@@ -98,12 +113,22 @@
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
     //   callResult and jump to the step labeled return.
-    return false;
+    return v8::Nothing<void>();
   }
 
   // step 13. Set completion to the result of converting callResult.[[Value]] to
   //   an IDL value of the same type as the operation's return type.
-  return true;
+  return v8::JustVoid();
+}
+
+void V8VoidCallbackFunctionEnumArg::InvokeAndReportException(ScriptWrappable* callback_this_value, const String& arg) {
+  v8::TryCatch try_catch(GetIsolate());
+  try_catch.SetVerbose(true);
+
+  v8::Maybe<void> maybe_result =
+      Invoke(callback_this_value, arg);
+  // An exception if any is killed with the v8::TryCatch above.
+  ALLOW_UNUSED_LOCAL(maybe_result);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_enum_arg.h b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_enum_arg.h
index 1719c4a..41e4804 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_enum_arg.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_enum_arg.h
@@ -29,7 +29,11 @@
 
   // Performs "invoke".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
-  bool call(ScriptWrappable* callback_this_value, const String& arg);
+  v8::Maybe<void> Invoke(ScriptWrappable* callback_this_value, const String& arg) WARN_UNUSED_RESULT;
+
+  // Performs "invoke", and then reports an exception, if any, to the global
+  // error handler such as DevTools' console.
+  void InvokeAndReportException(ScriptWrappable* callback_this_value, const String& arg);
 
  private:
   explicit V8VoidCallbackFunctionEnumArg(v8::Local<v8::Function> callback_function)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
index 1a59f4e..00fb919 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
@@ -21,13 +21,25 @@
 
 namespace blink {
 
-bool V8VoidCallbackFunctionInterfaceArg::call(ScriptWrappable* callback_this_value, HTMLDivElement* divElement) {
+v8::Maybe<void> V8VoidCallbackFunctionInterfaceArg::Invoke(ScriptWrappable* callback_this_value, HTMLDivElement* divElement) {
   // This function implements "invoke" steps in
   // "3.10. Invoking callback functions".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
 
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
-    return false;
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Context::Scope context_scope(
+        CallbackRelevantScriptState()->GetContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionInterfaceArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
 
   // step 4. If ! IsCallable(F) is false:
@@ -46,14 +58,17 @@
       CallbackRelevantScriptState());
   // step 9. Prepare to run a callback with stored settings.
   if (IncumbentScriptState()->GetContext().IsEmpty()) {
-    return false;
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionInterfaceArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
   v8::Context::BackupIncumbentScope backup_incumbent_scope(
       IncumbentScriptState()->GetContext());
 
-  v8::TryCatch try_catch(GetIsolate());
-  try_catch.SetVerbose(true);
-
   v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
                                        CallbackRelevantScriptState());
 
@@ -78,12 +93,22 @@
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
     //   callResult and jump to the step labeled return.
-    return false;
+    return v8::Nothing<void>();
   }
 
   // step 13. Set completion to the result of converting callResult.[[Value]] to
   //   an IDL value of the same type as the operation's return type.
-  return true;
+  return v8::JustVoid();
+}
+
+void V8VoidCallbackFunctionInterfaceArg::InvokeAndReportException(ScriptWrappable* callback_this_value, HTMLDivElement* divElement) {
+  v8::TryCatch try_catch(GetIsolate());
+  try_catch.SetVerbose(true);
+
+  v8::Maybe<void> maybe_result =
+      Invoke(callback_this_value, divElement);
+  // An exception if any is killed with the v8::TryCatch above.
+  ALLOW_UNUSED_LOCAL(maybe_result);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_interface_arg.h b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_interface_arg.h
index a14e7c8..17431d4f 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_interface_arg.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_interface_arg.h
@@ -30,7 +30,11 @@
 
   // Performs "invoke".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
-  bool call(ScriptWrappable* callback_this_value, HTMLDivElement* divElement);
+  v8::Maybe<void> Invoke(ScriptWrappable* callback_this_value, HTMLDivElement* divElement) WARN_UNUSED_RESULT;
+
+  // Performs "invoke", and then reports an exception, if any, to the global
+  // error handler such as DevTools' console.
+  void InvokeAndReportException(ScriptWrappable* callback_this_value, HTMLDivElement* divElement);
 
  private:
   explicit V8VoidCallbackFunctionInterfaceArg(v8::Local<v8::Function> callback_function)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
index 6d106b2..aa35177 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
@@ -22,13 +22,25 @@
 
 namespace blink {
 
-bool V8VoidCallbackFunctionTestInterfaceSequenceArg::call(ScriptWrappable* callback_this_value, const HeapVector<Member<TestInterfaceImplementation>>& arg) {
+v8::Maybe<void> V8VoidCallbackFunctionTestInterfaceSequenceArg::Invoke(ScriptWrappable* callback_this_value, const HeapVector<Member<TestInterfaceImplementation>>& arg) {
   // This function implements "invoke" steps in
   // "3.10. Invoking callback functions".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
 
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
-    return false;
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Context::Scope context_scope(
+        CallbackRelevantScriptState()->GetContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionTestInterfaceSequenceArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
 
   // step 4. If ! IsCallable(F) is false:
@@ -47,14 +59,17 @@
       CallbackRelevantScriptState());
   // step 9. Prepare to run a callback with stored settings.
   if (IncumbentScriptState()->GetContext().IsEmpty()) {
-    return false;
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionTestInterfaceSequenceArg",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
   v8::Context::BackupIncumbentScope backup_incumbent_scope(
       IncumbentScriptState()->GetContext());
 
-  v8::TryCatch try_catch(GetIsolate());
-  try_catch.SetVerbose(true);
-
   v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
                                        CallbackRelevantScriptState());
 
@@ -79,12 +94,22 @@
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
     //   callResult and jump to the step labeled return.
-    return false;
+    return v8::Nothing<void>();
   }
 
   // step 13. Set completion to the result of converting callResult.[[Value]] to
   //   an IDL value of the same type as the operation's return type.
-  return true;
+  return v8::JustVoid();
+}
+
+void V8VoidCallbackFunctionTestInterfaceSequenceArg::InvokeAndReportException(ScriptWrappable* callback_this_value, const HeapVector<Member<TestInterfaceImplementation>>& arg) {
+  v8::TryCatch try_catch(GetIsolate());
+  try_catch.SetVerbose(true);
+
+  v8::Maybe<void> maybe_result =
+      Invoke(callback_this_value, arg);
+  // An exception if any is killed with the v8::TryCatch above.
+  ALLOW_UNUSED_LOCAL(maybe_result);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.h b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.h
index af2f7c4..57572e2 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.h
@@ -30,7 +30,11 @@
 
   // Performs "invoke".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
-  bool call(ScriptWrappable* callback_this_value, const HeapVector<Member<TestInterfaceImplementation>>& arg);
+  v8::Maybe<void> Invoke(ScriptWrappable* callback_this_value, const HeapVector<Member<TestInterfaceImplementation>>& arg) WARN_UNUSED_RESULT;
+
+  // Performs "invoke", and then reports an exception, if any, to the global
+  // error handler such as DevTools' console.
+  void InvokeAndReportException(ScriptWrappable* callback_this_value, const HeapVector<Member<TestInterfaceImplementation>>& arg);
 
  private:
   explicit V8VoidCallbackFunctionTestInterfaceSequenceArg(v8::Local<v8::Function> callback_function)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_typedef.cc b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_typedef.cc
index ea721cc..5645903 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_typedef.cc
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_typedef.cc
@@ -21,13 +21,25 @@
 
 namespace blink {
 
-bool V8VoidCallbackFunctionTypedef::call(ScriptWrappable* callback_this_value, const String& arg) {
+v8::Maybe<void> V8VoidCallbackFunctionTypedef::Invoke(ScriptWrappable* callback_this_value, const String& arg) {
   // This function implements "invoke" steps in
   // "3.10. Invoking callback functions".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
 
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
-    return false;
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Context::Scope context_scope(
+        CallbackRelevantScriptState()->GetContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionTypedef",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
 
   // step 4. If ! IsCallable(F) is false:
@@ -46,14 +58,17 @@
       CallbackRelevantScriptState());
   // step 9. Prepare to run a callback with stored settings.
   if (IncumbentScriptState()->GetContext().IsEmpty()) {
-    return false;
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionTypedef",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
   v8::Context::BackupIncumbentScope backup_incumbent_scope(
       IncumbentScriptState()->GetContext());
 
-  v8::TryCatch try_catch(GetIsolate());
-  try_catch.SetVerbose(true);
-
   v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
                                        CallbackRelevantScriptState());
 
@@ -78,12 +93,22 @@
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
     //   callResult and jump to the step labeled return.
-    return false;
+    return v8::Nothing<void>();
   }
 
   // step 13. Set completion to the result of converting callResult.[[Value]] to
   //   an IDL value of the same type as the operation's return type.
-  return true;
+  return v8::JustVoid();
+}
+
+void V8VoidCallbackFunctionTypedef::InvokeAndReportException(ScriptWrappable* callback_this_value, const String& arg) {
+  v8::TryCatch try_catch(GetIsolate());
+  try_catch.SetVerbose(true);
+
+  v8::Maybe<void> maybe_result =
+      Invoke(callback_this_value, arg);
+  // An exception if any is killed with the v8::TryCatch above.
+  ALLOW_UNUSED_LOCAL(maybe_result);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_typedef.h b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_typedef.h
index 63b7ef5..e8dde92 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_typedef.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/v8_void_callback_function_typedef.h
@@ -29,7 +29,11 @@
 
   // Performs "invoke".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
-  bool call(ScriptWrappable* callback_this_value, const String& arg);
+  v8::Maybe<void> Invoke(ScriptWrappable* callback_this_value, const String& arg) WARN_UNUSED_RESULT;
+
+  // Performs "invoke", and then reports an exception, if any, to the global
+  // error handler such as DevTools' console.
+  void InvokeAndReportException(ScriptWrappable* callback_this_value, const String& arg);
 
  private:
   explicit V8VoidCallbackFunctionTypedef(v8::Local<v8::Function> callback_function)
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/v8_void_callback_function_modules.cc b/third_party/WebKit/Source/bindings/tests/results/modules/v8_void_callback_function_modules.cc
index acafba1..49eb7cf7 100644
--- a/third_party/WebKit/Source/bindings/tests/results/modules/v8_void_callback_function_modules.cc
+++ b/third_party/WebKit/Source/bindings/tests/results/modules/v8_void_callback_function_modules.cc
@@ -20,13 +20,25 @@
 
 namespace blink {
 
-bool V8VoidCallbackFunctionModules::call(ScriptWrappable* callback_this_value) {
+v8::Maybe<void> V8VoidCallbackFunctionModules::Invoke(ScriptWrappable* callback_this_value) {
   // This function implements "invoke" steps in
   // "3.10. Invoking callback functions".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
 
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
-    return false;
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Context::Scope context_scope(
+        CallbackRelevantScriptState()->GetContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionModules",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
 
   // step 4. If ! IsCallable(F) is false:
@@ -45,14 +57,17 @@
       CallbackRelevantScriptState());
   // step 9. Prepare to run a callback with stored settings.
   if (IncumbentScriptState()->GetContext().IsEmpty()) {
-    return false;
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "VoidCallbackFunctionModules",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
   }
   v8::Context::BackupIncumbentScope backup_incumbent_scope(
       IncumbentScriptState()->GetContext());
 
-  v8::TryCatch try_catch(GetIsolate());
-  try_catch.SetVerbose(true);
-
   v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
                                        CallbackRelevantScriptState());
 
@@ -76,12 +91,22 @@
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
     //   callResult and jump to the step labeled return.
-    return false;
+    return v8::Nothing<void>();
   }
 
   // step 13. Set completion to the result of converting callResult.[[Value]] to
   //   an IDL value of the same type as the operation's return type.
-  return true;
+  return v8::JustVoid();
+}
+
+void V8VoidCallbackFunctionModules::InvokeAndReportException(ScriptWrappable* callback_this_value) {
+  v8::TryCatch try_catch(GetIsolate());
+  try_catch.SetVerbose(true);
+
+  v8::Maybe<void> maybe_result =
+      Invoke(callback_this_value);
+  // An exception if any is killed with the v8::TryCatch above.
+  ALLOW_UNUSED_LOCAL(maybe_result);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/v8_void_callback_function_modules.h b/third_party/WebKit/Source/bindings/tests/results/modules/v8_void_callback_function_modules.h
index bff59cdb..156abbf 100644
--- a/third_party/WebKit/Source/bindings/tests/results/modules/v8_void_callback_function_modules.h
+++ b/third_party/WebKit/Source/bindings/tests/results/modules/v8_void_callback_function_modules.h
@@ -29,7 +29,11 @@
 
   // Performs "invoke".
   // https://heycam.github.io/webidl/#es-invoking-callback-functions
-  bool call(ScriptWrappable* callback_this_value);
+  v8::Maybe<void> Invoke(ScriptWrappable* callback_this_value) WARN_UNUSED_RESULT;
+
+  // Performs "invoke", and then reports an exception, if any, to the global
+  // error handler such as DevTools' console.
+  void InvokeAndReportException(ScriptWrappable* callback_this_value);
 
  private:
   explicit V8VoidCallbackFunctionModules(v8::Local<v8::Function> callback_function)
diff --git a/third_party/WebKit/Source/core/clipboard/DataTransferItem.cpp b/third_party/WebKit/Source/core/clipboard/DataTransferItem.cpp
index bc00a63..da1d122 100644
--- a/third_party/WebKit/Source/core/clipboard/DataTransferItem.cpp
+++ b/third_party/WebKit/Source/core/clipboard/DataTransferItem.cpp
@@ -103,7 +103,7 @@
   DCHECK(callback);
   probe::AsyncTask async_task(context, callback);
   if (context)
-    callback->call(nullptr, data);
+    callback->InvokeAndReportException(nullptr, data);
   size_t index = callbacks_.Find(callback);
   DCHECK(index != kNotFound);
   callbacks_.EraseAt(index);
diff --git a/third_party/WebKit/Source/core/css/cssom/ComputedStylePropertyMap.cpp b/third_party/WebKit/Source/core/css/cssom/ComputedStylePropertyMap.cpp
index 1ab36bf..c6da074a 100644
--- a/third_party/WebKit/Source/core/css/cssom/ComputedStylePropertyMap.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/ComputedStylePropertyMap.cpp
@@ -6,6 +6,7 @@
 
 #include "core/css/ComputedStyleCSSValueMapping.h"
 #include "core/css/cssom/StyleValueFactory.h"
+#include "core/dom/Document.h"
 #include "core/dom/PseudoElement.h"
 
 namespace blink {
@@ -45,28 +46,22 @@
   return style;
 }
 
-CSSStyleValueVector ComputedStylePropertyMap::GetAllInternal(
+const CSSValue* ComputedStylePropertyMap::GetProperty(
     CSSPropertyID property_id) {
   const ComputedStyle* style = UpdateStyle();
   if (!style)
-    return CSSStyleValueVector();
-  const CSSValue* css_value = ComputedStyleCSSValueMapping::Get(
-      property_id, *style, nullptr /* layout_object */);
-  if (!css_value)
-    return CSSStyleValueVector();
-  return StyleValueFactory::CssValueToStyleValueVector(property_id, *css_value);
+    return nullptr;
+  return ComputedStyleCSSValueMapping::Get(property_id, *style,
+                                           nullptr /* layout_object */);
 }
 
-CSSStyleValueVector ComputedStylePropertyMap::GetAllInternal(
-    AtomicString custom_property_name) {
+const CSSValue* ComputedStylePropertyMap::GetCustomProperty(
+    AtomicString property_name) {
   const ComputedStyle* style = UpdateStyle();
   if (!style)
-    return CSSStyleValueVector();
-  const CSSValue* css_value = ComputedStyleCSSValueMapping::Get(
-      custom_property_name, *style, node_->GetDocument().GetPropertyRegistry());
-  if (!css_value)
-    return CSSStyleValueVector();
-  return StyleValueFactory::CssValueToStyleValueVector(*css_value);
+    return nullptr;
+  return ComputedStyleCSSValueMapping::Get(
+      property_name, *style, node_->GetDocument().GetPropertyRegistry());
 }
 
 Vector<String> ComputedStylePropertyMap::getProperties() {
diff --git a/third_party/WebKit/Source/core/css/cssom/ComputedStylePropertyMap.h b/third_party/WebKit/Source/core/css/cssom/ComputedStylePropertyMap.h
index 0b65389..f91cd5f 100644
--- a/third_party/WebKit/Source/core/css/cssom/ComputedStylePropertyMap.h
+++ b/third_party/WebKit/Source/core/css/cssom/ComputedStylePropertyMap.h
@@ -7,9 +7,9 @@
 
 #include "base/macros.h"
 #include "core/css/CSSComputedStyleDeclaration.h"
+#include "core/css/CSSSelector.h"
 #include "core/css/cssom/StylePropertyMapReadonly.h"
 #include "core/dom/Node.h"
-#include "core/layout/LayoutObject.h"
 
 namespace blink {
 
@@ -40,9 +40,8 @@
         pseudo_id_(CSSSelector::ParsePseudoId(pseudo_element)),
         node_(node) {}
 
-  CSSStyleValueVector GetAllInternal(CSSPropertyID) override;
-  CSSStyleValueVector GetAllInternal(
-      AtomicString custom_property_name) override;
+  const CSSValue* GetProperty(CSSPropertyID) override;
+  const CSSValue* GetCustomProperty(AtomicString) override;
 
   HeapVector<StylePropertyMapEntry> GetIterationEntries() override {
     return HeapVector<StylePropertyMapEntry>();
diff --git a/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.cpp b/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.cpp
index b286359..3a55305 100644
--- a/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.cpp
@@ -21,74 +21,20 @@
   }
 }
 
-CSSStyleValue* FilteredComputedStylePropertyMap::get(
-    const String& property_name,
-    ExceptionState& exception_state) {
-  CSSPropertyID property_id = cssPropertyID(property_name);
-  if (property_id == CSSPropertyInvalid) {
-    exception_state.ThrowTypeError("Invalid propertyName: " + property_name);
+const CSSValue* FilteredComputedStylePropertyMap::GetProperty(
+    CSSPropertyID property_id) {
+  if (!native_properties_.Contains(property_id))
     return nullptr;
-  }
 
-  if (property_id >= firstCSSProperty &&
-      native_properties_.Contains(property_id)) {
-    CSSStyleValueVector style_vector = GetAllInternal(property_id);
-    if (style_vector.IsEmpty())
-      return nullptr;
-
-    return style_vector[0];
-  }
-
-  if (property_id == CSSPropertyVariable &&
-      custom_properties_.Contains(AtomicString(property_name))) {
-    CSSStyleValueVector style_vector =
-        GetAllInternal(AtomicString(property_name));
-    if (style_vector.IsEmpty())
-      return nullptr;
-
-    return style_vector[0];
-  }
-
-  return nullptr;
+  return ComputedStylePropertyMap::GetProperty(property_id);
 }
 
-CSSStyleValueVector FilteredComputedStylePropertyMap::getAll(
-    const String& property_name,
-    ExceptionState& exception_state) {
-  CSSPropertyID property_id = cssPropertyID(property_name);
-  if (property_id == CSSPropertyInvalid) {
-    exception_state.ThrowTypeError("Invalid propertyName: " + property_name);
-    return CSSStyleValueVector();
-  }
+const CSSValue* FilteredComputedStylePropertyMap::GetCustomProperty(
+    AtomicString property_name) {
+  if (!custom_properties_.Contains(AtomicString(property_name)))
+    return nullptr;
 
-  if (property_id >= firstCSSProperty &&
-      native_properties_.Contains(property_id))
-    return GetAllInternal(property_id);
-
-  if (property_id == CSSPropertyVariable &&
-      custom_properties_.Contains(AtomicString(property_name)))
-    return GetAllInternal(AtomicString(property_name));
-
-  return CSSStyleValueVector();
-}
-
-bool FilteredComputedStylePropertyMap::has(const String& property_name,
-                                           ExceptionState& exception_state) {
-  CSSPropertyID property_id = cssPropertyID(property_name);
-  if (property_id == CSSPropertyInvalid) {
-    exception_state.ThrowTypeError("Invalid propertyName: " + property_name);
-    return false;
-  }
-
-  if (property_id >= firstCSSProperty &&
-      native_properties_.Contains(property_id))
-    return !GetAllInternal(property_id).IsEmpty();
-
-  if (property_id == CSSPropertyVariable &&
-      custom_properties_.Contains(AtomicString(property_name)))
-    return !GetAllInternal(AtomicString(property_name)).IsEmpty();
-
-  return false;
+  return ComputedStylePropertyMap::GetCustomProperty(property_name);
 }
 
 Vector<String> FilteredComputedStylePropertyMap::getProperties() {
diff --git a/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.h b/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.h
index 4ba6896b..78ad45d 100644
--- a/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.h
+++ b/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.h
@@ -24,11 +24,6 @@
         computed_style_declaration, native_properties, custom_properties, node);
   }
 
-  CSSStyleValue* get(const String& property_name, ExceptionState&) override;
-  CSSStyleValueVector getAll(const String& property_name,
-                             ExceptionState&) override;
-  bool has(const String& property_name, ExceptionState&) override;
-
   Vector<String> getProperties() override;
 
  private:
@@ -38,6 +33,9 @@
       const Vector<AtomicString>& custom_properties,
       Node*);
 
+  const CSSValue* GetProperty(CSSPropertyID) override;
+  const CSSValue* GetCustomProperty(AtomicString) override;
+
   HashSet<CSSPropertyID> native_properties_;
   HashSet<AtomicString> custom_properties_;
   DISALLOW_COPY_AND_ASSIGN(FilteredComputedStylePropertyMap);
diff --git a/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp b/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp
index 8646f10..f272ec3 100644
--- a/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp
@@ -67,27 +67,15 @@
 
 }  // namespace
 
-CSSStyleValueVector InlineStylePropertyMap::GetAllInternal(
-    CSSPropertyID property_id) {
-  const CSSValue* css_value =
-      owner_element_->EnsureMutableInlineStyle().GetPropertyCSSValue(
-          property_id);
-  if (!css_value)
-    return CSSStyleValueVector();
-
-  return StyleValueFactory::CssValueToStyleValueVector(property_id, *css_value);
+const CSSValue* InlineStylePropertyMap::GetProperty(CSSPropertyID property_id) {
+  return owner_element_->EnsureMutableInlineStyle().GetPropertyCSSValue(
+      property_id);
 }
 
-CSSStyleValueVector InlineStylePropertyMap::GetAllInternal(
-    AtomicString custom_property_name) {
-  const CSSValue* css_value =
-      owner_element_->EnsureMutableInlineStyle().GetPropertyCSSValue(
-          custom_property_name);
-  if (!css_value)
-    return CSSStyleValueVector();
-
-  return StyleValueFactory::CssValueToStyleValueVector(CSSPropertyInvalid,
-                                                       *css_value);
+const CSSValue* InlineStylePropertyMap::GetCustomProperty(
+    AtomicString property_name) {
+  return owner_element_->EnsureMutableInlineStyle().GetPropertyCSSValue(
+      property_name);
 }
 
 Vector<String> InlineStylePropertyMap::getProperties() {
diff --git a/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.h b/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.h
index daf957c..04c0437 100644
--- a/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.h
+++ b/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.h
@@ -34,9 +34,8 @@
   }
 
  protected:
-  CSSStyleValueVector GetAllInternal(CSSPropertyID) override;
-  CSSStyleValueVector GetAllInternal(
-      AtomicString custom_property_name) override;
+  const CSSValue* GetProperty(CSSPropertyID) override;
+  const CSSValue* GetCustomProperty(AtomicString) override;
 
   HeapVector<StylePropertyMapEntry> GetIterationEntries() override;
 
diff --git a/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.cpp b/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.cpp
index bacb00e..a5c0228 100644
--- a/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.cpp
@@ -58,11 +58,19 @@
     const String& property_name,
     ExceptionState& exception_state) {
   CSSPropertyID property_id = cssPropertyID(property_name);
-  if (property_id == CSSPropertyInvalid)
+  if (property_id == CSSPropertyInvalid) {
     exception_state.ThrowTypeError("Invalid propertyName: " + property_name);
-  if (property_id == CSSPropertyVariable)
-    return GetAllInternal(AtomicString(property_name));
-  return GetAllInternal(property_id);
+    return CSSStyleValueVector();
+  }
+
+  DCHECK(isValidCSSPropertyID(property_id));
+  const CSSValue* value = (property_id == CSSPropertyVariable)
+                              ? GetCustomProperty(AtomicString(property_name))
+                              : GetProperty(property_id);
+  if (!value)
+    return CSSStyleValueVector();
+
+  return StyleValueFactory::CssValueToStyleValueVector(property_id, *value);
 }
 
 bool StylePropertyMapReadonly::has(const String& property_name,
diff --git a/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.h b/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.h
index d85496d5..9ccd59c 100644
--- a/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.h
+++ b/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.h
@@ -26,19 +26,17 @@
 
   virtual ~StylePropertyMapReadonly() {}
 
-  virtual CSSStyleValue* get(const String& property_name, ExceptionState&);
-  virtual CSSStyleValueVector getAll(const String& property_name,
-                                     ExceptionState&);
-  virtual bool has(const String& property_name, ExceptionState&);
+  CSSStyleValue* get(const String& property_name, ExceptionState&);
+  CSSStyleValueVector getAll(const String& property_name, ExceptionState&);
+  bool has(const String& property_name, ExceptionState&);
 
   virtual Vector<String> getProperties() = 0;
 
  protected:
   StylePropertyMapReadonly() = default;
 
-  virtual CSSStyleValueVector GetAllInternal(CSSPropertyID) = 0;
-  virtual CSSStyleValueVector GetAllInternal(
-      AtomicString custom_property_name) = 0;
+  virtual const CSSValue* GetProperty(CSSPropertyID) = 0;
+  virtual const CSSValue* GetCustomProperty(AtomicString) = 0;
 
   virtual HeapVector<StylePropertyMapEntry> GetIterationEntries() = 0;
   IterationSource* StartIteration(ScriptState*, ExceptionState&) override;
diff --git a/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp b/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp
index 7c1b0dd..11bb8aea 100644
--- a/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp
+++ b/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp
@@ -112,7 +112,7 @@
 
 void FrameRequestCallbackCollection::V8FrameCallback::Invoke(
     double highResTime) {
-  callback_->call(nullptr, highResTime);
+  callback_->InvokeAndReportException(nullptr, highResTime);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/MutationObserver.cpp b/third_party/WebKit/Source/core/dom/MutationObserver.cpp
index f68a75ba..b8da1709 100644
--- a/third_party/WebKit/Source/core/dom/MutationObserver.cpp
+++ b/third_party/WebKit/Source/core/dom/MutationObserver.cpp
@@ -65,7 +65,7 @@
                MutationObserver& observer) override {
     // https://dom.spec.whatwg.org/#notify-mutation-observers
     // step 5-4. specifies that the callback this value is a MutationObserver.
-    callback_->call(&observer, records, &observer);
+    callback_->InvokeAndReportException(&observer, records, &observer);
   }
 
   virtual void Trace(blink::Visitor* visitor) {
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index 72a6636fe..eb3394b 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -747,6 +747,9 @@
   if (!RuntimeEnabledFeatures::IncrementalShadowDOMEnabled())
     return true;
   if (isConnected() && !GetDocument().MayContainV0Shadow()) {
+    // TODO(crbug.com/787717): Some built-in elements still use <content>
+    // elements in their user-agent shadow roots. DCHECK() fails if such an
+    // element is used.
     DCHECK(!GetDocument().ChildNeedsDistributionRecalc());
     return false;
   }
diff --git a/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp b/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp
index e9da30c3b..e61e8964 100644
--- a/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp
@@ -96,7 +96,7 @@
 }
 
 void ScriptedIdleTaskController::V8IdleTask::invoke(IdleDeadline* deadline) {
-  callback_->call(nullptr, deadline);
+  callback_->InvokeAndReportException(nullptr, deadline);
 }
 
 ScriptedIdleTaskController::ScriptedIdleTaskController(
diff --git a/third_party/WebKit/Source/core/dom/V0InsertionPoint.cpp b/third_party/WebKit/Source/core/dom/V0InsertionPoint.cpp
index b891b08e..b196cb8 100644
--- a/third_party/WebKit/Source/core/dom/V0InsertionPoint.cpp
+++ b/third_party/WebKit/Source/core/dom/V0InsertionPoint.cpp
@@ -210,8 +210,11 @@
 void V0InsertionPoint::ChildrenChanged(const ChildrenChange& change) {
   HTMLElement::ChildrenChanged(change);
   if (ShadowRoot* root = ContainingShadowRoot()) {
-    if (ElementShadow* root_owner = root->Owner())
-      root_owner->SetNeedsDistributionRecalc();
+    if (ElementShadow* root_owner = root->Owner()) {
+      if (!(RuntimeEnabledFeatures::IncrementalShadowDOMEnabled() &&
+            root_owner->IsV1()))
+        root_owner->SetNeedsDistributionRecalc();
+    }
   }
 }
 
@@ -221,7 +224,9 @@
   if (ShadowRoot* root = ContainingShadowRoot()) {
     if (!root->IsV1()) {
       if (ElementShadow* root_owner = root->Owner()) {
-        root_owner->SetNeedsDistributionRecalc();
+        if (!(RuntimeEnabledFeatures::IncrementalShadowDOMEnabled() &&
+              root_owner->IsV1()))
+          root_owner->SetNeedsDistributionRecalc();
         if (CanBeActive() && !registered_with_shadow_root_ &&
             insertion_point->GetTreeScope().RootNode() == root) {
           registered_with_shadow_root_ = true;
diff --git a/third_party/WebKit/Source/core/editing/FrameCaretTest.cpp b/third_party/WebKit/Source/core/editing/FrameCaretTest.cpp
index fabd0e91..e1e095b8c 100644
--- a/third_party/WebKit/Source/core/editing/FrameCaretTest.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameCaretTest.cpp
@@ -39,7 +39,7 @@
 TEST_F(FrameCaretTest, BlinkAfterTyping) {
   FrameCaret& caret = Selection().FrameCaretForTesting();
   scoped_refptr<scheduler::FakeWebTaskRunner> task_runner =
-      base::AdoptRef(new scheduler::FakeWebTaskRunner);
+      base::MakeRefCounted<scheduler::FakeWebTaskRunner>();
   task_runner->SetTime(0);
   caret.RecreateCaretBlinkTimerForTesting(task_runner.get());
   const double kInterval = 10;
diff --git a/third_party/WebKit/Source/core/exported/WebSettingsImpl.cpp b/third_party/WebKit/Source/core/exported/WebSettingsImpl.cpp
index 51f82e7..02a6d43e 100644
--- a/third_party/WebKit/Source/core/exported/WebSettingsImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebSettingsImpl.cpp
@@ -688,12 +688,6 @@
   settings_->SetV8CacheOptions(static_cast<blink::V8CacheOptions>(options));
 }
 
-void WebSettingsImpl::SetV8CacheStrategiesForCacheStorage(
-    V8CacheStrategiesForCacheStorage strategies) {
-  settings_->SetV8CacheStrategiesForCacheStorage(
-      static_cast<blink::V8CacheStrategiesForCacheStorage>(strategies));
-}
-
 void WebSettingsImpl::SetViewportStyle(WebViewportStyle style) {
   dev_tools_emulator_->SetViewportStyle(style);
 }
diff --git a/third_party/WebKit/Source/core/exported/WebSettingsImpl.h b/third_party/WebKit/Source/core/exported/WebSettingsImpl.h
index 22a160e..dc157ed2 100644
--- a/third_party/WebKit/Source/core/exported/WebSettingsImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebSettingsImpl.h
@@ -187,8 +187,6 @@
   void SetUseSolidColorScrollbars(bool) override;
   void SetUseWideViewport(bool) override;
   void SetV8CacheOptions(V8CacheOptions) override;
-  void SetV8CacheStrategiesForCacheStorage(
-      V8CacheStrategiesForCacheStorage) override;
   void SetValidationMessageTimerMagnification(int) override;
   void SetViewportEnabled(bool) override;
   void SetViewportMetaEnabled(bool) override;
diff --git a/third_party/WebKit/Source/core/frame/BUILD.gn b/third_party/WebKit/Source/core/frame/BUILD.gn
index 591fce49..67e6198 100644
--- a/third_party/WebKit/Source/core/frame/BUILD.gn
+++ b/third_party/WebKit/Source/core/frame/BUILD.gn
@@ -87,6 +87,8 @@
     "PageScaleConstraints.h",
     "PageScaleConstraintsSet.cpp",
     "PageScaleConstraintsSet.h",
+    "PausableScriptExecutor.cpp",
+    "PausableScriptExecutor.h",
     "PausableTimer.cpp",
     "PausableTimer.h",
     "PerformanceMonitor.cpp",
@@ -128,8 +130,6 @@
     "SettingsDelegate.h",
     "SmartClip.cpp",
     "SmartClip.h",
-    "SuspendableScriptExecutor.cpp",
-    "SuspendableScriptExecutor.h",
     "UseCounter.cpp",
     "UseCounter.h",
     "UserActivationState.cpp",
diff --git a/third_party/WebKit/Source/core/frame/SuspendableScriptExecutor.cpp b/third_party/WebKit/Source/core/frame/PausableScriptExecutor.cpp
similarity index 87%
rename from third_party/WebKit/Source/core/frame/SuspendableScriptExecutor.cpp
rename to third_party/WebKit/Source/core/frame/PausableScriptExecutor.cpp
index 897f4c4..9074560 100644
--- a/third_party/WebKit/Source/core/frame/SuspendableScriptExecutor.cpp
+++ b/third_party/WebKit/Source/core/frame/PausableScriptExecutor.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 "core/frame/SuspendableScriptExecutor.h"
+#include "core/frame/PausableScriptExecutor.h"
 
 #include <memory>
 #include "bindings/core/v8/ScriptController.h"
@@ -22,7 +22,7 @@
 
 namespace {
 
-class WebScriptExecutor : public SuspendableScriptExecutor::Executor {
+class WebScriptExecutor : public PausableScriptExecutor::Executor {
  public:
   WebScriptExecutor(const HeapVector<ScriptSourceCode>& sources,
                     int world_id,
@@ -32,7 +32,7 @@
 
   virtual void Trace(blink::Visitor* visitor) {
     visitor->Trace(sources_);
-    SuspendableScriptExecutor::Executor::Trace(visitor);
+    PausableScriptExecutor::Executor::Trace(visitor);
   }
 
  private:
@@ -68,7 +68,7 @@
   return results;
 }
 
-class V8FunctionExecutor : public SuspendableScriptExecutor::Executor {
+class V8FunctionExecutor : public PausableScriptExecutor::Executor {
  public:
   V8FunctionExecutor(v8::Isolate*,
                      v8::Local<v8::Function>,
@@ -125,19 +125,19 @@
 
 }  // namespace
 
-SuspendableScriptExecutor* SuspendableScriptExecutor::Create(
+PausableScriptExecutor* PausableScriptExecutor::Create(
     LocalFrame* frame,
     scoped_refptr<DOMWrapperWorld> world,
     const HeapVector<ScriptSourceCode>& sources,
     bool user_gesture,
     WebScriptExecutionCallback* callback) {
   ScriptState* script_state = ToScriptState(frame, *world);
-  return new SuspendableScriptExecutor(
+  return new PausableScriptExecutor(
       frame, script_state, callback,
       new WebScriptExecutor(sources, world->GetWorldId(), user_gesture));
 }
 
-void SuspendableScriptExecutor::CreateAndRun(
+void PausableScriptExecutor::CreateAndRun(
     LocalFrame* frame,
     v8::Isolate* isolate,
     v8::Local<v8::Context> context,
@@ -152,13 +152,13 @@
       callback->Completed(Vector<v8::Local<v8::Value>>());
     return;
   }
-  SuspendableScriptExecutor* executor = new SuspendableScriptExecutor(
+  PausableScriptExecutor* executor = new PausableScriptExecutor(
       frame, script_state, callback,
       new V8FunctionExecutor(isolate, function, receiver, argc, argv));
   executor->Run();
 }
 
-void SuspendableScriptExecutor::ContextDestroyed(
+void PausableScriptExecutor::ContextDestroyed(
     ExecutionContext* destroyed_context) {
   PausableTimer::ContextDestroyed(destroyed_context);
   if (callback_)
@@ -166,7 +166,7 @@
   Dispose();
 }
 
-SuspendableScriptExecutor::SuspendableScriptExecutor(
+PausableScriptExecutor::PausableScriptExecutor(
     LocalFrame* frame,
     ScriptState* script_state,
     WebScriptExecutionCallback* callback,
@@ -181,13 +181,13 @@
   CHECK(script_state_->ContextIsValid());
 }
 
-SuspendableScriptExecutor::~SuspendableScriptExecutor() {}
+PausableScriptExecutor::~PausableScriptExecutor() {}
 
-void SuspendableScriptExecutor::Fired() {
+void PausableScriptExecutor::Fired() {
   ExecuteAndDestroySelf();
 }
 
-void SuspendableScriptExecutor::Run() {
+void PausableScriptExecutor::Run() {
   ExecutionContext* context = GetExecutionContext();
   DCHECK(context);
   if (!context->IsContextPaused()) {
@@ -199,7 +199,7 @@
   PauseIfNeeded();
 }
 
-void SuspendableScriptExecutor::RunAsync(BlockingOption blocking) {
+void PausableScriptExecutor::RunAsync(BlockingOption blocking) {
   ExecutionContext* context = GetExecutionContext();
   DCHECK(context);
   blocking_option_ = blocking;
@@ -210,7 +210,7 @@
   PauseIfNeeded();
 }
 
-void SuspendableScriptExecutor::ExecuteAndDestroySelf() {
+void PausableScriptExecutor::ExecuteAndDestroySelf() {
   CHECK(script_state_->ContextIsValid());
 
   if (callback_)
@@ -234,14 +234,14 @@
   Dispose();
 }
 
-void SuspendableScriptExecutor::Dispose() {
+void PausableScriptExecutor::Dispose() {
   // Remove object as a ContextLifecycleObserver.
   PausableObject::ClearContext();
   keep_alive_.Clear();
   Stop();
 }
 
-void SuspendableScriptExecutor::Trace(blink::Visitor* visitor) {
+void PausableScriptExecutor::Trace(blink::Visitor* visitor) {
   visitor->Trace(executor_);
   PausableTimer::Trace(visitor);
 }
diff --git a/third_party/WebKit/Source/core/frame/SuspendableScriptExecutor.h b/third_party/WebKit/Source/core/frame/PausableScriptExecutor.h
similarity index 75%
rename from third_party/WebKit/Source/core/frame/SuspendableScriptExecutor.h
rename to third_party/WebKit/Source/core/frame/PausableScriptExecutor.h
index 2e1ce1c..7fab821 100644
--- a/third_party/WebKit/Source/core/frame/SuspendableScriptExecutor.h
+++ b/third_party/WebKit/Source/core/frame/PausableScriptExecutor.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SuspendableScriptExecutor_h
-#define SuspendableScriptExecutor_h
+#ifndef PausableScriptExecutor_h
+#define PausableScriptExecutor_h
 
 #include "base/memory/scoped_refptr.h"
 #include "core/CoreExport.h"
@@ -21,15 +21,15 @@
 class ScriptState;
 class WebScriptExecutionCallback;
 
-class CORE_EXPORT SuspendableScriptExecutor final
-    : public GarbageCollectedFinalized<SuspendableScriptExecutor>,
+class CORE_EXPORT PausableScriptExecutor final
+    : public GarbageCollectedFinalized<PausableScriptExecutor>,
       public PausableTimer {
-  USING_GARBAGE_COLLECTED_MIXIN(SuspendableScriptExecutor);
+  USING_GARBAGE_COLLECTED_MIXIN(PausableScriptExecutor);
 
  public:
   enum BlockingOption { kNonBlocking, kOnloadBlocking };
 
-  static SuspendableScriptExecutor* Create(
+  static PausableScriptExecutor* Create(
       LocalFrame*,
       scoped_refptr<DOMWrapperWorld>,
       const HeapVector<ScriptSourceCode>& sources,
@@ -43,7 +43,7 @@
                            int argc,
                            v8::Local<v8::Value> argv[],
                            WebScriptExecutionCallback*);
-  ~SuspendableScriptExecutor() override;
+  ~PausableScriptExecutor() override;
 
   void Run();
   void RunAsync(BlockingOption);
@@ -61,10 +61,10 @@
   };
 
  private:
-  SuspendableScriptExecutor(LocalFrame*,
-                            ScriptState*,
-                            WebScriptExecutionCallback*,
-                            Executor*);
+  PausableScriptExecutor(LocalFrame*,
+                         ScriptState*,
+                         WebScriptExecutionCallback*,
+                         Executor*);
 
   void Fired() override;
 
@@ -75,11 +75,11 @@
   WebScriptExecutionCallback* callback_;
   BlockingOption blocking_option_;
 
-  SelfKeepAlive<SuspendableScriptExecutor> keep_alive_;
+  SelfKeepAlive<PausableScriptExecutor> keep_alive_;
 
   Member<Executor> executor_;
 };
 
 }  // namespace blink
 
-#endif  // SuspendableScriptExecutor_h
+#endif  // PausableScriptExecutor_h
diff --git a/third_party/WebKit/Source/core/frame/ReportingObserver.cpp b/third_party/WebKit/Source/core/frame/ReportingObserver.cpp
index 801231f..0ed09e6 100644
--- a/third_party/WebKit/Source/core/frame/ReportingObserver.cpp
+++ b/third_party/WebKit/Source/core/frame/ReportingObserver.cpp
@@ -23,7 +23,7 @@
 
 void ReportingObserver::ReportToCallback(
     const HeapVector<Member<Report>>& reports) {
-  callback_->call(this, reports, this);
+  callback_->InvokeAndReportException(this, reports, this);
 }
 
 void ReportingObserver::observe() {
diff --git a/third_party/WebKit/Source/core/frame/Settings.h b/third_party/WebKit/Source/core/frame/Settings.h
index e4be3ba..d9dbb290 100644
--- a/third_party/WebKit/Source/core/frame/Settings.h
+++ b/third_party/WebKit/Source/core/frame/Settings.h
@@ -30,7 +30,6 @@
 
 #include <memory>
 #include "bindings/core/v8/V8CacheOptions.h"
-#include "bindings/core/v8/V8CacheStrategiesForCacheStorage.h"
 #include "core/CoreExport.h"
 #include "core/dom/events/AddEventListenerOptionsDefaults.h"
 #include "core/editing/EditingBehaviorTypes.h"
diff --git a/third_party/WebKit/Source/core/frame/Settings.json5 b/third_party/WebKit/Source/core/frame/Settings.json5
index 7acc85a..3b2cb92f 100644
--- a/third_party/WebKit/Source/core/frame/Settings.json5
+++ b/third_party/WebKit/Source/core/frame/Settings.json5
@@ -641,13 +641,6 @@
       type: "V8CacheOptions",
     },
 
-    // V8 code cache for CacheStorage supports three types of strategies (none, normal and aggressive).
-    {
-      name: "v8CacheStrategiesForCacheStorage",
-      initial: "V8CacheStrategiesForCacheStorage::kDefault",
-      type: "V8CacheStrategiesForCacheStorage",
-    },
-
     // These values are bit fields for the properties of available pointing devices
     // and may take on multiple values (e.g. laptop with touchpad and touchscreen
     // has pointerType coarse *and* fine).
diff --git a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
index 078e1ac2..9692de0 100644
--- a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
@@ -138,12 +138,12 @@
 #include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/PageScaleConstraintsSet.h"
+#include "core/frame/PausableScriptExecutor.h"
 #include "core/frame/RemoteFrame.h"
 #include "core/frame/RemoteFrameOwner.h"
 #include "core/frame/ScreenOrientationController.h"
 #include "core/frame/Settings.h"
 #include "core/frame/SmartClip.h"
-#include "core/frame/SuspendableScriptExecutor.h"
 #include "core/frame/UseCounter.h"
 #include "core/frame/VisualViewport.h"
 #include "core/frame/WebFrameWidgetImpl.h"
@@ -738,7 +738,7 @@
   DCHECK(GetFrame());
 
   scoped_refptr<DOMWrapperWorld> main_world = &DOMWrapperWorld::MainWorld();
-  SuspendableScriptExecutor* executor = SuspendableScriptExecutor::Create(
+  PausableScriptExecutor* executor = PausableScriptExecutor::Create(
       GetFrame(), std::move(main_world), CreateSourcesVector(&source, 1),
       user_gesture, callback);
   executor->Run();
@@ -752,9 +752,9 @@
     v8::Local<v8::Value> argv[],
     WebScriptExecutionCallback* callback) {
   DCHECK(GetFrame());
-  SuspendableScriptExecutor::CreateAndRun(GetFrame(), ToIsolate(GetFrame()),
-                                          context, function, receiver, argc,
-                                          argv, callback);
+  PausableScriptExecutor::CreateAndRun(GetFrame(), ToIsolate(GetFrame()),
+                                       context, function, receiver, argc, argv,
+                                       callback);
 }
 
 void WebLocalFrameImpl::ExecuteScriptInIsolatedWorld(
@@ -799,15 +799,15 @@
 
   scoped_refptr<DOMWrapperWorld> isolated_world =
       DOMWrapperWorld::EnsureIsolatedWorld(ToIsolate(GetFrame()), world_id);
-  SuspendableScriptExecutor* executor = SuspendableScriptExecutor::Create(
+  PausableScriptExecutor* executor = PausableScriptExecutor::Create(
       GetFrame(), std::move(isolated_world),
       CreateSourcesVector(sources_in, num_sources), user_gesture, callback);
   switch (option) {
     case kAsynchronousBlockingOnload:
-      executor->RunAsync(SuspendableScriptExecutor::kOnloadBlocking);
+      executor->RunAsync(PausableScriptExecutor::kOnloadBlocking);
       break;
     case kAsynchronous:
-      executor->RunAsync(SuspendableScriptExecutor::kNonBlocking);
+      executor->RunAsync(PausableScriptExecutor::kNonBlocking);
       break;
     case kSynchronous:
       executor->Run();
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp
index 06e44d2..ce6c6cc 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp
@@ -136,10 +136,12 @@
 
   // Step 5. "... referrer is referrer, ..." [spec text]
   if (!module_request.GetReferrer().IsNull()) {
-    resource_request.SetHTTPReferrer(SecurityPolicy::GenerateReferrer(
-        module_request.GetReferrerPolicy(), module_request.Url(),
-        module_request.GetReferrer()));
+    fetch_params.MutableResourceRequest().SetHTTPReferrer(
+        SecurityPolicy::GenerateReferrer(module_request.GetReferrerPolicy(),
+                                         module_request.Url(),
+                                         module_request.GetReferrer()));
   }
+
   // Step 5. "... and client is fetch client settings object." [spec text]
   // -> set by ResourceFetcher
 
diff --git a/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp b/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp
index 9a6d79b..d4aede9 100644
--- a/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp
+++ b/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp
@@ -17,7 +17,7 @@
 static void RunWatchCallback(V8MojoWatchCallback* callback,
                              ScriptWrappable* wrappable,
                              MojoResult result) {
-  callback->call(wrappable, result);
+  callback->InvokeAndReportException(wrappable, result);
 }
 
 // static
diff --git a/third_party/WebKit/Source/core/resize_observer/ResizeObserver.cpp b/third_party/WebKit/Source/core/resize_observer/ResizeObserver.cpp
index f3029f42..b989cb2e 100644
--- a/third_party/WebKit/Source/core/resize_observer/ResizeObserver.cpp
+++ b/third_party/WebKit/Source/core/resize_observer/ResizeObserver.cpp
@@ -132,7 +132,7 @@
   }
   DCHECK(callback_ || delegate_);
   if (callback_)
-    callback_->call(this, entries, this);
+    callback_->InvokeAndReportException(this, entries, this);
   if (delegate_)
     delegate_->OnResize(entries);
   ClearObservations();
diff --git a/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp b/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp
index b56704d..275c503d 100644
--- a/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp
+++ b/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp
@@ -18,14 +18,16 @@
                                           const String& message1,
                                           const String& message2,
                                           ExceptionState& exception_state) {
-  ScriptWrappable* script_wrappable;
   String return_value;
 
-  if (callback->call(script_wrappable = nullptr, message1, message2,
-                     return_value)) {
-    return String("SUCCESS: ") + return_value;
+  v8::TryCatch try_catch(callback->GetIsolate());
+  try_catch.SetVerbose(true);
+
+  if (!callback->Invoke(nullptr, message1, message2).To(&return_value)) {
+    return String("Error!");
   }
-  return String("Error!");
+
+  return String("SUCCESS: ") + return_value;
 }
 
 String CallbackFunctionTest::testNullableCallback(
@@ -42,17 +44,13 @@
     V8TestInterfaceCallback* callback,
     HTMLDivElement* div_element,
     ExceptionState& exception_state) {
-  ScriptWrappable* script_wrappable;
-
-  callback->call(script_wrappable = nullptr, div_element);
-  return;
+  callback->InvokeAndReportException(nullptr, div_element);
 }
 
 void CallbackFunctionTest::testReceiverObjectCallback(
     V8TestReceiverObjectCallback* callback,
     ExceptionState& exception_state) {
-  callback->call(this);
-  return;
+  callback->InvokeAndReportException(this);
 }
 
 Vector<String> CallbackFunctionTest::testSequenceCallback(
@@ -60,16 +58,21 @@
     const Vector<int>& numbers,
     ExceptionState& exception_state) {
   Vector<String> return_value;
-  if (callback->call(nullptr, numbers, return_value)) {
-    return return_value;
+
+  v8::TryCatch try_catch(callback->GetIsolate());
+  try_catch.SetVerbose(true);
+
+  if (!callback->Invoke(nullptr, numbers).To(&return_value)) {
+    return Vector<String>();
   }
-  return Vector<String>();
+
+  return return_value;
 }
 
 void CallbackFunctionTest::testEnumCallback(V8TestEnumCallback* callback,
                                             const String& enum_value,
                                             ExceptionState& exception_state) {
-  callback->call(nullptr, enum_value);
+  callback->InvokeAndReportException(nullptr, enum_value);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
index 5fce580..bca9b16f 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
@@ -120,7 +120,7 @@
   performance_entries.swap(performance_entries_);
   PerformanceObserverEntryList* entry_list =
       new PerformanceObserverEntryList(performance_entries);
-  callback_->call(this, entry_list, this);
+  callback_->InvokeAndReportException(this, entry_list, this);
 }
 
 void PerformanceObserver::Trace(blink::Visitor* visitor) {
diff --git a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
index 3aa42028..2c8701e 100644
--- a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
@@ -172,14 +172,10 @@
     return;
 
   if (!decoder_) {
-    if (!response_encoding_.IsEmpty()) {
-      decoder_ = TextResourceDecoder::Create(TextResourceDecoderOptions(
-          TextResourceDecoderOptions::kPlainTextContent,
-          WTF::TextEncoding(response_encoding_)));
-    } else {
-      decoder_ = TextResourceDecoder::Create(TextResourceDecoderOptions(
-          TextResourceDecoderOptions::kPlainTextContent, UTF8Encoding()));
-    }
+    decoder_ = TextResourceDecoder::Create(TextResourceDecoderOptions(
+        TextResourceDecoderOptions::kPlainTextContent,
+        response_encoding_.IsEmpty() ? UTF8Encoding()
+                                     : WTF::TextEncoding(response_encoding_)));
   }
 
   if (!len)
diff --git a/third_party/WebKit/Source/devtools/front_end/layers_test_runner/LayersTestRunner.js b/third_party/WebKit/Source/devtools/front_end/layers_test_runner/LayersTestRunner.js
index 6f64c36..0b2df3c8 100644
--- a/third_party/WebKit/Source/devtools/front_end/layers_test_runner/LayersTestRunner.js
+++ b/third_party/WebKit/Source/devtools/front_end/layers_test_runner/LayersTestRunner.js
@@ -61,14 +61,9 @@
     LayersTestRunner.dumpLayers3DView(prefix + '    ', element);
 };
 
-LayersTestRunner.evaluateAndRunWhenTreeChanges = async function(expression, callback) {
-  function eventHandler() {
-    LayersTestRunner.layerTreeModel().removeEventListener(Layers.LayerTreeModel.Events.LayerTreeChanged, eventHandler);
-    callback();
-  }
-
+LayersTestRunner.evaluateAndWaitForTreeChange = async function(expression) {
   await TestRunner.evaluateInPageAnonymously(expression);
-  LayersTestRunner.layerTreeModel().addEventListener(Layers.LayerTreeModel.Events.LayerTreeChanged, eventHandler);
+  return LayersTestRunner.layerTreeModel().once(Layers.LayerTreeModel.Events.LayerTreeChanged);
 };
 
 LayersTestRunner.findLayerByNodeIdAttribute = function(nodeIdAttribute) {
@@ -95,40 +90,9 @@
   return result;
 };
 
-LayersTestRunner.requestLayers = function(callback) {
-  LayersTestRunner.layerTreeModel().addEventListener(Layers.LayerTreeModel.Events.LayerTreeChanged, onLayerTreeChanged);
+LayersTestRunner.requestLayers = function() {
   LayersTestRunner.layerTreeModel().enable();
-
-  function onLayerTreeChanged() {
-    LayersTestRunner.layerTreeModel().removeEventListener(
-        Layers.LayerTreeModel.Events.LayerTreeChanged, onLayerTreeChanged);
-    callback();
-  }
-};
-
-LayersTestRunner.dumpModelScrollRects = function() {
-  function dumpScrollRectsForLayer(layer) {
-    if (layer._scrollRects.length > 0)
-      TestRunner.addObject(layer._scrollRects);
-  }
-
-  TestRunner.addResult('Model elements dump');
-  LayersTestRunner.layerTreeModel().layerTree().forEachLayer(dumpScrollRectsForLayer.bind(this));
-};
-
-LayersTestRunner.dumpModelStickyPositionConstraint = function() {
-  function dumpModelStickyPositionConstraintForLayer(layer) {
-    var stickyFormatters = {
-      '_nearestLayerShiftingContainingBlock': 'formatAsTypeNameOrNull',
-      '_nearestLayerShiftingStickyBox': 'formatAsTypeNameOrNull'
-    };
-
-    if (layer._stickyPositionConstraint)
-      TestRunner.addObject(layer._stickyPositionConstraint, stickyFormatters);
-  }
-
-  TestRunner.addResult('Model elements dump');
-  LayersTestRunner.layerTreeModel().layerTree().forEachLayer(dumpModelStickyPositionConstraintForLayer.bind(this));
+  return LayersTestRunner.layerTreeModel().once(Layers.LayerTreeModel.Events.LayerTreeChanged);
 };
 
 LayersTestRunner.dispatchMouseEvent = function(eventType, button, element, offsetX, offsetY) {
@@ -154,3 +118,25 @@
 
   element.dispatchEvent(new MouseEvent(eventType, eventArguments));
 };
+
+LayersTestRunner.findLayerTreeElement = function(layer) {
+  var element = layer[LayerViewer.LayerTreeElement._symbol];
+  element.reveal();
+  return element.listItemElement;
+};
+
+LayersTestRunner.dispatchMouseEventToLayerTree = function(eventType, button, layer) {
+  var element = LayersTestRunner.findLayerTreeElement(layer);
+  TestRunner.assertTrue(!!element);
+  LayersTestRunner.dispatchMouseEvent(eventType, button, element, element.clientWidth >> 1, element.clientHeight >> 1);
+};
+
+LayersTestRunner.dumpSelectedStyles = function(message, element) {
+  var classes = [];
+  if (element.classList.contains('selected'))
+    classes.push('selected');
+  if (element.classList.contains('hovered'))
+    classes.push('hovered');
+
+  TestRunner.addResult(message + ': ' + classes.join(', '));
+};
diff --git a/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp b/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp
index a810efd6..2a4f145c 100644
--- a/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp
+++ b/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp
@@ -66,12 +66,12 @@
 }
 
 void GeoNotifier::RunSuccessCallback(Geoposition* position) {
-  success_callback_->call(nullptr, position);
+  success_callback_->InvokeAndReportException(nullptr, position);
 }
 
 void GeoNotifier::RunErrorCallback(PositionError* error) {
   if (error_callback_)
-    error_callback_->call(nullptr, error);
+    error_callback_->InvokeAndReportException(nullptr, error);
 }
 
 void GeoNotifier::StartTimer() {
@@ -102,10 +102,11 @@
     return;
   }
 
-  if (error_callback_)
-    error_callback_->call(
+  if (error_callback_) {
+    error_callback_->InvokeAndReportException(
         nullptr,
         PositionError::Create(PositionError::kTimeout, "Timeout expired"));
+  }
 
   DEFINE_STATIC_LOCAL(CustomCountHistogram, timeout_expired_histogram,
                       ("Geolocation.TimeoutExpired", 0,
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
index e841a88..452595f 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
@@ -212,7 +212,7 @@
             GetExecutionContext(), obs_txn.first, stores, this);
       }
 
-      observer->Callback()->call(
+      observer->Callback()->InvokeAndReportException(
           observer, IDBObserverChanges::Create(this, transaction, observations,
                                                map_entry.second, isolate_));
       if (transaction)
diff --git a/third_party/WebKit/Source/modules/mediasession/MediaSession.cpp b/third_party/WebKit/Source/modules/mediasession/MediaSession.cpp
index c27f518c..83d16574 100644
--- a/third_party/WebKit/Source/modules/mediasession/MediaSession.cpp
+++ b/third_party/WebKit/Source/modules/mediasession/MediaSession.cpp
@@ -225,7 +225,7 @@
   if (iter == action_handlers_.end())
     return;
 
-  iter->value->call(this);
+  iter->value->InvokeAndReportException(this);
 }
 
 void MediaSession::Trace(blink::Visitor* visitor) {
diff --git a/third_party/WebKit/Source/modules/presentation/PresentationConnectionList.idl b/third_party/WebKit/Source/modules/presentation/PresentationConnectionList.idl
index 6e1fe7e..419eeec 100644
--- a/third_party/WebKit/Source/modules/presentation/PresentationConnectionList.idl
+++ b/third_party/WebKit/Source/modules/presentation/PresentationConnectionList.idl
@@ -4,7 +4,9 @@
 
 // https://w3c.github.io/presentation-api/#interface-presentationconnectionlist
 
-interface PresentationConnectionList : EventTarget {
+[
+    RuntimeEnabled=Presentation
+] interface PresentationConnectionList : EventTarget {
     readonly attribute FrozenArray<PresentationConnection> connections;
     attribute EventHandler onconnectionavailable;
 };
diff --git a/third_party/WebKit/Source/modules/presentation/PresentationReceiver.idl b/third_party/WebKit/Source/modules/presentation/PresentationReceiver.idl
index 0058b57..f29e0e8 100644
--- a/third_party/WebKit/Source/modules/presentation/PresentationReceiver.idl
+++ b/third_party/WebKit/Source/modules/presentation/PresentationReceiver.idl
@@ -4,6 +4,8 @@
 
 // https://w3c.github.io/presentation-api/#idl-def-presentationreceiver
 
-interface PresentationReceiver {
+[
+    RuntimeEnabled=Presentation
+] interface PresentationReceiver {
     [SameObject, CallWith=ScriptState] readonly attribute Promise<PresentationConnectionList> connectionList;
 };
diff --git a/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.cpp b/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.cpp
index 6f89e49..86866966 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.cpp
+++ b/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.cpp
@@ -24,7 +24,7 @@
     return;
   }
 
-  bindings_cb_->call(remote_playback, new_availability);
+  bindings_cb_->InvokeAndReportException(remote_playback, new_availability);
 }
 
 void AvailabilityCallbackWrapper::Trace(blink::Visitor* visitor) {
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerInstalledScriptsManager.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerInstalledScriptsManager.cpp
index ae2f3fc4..626ca79e 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerInstalledScriptsManager.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerInstalledScriptsManager.cpp
@@ -39,15 +39,12 @@
   }
 
   // This is from WorkerScriptLoader::DidReceiveData.
-  std::unique_ptr<TextResourceDecoder> decoder;
-  if (!raw_script_data->Encoding().IsEmpty()) {
-    decoder = TextResourceDecoder::Create(TextResourceDecoderOptions(
-        TextResourceDecoderOptions::kPlainTextContent,
-        WTF::TextEncoding(raw_script_data->Encoding())));
-  } else {
-    decoder = TextResourceDecoder::Create(TextResourceDecoderOptions(
-        TextResourceDecoderOptions::kPlainTextContent));
-  }
+  std::unique_ptr<TextResourceDecoder> decoder =
+      TextResourceDecoder::Create(TextResourceDecoderOptions(
+          TextResourceDecoderOptions::kPlainTextContent,
+          raw_script_data->Encoding().IsEmpty()
+              ? UTF8Encoding()
+              : WTF::TextEncoding(raw_script_data->Encoding())));
 
   StringBuilder source_text_builder;
   for (const auto& chunk : raw_script_data->ScriptTextChunks())
diff --git a/third_party/WebKit/Source/modules/vr/latest/VRFrameRequestCallbackCollection.cpp b/third_party/WebKit/Source/modules/vr/latest/VRFrameRequestCallbackCollection.cpp
index 81568eb..e165d846 100644
--- a/third_party/WebKit/Source/modules/vr/latest/VRFrameRequestCallbackCollection.cpp
+++ b/third_party/WebKit/Source/modules/vr/latest/VRFrameRequestCallbackCollection.cpp
@@ -50,7 +50,7 @@
 
     probe::AsyncTask async_task(context_, callback);
     probe::UserCallback probe(context_, "VRRequestFrame", AtomicString(), true);
-    callback->call(session, frame);
+    callback->InvokeAndReportException(session, frame);
   }
 
   callbacks_to_invoke_.clear();
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
index d020f83..721247f 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
@@ -354,7 +354,7 @@
         kDataCloneError, "Cannot decode detached ArrayBuffer");
     resolver->Reject(error);
     if (error_callback) {
-      error_callback->call(this, error);
+      error_callback->InvokeAndReportException(this, error);
     }
   }
 
@@ -372,14 +372,14 @@
     // Resolve promise successfully and run the success callback
     resolver->Resolve(audio_buffer);
     if (success_callback)
-      success_callback->call(this, audio_buffer);
+      success_callback->InvokeAndReportException(this, audio_buffer);
   } else {
     // Reject the promise and run the error callback
     DOMException* error =
         DOMException::Create(kEncodingError, "Unable to decode audio data");
     resolver->Reject(error);
     if (error_callback)
-      error_callback->call(this, error);
+      error_callback->InvokeAndReportException(this, error);
   }
 
   // We've resolved the promise.  Remove it now.
diff --git a/third_party/WebKit/Source/modules/webdatabase/Database.cpp b/third_party/WebKit/Source/modules/webdatabase/Database.cpp
index c3c8147a..01beae2 100644
--- a/third_party/WebKit/Source/modules/webdatabase/Database.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/Database.cpp
@@ -324,8 +324,7 @@
 
 void Database::RunCreationCallback() {
   probe::AsyncTask async_task(GetExecutionContext(), creation_callback_);
-  bool return_value;
-  creation_callback_->call(nullptr, this, return_value);
+  creation_callback_->InvokeAndReportException(nullptr, this);
   creation_callback_ = nullptr;
 }
 
diff --git a/third_party/WebKit/Source/modules/webdatabase/WindowWebDatabase.idl b/third_party/WebKit/Source/modules/webdatabase/WindowWebDatabase.idl
index 3018a2c3..43295cb 100644
--- a/third_party/WebKit/Source/modules/webdatabase/WindowWebDatabase.idl
+++ b/third_party/WebKit/Source/modules/webdatabase/WindowWebDatabase.idl
@@ -25,7 +25,7 @@
  */
 
 // https://www.w3.org/TR/webdatabase/#databasecallback
-callback DatabaseCallback = boolean (Database database);
+callback DatabaseCallback = void (Database database);
 
 // https://www.w3.org/TR/webdatabase/#databases
 [
diff --git a/third_party/WebKit/Source/platform/Timer.cpp b/third_party/WebKit/Source/platform/Timer.cpp
index 1f3450e4..556e548 100644
--- a/third_party/WebKit/Source/platform/Timer.cpp
+++ b/third_party/WebKit/Source/platform/Timer.cpp
@@ -132,9 +132,9 @@
     // Cancel any previously posted task.
     weak_ptr_factory_.RevokeAll();
 
-    TimerTaskRunner()->ToSingleThreadTaskRunner()->PostDelayedTask(
+    TimerTaskRunner()->PostDelayedTask(
         location_,
-        base::Bind(&TimerBase::RunInternal, weak_ptr_factory_.CreateWeakPtr()),
+        WTF::Bind(&TimerBase::RunInternal, weak_ptr_factory_.CreateWeakPtr()),
         TimeDelta::FromSecondsD(delay));
   }
 }
diff --git a/third_party/WebKit/Source/platform/Timer.h b/third_party/WebKit/Source/platform/Timer.h
index dc4a5530..d487b18 100644
--- a/third_party/WebKit/Source/platform/Timer.h
+++ b/third_party/WebKit/Source/platform/Timer.h
@@ -52,6 +52,12 @@
   void Start(double next_fire_interval,
              double repeat_interval,
              const WebTraceLocation&);
+  void Start(TimeDelta next_fire_interval,
+             TimeDelta repeat_interval,
+             const WebTraceLocation& from_here) {
+    Start(next_fire_interval.InSecondsF(), repeat_interval.InSecondsF(),
+          from_here);
+  }
 
   void StartRepeating(double repeat_interval, const WebTraceLocation& caller) {
     Start(repeat_interval, repeat_interval, caller);
@@ -74,13 +80,23 @@
   const WebTraceLocation& GetLocation() const { return location_; }
 
   double NextFireInterval() const;
+  TimeDelta NextFireIntervalDelta() const {
+    return TimeDelta::FromSecondsD(NextFireInterval());
+  }
+
   double RepeatInterval() const { return repeat_interval_; }
+  TimeDelta RepeatIntervalDelta() const {
+    return TimeDelta::FromSecondsD(RepeatInterval());
+  }
 
   void AugmentRepeatInterval(double delta) {
     double now = TimerMonotonicallyIncreasingTime();
     SetNextFireTime(now, std::max(next_fire_time_ - now + delta, 0.0));
     repeat_interval_ += delta;
   }
+  void AugmentRepeatInterval(TimeDelta delta) {
+    AugmentRepeatInterval(delta.InSecondsF());
+  }
 
   void MoveToNewTaskRunner(scoped_refptr<WebTaskRunner>);
 
diff --git a/third_party/WebKit/Source/platform/TimerTest.cpp b/third_party/WebKit/Source/platform/TimerTest.cpp
index dbecdfe..87549fa 100644
--- a/third_party/WebKit/Source/platform/TimerTest.cpp
+++ b/third_party/WebKit/Source/platform/TimerTest.cpp
@@ -541,7 +541,7 @@
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable));
   scoped_refptr<scheduler::WebTaskRunnerImpl> web_task_runner =
-      scheduler::WebTaskRunnerImpl::Create(task_runner);
+      scheduler::WebTaskRunnerImpl::Create(task_runner, base::nullopt);
   TimerForTest<TimerTest> timer(web_task_runner, this,
                                 &TimerTest::CountingTask);
   timer.StartOneShot(0, BLINK_FROM_HERE);
@@ -632,7 +632,7 @@
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable));
   scoped_refptr<scheduler::WebTaskRunnerImpl> web_task_runner1 =
-      scheduler::WebTaskRunnerImpl::Create(task_runner1);
+      scheduler::WebTaskRunnerImpl::Create(task_runner1, base::nullopt);
   TaskObserver task_observer1(web_task_runner1, &run_order);
   task_runner1->AddTaskObserver(&task_observer1);
 
@@ -640,7 +640,7 @@
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable));
   scoped_refptr<scheduler::WebTaskRunnerImpl> web_task_runner2 =
-      scheduler::WebTaskRunnerImpl::Create(task_runner2);
+      scheduler::WebTaskRunnerImpl::Create(task_runner2, base::nullopt);
   TaskObserver task_observer2(web_task_runner2, &run_order);
   task_runner2->AddTaskObserver(&task_observer2);
 
@@ -672,7 +672,7 @@
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable));
   scoped_refptr<scheduler::WebTaskRunnerImpl> web_task_runner1 =
-      scheduler::WebTaskRunnerImpl::Create(task_runner1);
+      scheduler::WebTaskRunnerImpl::Create(task_runner1, base::nullopt);
   TaskObserver task_observer1(web_task_runner1, &run_order);
   task_runner1->AddTaskObserver(&task_observer1);
 
@@ -680,7 +680,7 @@
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable));
   scoped_refptr<scheduler::WebTaskRunnerImpl> web_task_runner2 =
-      scheduler::WebTaskRunnerImpl::Create(task_runner2);
+      scheduler::WebTaskRunnerImpl::Create(task_runner2, base::nullopt);
   TaskObserver task_observer2(web_task_runner2, &run_order);
   task_runner2->AddTaskObserver(&task_observer2);
 
@@ -714,13 +714,13 @@
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable));
   scoped_refptr<scheduler::WebTaskRunnerImpl> web_task_runner1 =
-      scheduler::WebTaskRunnerImpl::Create(task_runner1);
+      scheduler::WebTaskRunnerImpl::Create(task_runner1, base::nullopt);
 
   scoped_refptr<scheduler::TaskQueue> task_runner2(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable));
   scoped_refptr<scheduler::WebTaskRunnerImpl> web_task_runner2 =
-      scheduler::WebTaskRunnerImpl::Create(task_runner2);
+      scheduler::WebTaskRunnerImpl::Create(task_runner2, base::nullopt);
 
   TimerForTest<TimerTest> timer(web_task_runner1, this,
                                 &TimerTest::CountingTask);
diff --git a/third_party/WebKit/Source/platform/WebTaskRunnerTest.cpp b/third_party/WebKit/Source/platform/WebTaskRunnerTest.cpp
index 9301456e..ba09c95 100644
--- a/third_party/WebKit/Source/platform/WebTaskRunnerTest.cpp
+++ b/third_party/WebKit/Source/platform/WebTaskRunnerTest.cpp
@@ -39,7 +39,7 @@
 
 TEST(WebTaskRunnerTest, PostCancellableTaskTest) {
   scoped_refptr<scheduler::FakeWebTaskRunner> task_runner =
-      base::AdoptRef(new scheduler::FakeWebTaskRunner);
+      base::MakeRefCounted<scheduler::FakeWebTaskRunner>();
 
   // Run without cancellation.
   int count = 0;
@@ -120,7 +120,7 @@
 
 TEST(WebTaskRunnerTest, CancellationCheckerTest) {
   scoped_refptr<scheduler::FakeWebTaskRunner> task_runner =
-      base::AdoptRef(new scheduler::FakeWebTaskRunner);
+      base::MakeRefCounted<scheduler::FakeWebTaskRunner>();
 
   int count = 0;
   TaskHandle handle = task_runner->PostCancellableTask(
diff --git a/third_party/WebKit/Source/platform/bindings/CallbackFunctionBase.h b/third_party/WebKit/Source/platform/bindings/CallbackFunctionBase.h
index de625828..d58c0acb 100644
--- a/third_party/WebKit/Source/platform/bindings/CallbackFunctionBase.h
+++ b/third_party/WebKit/Source/platform/bindings/CallbackFunctionBase.h
@@ -19,7 +19,7 @@
 // implementation of callback functions.
 //
 // As the signatures of callback functions vary, this class does not implement
-// |call| member function that performs "invoke" steps. Subclasses will
+// |Invoke| member function that performs "invoke" steps. Subclasses will
 // implement it.
 class PLATFORM_EXPORT CallbackFunctionBase
     : public GarbageCollectedFinalized<CallbackFunctionBase>,
diff --git a/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp b/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp
index 79ac677a..700f308 100644
--- a/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp
@@ -471,7 +471,7 @@
   image_->SetData(SharedBuffer::Create("data", sizeof("data")), true);
 
   scoped_refptr<scheduler::FakeWebTaskRunner> task_runner =
-      base::AdoptRef(new scheduler::FakeWebTaskRunner);
+      base::MakeRefCounted<scheduler::FakeWebTaskRunner>();
   image_->SetTaskRunnerForTesting(task_runner);
   task_runner->SetTime(10);
 
@@ -506,7 +506,7 @@
   image_->SetData(SharedBuffer::Create("data", sizeof("data")), false);
 
   scoped_refptr<scheduler::FakeWebTaskRunner> task_runner =
-      base::AdoptRef(new scheduler::FakeWebTaskRunner);
+      base::MakeRefCounted<scheduler::FakeWebTaskRunner>();
   image_->SetTaskRunnerForTesting(task_runner);
   task_runner->SetTime(10);
 
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h
index 4def4f1b..435da79 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h
@@ -53,7 +53,7 @@
   void SetLostContextCallback(const base::Closure&) {}
   void SetErrorMessageCallback(
       const base::Callback<void(const char*, int32_t id)>&) {}
-  void SignalQuery(uint32_t, const base::Closure&) override {}
+  void SignalQuery(uint32_t, base::OnceClosure) override {}
 
  private:
   std::unique_ptr<gpu::gles2::GLES2Interface> gl_;
diff --git a/third_party/WebKit/Source/platform/graphics/test/FakeWebGraphicsContext3DProvider.h b/third_party/WebKit/Source/platform/graphics/test/FakeWebGraphicsContext3DProvider.h
index a2a30aba..9fa8519 100644
--- a/third_party/WebKit/Source/platform/graphics/test/FakeWebGraphicsContext3DProvider.h
+++ b/third_party/WebKit/Source/platform/graphics/test/FakeWebGraphicsContext3DProvider.h
@@ -47,7 +47,7 @@
   void SetLostContextCallback(const base::Closure&) override {}
   void SetErrorMessageCallback(
       const base::Callback<void(const char*, int32_t id)>&) {}
-  void SignalQuery(uint32_t, const base::Closure&) override {}
+  void SignalQuery(uint32_t, base::OnceClosure) override {}
 
  private:
   gpu::gles2::GLES2Interface* gl_;
diff --git a/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h b/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
index 64f6d94..73a0cf81 100644
--- a/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
+++ b/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
@@ -115,7 +115,7 @@
 
   MockFetchContext(LoadPolicy load_policy)
       : load_policy_(load_policy),
-        runner_(base::AdoptRef(new scheduler::FakeWebTaskRunner)),
+        runner_(base::MakeRefCounted<scheduler::FakeWebTaskRunner>()),
         security_origin_(SecurityOrigin::CreateUnique()),
         frame_scheduler_(new MockFrameScheduler(runner_)),
         complete_(false),
diff --git a/third_party/WebKit/Source/platform/network/NetworkStateNotifierTest.cpp b/third_party/WebKit/Source/platform/network/NetworkStateNotifierTest.cpp
index 7da870d6..c5786cc 100644
--- a/third_party/WebKit/Source/platform/network/NetworkStateNotifierTest.cpp
+++ b/third_party/WebKit/Source/platform/network/NetworkStateNotifierTest.cpp
@@ -162,8 +162,8 @@
 class NetworkStateNotifierTest : public ::testing::Test {
  public:
   NetworkStateNotifierTest()
-      : task_runner_(base::AdoptRef(new FakeWebTaskRunner())),
-        task_runner2_(base::AdoptRef(new FakeWebTaskRunner())) {
+      : task_runner_(base::MakeRefCounted<FakeWebTaskRunner>()),
+        task_runner2_(base::MakeRefCounted<FakeWebTaskRunner>()) {
     // Initialize connection, so that future calls to setWebConnection issue
     // notifications.
     notifier_.SetWebConnection(kWebConnectionTypeUnknown, 0.0);
diff --git a/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.cc
index ae0c15f..fba7a9e 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.cc
@@ -23,9 +23,12 @@
     scoped_refptr<TaskQueue> v8_task_runner)
     : child_scheduler_(child_scheduler),
       idle_task_runner_(idle_task_runner),
-      loading_web_task_runner_(WebTaskRunnerImpl::Create(loading_task_runner)),
-      timer_web_task_runner_(WebTaskRunnerImpl::Create(timer_task_runner)),
-      v8_web_task_runner_(WebTaskRunnerImpl::Create(v8_task_runner)) {}
+      loading_web_task_runner_(
+          WebTaskRunnerImpl::Create(loading_task_runner, base::nullopt)),
+      timer_web_task_runner_(
+          WebTaskRunnerImpl::Create(timer_task_runner, base::nullopt)),
+      v8_web_task_runner_(
+          WebTaskRunnerImpl::Create(v8_task_runner, base::nullopt)) {}
 
 WebSchedulerImpl::~WebSchedulerImpl() {}
 
diff --git a/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.h b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.h
index 50b23fc..57b67159 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.h
@@ -24,7 +24,7 @@
  public:
   static scoped_refptr<WebTaskRunnerImpl> Create(
       scoped_refptr<TaskQueue> task_queue,
-      base::Optional<TaskType> task_type = base::nullopt);
+      base::Optional<TaskType> task_type);
 
   // WebTaskRunner implementation:
   bool RunsTasksInCurrentSequence() override;
diff --git a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
index fb2809d..af72e97 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
@@ -74,7 +74,7 @@
       worker_scheduler_->DefaultTaskQueue(),
       worker_scheduler_->DefaultTaskQueue()));
   base::MessageLoop::current()->AddDestructionObserver(this);
-  web_task_runner_ = WebTaskRunnerImpl::Create(task_queue_);
+  web_task_runner_ = WebTaskRunnerImpl::Create(task_queue_, base::nullopt);
   completion->Signal();
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.cc
index acce1f0b..faaa7856 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.cc
@@ -23,8 +23,9 @@
                        renderer_scheduler->TimerTaskQueue(),
                        renderer_scheduler->kV8TaskQueue()),
       renderer_scheduler_(renderer_scheduler),
-      compositor_task_runner_(WebTaskRunnerImpl::Create(
-          renderer_scheduler_->CompositorTaskQueue())) {}
+      compositor_task_runner_(
+          WebTaskRunnerImpl::Create(renderer_scheduler_->CompositorTaskQueue(),
+                                    base::nullopt)) {}
 
 RendererWebSchedulerImpl::~RendererWebSchedulerImpl() {}
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
index a4126a5..394d895 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
@@ -67,11 +67,11 @@
   }
 
   scoped_refptr<WebTaskRunner> ThrottleableTaskRunner() {
-    return WebTaskRunnerImpl::Create(ThrottleableTaskQueue());
+    return WebTaskRunnerImpl::Create(ThrottleableTaskQueue(), base::nullopt);
   }
 
   scoped_refptr<WebTaskRunner> LoadingTaskRunner() {
-    return WebTaskRunnerImpl::Create(LoadingTaskQueue());
+    return WebTaskRunnerImpl::Create(LoadingTaskQueue(), base::nullopt);
   }
 
   scoped_refptr<TaskQueue> ThrottleableTaskQueue() {
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
index 0822789..860a48b 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
@@ -20,8 +20,8 @@
       idle_task_runner_(scheduler->IdleTaskRunner()),
       scheduler_(scheduler),
       thread_id_(base::PlatformThread::CurrentId()),
-      web_task_runner_(
-          WebTaskRunnerImpl::Create(scheduler->DefaultTaskQueue())) {}
+      web_task_runner_(WebTaskRunnerImpl::Create(scheduler->DefaultTaskQueue(),
+                                                 base::nullopt)) {}
 
 WebThreadImplForRendererScheduler::~WebThreadImplForRendererScheduler() {}
 
diff --git a/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py b/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py
index 3fb63d8..e2ecca5 100755
--- a/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py
+++ b/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py
@@ -31,6 +31,7 @@
 
             # //base constructs that are allowed everywhere
             'base::AdoptRef',
+            'base::MakeRefCounted',
             'base::Optional',
             'base::SingleThreadTaskRunner',
             'base::UnguessableToken',
diff --git a/third_party/WebKit/public/platform/WebGraphicsContext3DProvider.h b/third_party/WebKit/public/platform/WebGraphicsContext3DProvider.h
index 63e579b..f475cf6d 100644
--- a/third_party/WebKit/public/platform/WebGraphicsContext3DProvider.h
+++ b/third_party/WebKit/public/platform/WebGraphicsContext3DProvider.h
@@ -73,7 +73,7 @@
   virtual void SetLostContextCallback(const base::Closure&) = 0;
   virtual void SetErrorMessageCallback(
       const base::Callback<void(const char* msg, int32_t id)>&) = 0;
-  virtual void SignalQuery(uint32_t, const base::Closure&) = 0;
+  virtual void SignalQuery(uint32_t, base::OnceClosure) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/web/WebSettings.h b/third_party/WebKit/public/web/WebSettings.h
index 5a9b757b..c8b21e71 100644
--- a/third_party/WebKit/public/web/WebSettings.h
+++ b/third_party/WebKit/public/web/WebSettings.h
@@ -67,13 +67,6 @@
     kV8CacheOptionsCode,
   };
 
-  enum class V8CacheStrategiesForCacheStorage {
-    kDefault,
-    kNone,
-    kNormal,
-    kAggressive,
-  };
-
   enum class ProgressBarCompletion {
     kLoadEvent,
     kResourcesBeforeDCL,
@@ -291,8 +284,6 @@
   virtual void SetUseSolidColorScrollbars(bool) = 0;
   virtual void SetUseWideViewport(bool) = 0;
   virtual void SetV8CacheOptions(V8CacheOptions) = 0;
-  virtual void SetV8CacheStrategiesForCacheStorage(
-      V8CacheStrategiesForCacheStorage) = 0;
   virtual void SetValidationMessageTimerMagnification(int) = 0;
   virtual void SetViewportEnabled(bool) = 0;
   virtual void SetViewportMetaEnabled(bool) = 0;
diff --git a/third_party/openvr/BUILD.gn b/third_party/openvr/BUILD.gn
index 7689a3c7..276b947 100644
--- a/third_party/openvr/BUILD.gn
+++ b/third_party/openvr/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-shared_library("openvr") {
+component("openvr") {
   output_name = "openvr_api"
 
   # Some ascii versions of Windows APIs are used in this code.
diff --git a/third_party/openvr/README.chromium b/third_party/openvr/README.chromium
index 94f2014..e28526f 100644
--- a/third_party/openvr/README.chromium
+++ b/third_party/openvr/README.chromium
@@ -14,6 +14,8 @@
 Local Modifications:
 Only contains a subset of the git repo necessary to build Chromium.  jsoncpp.cpp
 has been modified to remove exceptions.
+openvr.h has been modified to remove dllimport/dllexport when building a
+non-component build so this can be built as a static library.
 
 Copy the correct files with these commands:
 copy %openvrsdk%\README.md %chromium%\src\third_party\openvr\src
diff --git a/third_party/openvr/src/headers/openvr.h b/third_party/openvr/src/headers/openvr.h
index 19f2a0b..99e6a6f 100644
--- a/third_party/openvr/src/headers/openvr.h
+++ b/third_party/openvr/src/headers/openvr.h
@@ -1141,23 +1141,30 @@
 #pragma pack( pop )
 
 // figure out how to import from the VR API dll
+// for COMPONENT_BUILD
 #if defined(_WIN32)
 
+#if defined(COMPONENT_BUILD)
+
 #ifdef VR_API_EXPORT
 #define VR_INTERFACE extern "C" __declspec( dllexport )
 #else
 #define VR_INTERFACE extern "C" __declspec( dllimport )
-#endif
+#endif // VR_API_EXPORT
+
+#else // !defined(COMPONENT_BUILD)
+#define VR_INTERFACE extern "C"
+#endif // COMPONENT_BUILD
 
 #elif defined(__GNUC__) || defined(COMPILER_GCC) || defined(__APPLE__)
 
-#ifdef VR_API_EXPORT
+#if defined(VR_API_EXPORT) && defined(COMPONENT_BUILD)
 #define VR_INTERFACE extern "C" __attribute__((visibility("default")))
 #else
 #define VR_INTERFACE extern "C" 
-#endif
+#endif // defined(VR_API_EXPORT) && defined(COMPONENT_BUILD)
 
-#else
+#else // !defined(_WIN32) && !(defined(__GNUC__) || defined(COMPILER_GCC) || ...
 #error "Unsupported Platform."
 #endif
 
diff --git a/third_party/opus/README.chromium b/third_party/opus/README.chromium
index d1ff674..299bd39 100644
--- a/third_party/opus/README.chromium
+++ b/third_party/opus/README.chromium
@@ -14,3 +14,4 @@
 Local changes:
 * copy .gitignore from https://git.xiph.org/?p=opus.git;a=tree
 * set 'x' flags: "chmod 750 win32/genversion.bat"
+* Apply https://git.xiph.org/?p=opus.git;a=commitdiff;h=46560534fcb5710a894a341c2f9526db58fd7087#patch1
diff --git a/third_party/opus/src/include/opus_types.h b/third_party/opus/src/include/opus_types.h
index 7180826..7cf6755 100644
--- a/third_party/opus/src/include/opus_types.h
+++ b/third_party/opus/src/include/opus_types.h
@@ -33,14 +33,29 @@
 #ifndef OPUS_TYPES_H
 #define OPUS_TYPES_H
 
+#define opus_int         int                     /* used for counters etc; at least 16 bits */
+#define opus_int64       long long
+#define opus_int8        signed char
+
+#define opus_uint        unsigned int            /* used for counters etc; at least 16 bits */
+#define opus_uint64      unsigned long long
+#define opus_uint8       unsigned char
+
 /* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */
 #if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H))
 #include <stdint.h>
-
+#  undef opus_int64
+#  undef opus_int8
+#  undef opus_uint64
+#  undef opus_uint8
+   typedef int8_t opus_int8;
+   typedef uint8_t opus_uint8;
    typedef int16_t opus_int16;
    typedef uint16_t opus_uint16;
    typedef int32_t opus_int32;
    typedef uint32_t opus_uint32;
+   typedef int64_t opus_int64;
+   typedef uint64_t opus_uint64;
 #elif defined(_WIN32)
 
 #  if defined(__CYGWIN__)
@@ -148,12 +163,4 @@
 
 #endif
 
-#define opus_int         int                     /* used for counters etc; at least 16 bits */
-#define opus_int64       long long
-#define opus_int8        signed char
-
-#define opus_uint        unsigned int            /* used for counters etc; at least 16 bits */
-#define opus_uint64      unsigned long long
-#define opus_uint8       unsigned char
-
 #endif  /* OPUS_TYPES_H */
diff --git a/third_party/robolectric/BUILD.gn b/third_party/robolectric/BUILD.gn
index a83966f..cdeac428 100644
--- a/third_party/robolectric/BUILD.gn
+++ b/third_party/robolectric/BUILD.gn
@@ -670,7 +670,6 @@
   deps = [
     ":android-all-o-preview-4-robolectric-0_java",
     ":robolectric_annotations_java",
-    ":robolectric_processor_java",
     ":robolectric_resources_java",
     ":robolectric_shadowapi_java",
     ":robolectric_utils_java",
@@ -686,6 +685,7 @@
     "//third_party/intellij:intellij_annotations_java",
     "//third_party/sqlite4java:sqlite4java_java",
   ]
+  classpath_deps = [ ":robolectric_processor_java" ]
 
   # Work-around for gradle generator not yet supporting annotation processors.
   gradle_treat_as_prebuilt = true
@@ -706,10 +706,10 @@
     "robolectric/shadows/multidex/src/main/java/org/robolectric/shadows/multidex/package-info.java",
   ]
 
+  classpath_deps = [ ":robolectric_processor_java" ]
   deps = [
     ":android-all-o-preview-4-robolectric-0_java",
     ":robolectric_annotations_java",
-    ":robolectric_processor_java",
     ":robolectric_shadowapi_java",
     ":robolectric_utils_java",
     ":shadows_core_java",
@@ -740,10 +740,10 @@
     "robolectric/shadows/playservices/src/main/java/org/robolectric/shadows/gms/package-info.java",
   ]
 
+  classpath_deps = [ ":robolectric_processor_java" ]
   deps = [
     ":android-all-o-preview-4-robolectric-0_java",
     ":robolectric_annotations_java",
-    ":robolectric_processor_java",
     ":robolectric_resources_java",
     ":robolectric_shadowapi_java",
     ":robolectric_utils_java",
diff --git a/third_party/robolectric/OWNERS b/third_party/robolectric/OWNERS
index 2cfd26c3..3d7d347 100644
--- a/third_party/robolectric/OWNERS
+++ b/third_party/robolectric/OWNERS
@@ -1,3 +1,3 @@
+agrieve@chromium.org
 jbudorick@chromium.org
-mikecase@chromium.org
 yolandyan@chromium.org
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 5f87b1c..66f1371 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -24595,6 +24595,7 @@
   <int value="-1302904242" label="enable-navigation-tracing"/>
   <int value="-1294050129" label="ContentFullscreen:disabled"/>
   <int value="-1289678848" label="SystemDownloadManager:enabled"/>
+  <int value="-1288130734" label="OpenVR:disabled"/>
   <int value="-1285021473" label="save-page-as-mhtml"/>
   <int value="-1284637134" label="pull-to-refresh"/>
   <int value="-1276912933" label="enable-quick-unlock-pin"/>
@@ -25747,6 +25748,7 @@
   <int value="1928407249" label="NewPhotoPicker:enabled"/>
   <int value="1930901873" label="disable-sync-app-list"/>
   <int value="1931309368" label="fill-on-account-select:disabled"/>
+  <int value="1932732886" label="OpenVR:enabled"/>
   <int value="1936810062" label="WebVrVsyncAlign:enabled"/>
   <int value="1939413645" label="enable-invalid-cert-collection"/>
   <int value="1942911276" label="enable-grouped-history"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 37021cd..c313281d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -38222,6 +38222,11 @@
 </histogram>
 
 <histogram name="MultiProfile.DiscardedTabsPerUser">
+  <obsolete>
+    Deprecated 11/2017. Analysis confirms that the number of discards increases
+    with the number of logged in users. No action will be taken based on this
+    information.
+  </obsolete>
   <owner>skuhne@chromium.org</owner>
   <summary>
     The relation of discarded tabs vs. the amount of simultaneous users. The
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index 1f739cd..dff14cb 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -98,11 +98,9 @@
 thread_times.tough_scrolling_cases,tdresser@chromium.org,
 tracing.tracing_with_background_memory_infra,ssid@chromium.org,
 tracing_perftests,"kkraynov@chromium.org, primiano@chromium.org",
-v8.browsing_desktop,ulan@chromium.org,
-v8.browsing_mobile,ulan@chromium.org,
+v8.browsing_desktop,"mythria@chromium.org, ulan@chromium.org",
+v8.browsing_mobile,"mythria@chromium.org, ulan@chromium.org",
 v8.detached_context_age_in_gc,ulan@chromium.org,
 v8.runtime_stats.top_25,cbruni@chromium.org,
-v8.runtimestats.browsing_desktop,mythria@chromium.org,
-v8.runtimestats.browsing_mobile,mythria@chromium.org,
 validating_command_buffer_perftests,"piman@chromium.org, chrome-gpu-perf-owners@chromium.org",Internals>GPU
 webrtc,"qiangchen@chromium.org, ehmaldonado@chromium.org, phoglund@chromium.org",
diff --git a/tools/perf/benchmarks/v8_browsing.py b/tools/perf/benchmarks/v8_browsing.py
index 5a3fcd3..68f8251 100644
--- a/tools/perf/benchmarks/v8_browsing.py
+++ b/tools/perf/benchmarks/v8_browsing.py
@@ -31,76 +31,15 @@
     r'total_)')
 
 
-class _v8BrowsingBenchmarkBaseClass(perf_benchmark.PerfBenchmark):
-  """Base class for all v8 browsing benchmarks."""
+class _V8BrowsingBenchmark(perf_benchmark.PerfBenchmark):
+  """Base class for V8 browsing benchmarks that measure RuntimeStats,
+  eqt, gc and memory metrics.
+  See browsing_stories._BrowsingStory for workload description.
+  """
+
   def CreateStorySet(self, options):
     return page_sets.SystemHealthStorySet(platform=self.PLATFORM, case='browse')
 
-
-class _V8BrowsingBenchmark(_v8BrowsingBenchmarkBaseClass):
-  """Base class for V8 browsing benchmarks.
-  This benchmark measures memory usage with periodic memory dumps and v8 times.
-  See browsing_stories._BrowsingStory for workload description.
-  """
-
-  def CreateCoreTimelineBasedMeasurementOptions(self):
-    categories = [
-      # Disable all categories by default.
-      '-*',
-      # Memory categories.
-      'disabled-by-default-memory-infra',
-      # EQT categories.
-      'blink.user_timing',
-      'loading',
-      'navigation',
-      'toplevel',
-      # V8 categories.
-      'blink.console',
-      'disabled-by-default-v8.compile',
-      'disabled-by-default-v8.gc',
-      'renderer.scheduler',
-      'v8',
-      'webkit.console',
-      # TODO(crbug.com/616441, primiano): Remove this temporary workaround,
-      # which enables memory-infra V8 code stats in V8 code size benchmarks
-      # only (to not slow down detailed memory dumps in other benchmarks).
-      'disabled-by-default-memory-infra.v8.code_stats',
-      # Blink categories.
-      'blink_gc',
-    ]
-    options = timeline_based_measurement.Options(
-        chrome_trace_category_filter.ChromeTraceCategoryFilter(
-            ','.join(categories)))
-    options.config.enable_android_graphics_memtrack = True
-    # Trigger periodic light memory dumps every 1000 ms.
-    memory_dump_config = chrome_trace_config.MemoryDumpConfig()
-    memory_dump_config.AddTrigger('light', 1000)
-    options.config.chrome_trace_config.SetMemoryDumpConfig(memory_dump_config)
-    options.SetTimelineBasedMetrics([
-      'expectedQueueingTimeMetric', 'v8AndMemoryMetrics', 'blinkGcMetric'])
-    return options
-
-  @classmethod
-  def ValueCanBeAddedPredicate(cls, value, is_first_result):
-    # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard
-    # is able to cope with the data load generated by TBMv2 metrics.
-    if 'memory:chrome' in value.name:
-      return ('renderer_processes' in value.name and
-              not _IGNORED_MEMORY_STATS_RE.search(value.name))
-    if 'v8-gc' in value.name:
-      return (_V8_GC_HIGH_LEVEL_STATS_RE.search(value.name) and
-              not _IGNORED_V8_STATS_RE.search(value.name))
-    # Allow all other metrics.
-    return True
-
-
-class _V8RuntimeStatsBrowsingBenchmark(_v8BrowsingBenchmarkBaseClass):
-  """Base class for V8 browsing benchmarks that measure RuntimeStats.
-  RuntimeStats measure the time spent by v8 in different phases like
-  compile, JS execute, runtime etc.,
-  See browsing_stories._BrowsingStory for workload description.
-  """
-
   def CreateCoreTimelineBasedMeasurementOptions(self):
     categories = [
       # Disable all categories by default.
@@ -162,74 +101,9 @@
     return True
 
 
-
-@benchmark.Owner(emails=['ulan@chromium.org'])
-class V8DesktopBrowsingBenchmark(_V8BrowsingBenchmark):
-  PLATFORM = 'desktop'
-  SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP]
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-             'browse:news:hackernews',
-             [story.expectations.ALL_WIN, story.expectations.ALL_MAC],
-             'crbug.com/676336')
-        self.DisableStory(
-             'browse:news:cnn',
-             [story.expectations.ALL_MAC],
-             'mac:crbug.com/728576')
-        self.DisableStory(
-             'browse:tools:maps',
-             [story.expectations.ALL_MAC],
-             'crbug.com/773084')
-    return StoryExpectations()
-
-  @classmethod
-  def Name(cls):
-    return 'v8.browsing_desktop'
-
-
-@benchmark.Owner(emails=['ulan@chromium.org'])
-class V8MobileBrowsingBenchmark(_V8BrowsingBenchmark):
-  PLATFORM = 'mobile'
-  SUPPORTED_PLATFORMS = [story.expectations.ALL_MOBILE]
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-             'browse:shopping:flipkart',
-             [story.expectations.ALL_ANDROID],
-             'crbug.com/708300')
-        self.DisableStory(
-             'browse:news:globo',
-             [story.expectations.ALL_ANDROID],
-             'crbug.com/714650')
-        self.DisableStory(
-             'browse:news:toi',
-             [story.expectations.ALL_ANDROID],
-             'crbug.com/728081')
-        # TODO(rnephew): This disabling should move to CanRunOnBrowser.
-        self.DisableStory(
-             'browse:chrome:omnibox',
-             [story.expectations.ANDROID_WEBVIEW],
-             'Webview does not have omnibox')
-        # TODO(rnephew): This disabling should move to CanRunOnBrowser.
-        self.DisableStory(
-             'browse:chrome:newtab',
-             [story.expectations.ANDROID_WEBVIEW],
-             'Webview does not have NTP')
-    return StoryExpectations()
-
-  @classmethod
-  def Name(cls):
-    return 'v8.browsing_mobile'
-
-
-@benchmark.Owner(emails=['mythria@chromium.org'])
-class V8RuntimeStatsDesktopBrowsingBenchmark(
-    _V8RuntimeStatsBrowsingBenchmark):
+@benchmark.Owner(emails=['mythria@chromium.org','ulan@chromium.org'])
+class V8DesktopBrowsingBenchmark(
+    _V8BrowsingBenchmark):
   PLATFORM = 'desktop'
   SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP]
 
@@ -256,12 +130,12 @@
 
   @classmethod
   def Name(cls):
-    return 'v8.runtimestats.browsing_desktop'
+    return 'v8.browsing_desktop'
 
 
-@benchmark.Owner(emails=['mythria@chromium.org'])
-class V8RuntimeStatsMobileBrowsingBenchmark(
-    _V8RuntimeStatsBrowsingBenchmark):
+@benchmark.Owner(emails=['mythria@chromium.org','ulan@chromium.org'])
+class V8MobileBrowsingBenchmark(
+    _V8BrowsingBenchmark):
   PLATFORM = 'mobile'
   SUPPORTED_PLATFORMS = [story.expectations.ALL_MOBILE]
 
@@ -314,4 +188,4 @@
 
   @classmethod
   def Name(cls):
-    return 'v8.runtimestats.browsing_mobile'
+    return 'v8.browsing_mobile'
diff --git a/ui/PRESUBMIT.py b/ui/PRESUBMIT.py
index ce355c8..105c536 100644
--- a/ui/PRESUBMIT.py
+++ b/ui/PRESUBMIT.py
@@ -51,7 +51,7 @@
 
   source_file_filter = lambda x: input_api.FilterSourceFile(
     x,
-    white_list=tuple([r'.*ui.(aura|events|gfx|gl)..*\.(cc|h)$']))
+    white_list=tuple([r'.*ui.(aura|events|gfx|gl|views)..*\.(cc|h)$']))
   errors = []
   x11_include_pattern = input_api.re.compile(r'#include\s+<X11/.*\.h>')
   for f in input_api.AffectedSourceFiles(source_file_filter):
diff --git a/ui/accessibility/ax_node_position_unittest.cc b/ui/accessibility/ax_node_position_unittest.cc
index 419777ca..326c7ce 100644
--- a/ui/accessibility/ax_node_position_unittest.cc
+++ b/ui/accessibility/ax_node_position_unittest.cc
@@ -747,7 +747,27 @@
   EXPECT_EQ(tree_.data().tree_id, test_position->tree_id());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(1, test_position->text_offset());
-  EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity());
+  // Even though upstream affinity doesn't make sense on a leaf node, there is
+  // no need to reset it to downstream.
+  EXPECT_EQ(AX_TEXT_AFFINITY_UPSTREAM, test_position->affinity());
+
+  // Create a text position on the root, pointing to the line break character
+  // inside the text field but with an upstream affinity which will cause the
+  // leaf text position to be placed after the text of the first inline text
+  // box.
+  text_position = AXNodePosition::CreateTextPosition(
+      tree_.data().tree_id, root_.id, 21 /* text_offset */,
+      AX_TEXT_AFFINITY_UPSTREAM);
+  ASSERT_NE(nullptr, text_position);
+  test_position = text_position->AsLeafTextPosition();
+  ASSERT_NE(nullptr, test_position);
+  EXPECT_TRUE(test_position->IsTextPosition());
+  EXPECT_EQ(tree_.data().tree_id, test_position->tree_id());
+  EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
+  EXPECT_EQ(6, test_position->text_offset());
+  // Even though upstream affinity doesn't make sense on a leaf node, there is
+  // no need to reset it to downstream.
+  EXPECT_EQ(AX_TEXT_AFFINITY_UPSTREAM, test_position->affinity());
 
   // Create a text position pointing to the line break character inside the text
   // field but with an upstream affinity which will cause the leaf text position
@@ -762,6 +782,22 @@
   EXPECT_EQ(tree_.data().tree_id, test_position->tree_id());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
+  // Even though upstream affinity doesn't make sense on a leaf node, there is
+  // no need to reset it to downstream.
+  EXPECT_EQ(AX_TEXT_AFFINITY_UPSTREAM, test_position->affinity());
+
+  // Create a text position on the root, pointing to the line break character
+  // inside the text field.
+  text_position = AXNodePosition::CreateTextPosition(
+      tree_.data().tree_id, root_.id, 21 /* text_offset */,
+      AX_TEXT_AFFINITY_DOWNSTREAM);
+  ASSERT_NE(nullptr, text_position);
+  test_position = text_position->AsLeafTextPosition();
+  ASSERT_NE(nullptr, test_position);
+  EXPECT_TRUE(test_position->IsTextPosition());
+  EXPECT_EQ(tree_.data().tree_id, test_position->tree_id());
+  EXPECT_EQ(line_break_.id, test_position->anchor_id());
+  EXPECT_EQ(0, test_position->text_offset());
   EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity());
 
   // Create a text position pointing to the line break character inside the text
diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h
index 58c3d23..7f8af93b 100644
--- a/ui/accessibility/ax_position.h
+++ b/ui/accessibility/ax_position.h
@@ -457,6 +457,10 @@
 
     child_position = child_position->AsTextPosition();
     child_position->text_offset_ = adjusted_offset;
+    // Maintain affinity from parent so that we'll be able to choose the correct
+    // leaf anchor if the text offset is right on the boundary between two
+    // leaves.
+    child_position->affinity_ = affinity_;
     return child_position->AsLeafTextPosition();
   }
 
diff --git a/ui/aura/env.cc b/ui/aura/env.cc
index 2c101c0..08d1d4d 100644
--- a/ui/aura/env.cc
+++ b/ui/aura/env.cc
@@ -145,11 +145,6 @@
   window_tree_client_ = window_tree_client;
 }
 
-ui::Gpu* Env::GetGpuConnection() {
-  DCHECK(window_tree_client_);
-  return window_tree_client_->gpu();
-}
-
 void Env::ScheduleEmbed(
     ui::mojom::WindowTreeClientPtr client,
     base::OnceCallback<void(const base::UnguessableToken&)> callback) {
diff --git a/ui/aura/env.h b/ui/aura/env.h
index 1882bf0..52b2c9e 100644
--- a/ui/aura/env.h
+++ b/ui/aura/env.h
@@ -40,7 +40,6 @@
 namespace ui {
 class ContextFactory;
 class ContextFactoryPrivate;
-class Gpu;
 class PlatformEventSource;
 namespace mojom {
 class WindowTreeClient;
@@ -130,8 +129,6 @@
   void SetWindowTreeClient(WindowTreeClient* window_tree_client);
   bool HasWindowTreeClient() const { return window_tree_client_ != nullptr; }
 
-  ui::Gpu* GetGpuConnection();
-
   // Schedules an embed of a client. See
   // mojom::WindowTreeClient::ScheduleEmbed() for details.
   void ScheduleEmbed(
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h
index 8a1a136..0aacfd4 100644
--- a/ui/aura/mus/window_tree_client.h
+++ b/ui/aura/mus/window_tree_client.h
@@ -191,8 +191,6 @@
   void AddTestObserver(WindowTreeClientTestObserver* observer);
   void RemoveTestObserver(WindowTreeClientTestObserver* observer);
 
-  ui::Gpu* gpu() { return gpu_.get(); }
-
  private:
   friend class InFlightBoundsChange;
   friend class InFlightFocusChange;
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index a7505ef..71942eeb 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -41,6 +41,7 @@
 #include "ui/aura/window_tree_host.h"
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animator.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 #include "ui/events/event_target_iterator.h"
@@ -1159,6 +1160,14 @@
 }
 
 std::unique_ptr<ui::Layer> Window::RecreateLayer() {
+  WindowOcclusionTracker::ScopedPauseOcclusionTracking pause_occlusion_tracking;
+
+  ui::LayerAnimator* const animator = layer()->GetAnimator();
+  const bool was_animating_opacity =
+      animator->IsAnimatingProperty(ui::LayerAnimationElement::OPACITY);
+  const bool was_animating_transform =
+      animator->IsAnimatingProperty(ui::LayerAnimationElement::TRANSFORM);
+
   std::unique_ptr<ui::Layer> old_layer = LayerOwner::RecreateLayer();
 
   // If a frame sink is attached to the window, then allocate a new surface
@@ -1167,6 +1176,24 @@
   if (GetFrameSinkId().is_valid() && old_layer)
     AllocateLocalSurfaceId();
 
+  // Observers are guaranteed to be notified when an opacity or transform
+  // animation ends.
+  if (was_animating_opacity) {
+    for (WindowObserver& observer : observers_) {
+      observer.OnWindowOpacityChanged(this,
+                                      ui::PropertyChangeReason::FROM_ANIMATION);
+    }
+  }
+  if (was_animating_transform) {
+    for (WindowObserver& observer : observers_) {
+      observer.OnWindowTransformed(this,
+                                   ui::PropertyChangeReason::FROM_ANIMATION);
+    }
+  }
+
+  for (WindowObserver& observer : observers_)
+    observer.OnWindowLayerRecreated(this);
+
   return old_layer;
 }
 
diff --git a/ui/aura/window_observer.h b/ui/aura/window_observer.h
index 9d830db..5d63785 100644
--- a/ui/aura/window_observer.h
+++ b/ui/aura/window_observer.h
@@ -146,6 +146,14 @@
   // Called when the window title has changed.
   virtual void OnWindowTitleChanged(Window* window) {}
 
+  // Called when the window's layer is recreated. The new layer may not carry
+  // animations from the old layer and animation observers attached to the old
+  // layer won't automatically be attached to the new layer. Clients that need
+  // to know when window animations end should implement this method and call
+  // window->layer()->GetAnimator()->
+  // (is_animating|IsAnimatingProperty|IsAnimatingOnePropertyOf)() from it.
+  virtual void OnWindowLayerRecreated(Window* window) {}
+
   // Called when the app embedded in |window| disconnects (is no longer
   // embedded).
   virtual void OnEmbeddedAppDisconnected(Window* window);
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc
index e53c6dad..3931fe05 100644
--- a/ui/aura/window_unittest.cc
+++ b/ui/aura/window_unittest.cc
@@ -37,6 +37,7 @@
 #include "ui/base/hit_test.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_animation_observer.h"
+#include "ui/compositor/layer_animator.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/compositor/test/layer_animator_test_controller.h"
@@ -1777,14 +1778,13 @@
         ui::PropertyChangeReason::NOT_FROM_ANIMATION;
   };
 
-  WindowObserverTest()
-      : added_count_(0),
-        removed_count_(0),
-        destroyed_count_(0),
-        old_property_value_(-3) {
-  }
+  struct LayerRecreatedInfo {
+    int count = 0;
+    Window* window = nullptr;
+  };
 
-  ~WindowObserverTest() override {}
+  WindowObserverTest() = default;
+  ~WindowObserverTest() override = default;
 
   const VisibilityInfo* GetVisibilityInfo() const {
     return visibility_info_.get();
@@ -1807,6 +1807,10 @@
     return window_transformed_info_;
   }
 
+  const LayerRecreatedInfo& layer_recreated_info() const {
+    return layer_recreated_info_;
+  }
+
   void ResetVisibilityInfo() {
     visibility_info_.reset();
   }
@@ -1894,17 +1898,23 @@
     window_transformed_info_.reason = reason;
   }
 
-  int added_count_;
-  int removed_count_;
-  int destroyed_count_;
+  void OnWindowLayerRecreated(Window* window) override {
+    ++layer_recreated_info_.count;
+    layer_recreated_info_.window = window;
+  }
+
+  int added_count_ = 0;
+  int removed_count_ = 0;
+  int destroyed_count_ = 0;
   std::unique_ptr<VisibilityInfo> visibility_info_;
-  const void* property_key_;
-  intptr_t old_property_value_;
+  const void* property_key_ = nullptr;
+  intptr_t old_property_value_ = -3;
   std::vector<std::pair<int, int> > transform_notifications_;
   WindowBoundsInfo window_bounds_info_;
   WindowOpacityInfo window_opacity_info_;
   WindowTargetTransformChangingInfo window_target_transform_changing_info_;
   WindowTransformedInfo window_transformed_info_;
+  LayerRecreatedInfo layer_recreated_info_;
 
   DISALLOW_COPY_AND_ASSIGN(WindowObserverTest);
 };
@@ -2175,6 +2185,64 @@
             window_transformed_info().reason);
 }
 
+TEST_P(WindowObserverTest, OnWindowLayerRecreated) {
+  std::unique_ptr<Window> window(CreateTestWindowWithId(1, root_window()));
+  window->AddObserver(this);
+
+  EXPECT_EQ(0, layer_recreated_info().count);
+  std::unique_ptr<ui::Layer> old_layer = window->RecreateLayer();
+  EXPECT_EQ(1, layer_recreated_info().count);
+  EXPECT_EQ(window.get(), layer_recreated_info().window);
+}
+
+TEST_P(WindowObserverTest, OnWindowLayerRecreatedWithOpacityAnimation) {
+  std::unique_ptr<Window> window(CreateTestWindowWithId(1, root_window()));
+
+  ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
+      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+  ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
+  window->layer()->SetOpacity(0.5);
+  EXPECT_TRUE(window->layer()->GetAnimator()->IsAnimatingProperty(
+      ui::LayerAnimationElement::OPACITY));
+
+  window->AddObserver(this);
+
+  EXPECT_EQ(0, layer_recreated_info().count);
+  EXPECT_EQ(0, window_opacity_info().changed_count);
+  std::unique_ptr<ui::Layer> old_layer = window->RecreateLayer();
+  EXPECT_EQ(1, layer_recreated_info().count);
+  EXPECT_EQ(window.get(), layer_recreated_info().window);
+  EXPECT_EQ(1, window_opacity_info().changed_count);
+  EXPECT_EQ(window.get(), window_opacity_info().window);
+  EXPECT_EQ(ui::PropertyChangeReason::FROM_ANIMATION,
+            window_opacity_info().reason);
+}
+
+TEST_P(WindowObserverTest, OnWindowLayerRecreatedWithTransformAnimation) {
+  std::unique_ptr<Window> window(CreateTestWindowWithId(1, root_window()));
+
+  ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
+      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+  ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
+  gfx::Transform target_transform;
+  target_transform.Skew(10.0, 5.0);
+  window->SetTransform(target_transform);
+  EXPECT_TRUE(window->layer()->GetAnimator()->IsAnimatingProperty(
+      ui::LayerAnimationElement::TRANSFORM));
+
+  window->AddObserver(this);
+
+  EXPECT_EQ(0, layer_recreated_info().count);
+  EXPECT_EQ(0, window_transformed_info().changed_count);
+  std::unique_ptr<ui::Layer> old_layer = window->RecreateLayer();
+  EXPECT_EQ(1, layer_recreated_info().count);
+  EXPECT_EQ(window.get(), layer_recreated_info().window);
+  EXPECT_EQ(1, window_transformed_info().changed_count);
+  EXPECT_EQ(window.get(), window_transformed_info().window);
+  EXPECT_EQ(ui::PropertyChangeReason::FROM_ANIMATION,
+            window_transformed_info().reason);
+}
+
 TEST_P(WindowTest, AcquireLayer) {
   std::unique_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
   std::unique_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
diff --git a/ui/gfx/font_fallback_linux.cc b/ui/gfx/font_fallback_linux.cc
index 10e266a4..9c2e99c 100644
--- a/ui/gfx/font_fallback_linux.cc
+++ b/ui/gfx/font_fallback_linux.cc
@@ -19,15 +19,15 @@
 
 namespace {
 
+const char kFontFormatTrueType[] = "TrueType";
+const char kFontFormatCFF[] = "CFF";
+
 typedef std::map<std::string, std::vector<Font> > FallbackCache;
 base::LazyInstance<FallbackCache>::Leaky g_fallback_cache =
     LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
 
-const char* kFontFormatTrueType = "TrueType";
-const char* kFontFormatCFF = "CFF";
-
 std::vector<Font> GetFallbackFonts(const Font& font) {
   std::string font_family = font.GetFontName();
   std::vector<Font>* fallback_fonts =
@@ -218,8 +218,9 @@
       // Take only supported font formats on board.
       FcChar8* font_format;
       if (FcPatternGetString(pattern, FC_FONTFORMAT, 0, &font_format) !=
-          FcResultMatch)
+          FcResultMatch) {
         continue;
+      }
       if (font_format &&
           strcmp(reinterpret_cast<char*>(font_format), kFontFormatTrueType) &&
           strcmp(reinterpret_cast<char*>(font_format), kFontFormatCFF)) {
diff --git a/ui/gfx/font_fallback_linux_unittest.cc b/ui/gfx/font_fallback_linux_unittest.cc
index 61485aa..801ccb8 100644
--- a/ui/gfx/font_fallback_linux_unittest.cc
+++ b/ui/gfx/font_fallback_linux_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 40a58d1..9389f25 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -55,7 +55,6 @@
 #include "ui/views/controls/menu/menu_pre_target_handler.h"
 #endif
 
-using base::Time;
 using base::TimeDelta;
 using ui::OSExchangeData;
 
diff --git a/ui/views/style/typography_provider.cc b/ui/views/style/typography_provider.cc
index e9089e3..a66e387 100644
--- a/ui/views/style/typography_provider.cc
+++ b/ui/views/style/typography_provider.cc
@@ -16,35 +16,33 @@
 #include "base/mac/mac_util.h"
 #endif
 
-using gfx::Font;
-
 namespace views {
 namespace {
 
-Font::Weight GetValueBolderThan(Font::Weight weight) {
+gfx::Font::Weight GetValueBolderThan(gfx::Font::Weight weight) {
   switch (weight) {
-    case Font::Weight::BOLD:
-      return Font::Weight::EXTRA_BOLD;
-    case Font::Weight::EXTRA_BOLD:
-    case Font::Weight::BLACK:
-      return Font::Weight::BLACK;
+    case gfx::Font::Weight::BOLD:
+      return gfx::Font::Weight::EXTRA_BOLD;
+    case gfx::Font::Weight::EXTRA_BOLD:
+    case gfx::Font::Weight::BLACK:
+      return gfx::Font::Weight::BLACK;
     default:
-      return Font::Weight::BOLD;
+      return gfx::Font::Weight::BOLD;
   }
 }
 
 }  // namespace
 
 // static
-Font::Weight TypographyProvider::MediumWeightForUI() {
+gfx::Font::Weight TypographyProvider::MediumWeightForUI() {
 #if defined(OS_MACOSX)
   // System fonts are not user-configurable on Mac, so there's a simpler check.
   // However, 10.9 and 10.11 do not ship with a MEDIUM weight system font.  In
   // that case, trying to use MEDIUM there will give a bold font, which will
   // look worse with the surrounding NORMAL text than just using NORMAL.
   return (base::mac::IsOS10_9() || base::mac::IsOS10_11())
-             ? Font::Weight::NORMAL
-             : Font::Weight::MEDIUM;
+             ? gfx::Font::Weight::NORMAL
+             : gfx::Font::Weight::MEDIUM;
 #else
   // NORMAL may already have at least MEDIUM weight. Return NORMAL in that case
   // since trying to return MEDIUM would actually make the font lighter-weight
@@ -52,20 +50,20 @@
   // BOLD font for dialog text; deriving MEDIUM from that would replace the BOLD
   // attribute with something lighter.
   if (ui::ResourceBundle::GetSharedInstance()
-          .GetFontListWithDelta(0, Font::NORMAL, Font::Weight::NORMAL)
-          .GetFontWeight() < Font::Weight::MEDIUM)
-    return Font::Weight::MEDIUM;
-  return Font::Weight::NORMAL;
+          .GetFontListWithDelta(0, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL)
+          .GetFontWeight() < gfx::Font::Weight::MEDIUM)
+    return gfx::Font::Weight::MEDIUM;
+  return gfx::Font::Weight::NORMAL;
 #endif
 }
 
 const gfx::FontList& DefaultTypographyProvider::GetFont(int context,
                                                         int style) const {
   int size_delta;
-  Font::Weight font_weight;
+  gfx::Font::Weight font_weight;
   GetDefaultFont(context, style, &size_delta, &font_weight);
   return ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
-      size_delta, Font::NORMAL, font_weight);
+      size_delta, gfx::Font::NORMAL, font_weight);
 }
 
 SkColor DefaultTypographyProvider::GetColor(const views::View& view,
@@ -106,8 +104,8 @@
 void DefaultTypographyProvider::GetDefaultFont(int context,
                                                int style,
                                                int* size_delta,
-                                               Font::Weight* font_weight) {
-  *font_weight = Font::Weight::NORMAL;
+                                               gfx::Font::Weight* font_weight) {
+  *font_weight = gfx::Font::Weight::NORMAL;
 
   switch (context) {
     case style::CONTEXT_BUTTON_MD:
@@ -127,14 +125,15 @@
 
   switch (style) {
     case style::STYLE_TAB_ACTIVE:
-      *font_weight = Font::Weight::BOLD;
+      *font_weight = gfx::Font::Weight::BOLD;
       break;
     case style::STYLE_DIALOG_BUTTON_DEFAULT:
       // Only non-MD default buttons should "increase" in boldness.
       if (context == style::CONTEXT_BUTTON) {
         *font_weight = GetValueBolderThan(
             ui::ResourceBundle::GetSharedInstance()
-                .GetFontListWithDelta(*size_delta, Font::NORMAL, *font_weight)
+                .GetFontListWithDelta(*size_delta, gfx::Font::NORMAL,
+                                      *font_weight)
                 .GetFontWeight());
       }
       break;
diff --git a/ui/views/test/widget_test_aura.cc b/ui/views/test/widget_test_aura.cc
index d4445d6..c365eea8 100644
--- a/ui/views/test/widget_test_aura.cc
+++ b/ui/views/test/widget_test_aura.cc
@@ -15,7 +15,7 @@
 #include "ui/views/widget/widget.h"
 
 #if defined(USE_X11)
-#include <X11/Xutil.h>
+#include "ui/gfx/x/x11.h"        // nogncheck
 #include "ui/gfx/x/x11_types.h"  // nogncheck
 #endif
 
diff --git a/ui/views/test/x11_property_change_waiter.cc b/ui/views/test/x11_property_change_waiter.cc
index d267b82..5747ee6b 100644
--- a/ui/views/test/x11_property_change_waiter.cc
+++ b/ui/views/test/x11_property_change_waiter.cc
@@ -4,12 +4,11 @@
 
 #include "ui/views/test/x11_property_change_waiter.h"
 
-#include <X11/Xlib.h>
-
 #include "base/run_loop.h"
 #include "ui/base/x/x11_window_event_manager.h"
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/events/platform/scoped_event_dispatcher.h"
+#include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_atom_cache.h"
 
 namespace views {
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
index a421178..55dcdf78 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
@@ -6,7 +6,6 @@
 
 #include <stddef.h>
 #include <stdint.h>
-#include <X11/Xatom.h>
 
 #include "base/event_types.h"
 #include "base/lazy_instance.h"
@@ -32,6 +31,7 @@
 #include "ui/events/event_utils.h"
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_atom_cache.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
@@ -492,7 +492,7 @@
 DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11(
     aura::Window* root_window,
     views::DesktopNativeCursorManager* cursor_manager,
-    Display* xdisplay,
+    ::Display* xdisplay,
     ::Window xwindow)
     : root_window_(root_window),
       cursor_manager_(cursor_manager),
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
index 53a8f237..37c90c1 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
@@ -5,8 +5,6 @@
 #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_
 #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_
 
-#include <X11/Xlib.h>
-
 #include <memory>
 #include <set>
 #include <vector>
@@ -21,6 +19,7 @@
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/x/x11.h"
 #include "ui/views/views_export.h"
 #include "ui/views/widget/desktop_aura/x11_move_loop_delegate.h"
 
@@ -59,7 +58,7 @@
   DesktopDragDropClientAuraX11(
       aura::Window* root_window,
       views::DesktopNativeCursorManager* cursor_manager,
-      Display* xdisplay,
+      ::Display* xdisplay,
       ::Window xwindow);
   ~DesktopDragDropClientAuraX11() override;
 
@@ -211,7 +210,7 @@
 
   DesktopNativeCursorManager* cursor_manager_;
 
-  Display* xdisplay_;
+  ::Display* xdisplay_;
   ::Window xwindow_;
 
   // Target side information.
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
index b2ee3f926a..a6fe148 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
@@ -24,6 +24,7 @@
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/x/x11_util.h"
 #include "ui/events/event_utils.h"
+#include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_atom_cache.h"
 #include "ui/gfx/x/x11_types.h"
 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
@@ -32,8 +33,6 @@
 #include "ui/views/widget/desktop_aura/x11_move_loop.h"
 #include "ui/views/widget/widget.h"
 
-#include <X11/Xlib.h>
-
 namespace views {
 
 namespace {
@@ -258,9 +257,8 @@
                                    cursor_manager,
                                    gfx::GetXDisplay(),
                                    window->GetHost()->GetAcceleratedWidget()),
-      target_xid_(None),
-      loop_(NULL) {
-}
+      target_xid_(x11::None),
+      loop_(NULL) {}
 
 SimpleTestDragDropClient::~SimpleTestDragDropClient() {
 }
@@ -730,7 +728,7 @@
 
   client->OnMouseReleased();
   // Reject the drop.
-  client->OnStatus(toplevel, false, None);
+  client->OnStatus(toplevel, false, x11::None);
 
   events = collector.PopAllEvents();
   ASSERT_EQ(1u, events.size());
@@ -759,7 +757,7 @@
   EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
 
   EXPECT_TRUE(client->IsMoveLoopRunning());
-  client->OnFinished(toplevel, false, None);
+  client->OnFinished(toplevel, false, x11::None);
   EXPECT_FALSE(client->IsMoveLoopRunning());
 }
 
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.h b/ui/views/widget/desktop_aura/desktop_screen_x11.h
index 91a85ce..842eb01 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_screen_x11.h
@@ -84,7 +84,7 @@
   // factor.
   void SetDisplaysInternal(const std::vector<display::Display>& displays);
 
-  Display* xdisplay_;
+  ::Display* xdisplay_;
   ::Window x_root_window_;
 
   // Whether the x server supports the XRandR extension.
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index a47b80f..41bb4117 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -7,9 +7,6 @@
 
 #include <stddef.h>
 #include <stdint.h>
-#include <X11/extensions/shape.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
 
 #include "base/cancelable_callback.h"
 #include "base/macros.h"
@@ -22,6 +19,7 @@
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/x/x11.h"
 #include "ui/views/views_export.h"
 #include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
 
diff --git a/ui/views/widget/desktop_aura/x11_desktop_handler.cc b/ui/views/widget/desktop_aura/x11_desktop_handler.cc
index f5e7f20..1ed79cf 100644
--- a/ui/views/widget/desktop_aura/x11_desktop_handler.cc
+++ b/ui/views/widget/desktop_aura/x11_desktop_handler.cc
@@ -4,9 +4,6 @@
 
 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
 
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
-
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "ui/aura/env.h"
@@ -14,6 +11,7 @@
 #include "ui/base/x/x11_menu_list.h"
 #include "ui/base/x/x11_window_event_manager.h"
 #include "ui/events/platform/platform_event_source.h"
+#include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_atom_cache.h"
 #include "ui/gfx/x/x11_error_tracker.h"
 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
diff --git a/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc b/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
index 86cd9521..6e4dddeb 100644
--- a/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
+++ b/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
@@ -4,8 +4,6 @@
 
 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
 
-#include <X11/Xlib.h>
-
 #include "base/debug/stack_trace.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
@@ -14,6 +12,7 @@
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/x/x11_util.h"
 #include "ui/events/event.h"
+#include "ui/gfx/x/x11.h"
 
 namespace views {
 
diff --git a/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h b/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
index 7868c49..6d074456 100644
--- a/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
+++ b/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
@@ -5,12 +5,11 @@
 #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_WINDOW_MOVE_CLIENT_H_
 #define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_WINDOW_MOVE_CLIENT_H_
 
-#include <X11/Xlib.h>
-
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/message_loop/message_loop.h"
 #include "ui/gfx/geometry/point.h"
+#include "ui/gfx/x/x11.h"
 #include "ui/views/views_export.h"
 #include "ui/views/widget/desktop_aura/x11_move_loop_delegate.h"
 #include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
diff --git a/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc b/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc
index 4907751..95f7d94 100644
--- a/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc
+++ b/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc
@@ -5,10 +5,10 @@
 #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
 
 #include <stddef.h>
-#include <X11/Xutil.h>
 
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/window.h"
+#include "ui/gfx/x/x11.h"
 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
 
 namespace views {
diff --git a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
index 9350d3df..cb78410 100644
--- a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
+++ b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
@@ -5,8 +5,6 @@
 #include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
 
 #include <stddef.h>
-#include <X11/keysym.h>
-#include <X11/Xlib.h>
 #include <utility>
 
 #include "base/bind.h"
@@ -30,6 +28,7 @@
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/events/platform/scoped_event_dispatcher.h"
 #include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/x/x11.h"
 
 namespace views {
 
@@ -50,7 +49,7 @@
       in_move_loop_(false),
       initial_cursor_(ui::CursorType::kNull),
       should_reset_mouse_flags_(false),
-      grab_input_window_(None),
+      grab_input_window_(x11::None),
       grabbed_pointer_(false),
       canceled_(false),
       weak_factory_(this) {}
@@ -232,7 +231,7 @@
   delegate_->OnMoveLoopEnded();
   grab_input_window_events_.reset();
   XDestroyWindow(display, grab_input_window_);
-  grab_input_window_ = None;
+  grab_input_window_ = x11::None;
 
   in_move_loop_ = false;
   quit_closure_.Run();
@@ -257,7 +256,7 @@
   unsigned int esc_keycode = XKeysymToKeycode(display, XK_Escape);
   for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
     XGrabKey(display, esc_keycode, kModifiersMasks[i], grab_input_window_,
-             False, GrabModeAsync, GrabModeAsync);
+             x11::False, GrabModeAsync, GrabModeAsync);
   }
 }
 
@@ -265,7 +264,7 @@
   unsigned long attribute_mask = CWEventMask | CWOverrideRedirect;
   XSetWindowAttributes swa;
   memset(&swa, 0, sizeof(swa));
-  swa.override_redirect = True;
+  swa.override_redirect = x11::True;
   grab_input_window_ = XCreateWindow(display, DefaultRootWindow(display), -100,
                                      -100, 10, 10, 0, CopyFromParent, InputOnly,
                                      CopyFromParent, attribute_mask, &swa);
diff --git a/ui/views/widget/desktop_aura/x11_window_event_filter.cc b/ui/views/widget/desktop_aura/x11_window_event_filter.cc
index be85b35..ccde928 100644
--- a/ui/views/widget/desktop_aura/x11_window_event_filter.cc
+++ b/ui/views/widget/desktop_aura/x11_window_event_filter.cc
@@ -4,11 +4,6 @@
 
 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
 
-#include <X11/extensions/XInput.h>
-#include <X11/extensions/XInput2.h>
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
-
 #include "services/ui/public/interfaces/window_manager_constants.mojom.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
@@ -19,6 +14,7 @@
 #include "ui/display/screen.h"
 #include "ui/events/event.h"
 #include "ui/events/event_utils.h"
+#include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_atom_cache.h"
 #include "ui/gfx/x/x11_types.h"
 #include "ui/views/linux_ui/linux_ui.h"
@@ -110,7 +106,7 @@
   // because what we're about to do is tell the window manager
   // that it's now responsible for moving the window around; it immediately
   // grabs when it receives the event below.
-  XUngrabPointer(xdisplay_, CurrentTime);
+  XUngrabPointer(xdisplay_, x11::CurrentTime);
 
   XEvent event;
   memset(&event, 0, sizeof(event));
@@ -125,9 +121,8 @@
   event.xclient.data.l[3] = 0;
   event.xclient.data.l[4] = 0;
 
-  XSendEvent(xdisplay_, x_root_window_, False,
-             SubstructureRedirectMask | SubstructureNotifyMask,
-             &event);
+  XSendEvent(xdisplay_, x_root_window_, x11::False,
+             SubstructureRedirectMask | SubstructureNotifyMask, &event);
 
   return true;
 }
diff --git a/ui/views/widget/desktop_aura/x11_window_event_filter.h b/ui/views/widget/desktop_aura/x11_window_event_filter.h
index 4fc53ea1..54a27a6 100644
--- a/ui/views/widget/desktop_aura/x11_window_event_filter.h
+++ b/ui/views/widget/desktop_aura/x11_window_event_filter.h
@@ -5,12 +5,11 @@
 #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WINDOW_EVENT_FILTER_H_
 #define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WINDOW_EVENT_FILTER_H_
 
-#include <X11/Xlib.h>
-
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "ui/events/event_handler.h"
+#include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_types.h"
 #include "ui/views/views_export.h"
 #include "ui/views/widget/desktop_aura/window_event_filter.h"