diff --git a/DEPS b/DEPS
index 4ef66bc..72c8215d 100644
--- a/DEPS
+++ b/DEPS
@@ -137,7 +137,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': 'fb86b888ef1c1265719208fd6c27a53ceb4920f7',
+  'boringssl_revision': '13fd627449cefbae7576d4b145cb24fac303fc7d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -165,7 +165,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': '7453eba4feb2d90136a9415a6670ad41b866c93f',
+  'catapult_revision': 'd525ef309fcaf7f1e5361c08592dbec3ae8ffa4c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -213,7 +213,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '6ff2f64702dcf298bcbbb33182ce82aa206e2b0a',
+  'spv_tools_revision': '32381e30ef56f5a15207679a55c73a206483c1c4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -333,7 +333,7 @@
   },
 
   'src/ios/third_party/material_sprited_animation_view_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-foundation/material-sprited-animation-view-ios.git' + '@' + 'c6e16d06bdafd95540c62b3402d9414692fbca81',
+      'url': Var('chromium_git') + '/external/github.com/material-foundation/material-sprited-animation-view-ios.git' + '@' + '8af9adaa182044cf2920dfb620b863669e1aeb7c',
       'condition': 'checkout_ios',
   },
 
@@ -586,7 +586,7 @@
     Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'),
 
   'src/third_party/cct_dynamic_module/src': {
-      'url': Var('chromium_git') + '/dynamicmodule' + '@' + 'dd6520c2ecc1b41c435a2ccf822b302489de0016',
+      'url': Var('chromium_git') + '/dynamicmodule' + '@' + 'b89f5147c1fdf1d02850932ecd1ff16b8c0be545',
       'condition': 'checkout_android',
   },
 
@@ -595,7 +595,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8241a7599974ed98de3e87c521b3a85047f614d3',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '82b404766db2865f290fb939577b2a0a931508eb',
       'condition': 'checkout_linux',
   },
 
@@ -954,7 +954,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '40a2e1ea24495c6df976f194890e0843d52ada68',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '5cfa93810a407da48fe72b9e11df6e2bb7f17d9b',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1106,7 +1106,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6d2f3f4cb8bac1f7c4a945c73d07a33df74f22f9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'cbcbc225687faf8226995c2823380adf06bd1afb',
+    Var('webrtc_git') + '/src.git' + '@' + '1ee9160a2e0bc6381caca2b8c42f7ce5507619bc',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1137,7 +1137,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@bea5a39cb8956b75ebf37087530c71e3e6fdd6e3',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@928526013073be9b73b8ca5140d37030a66bc0a2',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index b14dd954..8a85cbf 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -10,24 +10,24 @@
 
 
 _EXCLUDED_PATHS = (
-    r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
-    r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
-    r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
-    r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
-    r"^skia[\\\/].*",
-    r"^third_party[\\\/](WebKit|blink)[\\\/].*",
-    r"^third_party[\\\/]breakpad[\\\/].*",
-    r"^v8[\\\/].*",
+    r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
+    r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
+    r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
+    r"^net[\\/]tools[\\/]spdyshark[\\/].*",
+    r"^skia[\\/].*",
+    r"^third_party[\\/](WebKit|blink)[\\/].*",
+    r"^third_party[\\/]breakpad[\\/].*",
+    r"^v8[\\/].*",
     r".*MakeFile$",
     r".+_autogen\.h$",
-    r".+[\\\/]pnacl_shim\.c$",
-    r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
-    r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
-    r"tools[\\\/]md_browser[\\\/].*\.css$",
+    r".+[\\/]pnacl_shim\.c$",
+    r"^gpu[\\/]config[\\/].*_list_json\.cc$",
+    r"^chrome[\\/]browser[\\/]resources[\\/]pdf[\\/]index.js",
+    r"tools[\\/]md_browser[\\/].*\.css$",
     # Test pages for Maps telemetry tests.
-    r"tools[\\\/]perf[\\\/]page_sets[\\\/]maps_perf_test.*",
+    r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
     # Test pages for WebRTC telemetry tests.
-    r"tools[\\\/]perf[\\\/]page_sets[\\\/]webrtc_cases.*",
+    r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
 )
 
 
@@ -44,18 +44,18 @@
 # Regular expression that matches code only used for test binaries
 # (best effort).
 _TEST_CODE_EXCLUDED_PATHS = (
-    r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
+    r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
     r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
     r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
         _IMPLEMENTATION_EXTENSIONS,
     r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
-    r'.*[\\\/](test|tool(s)?)[\\\/].*',
+    r'.*[\\/](test|tool(s)?)[\\/].*',
     # content_shell is used for running layout tests.
-    r'content[\\\/]shell[\\\/].*',
+    r'content[\\/]shell[\\/].*',
     # Non-production example code.
-    r'mojo[\\\/]examples[\\\/].*',
+    r'mojo[\\/]examples[\\/].*',
     # Launcher for running iOS tests on the simulator.
-    r'testing[\\\/]iossim[\\\/]iossim\.mm$',
+    r'testing[\\/]iossim[\\/]iossim\.mm$',
 )
 
 
@@ -238,9 +238,9 @@
       ),
       True,
       (
-        r"^ui[\\\/]gl[\\\/].*\.cc$",
-        r"^media[\\\/]gpu[\\\/].*\.cc$",
-        r"^gpu[\\\/].*\.cc$",
+        r"^ui[\\/]gl[\\/].*\.cc$",
+        r"^media[\\/]gpu[\\/].*\.cc$",
+        r"^gpu[\\/].*\.cc$",
       ),
     ),
     (
@@ -250,9 +250,9 @@
       ),
       True,
       (
-        r"^gpu[\\\/]ipc[\\\/]service[\\\/]gpu_watchdog_thread\.cc$",
-        r"^remoting[\\\/]host[\\\/]linux[\\\/]x_server_clipboard\.cc$",
-        r"^ui[\\\/]gfx[\\\/]x[\\\/]x11_atom_cache\.cc$",
+        r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
+        r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
+        r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
       ),
     ),
     (
@@ -321,8 +321,8 @@
       True,
       (
         # Files that #define IGNORE_EINTR.
-        r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
-        r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
+        r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
+        r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
       ),
     ),
     (
@@ -333,7 +333,7 @@
       ),
       True,
       (
-        r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
+        r'extensions[\\/]renderer[\\/]safe_builtins\.*',
       ),
     ),
     (
@@ -343,7 +343,7 @@
       ),
       True,
       (
-          r'^third_party[\\\/]abseil-cpp[\\\/].*',
+          r'^third_party[\\/]abseil-cpp[\\/].*',
       ),
     ),
     (
@@ -386,9 +386,9 @@
       ),
       False,
       (
-        r'^content[\\\/]browser[\\\/]webui[\\\/]web_ui_impl\.(cc|h)$',
-        r'^content[\\\/]public[\\\/]browser[\\\/]web_ui\.h$',
-        r'^content[\\\/]public[\\\/]test[\\\/]test_web_ui\.(cc|h)$',
+        r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
+        r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
+        r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
       ),
     ),
     (
@@ -557,11 +557,11 @@
       ),
       False,
       (
-        r'^ios[\\\/].*\.(cc|h)$',
-        r'.*[\\\/]ios[\\\/].*\.(cc|h)$',
+        r'^ios[\\/].*\.(cc|h)$',
+        r'.*[\\/]ios[\\/].*\.(cc|h)$',
         r'.*_ios\.(cc|h)$',
-        r'^net[\\\/].*\.(cc|h)$',
-        r'.*[\\\/]tools[\\\/].*\.(cc|h)$',
+        r'^net[\\/].*\.(cc|h)$',
+        r'.*[\\/]tools[\\/].*\.(cc|h)$',
       ),
     ),
     (
@@ -597,18 +597,18 @@
 )
 
 _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
-    r".*[\\\/]BuildHooksAndroidImpl\.java",
-    r".*[\\\/]LicenseContentProvider\.java",
-    r".*[\\\/]PlatformServiceBridgeImpl.java",
+    r".*[\\/]BuildHooksAndroidImpl\.java",
+    r".*[\\/]LicenseContentProvider\.java",
+    r".*[\\/]PlatformServiceBridgeImpl.java",
 ]
 
 # These paths contain test data and other known invalid JSON files.
 _KNOWN_INVALID_JSON_FILE_PATTERNS = [
-    r'test[\\\/]data[\\\/]',
-    r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
-    r'^third_party[\\\/]protobuf[\\\/]',
-    r'^third_party[\\\/]WebKit[\\\/]LayoutTests[\\\/]external[\\\/]wpt[\\\/]',
-    r'^third_party[\\\/]blink[\\\/]renderer[\\\/]devtools[\\\/]protocol\.json$',
+    r'test[\\/]data[\\/]',
+    r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
+    r'^third_party[\\/]protobuf[\\/]',
+    r'^third_party[\\/]WebKit[\\/]LayoutTests[\\/]external[\\/]wpt[\\/]',
+    r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
 ]
 
 
@@ -1412,7 +1412,7 @@
     """
     return input_api.FilterSourceFile(
       affected_file,
-      white_list=[r'^(android_webview|base|content|net)[\\\/].*'],
+      white_list=[r'^(android_webview|base|content|net)[\\/].*'],
       black_list=(_EXCLUDED_PATHS +
                   _TEST_CODE_EXCLUDED_PATHS +
                   input_api.DEFAULT_BLACK_LIST))
@@ -1445,7 +1445,7 @@
   """
   errors = []
   white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
-  black_list = [r'^native_client_sdk[\\\/]']
+  black_list = [r'^native_client_sdk[\\/]']
   file_filter = lambda f: input_api.FilterSourceFile(
       f, white_list=white_list, black_list=black_list)
   for f in input_api.AffectedFiles(include_deletes=False,
@@ -1540,7 +1540,7 @@
   virtual_depended_on_files = set()
 
   file_filter = lambda f: not input_api.re.match(
-      r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath())
+      r"^third_party[\\/](WebKit|blink)[\\/].*", f.LocalPath())
   for f in input_api.AffectedFiles(include_deletes=False,
                                    file_filter=file_filter):
     filename = input_api.os_path.basename(f.LocalPath())
@@ -1615,44 +1615,44 @@
   black_list = (_EXCLUDED_PATHS +
                 _TEST_CODE_EXCLUDED_PATHS +
                 input_api.DEFAULT_BLACK_LIST +
-                (r"^base[\\\/]logging\.h$",
-                 r"^base[\\\/]logging\.cc$",
-                 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
-                 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
-                 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
+                (r"^base[\\/]logging\.h$",
+                 r"^base[\\/]logging\.cc$",
+                 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
+                 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
+                 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
                      r"startup_browser_creator\.cc$",
-                 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
-                 r"^chrome[\\\/]chrome_cleaner[\\\/].*",
-                 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
+                 r"^chrome[\\/]installer[\\/]setup[\\/].*",
+                 r"^chrome[\\/]chrome_cleaner[\\/].*",
+                 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
                      r"diagnostics_writer\.cc$",
-                 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
-                 r"^chromecast[\\\/]",
-                 r"^cloud_print[\\\/]",
-                 r"^components[\\\/]browser_watcher[\\\/]"
+                 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
+                 r"^chromecast[\\/]",
+                 r"^cloud_print[\\/]",
+                 r"^components[\\/]browser_watcher[\\/]"
                      r"dump_stability_report_main_win.cc$",
-                 r"^components[\\\/]html_viewer[\\\/]"
+                 r"^components[\\/]html_viewer[\\/]"
                      r"web_test_delegate_impl\.cc$",
-                 r"^components[\\\/]zucchini[\\\/].*",
+                 r"^components[\\/]zucchini[\\/].*",
                  # TODO(peter): Remove this exception. https://crbug.com/534537
-                 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
+                 r"^content[\\/]browser[\\/]notifications[\\/]"
                      r"notification_event_dispatcher_impl\.cc$",
-                 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
+                 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
                      r"gl_helper_benchmark\.cc$",
-                 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
-                 r"^courgette[\\\/]courgette_tool\.cc$",
-                 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
-                 r"^ipc[\\\/]ipc_logging\.cc$",
-                 r"^native_client_sdk[\\\/]",
-                 r"^remoting[\\\/]base[\\\/]logging\.h$",
-                 r"^remoting[\\\/]host[\\\/].*",
-                 r"^sandbox[\\\/]linux[\\\/].*",
-                 r"^tools[\\\/]",
-                 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
-                 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
-                 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
-                 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
+                 r"^courgette[\\/]courgette_minimal_tool\.cc$",
+                 r"^courgette[\\/]courgette_tool\.cc$",
+                 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
+                 r"^ipc[\\/]ipc_logging\.cc$",
+                 r"^native_client_sdk[\\/]",
+                 r"^remoting[\\/]base[\\/]logging\.h$",
+                 r"^remoting[\\/]host[\\/].*",
+                 r"^sandbox[\\/]linux[\\/].*",
+                 r"^tools[\\/]",
+                 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
+                 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
+                 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
+                 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
                      r"dump_file_system.cc$",
-                 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
+                 r"^headless[\\/]app[\\/]headless_shell\.cc$"))
   source_file_filter = lambda x: input_api.FilterSourceFile(
       x, white_list=file_inclusion_pattern, black_list=black_list)
 
@@ -1916,12 +1916,12 @@
   }
   # Most JSON files are preprocessed and support comments, but these do not.
   json_no_comments_patterns = [
-    r'^testing[\\\/]',
+    r'^testing[\\/]',
   ]
   # Only run IDL checker on files in these directories.
   idl_included_patterns = [
-    r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
-    r'^extensions[\\\/]common[\\\/]api[\\\/]',
+    r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
+    r'^extensions[\\/]common[\\/]api[\\/]',
   ]
 
   def get_action(affected_file):
@@ -2217,8 +2217,8 @@
       black_list=(_EXCLUDED_PATHS +
                   _TEST_CODE_EXCLUDED_PATHS +
                   input_api.DEFAULT_BLACK_LIST +
-                  (r'^chromecast[\\\/].*',
-                   r'^remoting[\\\/].*')),
+                  (r'^chromecast[\\/].*',
+                   r'^remoting[\\/].*')),
       white_list=[r'.*\.java$'])
 
   for f in input_api.AffectedSourceFiles(sources):
@@ -2248,10 +2248,13 @@
   # Do not check format of logs in the given files
   cr_log_check_excluded_paths = [
     # //chrome/android/webapk cannot depend on //base
-    r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
+    r"^chrome[\\/]android[\\/]webapk[\\/].*",
     # WebView license viewer code cannot depend on //base; used in stub APK.
-    r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
-    r"webview[\\\/]chromium[\\\/]License.*",
+    r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
+    r"webview[\\/]chromium[\\/]License.*",
+    # The customtabs_benchmark is a small app that does not depend on Chromium
+    # java pieces.
+    r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
   ]
 
   cr_log_import_pattern = input_api.re.compile(
@@ -2456,7 +2459,7 @@
       black_list=(_EXCLUDED_PATHS +
                   _TEST_CODE_EXCLUDED_PATHS +
                   input_api.DEFAULT_BLACK_LIST +
-                  (r'^android_webview[\\\/]glue[\\\/].*',)),
+                  (r'^android_webview[\\/]glue[\\/].*',)),
       white_list=[r'.*\.java$'])
 
   for f in input_api.AffectedSourceFiles(sources):
@@ -2597,8 +2600,8 @@
     # It's ok for base/memory/singleton.h to have |Singleton<|.
     black_list = (_EXCLUDED_PATHS +
                   input_api.DEFAULT_BLACK_LIST +
-                  (r"^base[\\\/]memory[\\\/]singleton\.h$",
-                   r"^net[\\\/]quic[\\\/]platform[\\\/]impl[\\\/]"
+                  (r"^base[\\/]memory[\\/]singleton\.h$",
+                   r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
                        r"quic_singleton_impl\.h$"))
     return input_api.FilterSourceFile(affected_file, black_list=black_list)
 
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 48b0bc0..03e6faea 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -9,6 +9,7 @@
 import("//build/config/android/config.gni")
 import("//build/config/android/rules.gni")
 import("//build/config/locales.gni")
+import("//chrome/android/trichrome.gni")
 import("//components/spellcheck/spellcheck_build_features.gni")
 import("//tools/grit/repack.gni")
 import("//tools/resources/generate_resource_whitelist.gni")
@@ -109,6 +110,15 @@
   variables = [ "manifest_package=$system_webview_package_name" ]
 }
 
+jinja_template("trichrome_webview_manifest") {
+  input = "apk/java/AndroidManifest.xml"
+  output = trichrome_webview_android_manifest
+  variables = trichrome_jinja_variables + [
+                "manifest_package=$system_webview_package_name",
+                "library=libmonochrome.so",
+              ]
+}
+
 webview_repack_locales("repack_locales") {
   input_locales = locales
   output_locales = locales
@@ -1085,4 +1095,13 @@
     deps = upstream_only_webview_deps
     apk_name = "SystemWebView"
   }
+
+  system_webview_apk_tmpl("trichrome_webview_apk") {
+    version_name = chrome_version_name
+    android_manifest = trichrome_webview_android_manifest
+    android_manifest_dep = ":trichrome_webview_manifest"
+    deps = upstream_only_webview_deps
+    apk_name = "TrichromeWebView"
+    use_trichrome_library = true
+  }
 }
diff --git a/android_webview/apk/java/AndroidManifest.xml b/android_webview/apk/java/AndroidManifest.xml
index ff64d48c..39f5d97 100644
--- a/android_webview/apk/java/AndroidManifest.xml
+++ b/android_webview/apk/java/AndroidManifest.xml
@@ -80,5 +80,11 @@
         {% endfor %}
         <meta-data android:name="org.chromium.content.browser.NUM_PRIVILEGED_SERVICES"
                    android:value="0" />
+        {% if trichrome_library is defined %}
+        <uses-static-library
+            android:name="{{ trichrome_library }}"
+            android:version="{{ trichrome_version }}"
+            android:certDigest="{{ trichrome_certdigest }}" />
+        {% endif %}
     </application>
 </manifest>
diff --git a/android_webview/apk/java/proguard.flags b/android_webview/apk/java/proguard.flags
index 40de75d..95fe04a 100644
--- a/android_webview/apk/java/proguard.flags
+++ b/android_webview/apk/java/proguard.flags
@@ -71,3 +71,7 @@
 
 # We strip some unused resources when preprocessing the GMS client libs.
 -dontwarn com.google.android.gms.R**
+
+# Trichrome builds don't include a native library list in the main APK; it's
+# picked up from the library APK at runtime.
+-dontwarn org.chromium.base.library_loader.NativeLibraries
diff --git a/android_webview/common/aw_hit_test_data.h b/android_webview/common/aw_hit_test_data.h
index 8e5919b7..eefce49 100644
--- a/android_webview/common/aw_hit_test_data.h
+++ b/android_webview/common/aw_hit_test_data.h
@@ -22,7 +22,7 @@
     // except the special case described below.
     // For special case of invalid or javascript scheme url that would
     // otherwise be type an LINK type, |href| will contain the javascript
-    // string in the href attribute, and |anchor_text|i and |img_src| contain
+    // string in the href attribute, and |anchor_text| and |img_src| contain
     // their normal values for the respective type.
     UNKNOWN_TYPE = 0,
 
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 4ed0eac..cfe0af2d 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -2244,7 +2244,6 @@
 
         // In order to maintain compatibility with the old WebView's implementation,
         // the absolute (full) url is passed in the |url| field, not only the href attribute.
-        // Note: HitTestData could be cleaned up at this point. See http://crbug.com/290992.
         data.putString("url", mPossiblyStaleHitTestData.href);
         data.putString("title", mPossiblyStaleHitTestData.anchorText);
         data.putString("src", mPossiblyStaleHitTestData.imgSrc);
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index 759173f..819907a3a 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -25,14 +25,35 @@
     }
 
     shared_resources = true
-    shared_libraries = [ "//android_webview:libwebviewchromium" ]
-    native_lib_version_rule = "//build/util:chrome_version_json"
-    _native_lib_file =
-        rebase_path("$root_gen_dir/CHROME_VERSION.json", root_out_dir)
-    native_lib_version_arg = "@FileArg($_native_lib_file:full-quoted)"
-    if (build_apk_secondary_abi && android_64bit_target_cpu) {
-      secondary_abi_shared_libraries = [ "//android_webview:libwebviewchromium($android_secondary_abi_toolchain)" ]
+
+    if (!defined(use_trichrome_library) || !use_trichrome_library) {
+      shared_libraries = [ "//android_webview:libwebviewchromium" ]
+      if (build_apk_secondary_abi && android_64bit_target_cpu) {
+        secondary_abi_shared_libraries = [ "//android_webview:libwebviewchromium($android_secondary_abi_toolchain)" ]
+      }
+    } else {
+      # Include placeholder libraries to ensure we are treated as the desired
+      # architecture.
+      if (android_64bit_target_cpu) {
+        shared_libraries = [ "//android_webview:monochrome" ]
+        if (build_apk_secondary_abi) {
+          secondary_native_lib_placeholders = [ "libdummy.so" ]
+        }
+      } else {
+        native_lib_placeholders = [ "libdummy.so" ]
+      }
     }
+
+    if (!defined(use_trichrome_library) || !use_trichrome_library ||
+        android_64bit_target_cpu) {
+      # 32-bit TrichromeWebView doesn't have a native library, so only do this
+      # for other configs.
+      native_lib_version_rule = "//build/util:chrome_version_json"
+      _native_lib_file =
+          rebase_path("$root_gen_dir/CHROME_VERSION.json", root_out_dir)
+      native_lib_version_arg = "@FileArg($_native_lib_file:full-quoted)"
+    }
+
     aapt_locale_whitelist = locales
 
     resource_blacklist_regex = "[/-]xxxhdpi[/-]"
diff --git a/android_webview/variables.gni b/android_webview/variables.gni
index 94b8559..4e0b03b 100644
--- a/android_webview/variables.gni
+++ b/android_webview/variables.gni
@@ -4,6 +4,8 @@
 
 system_webview_android_manifest =
     "$root_gen_dir/android_webview/system_webview_apk/AndroidManifest.xml"
+trichrome_webview_android_manifest =
+    "$root_gen_dir/android_webview/trichrome_webview_apk/AndroidManifest.xml"
 
 upstream_only_webview_deps = [
   "//android_webview:platform_service_bridge_upstream_implementation_java",
diff --git a/ash/public/cpp/network_icon_image_source.cc b/ash/public/cpp/network_icon_image_source.cc
index 5cfb152..b48b064 100644
--- a/ash/public/cpp/network_icon_image_source.cc
+++ b/ash/public/cpp/network_icon_image_source.cc
@@ -5,6 +5,7 @@
 #include "ash/public/cpp/network_icon_image_source.h"
 
 #include "ash/public/cpp/ash_constants.h"
+#include "ash/public/cpp/ash_features.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
@@ -75,7 +76,8 @@
 
   // The other badges are flush against the edges of the canvas, except at the
   // top, where the badge is only 1dp higher than the base image.
-  const int top_badge_y = icon_y - 1;
+  const int top_badge_y =
+      features::IsSystemTrayUnifiedEnabled() ? icon_y : icon_y - 1;
   if (badges_.top_left.icon)
     paint_badge(badges_.top_left, 0, top_badge_y);
   if (badges_.bottom_left.icon) {
diff --git a/ash/resources/vector_icons/system_tray_managed.icon b/ash/resources/vector_icons/system_tray_managed.icon
index 631374d3..848cfea 100644
--- a/ash/resources/vector_icons/system_tray_managed.icon
+++ b/ash/resources/vector_icons/system_tray_managed.icon
@@ -3,57 +3,40 @@
 // found in the LICENSE file.
 
 CANVAS_DIMENSIONS, 20,
-MOVE_TO, 2, 3,
-R_H_LINE_TO, 10,
-R_V_LINE_TO, 4,
-R_H_LINE_TO, 6,
-R_V_LINE_TO, 10,
-H_LINE_TO, 2,
-V_LINE_TO, 3,
+MOVE_TO, 9, 16,
+LINE_TO, 9, 14,
+LINE_TO, 7, 14,
+LINE_TO, 7, 16,
+LINE_TO, 4, 16,
+LINE_TO, 4, 4,
+LINE_TO, 12, 4,
+LINE_TO, 12, 6,
+LINE_TO, 16, 6,
+LINE_TO, 16, 16,
+LINE_TO, 11.83f, 16,
+LINE_TO, 9, 16,
 CLOSE,
-R_MOVE_TO, 10, 10,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 4,
-V_LINE_TO, 9,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, -2,
+MOVE_TO, 6, 10,
+LINE_TO, 6, 12,
+LINE_TO, 10, 12,
+LINE_TO, 10, 10,
+LINE_TO, 6, 10,
 CLOSE,
-R_MOVE_TO, -4, 0,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, -2,
-H_LINE_TO, 8,
+MOVE_TO, 6, 6,
+LINE_TO, 6, 8,
+LINE_TO, 10, 8,
+LINE_TO, 10, 6,
+LINE_TO, 6, 6,
 CLOSE,
-R_MOVE_TO, -4, 0,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, -2,
-H_LINE_TO, 4,
+MOVE_TO, 12, 8,
+LINE_TO, 12, 10,
+LINE_TO, 14, 10,
+LINE_TO, 14, 8,
+LINE_TO, 12, 8,
 CLOSE,
-R_MOVE_TO, 4, -4,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-V_LINE_TO, 9,
-H_LINE_TO, 8,
-CLOSE,
-MOVE_TO, 4, 9,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-V_LINE_TO, 9,
-H_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 4, -4,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-V_LINE_TO, 5,
-H_LINE_TO, 8,
-CLOSE,
-MOVE_TO, 4, 5,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-V_LINE_TO, 5,
-H_LINE_TO, 4,
+MOVE_TO, 12, 12,
+LINE_TO, 12, 14,
+LINE_TO, 14, 14,
+LINE_TO, 14, 12,
+LINE_TO, 12, 12,
 CLOSE
diff --git a/ash/system/network/network_icon.cc b/ash/system/network/network_icon.cc
index 7698b79..4b287b7e 100644
--- a/ash/system/network/network_icon.cc
+++ b/ash/system/network/network_icon.cc
@@ -194,6 +194,8 @@
 }
 
 gfx::Size GetSizeForBaseIconSize(const gfx::Size& base_icon_size) {
+  if (features::IsSystemTrayUnifiedEnabled())
+    return base_icon_size;
   gfx::Size size = base_icon_size;
   const int badge_offset = base_icon_size.width() == kTrayIconSize
                                ? kTrayIconBadgeOffset
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
index 5336906b..cb4589b 100644
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -21,6 +21,7 @@
 import android.graphics.ColorFilter;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.VectorDrawable;
 import android.net.Uri;
 import android.os.Build;
@@ -711,4 +712,52 @@
             view.setAccessibilityTraversalBefore(viewFocusedAfter);
         }
     }
+
+    /**
+     * Creates regular LayerDrawable on Android L+. On older versions creates a helper class that
+     * fixes issues around {@link LayerDrawable#mutate()}. See https://crbug.com/890317 for details.
+     * @param layers A list of drawables to use as layers in this new drawable.
+     */
+    public static LayerDrawable createLayerDrawable(@NonNull Drawable[] layers) {
+        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
+            return new LayerDrawableCompat(layers);
+        }
+        return new LayerDrawable(layers);
+    }
+
+    private static class LayerDrawableCompat extends LayerDrawable {
+        private boolean mMutated;
+
+        LayerDrawableCompat(@NonNull Drawable[] layers) {
+            super(layers);
+        }
+
+        @Override
+        public Drawable mutate() {
+            // LayerDrawable in Android K loses bounds of layers, so this method works around that.
+            if (mMutated) {
+                // This object has already been mutated and shouldn't have any shared state.
+                return this;
+            }
+
+            // Save bounds before mutation.
+            Rect[] oldBounds = new Rect[getNumberOfLayers()];
+            for (int i = 0; i < getNumberOfLayers(); i++) {
+                oldBounds[i] = getDrawable(i).getBounds();
+            }
+
+            Drawable superResult = super.mutate();
+            if (superResult != this) {
+                // Unexpected, LayerDrawable.mutate() always returns this.
+                return superResult;
+            }
+
+            // Restore the saved bounds.
+            for (int i = 0; i < getNumberOfLayers(); i++) {
+                getDrawable(i).setBounds(oldBounds[i]);
+            }
+            mMutated = true;
+            return this;
+        }
+    }
 }
diff --git a/base/task/sequence_manager/sequence_manager_impl.cc b/base/task/sequence_manager/sequence_manager_impl.cc
index 810200d..d1627e1a 100644
--- a/base/task/sequence_manager/sequence_manager_impl.cc
+++ b/base/task/sequence_manager/sequence_manager_impl.cc
@@ -115,7 +115,10 @@
   graceful_shutdown_helper_->OnSequenceManagerDeleted();
 
   main_thread_only().selector.SetTaskQueueSelectorObserver(nullptr);
-  controller_->RemoveNestingObserver(this);
+
+  // In some tests a NestingObserver may not have been registered.
+  if (main_thread_only().nesting_observer_registered_)
+    controller_->RemoveNestingObserver(this);
 }
 
 SequenceManagerImpl::AnyThread::AnyThread() = default;
@@ -150,7 +153,6 @@
 
 void SequenceManagerImpl::BindToMessageLoop(MessageLoop* message_loop) {
   controller_->SetMessageLoop(message_loop);
-  BindToCurrentThread();
   CompleteInitializationOnBoundThread();
 }
 
@@ -160,6 +162,7 @@
 
 void SequenceManagerImpl::CompleteInitializationOnBoundThread() {
   controller_->AddNestingObserver(this);
+  main_thread_only().nesting_observer_registered_ = true;
 }
 
 void SequenceManagerImpl::RegisterTimeDomain(TimeDomain* time_domain) {
diff --git a/base/task/sequence_manager/sequence_manager_impl.h b/base/task/sequence_manager/sequence_manager_impl.h
index 7b3a68f4..1572ac4 100644
--- a/base/task/sequence_manager/sequence_manager_impl.h
+++ b/base/task/sequence_manager/sequence_manager_impl.h
@@ -90,7 +90,8 @@
   // MessageLoop. The SequenceManager can be initialized on the current thread
   // and then needs to be bound and initialized on the target thread by calling
   // BindToCurrentThread() and CompleteInitializationOnBoundThread() during the
-  // thread's startup.
+  // thread's startup. If |message_loop| is null then BindToMessageLoop() must
+  // be called instead of CompleteInitializationOnBoundThread.
   //
   // This function should be called only once per MessageLoop.
   static std::unique_ptr<SequenceManagerImpl> CreateUnbound(
@@ -251,6 +252,7 @@
     std::vector<internal::TaskQueueImpl*> queues_to_reload;
 
     bool task_was_run_on_quiescence_monitored_queue = false;
+    bool nesting_observer_registered_ = false;
 
     // Due to nested runloops more than one task can be executing concurrently.
     std::list<ExecutingTask> task_execution_stack;
diff --git a/base/task/sequence_manager/sequence_manager_impl_unittest.cc b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
index 7b721d8..7a6bb5a7 100644
--- a/base/task/sequence_manager/sequence_manager_impl_unittest.cc
+++ b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
@@ -3381,6 +3381,7 @@
        SequenceManagerCreatedBeforeMessageLoop) {
   std::unique_ptr<SequenceManager> manager =
       CreateUnboundSequenceManager(nullptr);
+  manager->BindToCurrentThread();
   scoped_refptr<TaskQueue> default_task_queue =
       manager->CreateTaskQueue<TestTaskQueue>(TaskQueue::Spec("default"));
   EXPECT_THAT(default_task_queue.get(), testing::NotNull());
@@ -3405,6 +3406,12 @@
   manager.reset();
 }
 
+TEST_P(SequenceManagerTestWithCustomInitialization,
+       CreateUnboundSequenceManagerWhichIsNeverBound) {
+  // This should not crash.
+  CreateUnboundSequenceManager(nullptr);
+}
+
 }  // namespace sequence_manager_impl_unittest
 }  // namespace internal
 }  // namespace sequence_manager
diff --git a/build/chromeos/create_vm_test_script.py b/build/chromeos/create_vm_test_script.py
index 80a7dbb4..5760cc7f 100755
--- a/build/chromeos/create_vm_test_script.py
+++ b/build/chromeos/create_vm_test_script.py
@@ -51,6 +51,8 @@
   parser.add_argument('--cros-cache')
   parser.add_argument('--board')
   parser.add_argument('--deploy-chrome', action='store_true')
+  parser.add_argument('--suite-name')
+  parser.add_argument('--tast-tests', action='append')
   args = parser.parse_args(args)
 
   def RelativizePathToScript(path):
@@ -70,6 +72,14 @@
         '--test-exe',
         args.test_exe,
     ])
+  elif args.tast_tests:
+    vm_test_args.extend([
+        'tast',
+        '--suite-name',
+        args.suite_name,
+    ])
+    for t in args.tast_tests:
+      vm_test_args.extend(['-t', t])
   else:
     vm_test_args.append('host-cmd')
     if args.deploy_chrome:
diff --git a/build/chromeos/run_vm_test.py b/build/chromeos/run_vm_test.py
index 964c0f3d..d40bb7c 100755
--- a/build/chromeos/run_vm_test.py
+++ b/build/chromeos/run_vm_test.py
@@ -60,6 +60,8 @@
         '--start',
         '--board', args.board,
         '--cache-dir', args.cros_cache,
+        # Don't persist any filesystem changes after the VM shutsdown.
+        '--copy-on-write',
     ]
     if args.vm_logs_dir:
       self._vm_test_cmd += [
@@ -80,6 +82,7 @@
       self._test_env['USE'] = 'highdpi'
     self._test_env['PATH'] = (
         self._test_env['PATH'] + ':' + os.path.join(CHROMITE_PATH, 'bin'))
+
   @property
   def suite_name(self):
     raise NotImplementedError('Child classes need to define suite name.')
@@ -407,6 +410,8 @@
       '--start',
       '--board', args.board,
       '--cache-dir', args.cros_cache,
+      # Don't persist any filesystem changes after the VM shutsdown.
+      '--copy-on-write',
   ]
   if args.verbose:
     cros_run_vm_test_cmd.append('--debug')
diff --git a/build/config/chromeos/rules.gni b/build/config/chromeos/rules.gni
index c87f0a8..047cab3 100644
--- a/build/config/chromeos/rules.gni
+++ b/build/config/chromeos/rules.gni
@@ -19,6 +19,10 @@
 # Args:
 #   test_exe: Name of test binary located in the out dir. This will get copied
 #       to the VM and executed there.
+#   tast_tests: List of Tast tests to run on the VM. Note that when this is
+#       specified, the target name used to invoke this template will be
+#       designated as the "name" of this test and will primarly used for test
+#       results tracking and displaying (eg: flakiness dashboard).
 #   generated_script: Path to place the generated script.
 #   deploy_chrome: If true, deploys a locally built chrome located in the root
 #       build dir to the VM after launching it.
@@ -35,6 +39,7 @@
                            "deploy_chrome",
                            "generated_script",
                            "runtime_deps_file",
+                           "tast_tests",
                            "testonly",
                            "test_exe",
                          ])
@@ -45,6 +50,9 @@
   assert(defined(generated_script),
          "Must specify where to place generated test launcher script via " +
              "'generated_script'")
+  assert(!(defined(tast_tests) && defined(test_exe)),
+         "Tast tests are invoked from binaries shipped with the VM image. " +
+             "There should be no locally built binary needed.")
 
   action(target_name) {
     if (defined(runtime_deps_file)) {
@@ -126,6 +134,36 @@
           rebase_path(runtime_deps_file, root_build_dir),
         ]
       }
+    } else if (defined(tast_tests)) {
+      # When --tast-tests is specified, run_vm_test will call local_test_runner
+      # on the VM to run the set of tests.
+      args += [
+        "--suite-name",
+        target_name,
+      ]
+      foreach(test, tast_tests) {
+        args += [
+          "--tast-tests",
+          test,
+        ]
+      }
     }
   }
 }
+
+# TODO(crbug.com/876587): Support Tast conditionals as well.
+template("tast_test") {
+  assert(defined(invoker.tast_tests), "A list of tast_tests must be specified.")
+
+  generate_vm_runner_script(target_name) {
+    testonly = true
+    tast_tests = invoker.tast_tests
+    generated_script = "$root_build_dir/bin/run_${target_name}"
+    runtime_deps_file = "$root_out_dir/${target_name}/.runtime_deps"
+    deploy_chrome = true
+    data_deps = [
+      "//:chromiumos_preflight",  # Builds the browser.
+      "//chromeos:cros_chrome_deploy",  # Adds additional browser run-time deps.
+    ]
+  }
+}
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 88f7a115..1ddc90353 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1503,6 +1503,12 @@
           "-Wno-ignored-pragma-optimize",
         ]
       }
+      if (llvm_force_head_revision) {
+        cflags += [
+          # TODO(hans): https://crbug.com/890307
+          "-Wno-defaulted-function-deleted",
+        ]
+      }
     }
   }
 }
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 38a1a97..3a41fb56 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -136,7 +136,7 @@
     ldflags += [ "/TIMESTAMP:" + build_timestamp ]
   }
 
-  if (!is_debug && !is_component_build && !use_libfuzzer) {
+  if (!is_debug && !is_component_build) {
     # Enable standard linker optimizations like GC (/OPT:REF) and ICF in static
     # release builds. These are implied by /PROFILE below, but /PROFILE is
     # incompatible with /debug:fastlink and LLD ignores it as of this writing.
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 0a7ea94c..01c693ac 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -54,6 +54,7 @@
       use_parent_backface_visibility(false),
       background_color(0),
       scrollable(false),
+      is_scrollbar(false),
       user_scrollable_horizontal(true),
       user_scrollable_vertical(true),
       main_thread_scrolling_reasons(
@@ -909,6 +910,14 @@
   SetNeedsCommit();
 }
 
+void Layer::SetIsScrollbar(bool is_scrollbar) {
+  if (inputs_.is_scrollbar == is_scrollbar)
+    return;
+
+  inputs_.is_scrollbar = is_scrollbar;
+  SetNeedsCommit();
+}
+
 void Layer::SetUserScrollable(bool horizontal, bool vertical) {
   DCHECK(IsPropertyChangeAllowed());
   if (inputs_.user_scrollable_horizontal == horizontal &&
@@ -1284,6 +1293,8 @@
   if (scrollable())
     layer->SetScrollable(inputs_.scroll_container_bounds);
 
+  layer->set_is_scrollbar(inputs_.is_scrollbar);
+
   // The property trees must be safe to access because they will be used below
   // to call |SetScrollOffsetClobberActiveValue|.
   DCHECK(layer->layer_tree_impl()->lifecycle().AllowsPropertyTreeAccess());
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index d525463..6522e552 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -395,6 +395,9 @@
     return inputs_.scroll_container_bounds;
   }
 
+  void SetIsScrollbar(bool is_scrollbar);
+  bool is_scrollbar() const { return inputs_.is_scrollbar; }
+
   // Set or get if this layer is able to be scrolled along each axis. These are
   // independant of the scrollable state, or size of the scrollable area
   // specified in SetScrollable(), as these may be enabled or disabled
@@ -905,6 +908,9 @@
     // |scroll_container_bounds|).
     bool scrollable : 1;
 
+    // Indicates that this layer is a scrollbar.
+    bool is_scrollbar : 1;
+
     bool user_scrollable_horizontal : 1;
     bool user_scrollable_vertical : 1;
 
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 4cd1b50..3a4bf453 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -78,6 +78,7 @@
       debug_info_(nullptr),
       has_will_change_transform_hint_(false),
       needs_push_properties_(false),
+      is_scrollbar_(false),
       scrollbars_hidden_(false),
       needs_show_scrollbars_(false),
       raster_even_if_not_drawn_(false),
@@ -347,6 +348,8 @@
   if (scrollable_)
     layer->SetScrollable(scroll_container_bounds_);
 
+  layer->set_is_scrollbar(is_scrollbar_);
+
   // If the main thread commits multiple times before the impl thread actually
   // draws, then damage tracking will become incorrect if we simply clobber the
   // update_rect here. The LayerImpl's update_rect needs to accumulate (i.e.
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 1065f4e..bdfd63a 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -421,9 +421,9 @@
     return contributes_to_drawn_render_surface_;
   }
 
-  bool IsDrawnScrollbar() {
-    return ToScrollbarLayer() && contributes_to_drawn_render_surface_;
-  }
+  bool is_scrollbar() const { return is_scrollbar_; }
+
+  void set_is_scrollbar(bool is_scrollbar) { is_scrollbar_ = is_scrollbar; }
 
   void set_may_contain_video(bool yes) { may_contain_video_ = yes; }
   bool may_contain_video() const { return may_contain_video_; }
@@ -597,6 +597,7 @@
 
   bool has_will_change_transform_hint_ : 1;
   bool needs_push_properties_ : 1;
+  bool is_scrollbar_ : 1;
   bool scrollbars_hidden_ : 1;
 
   // The needs_show_scrollbars_ bit tracks a pending request from Blink to show
diff --git a/cc/layers/painted_overlay_scrollbar_layer.cc b/cc/layers/painted_overlay_scrollbar_layer.cc
index 8bea0f87..ca94e661 100644
--- a/cc/layers/painted_overlay_scrollbar_layer.cc
+++ b/cc/layers/painted_overlay_scrollbar_layer.cc
@@ -45,6 +45,7 @@
       thumb_thickness_(scrollbar_->ThumbThickness()),
       thumb_length_(scrollbar_->ThumbLength()) {
   DCHECK(scrollbar_->UsesNinePatchThumbResource());
+  SetIsScrollbar(true);
 }
 
 PaintedOverlayScrollbarLayer::~PaintedOverlayScrollbarLayer() = default;
diff --git a/cc/layers/painted_scrollbar_layer.cc b/cc/layers/painted_scrollbar_layer.cc
index cf65df0..541c024e 100644
--- a/cc/layers/painted_scrollbar_layer.cc
+++ b/cc/layers/painted_scrollbar_layer.cc
@@ -54,9 +54,11 @@
       is_overlay_(scrollbar_->IsOverlay()),
       has_thumb_(scrollbar_->HasThumb()),
       thumb_opacity_(scrollbar_->ThumbOpacity()) {
-  if (!scrollbar_->IsOverlay())
+  if (!scrollbar_->IsOverlay()) {
     AddMainThreadScrollingReasons(
         MainThreadScrollingReason::kScrollbarScrolling);
+  }
+  SetIsScrollbar(true);
 }
 
 PaintedScrollbarLayer::~PaintedScrollbarLayer() = default;
diff --git a/cc/layers/scrollbar_layer_impl_base.cc b/cc/layers/scrollbar_layer_impl_base.cc
index 6a0f9eb6..24a855e2f 100644
--- a/cc/layers/scrollbar_layer_impl_base.cc
+++ b/cc/layers/scrollbar_layer_impl_base.cc
@@ -26,7 +26,9 @@
       scroll_layer_length_(0.f),
       orientation_(orientation),
       is_left_side_vertical_scrollbar_(is_left_side_vertical_scrollbar),
-      vertical_adjust_(0.f) {}
+      vertical_adjust_(0.f) {
+  set_is_scrollbar(true);
+}
 
 ScrollbarLayerImplBase::~ScrollbarLayerImplBase() {
   layer_tree_impl()->UnregisterScrollbar(this);
diff --git a/cc/layers/solid_color_scrollbar_layer.cc b/cc/layers/solid_color_scrollbar_layer.cc
index f514b6d..c73f241a 100644
--- a/cc/layers/solid_color_scrollbar_layer.cc
+++ b/cc/layers/solid_color_scrollbar_layer.cc
@@ -60,6 +60,7 @@
                                           is_left_side_vertical_scrollbar,
                                           scroll_element_id) {
   Layer::SetOpacity(0.f);
+  SetIsScrollbar(true);
 }
 
 SolidColorScrollbarLayer::~SolidColorScrollbarLayer() = default;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index e53875b..285ed7b67 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -3638,6 +3638,24 @@
 
   ClearCurrentlyScrollingNode();
 
+  gfx::Point viewport_point(scroll_state->position_x(),
+                            scroll_state->position_y());
+
+  gfx::PointF device_viewport_point = gfx::ScalePoint(
+      gfx::PointF(viewport_point), active_tree_->device_scale_factor());
+  LayerImpl* first_scrolling_layer_or_scrollbar =
+      active_tree_->FindFirstScrollingLayerOrScrollbarThatIsHitByPoint(
+          device_viewport_point);
+
+  if (IsTouchDraggingScrollbar(first_scrolling_layer_or_scrollbar, type)) {
+    TRACE_EVENT_INSTANT0("cc", "Scrollbar Scrolling", TRACE_EVENT_SCOPE_THREAD);
+    ScrollStatus scroll_status;
+    scroll_status.thread = SCROLL_ON_MAIN_THREAD;
+    scroll_status.main_thread_scrolling_reasons =
+        MainThreadScrollingReason::kScrollbarScrolling;
+    return scroll_status;
+  }
+
   return ScrollBeginImpl(scroll_state, OuterViewportScrollNode(), type);
 }
 
@@ -3667,7 +3685,21 @@
         active_tree_->FindLayerThatIsHitByPoint(device_viewport_point);
 
     if (layer_impl) {
-      if (!IsInitialScrollHitTestReliable(layer_impl, device_viewport_point)) {
+      LayerImpl* first_scrolling_layer_or_scrollbar =
+          active_tree_->FindFirstScrollingLayerOrScrollbarThatIsHitByPoint(
+              device_viewport_point);
+
+      // Touch dragging the scrollbar requires falling back to main-thread
+      // scrolling.
+      if (IsTouchDraggingScrollbar(first_scrolling_layer_or_scrollbar, type)) {
+        TRACE_EVENT_INSTANT0("cc", "Scrollbar Scrolling",
+                             TRACE_EVENT_SCOPE_THREAD);
+        scroll_status.thread = SCROLL_ON_MAIN_THREAD;
+        scroll_status.main_thread_scrolling_reasons =
+            MainThreadScrollingReason::kScrollbarScrolling;
+        return scroll_status;
+      } else if (!IsInitialScrollHitTestReliable(
+                     layer_impl, first_scrolling_layer_or_scrollbar)) {
         TRACE_EVENT_INSTANT0("cc", "Failed Hit Test", TRACE_EVENT_SCOPE_THREAD);
         scroll_status.thread = SCROLL_UNKNOWN;
         scroll_status.main_thread_scrolling_reasons =
@@ -3693,17 +3725,23 @@
   return ScrollBeginImpl(scroll_state, scrolling_node, type);
 }
 
-// Some initial scroll tests are known to be unreliable and require falling
-// back to main thread scrolling.
+// Requires falling back to main thread scrolling when it hit tests in scrollbar
+// from touch.
+bool LayerTreeHostImpl::IsTouchDraggingScrollbar(
+    LayerImpl* first_scrolling_layer_or_scrollbar,
+    InputHandler::ScrollInputType type) {
+  return first_scrolling_layer_or_scrollbar &&
+         first_scrolling_layer_or_scrollbar->is_scrollbar() &&
+         type == InputHandler::TOUCHSCREEN;
+}
+
+// Initial scroll hit testing can be unreliable in the presence of squashed
+// layers. In this case, we fall back to main thread scrolling.
 bool LayerTreeHostImpl::IsInitialScrollHitTestReliable(
     LayerImpl* layer_impl,
-    const gfx::PointF& device_viewport_point) {
-  LayerImpl* first_scrolling_layer_or_drawn_scrollbar =
-      active_tree_->FindFirstScrollingLayerOrDrawnScrollbarThatIsHitByPoint(
-          device_viewport_point);
-  if (!first_scrolling_layer_or_drawn_scrollbar)
+    LayerImpl* first_scrolling_layer_or_scrollbar) {
+  if (!first_scrolling_layer_or_scrollbar)
     return true;
-
   ScrollNode* closest_scroll_node = nullptr;
   auto& scroll_tree = active_tree_->property_trees()->scroll_tree;
   ScrollNode* scroll_node = scroll_tree.Node(layer_impl->scroll_tree_index());
@@ -3717,19 +3755,19 @@
   if (!closest_scroll_node)
     return false;
 
-  // If |first_scrolling_layer_or_drawn_scrollbar| is scrollable, it will
+  // If |first_scrolling_layer_or_scrollbar| is scrollable, it will
   // create a scroll node. If this scroll node corresponds to first scrollable
   // ancestor along the scroll tree for |layer_impl|, the hit test has not
   // escaped to other areas of the scroll tree and is reliable.
-  if (first_scrolling_layer_or_drawn_scrollbar->scrollable()) {
+  if (first_scrolling_layer_or_scrollbar->scrollable()) {
     return closest_scroll_node->id ==
-           first_scrolling_layer_or_drawn_scrollbar->scroll_tree_index();
+           first_scrolling_layer_or_scrollbar->scroll_tree_index();
   }
 
-  // If |first_scrolling_layer_or_drawn_scrollbar| is not scrollable, it must
-  // be a drawn scrollbar. These hit tests require falling back to main-thread
-  // scrolling.
-  DCHECK(first_scrolling_layer_or_drawn_scrollbar->IsDrawnScrollbar());
+  // If |first_scrolling_layer_or_scrollbar| is not scrollable, it must
+  // be a drawn scrollbar. It may hit the squashing layer at the same time.
+  // These hit tests require falling back to main-thread scrolling.
+  DCHECK(first_scrolling_layer_or_scrollbar->is_scrollbar());
   return false;
 }
 
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 34f94397..b9d0f9b 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -784,7 +784,12 @@
       ScrollState* scroll_state,
       ScrollNode* scrolling_node,
       InputHandler::ScrollInputType type);
-  bool IsInitialScrollHitTestReliable(LayerImpl* layer, const gfx::PointF&);
+  bool IsTouchDraggingScrollbar(
+      LayerImpl* first_scrolling_layer_or_drawn_scrollbar,
+      InputHandler::ScrollInputType type);
+  bool IsInitialScrollHitTestReliable(
+      LayerImpl* layer,
+      LayerImpl* first_scrolling_layer_or_drawn_scrollbar);
   void DistributeScrollDelta(ScrollState* scroll_state);
 
   bool AnimatePageScale(base::TimeTicks monotonic_time);
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 2955a50..f22b1f7 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -3954,9 +3954,10 @@
   EXPECT_EQ(scrollbar_2_->Opacity(), 0.f);
 
   // Scroll on root should flash all scrollbars.
-  host_impl_->RootScrollBegin(BeginState(gfx::Point(10, 10)).get(),
+  host_impl_->RootScrollBegin(BeginState(gfx::Point(20, 20)).get(),
                               InputHandler::WHEEL);
-  host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
+  host_impl_->ScrollBy(
+      UpdateState(gfx::Point(20, 20), gfx::Vector2d(0, 10)).get());
   host_impl_->ScrollEnd(EndState().get());
 
   EXPECT_TRUE(scrollbar_1_->Opacity());
@@ -3966,8 +3967,8 @@
   ResetScrollbars();
 
   // Scroll on child should flash all scrollbars.
-  host_impl_->ScrollAnimatedBegin(BeginState(gfx::Point(51, 51)).get());
-  host_impl_->ScrollAnimated(gfx::Point(51, 51), gfx::Vector2d(0, 100));
+  host_impl_->ScrollAnimatedBegin(BeginState(gfx::Point(70, 70)).get());
+  host_impl_->ScrollAnimated(gfx::Point(70, 70), gfx::Vector2d(0, 100));
   host_impl_->ScrollEnd(EndState().get());
 
   EXPECT_TRUE(scrollbar_1_->Opacity());
@@ -4002,6 +4003,49 @@
   EXPECT_FALSE(animation_task_.Equals(base::Closure()));
 }
 
+TEST_F(LayerTreeHostImplTestMultiScrollable, ScrollHitTestOnScrollbar) {
+  LayerTreeSettings settings = DefaultSettings();
+  settings.scrollbar_fade_delay = base::TimeDelta::FromMilliseconds(500);
+  settings.scrollbar_fade_duration = base::TimeDelta::FromMilliseconds(300);
+  settings.scrollbar_animator = LayerTreeSettings::NO_ANIMATOR;
+
+  SetUpLayers(settings);
+
+  // Wheel scroll on root scrollbar should process on impl thread.
+  {
+    InputHandler::ScrollStatus status = host_impl_->RootScrollBegin(
+        BeginState(gfx::Point(1, 1)).get(), InputHandler::WHEEL);
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  }
+
+  // Touch scroll on root scrollbar should process on main thread.
+  {
+    InputHandler::ScrollStatus status = host_impl_->RootScrollBegin(
+        BeginState(gfx::Point(1, 1)).get(), InputHandler::TOUCHSCREEN);
+    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(MainThreadScrollingReason::kScrollbarScrolling,
+              status.main_thread_scrolling_reasons);
+  }
+
+  // Wheel scroll on scrollbar should fallback to main thread.
+  {
+    InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+        BeginState(gfx::Point(51, 51)).get(), InputHandler::WHEEL);
+    EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread);
+    EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest,
+              status.main_thread_scrolling_reasons);
+  }
+
+  // Touch scroll on scrollbar should process on main thread.
+  {
+    InputHandler::ScrollStatus status = host_impl_->RootScrollBegin(
+        BeginState(gfx::Point(51, 51)).get(), InputHandler::TOUCHSCREEN);
+    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(MainThreadScrollingReason::kScrollbarScrolling,
+              status.main_thread_scrolling_reasons);
+  }
+}
+
 TEST_F(LayerTreeHostImplTest, ScrollbarVisibilityChangeCausesRedrawAndCommit) {
   LayerTreeSettings settings = DefaultSettings();
   settings.scrollbar_animator = LayerTreeSettings::AURA_OVERLAY;
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 4bd0719..018455c 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -2109,19 +2109,18 @@
   }
 }
 
-struct FindScrollingLayerOrDrawnScrollbarFunctor {
+struct FindScrollingLayerOrScrollbarFunctor {
   bool operator()(LayerImpl* layer) const {
-    return layer->scrollable() || layer->IsDrawnScrollbar();
+    return layer->scrollable() || layer->is_scrollbar();
   }
 };
 
-LayerImpl*
-LayerTreeImpl::FindFirstScrollingLayerOrDrawnScrollbarThatIsHitByPoint(
+LayerImpl* LayerTreeImpl::FindFirstScrollingLayerOrScrollbarThatIsHitByPoint(
     const gfx::PointF& screen_space_point) {
   FindClosestMatchingLayerState state;
   LayerImpl* root_layer = layer_list_.empty() ? nullptr : layer_list_[0];
   FindClosestMatchingLayer(screen_space_point, root_layer,
-                           FindScrollingLayerOrDrawnScrollbarFunctor(), &state);
+                           FindScrollingLayerOrScrollbarFunctor(), &state);
   return state.closest_match;
 }
 
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 299c9a832..f5dd26f 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -502,7 +502,7 @@
   void UnregisterScrollbar(ScrollbarLayerImplBase* scrollbar_layer);
   ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const;
 
-  LayerImpl* FindFirstScrollingLayerOrDrawnScrollbarThatIsHitByPoint(
+  LayerImpl* FindFirstScrollingLayerOrScrollbarThatIsHitByPoint(
       const gfx::PointF& screen_space_point);
 
   LayerImpl* FindLayerThatIsHitByPoint(const gfx::PointF& screen_space_point);
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index e4aa553..cc5f72b 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -22,6 +22,8 @@
 import("channel.gni")
 import("java_sources.gni")
 import("static_initializers.gni")
+import("trichrome.gni")
+
 if (modularize_ar) {
   import("//chrome/android/modules/ar/ar_module_tmpl.gni")
 }
@@ -41,6 +43,10 @@
     "$target_gen_dir/chrome_sync_shell_apk/AndroidManifest.xml"
 monochrome_public_android_manifest =
     "$target_gen_dir/monochrome_public_apk/AndroidManifest.xml"
+trichrome_library_android_manifest =
+    "$target_gen_dir/trichrome_library_apk/AndroidManifest.xml"
+trichrome_chrome_android_manifest =
+    "$target_gen_dir/trichrome_chrome_apk/AndroidManifest.xml"
 
 chrome_sync_shell_jinja_variables =
     default_chrome_public_jinja_variables +
@@ -89,6 +95,20 @@
               [ "target_sdk_version=$android_sdk_version" ]
 }
 
+jinja_template("trichrome_library_android_manifest") {
+  input = "java/AndroidManifest_trichrome_library.xml"
+  output = trichrome_library_android_manifest
+  variables = trichrome_jinja_variables +
+              [ "manifest_package=$trichrome_library_package" ]
+}
+
+jinja_template("trichrome_chrome_android_manifest") {
+  input = "java/AndroidManifest_trichrome_chrome.xml"
+  includes = [ "java/AndroidManifest.xml" ]
+  output = trichrome_chrome_android_manifest
+  variables = chrome_public_jinja_variables + trichrome_jinja_variables
+}
+
 jinja_template("chrome_sync_shell_android_manifest") {
   input = "java/AndroidManifest.xml"
   output = chrome_sync_shell_android_manifest
@@ -1441,15 +1461,20 @@
   monochrome_public_common_apk_or_module_tmpl(target_name) {
     forward_variables_from(invoker,
                            [
+                             "android_manifest",
+                             "android_manifest_dep",
                              "apk_name",
                              "is_base_module",
                              "module_name",
                              "proguard_jar_path",
                              "target_type",
+                             "use_trichrome_library",
                            ])
 
-    android_manifest = monochrome_public_android_manifest
-    android_manifest_dep = ":monochrome_public_android_manifest"
+    if (!defined(android_manifest) && !defined(android_manifest_dep)) {
+      android_manifest = monochrome_public_android_manifest
+      android_manifest_dep = ":monochrome_public_android_manifest"
+    }
 
     if (public_android_sdk) {
       # Resource whitelist used when generating R.java files and causes
@@ -1465,8 +1490,10 @@
       "//chrome/android:chrome_java",
     ]
 
-    add_unwind_tables_in_apk = _add_unwind_tables_in_chrome_public_apk
-    if (_add_unwind_tables_in_chrome_public_apk && can_unwind_with_cfi_table) {
+    add_unwind_tables_in_apk =
+        _add_unwind_tables_in_chrome_public_apk &&
+        (!defined(use_trichrome_library) || !use_trichrome_library)
+    if (add_unwind_tables_in_apk && can_unwind_with_cfi_table) {
       shared_library_for_unwind_asset = "monochrome"
     }
 
@@ -1486,6 +1513,52 @@
   is_base_module = true
 }
 
+android_apk("trichrome_library_apk") {
+  apk_name = "TrichromeLibrary"
+  android_manifest = trichrome_library_android_manifest
+  android_manifest_dep = ":trichrome_library_android_manifest"
+
+  # TODO(torne): this contains the list of locales amongst other things.
+  # Skip building it because the version in the library won't be used anyway;
+  # the one in the main APK will take precedence.
+  generate_buildconfig_java = false
+
+  # TODO(torne): since there's no real java code in the library right now,
+  # leave out the build hooks and let them get compiled into each APK. Later
+  # this should probably be in the library.
+  no_build_hooks = true
+
+  alternative_android_sdk_dep = webview_framework_dep
+  app_as_shared_lib = true
+  use_chromium_linker = false
+  uncompress_shared_libraries = true
+
+  _native_lib_file =
+      rebase_path("$root_gen_dir/CHROME_VERSION.json", root_out_dir)
+  native_lib_version_arg = "@FileArg($_native_lib_file:full-quoted)"
+  native_lib_version_rule = "//build/util:chrome_version_json"
+
+  if (android_64bit_target_cpu) {
+    # Include a 64-bit placeholder library to ensure that the library is treated
+    # as multiarch and gets its Java code precompiled for both architectures.
+    native_lib_placeholders = [ "libdummy.so" ]
+    if (build_apk_secondary_abi) {
+      # Include the actual 32-bit libmonochrome library.
+      secondary_abi_shared_libraries = [ ":monochrome_secondary_abi_lib" ]
+    }
+  } else {
+    shared_libraries = [ ":monochrome" ]
+  }
+}
+
+monochrome_public_apk_or_module_tmpl("trichrome_chrome_apk") {
+  apk_name = "TrichromeChrome"
+  target_type = "android_apk"
+  android_manifest = trichrome_chrome_android_manifest
+  android_manifest_dep = ":trichrome_chrome_android_manifest"
+  use_trichrome_library = true
+}
+
 chrome_public_common_apk_or_module_tmpl("chrome_sync_shell_apk") {
   testonly = true
   target_type = "android_apk"
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index a95fdead..883b7ab 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -195,16 +195,28 @@
     _enable_multidex = is_java_debug || multidex_in_release
   }
   chrome_public_common_apk_or_module_tmpl(target_name) {
-    # Always build 64-bit //android_webview:monochrome because Chrome runs
-    # in 32-bit mode.
-    if (android_64bit_target_cpu) {
-      shared_libraries = [ "//android_webview:monochrome" ]
+    if (!defined(invoker.use_trichrome_library) ||
+        !invoker.use_trichrome_library) {
+      # Always build 64-bit //android_webview:monochrome because Chrome runs
+      # in 32-bit mode.
+      if (android_64bit_target_cpu) {
+        shared_libraries = [ "//android_webview:monochrome" ]
+      } else {
+        shared_libraries = [ "//chrome/android:monochrome" ]
+      }
+      if (android_64bit_target_cpu && build_apk_secondary_abi) {
+        secondary_abi_shared_libraries =
+            [ "//chrome/android:monochrome_secondary_abi_lib" ]
+      }
     } else {
-      shared_libraries = [ "//chrome/android:monochrome" ]
-    }
-    if (android_64bit_target_cpu && build_apk_secondary_abi) {
-      secondary_abi_shared_libraries =
-          [ "//chrome/android:monochrome_secondary_abi_lib" ]
+      # Include a 32-bit placeholder library to ensure that Chrome runs in
+      # 32-bit mode.
+      if (android_64bit_target_cpu) {
+        # We don't want to be 64-bit, only include a placeholder for secondary.
+        secondary_native_lib_placeholders = [ "libdummy.so" ]
+      } else {
+        native_lib_placeholders = [ "libdummy.so" ]
+      }
     }
 
     alternative_android_sdk_dep = webview_framework_dep
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedBasicLogging.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedBasicLogging.java
index d1f8d84..c0f4410 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedBasicLogging.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedBasicLogging.java
@@ -11,7 +11,15 @@
  * Implementation of {@link BasicLoggingApi} that log actions performed on the Feed.
  */
 public class FeedBasicLogging implements BasicLoggingApi {
-    // TODO(gangwu): implement BasicLoggingApi functionality.
+    private FeedLoggingBridge mFeedLoggingBridge;
+
+    /**
+     * Creates a {@link FeedBasicLogging} for accessing native logging logic.
+     */
+    public FeedBasicLogging() {
+        mFeedLoggingBridge = new FeedLoggingBridge();
+    }
+
     @Override
     public void onContentViewed(ContentLoggingData data) {}
     @Override
@@ -26,8 +34,12 @@
     public void onMoreButtonViewed(int position) {}
     @Override
     public void onMoreButtonClicked(int position) {}
+
     @Override
-    public void onOpenedWithContent(int timeToPopulateMs, int contentCount) {}
+    public void onOpenedWithContent(int timeToPopulateMs, int contentCount) {
+        mFeedLoggingBridge.onOpenedWithContent(contentCount);
+    }
+
     @Override
     public void onOpenedWithNoImmediateContent() {}
     @Override
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedContentBridge.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedContentBridge.java
index 2a18f7b0..a53336d 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedContentBridge.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedContentBridge.java
@@ -45,11 +45,6 @@
     @VisibleForTesting
     public FeedContentBridge() {}
 
-    /**
-     * Initializes the native side of this bridge.
-     */
-    public void init() {}
-
     /** Cleans up native half of this bridge. */
     public void destroy() {
         assert mNativeFeedContentBridge != 0;
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java
new file mode 100644
index 0000000..fcf034a6
--- /dev/null
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.feed;
+
+import org.chromium.base.annotations.JNINamespace;
+
+/**
+ * Provides access to native implementation of feed logging.
+ */
+@JNINamespace("feed")
+public class FeedLoggingBridge {
+    private long mNativeFeedLoggingBridge;
+
+    /**
+     * Creates a {@link FeedLoggingBridge} for accessing native feed logging
+     * implementation for the current user, and initial native side bridge.
+     */
+    public FeedLoggingBridge() {
+        mNativeFeedLoggingBridge = nativeInit();
+    }
+
+    /** Cleans up native half of this bridge. */
+    public void destroy() {
+        assert mNativeFeedLoggingBridge != 0;
+        nativeDestroy(mNativeFeedLoggingBridge);
+        mNativeFeedLoggingBridge = 0;
+    }
+
+    public void onOpenedWithContent(int contentCount) {
+        assert mNativeFeedLoggingBridge != 0;
+        nativeOnOpenedWithContent(mNativeFeedLoggingBridge, contentCount);
+    }
+
+    private native long nativeInit();
+    private native void nativeDestroy(long nativeFeedLoggingBridge);
+    private native void nativeOnOpenedWithContent(long nativeFeedLoggingBridge, int contentCount);
+}
diff --git a/chrome/android/feed/feed_java_sources.gni b/chrome/android/feed/feed_java_sources.gni
index 40d9865..2b4debf 100644
--- a/chrome/android/feed/feed_java_sources.gni
+++ b/chrome/android/feed/feed_java_sources.gni
@@ -17,6 +17,7 @@
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedImageLoaderBridge.java",
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedJournalBridge.java",
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedJournalStorage.java",
+    "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java",
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNetworkBridge.java",
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java",
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPageMediator.java",
diff --git a/chrome/android/java/AndroidManifest_trichrome_chrome.xml b/chrome/android/java/AndroidManifest_trichrome_chrome.xml
new file mode 100644
index 0000000..5118d38
--- /dev/null
+++ b/chrome/android/java/AndroidManifest_trichrome_chrome.xml
@@ -0,0 +1,27 @@
+{% extends "chrome/android/java/AndroidManifest.xml" %}
+
+## Copyright 2018 The Chromium Authors. All rights reserved.
+## Use of this source code is governed by a BSD-style license that can be
+## found in the LICENSE file.
+
+## Note: This is a jinja2 template, processed at build time into the final manifest.
+
+## TODO(torne): we need a Trichrome application subclass to use the library preloader
+##{% block application_name %}org.chromium.chrome.browser.MonochromeApplication{% endblock %}
+
+{% block extra_application_attributes %}
+{{ super() }}
+android:extractNativeLibs="false"
+{% endblock %}
+
+{% block extra_keyset_definitions %}
+  <!-- No keyset definitions should exist for any trichrome apks -->
+{% endblock %}
+
+{% block extra_application_definitions %}
+{{ super() }}
+<uses-static-library
+    android:name="{{ trichrome_library }}"
+    android:version="{{ trichrome_version }}"
+    android:certDigest="{{ trichrome_certdigest }}" />
+{% endblock %}
diff --git a/chrome/android/java/AndroidManifest_trichrome_library.xml b/chrome/android/java/AndroidManifest_trichrome_library.xml
new file mode 100644
index 0000000..7c01616
--- /dev/null
+++ b/chrome/android/java/AndroidManifest_trichrome_library.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<!--
+Note: This is a jinja2 template, processed at build time into the final manifest.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="{{ manifest_package }}"
+    tools:ignore="MissingVersion">
+
+    <uses-sdk android:minSdkVersion="{{min_sdk_version}}" android:targetSdkVersion="{{target_sdk_version}}" />
+    <uses-feature android:glEsVersion="0x00020000" />
+    <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
+
+    <!-- TODO(torne): we should specify an icon, roundIcon, and label from resources. -->
+    <application
+        android:label="Trichrome Library"
+        android:multiArch="true"
+        android:extractNativeLibs="false">
+
+        <static-library android:name="{{ trichrome_library }}" android:version="{{ trichrome_version }}" />
+    </application>
+</manifest>
diff --git a/chrome/android/java/proguard.flags b/chrome/android/java/proguard.flags
index 9e169d00..e673817 100644
--- a/chrome/android/java/proguard.flags
+++ b/chrome/android/java/proguard.flags
@@ -26,3 +26,7 @@
 -keepclassmembers class android.support.design.internal.BottomNavigationMenuView {
     boolean mShiftingMode;
 }
+
+# Trichrome builds don't include a native library list in the main APK; it's
+# picked up from the library APK at runtime.
+-dontwarn org.chromium.base.library_loader.NativeLibraries
diff --git a/chrome/android/java/res/layout/custom_tabs_control_container.xml b/chrome/android/java/res/layout/custom_tabs_control_container.xml
index 05a03b2..cc22798c 100644
--- a/chrome/android/java/res/layout/custom_tabs_control_container.xml
+++ b/chrome/android/java/res/layout/custom_tabs_control_container.xml
@@ -42,5 +42,12 @@
             android:layout_marginEnd="@dimen/find_in_page_popup_margin_end"
             android:layout_gravity="end|top"
             android:layout="@layout/find_toolbar" />
+        <ViewStub
+            android:id="@+id/topbar_stub"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="start|top"
+            android:inflatedId="@+id/topbar"
+            android:layout="@layout/custom_tabs_topbar" />
     </view>
 </org.chromium.chrome.browser.toolbar.ToolbarControlContainer>
diff --git a/chrome/android/java/res/layout/custom_tabs_topbar.xml b/chrome/android/java/res/layout/custom_tabs_topbar.xml
new file mode 100644
index 0000000..371209e
--- /dev/null
+++ b/chrome/android/java/res/layout/custom_tabs_topbar.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<org.chromium.ui.widget.OptimizedFrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    />
diff --git a/chrome/android/java/res/layout/update_menu_item.xml b/chrome/android/java/res/layout/update_menu_item.xml
index 7f9e9bf8..f2f8a1b 100644
--- a/chrome/android/java/res/layout/update_menu_item.xml
+++ b/chrome/android/java/res/layout/update_menu_item.xml
@@ -24,15 +24,13 @@
             android:id="@+id/menu_item_text"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
-            android:textColor="#dc5554" />
+            android:textAppearance="@style/TextAppearance.UpdateMenuItem" />
 
         <TextView
             android:id="@+id/menu_item_summary"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:textSize="12sp"
-            android:textColor="#646464" />
+            android:textAppearance="@style/BlackCaption" />
 
     </LinearLayout>
 
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index 5e651cd..3d946cde 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -587,6 +587,10 @@
         <item name="android:paddingEnd">16dp</item>
         <item name="android:background">?attr/listChoiceBackgroundIndicator</item>
     </style>
+    <style name="TextAppearance.UpdateMenuItem">
+        <item name="android:textColor">@color/update_menu_item_text_color</item>
+        <item name="android:textSize">@dimen/text_size_large</item>
+    </style>
     <style name="SadTabBodyText">
         <item name="android:textAppearance">@style/BlackBody</item>
         <item name="android:layout_gravity">start</item>
diff --git a/chrome/android/java/res/values-v23/styles.xml b/chrome/android/java/res/values-v26/styles.xml
similarity index 100%
rename from chrome/android/java/res/values-v23/styles.xml
rename to chrome/android/java/res/values-v26/styles.xml
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index 131293c..bd9fe551 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -61,6 +61,9 @@
     <!-- App banner colors -->
     <color name="app_banner_install_button_bg">#0F9D58</color>
 
+    <!-- App menu colors -->
+    <color name="update_menu_item_text_color">#DC5554</color>
+
     <!-- Connection Info Popup colors -->
     <color name="connection_info_popup_reset_cert_decisions_button">#000000</color>
     <color name="connection_info_popup_text">@color/modern_grey_900</color>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 10f8228..7a21711c 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -267,6 +267,7 @@
     <dimen name="tablet_toolbar_start_padding">4dp</dimen>
     <dimen name="tablet_toolbar_end_padding">6dp</dimen>
     <dimen name="location_bar_status_separator_width">1dp</dimen>
+    <dimen name="toolbar_optional_button_animation_translation">10dp</dimen>
 
     <!-- Modern toolbar dimensions -->
     <dimen name="modern_toolbar_background_size">40dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java
index 2e032204..d6c633f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java
@@ -13,6 +13,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.layouts.content.TitleBitmapFactory;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
 import org.chromium.chrome.browser.favicon.FaviconHelper.DefaultFaviconHelper;
@@ -120,7 +121,8 @@
     private String getUpdatedTitleInternal(Tab tab, String titleString,
             boolean fetchFaviconFromHistory) {
         final int tabId = tab.getId();
-        boolean isDarkTheme = tab.isIncognito();
+        boolean isDarkTheme = tab.isIncognito()
+                && !ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID);
         Bitmap originalFavicon = tab.getFavicon();
         if (originalFavicon == null) {
             originalFavicon = mDefaultFaviconHelper.getDefaultFaviconBitmap(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
index 4dabb1e..13b8a399 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
@@ -65,6 +65,9 @@
                 viewport.top, viewport.width(), viewport.height(), layerTitleCache,
                 tabContentManager, resourceManager);
 
+        boolean isHTSEnabled =
+                ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID);
+
         for (int i = 0; i < tabsCount; i++) {
             LayoutTab t = tabs[i];
             assert t.isVisible() : "LayoutTab in that list should be visible";
@@ -72,14 +75,14 @@
 
             float shadowAlpha = decoration / 2;
             int urlBarBackgroundId = R.drawable.modern_location_bar;
+            boolean useLightIcon = t.isIncognito() && !isHTSEnabled;
 
-            int defaultThemeColor = ColorUtils.getDefaultThemeColor(res, t.isIncognito());
+            int defaultThemeColor = ColorUtils.getDefaultThemeColor(res, useLightIcon);
 
             // In the modern design, the text box is always drawn opaque in the compositor.
             float textBoxAlpha = 1.f;
 
-            int closeButtonColor =
-                    ColorUtils.getThemedAssetColor(defaultThemeColor, t.isIncognito());
+            int closeButtonColor = ColorUtils.getThemedAssetColor(defaultThemeColor, useLightIcon);
 
             int borderColorResource =
                     t.isIncognito() ? R.color.tab_back_incognito : R.color.tab_back;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java
index d64570a..84d7b75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java
@@ -25,6 +25,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.toolbar.ToolbarManager;
+import org.chromium.chrome.browser.toolbar.ToolbarPhone;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.chrome.browser.util.MathUtils;
 import org.chromium.chrome.browser.widget.ListMenuButton;
@@ -289,7 +290,8 @@
         reportEvent(ContextualSuggestionsEvent.UI_BUTTON_SHOWN);
         TrackerFactory.getTrackerForProfile(mProfile).notifyEvent(
                 EventConstants.CONTEXTUAL_SUGGESTIONS_BUTTON_SHOWN);
-        maybeShowHelpBubble();
+        mHandler.postDelayed(() -> maybeShowHelpBubble(),
+                ToolbarPhone.LOC_BAR_WIDTH_CHANGE_ANIMATION_DURATION_MS);
     }
 
     @Override
@@ -433,13 +435,19 @@
     }
 
     private void maybeShowHelpBubble() {
+        View anchorView =
+                mIphParentView.getRootView().findViewById(R.id.experimental_toolbar_button);
+        if (mToolbarManager.isUrlBarFocused() || anchorView == null
+                || anchorView.getVisibility() != View.VISIBLE) {
+            return;
+        }
+
         Tracker tracker = TrackerFactory.getTrackerForProfile(mProfile);
         if (!tracker.shouldTriggerHelpUI(FeatureConstants.CONTEXTUAL_SUGGESTIONS_FEATURE)) {
             return;
         }
 
-        ViewRectProvider rectProvider = new ViewRectProvider(
-                mIphParentView.getRootView().findViewById(R.id.experimental_toolbar_button));
+        ViewRectProvider rectProvider = new ViewRectProvider(anchorView);
         rectProvider.setInsetPx(0, 0, 0,
                 mIphParentView.getResources().getDimensionPixelOffset(
                         R.dimen.text_bubble_menu_anchor_y_inset));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index dd66286..f3bee68 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -155,6 +155,7 @@
     private BrowserSessionContentHandler mBrowserSessionContentHandler;
     private Tab mMainTab;
     private CustomTabBottomBarDelegate mBottomBarDelegate;
+    private CustomTabTopBarDelegate mTopBarDelegate;
     private CustomTabTabPersistencePolicy mTabPersistencePolicy;
 
     // This is to give the right package name while using the client's resources during an
@@ -437,6 +438,11 @@
         loadUrlInTab(mMainTab, new LoadUrlParams(uri.toString()), SystemClock.elapsedRealtime());
     }
 
+    public void setTopBarContentView(View view) {
+        mTopBarDelegate.setTopBarContentView(view);
+        mTopBarDelegate.showTopBarIfNecessary();
+    }
+
     @Override
     public boolean shouldAllocateChildConnection() {
         return !mHasCreatedTabEarly && !mHasSpeculated
@@ -475,6 +481,7 @@
         mBottomBarDelegate = new CustomTabBottomBarDelegate(this, mIntentDataProvider,
                 getFullscreenManager());
         mBottomBarDelegate.showBottomBarIfNecessary();
+        mTopBarDelegate = new CustomTabTopBarDelegate(this);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java
new file mode 100644
index 0000000..2802de7
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.customtabs;
+
+import android.support.annotation.Nullable;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeActivity;
+
+/**
+ * Delegate that manages top bar area inside of {@link CustomTabActivity}.
+ */
+class CustomTabTopBarDelegate {
+    private ChromeActivity mActivity;
+    private ViewGroup mTopBarView;
+    @Nullable
+    private View mTopBarContentView;
+
+    public CustomTabTopBarDelegate(ChromeActivity activity) {
+        mActivity = activity;
+    }
+
+    /**
+     * Makes the top bar area to show, if any.
+     */
+    public void showTopBarIfNecessary() {
+        if (mTopBarContentView != null && mTopBarContentView.getParent() == null) {
+            getTopBarView().addView(mTopBarContentView);
+        }
+    }
+
+    /**
+     * Sets the content of the top bar.
+     */
+    public void setTopBarContentView(View view) {
+        mTopBarContentView = view;
+    }
+
+    /**
+     * Gets the {@link ViewGroup} of the top bar. If it has not been inflated, inflate it first.
+     */
+    private ViewGroup getTopBarView() {
+        if (mTopBarView == null) {
+            ViewStub topBarStub = ((ViewStub) mActivity.findViewById(R.id.topbar_stub));
+            mTopBarView = (ViewGroup) topBarStub.inflate();
+        }
+        return mTopBarView;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java
index 8a4a617..2e1cc5c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java
@@ -43,4 +43,9 @@
     public void loadUri(Uri uri) {
         mActivity.loadUri(uri);
     }
+
+    @Override
+    public void setTopBarView(IObjectWrapper topBarView) {
+        mActivity.setTopBarContentView(ObjectWrapper.unwrap(topBarView, View.class));
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ThumbnailGradient.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ThumbnailGradient.java
index 9154f09f..60e42ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ThumbnailGradient.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ThumbnailGradient.java
@@ -9,7 +9,6 @@
 import android.graphics.Color;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
 import android.os.SystemClock;
 import android.support.annotation.IntDef;
 
@@ -84,7 +83,7 @@
                             ? R.drawable.thumbnail_gradient_top_left
                             : R.drawable.thumbnail_gradient_top_right);
 
-            return new LayerDrawable(
+            return ApiCompatibilityUtils.createLayerDrawable(
                     new Drawable[] {new BitmapDrawable(resources, bitmap), gradient});
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
index 9734c6ae..125178c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
@@ -63,7 +63,7 @@
     /**
      * The ImageButton view that represents the menu button.
      */
-    private TintedImageButton mMenuButton;
+    protected TintedImageButton mMenuButton;
     private ImageView mMenuBadge;
     private View mMenuButtonWrapper;
     private AppMenuButtonHelper mAppMenuButtonHelper;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 1de9970..26792e8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -668,6 +668,13 @@
     }
 
     /**
+     * @return  Whether the UrlBar currently has focus.
+     */
+    public boolean isUrlBarFocused() {
+        return getToolbarLayout().getLocationBar().isUrlBarFocused();
+    }
+
+    /**
      * @param reason A {@link OmniboxFocusReason} that the omnibox was focused.
      */
     public static void recordOmniboxFocusReason(@OmniboxFocusReason int reason) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 17524e97..789ce1d7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -105,6 +105,7 @@
     public static final int URL_FOCUS_CHANGE_ANIMATION_DURATION_MS = 225;
     private static final int URL_FOCUS_TOOLBAR_BUTTONS_TRANSLATION_X_DP = 10;
     private static final int URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS = 100;
+    private static final int URL_CLEAR_FOCUS_EXPERIMENTAL_BUTTON_DELAY_MS = 150;
     private static final int URL_CLEAR_FOCUS_TABSTACK_DELAY_MS = 200;
     private static final int URL_CLEAR_FOCUS_MENU_DELAY_MS = 250;
 
@@ -113,6 +114,11 @@
     private static final int TAB_SWITCHER_MODE_EXIT_FADE_ANIMATION_DURATION_MS = 100;
     private static final int TAB_SWITCHER_MODE_POST_EXIT_ANIMATION_DURATION_MS = 100;
 
+    // Values used during animation to show/hide optional toolbar button.
+    public static final int LOC_BAR_WIDTH_CHANGE_ANIMATION_DURATION_MS = 225;
+    private static final int EXPERIMENTAL_ICON_ANIMATION_DURATION_MS = 100;
+    private static final int EXPERIMENTAL_ICON_ANIMATION_DELAY_MS = 125;
+
     private static final float UNINITIALIZED_PERCENT = -1f;
 
     /** States that the toolbar can be in regarding the tab switcher. */
@@ -210,6 +216,7 @@
 
     protected boolean mDisableLocationBarRelayout;
     protected boolean mLayoutLocationBarInFocusedMode;
+    private boolean mLayoutLocationBarWithoutExtraButton;
     protected int mUnfocusedLocationBarLayoutWidth;
     protected int mUnfocusedLocationBarLayoutLeft;
     protected int mUnfocusedLocationBarLayoutRight;
@@ -300,6 +307,17 @@
     private float mPreTextureCaptureAlpha = 1f;
     private boolean mIsOverlayTabStackDrawableLight;
 
+    private AnimatorSet mExperimentalButtonAnimator;
+    private boolean mExperimentalButtonAnimationRunning;
+    private int mExperimentalButtonTranslation;
+    /**
+     * The percent completion for the location bar width change animation that is run when the
+     * experimental button is shown/hidden. Animates from 1.f to 0.f when showing the button and
+     * 0.f to 1.f when hiding the button, where 0.f indicates the location bar width is not offset
+     * at all for the animation.
+     */
+    private float mLocBarWidthChangePercent;
+
     /**
      * A global layout listener used to capture a new texture when the experimental toolbar button
      * is added or removed.
@@ -336,6 +354,20 @@
         }
     };
 
+    private final Property<ToolbarPhone, Float> mLocBarWidthChangePercentProperty =
+            new Property<ToolbarPhone, Float>(Float.class, "") {
+                @Override
+                public Float get(ToolbarPhone object) {
+                    return object.mLocBarWidthChangePercent;
+                }
+
+                @Override
+                public void set(ToolbarPhone object, Float value) {
+                    mLocBarWidthChangePercent = value;
+                    updateLocationBarLayoutForExpansionAnimation();
+                }
+            };
+
     /**
      * Constructs a ToolbarPhone object.
      * @param context The Context in which this View object is created.
@@ -684,6 +716,12 @@
             leftMargin = mUnfocusedLocationBarLayoutLeft;
         }
 
+        if (mLayoutLocationBarWithoutExtraButton) {
+            float offset = getLocationBarWidthOffsetForExperimentalButton();
+            if (ApiCompatibilityUtils.isLayoutRtl(this)) leftMargin -= (int) offset;
+            width += (int) offset;
+        }
+
         boolean changed = false;
         changed |= (width != locationBarLayoutParams.width);
         locationBarLayoutParams.width = width;
@@ -915,6 +953,11 @@
         int leftViewPosition =
                 (int) MathUtils.interpolate(getViewBoundsLeftOfLocationBar(visualState),
                         getFocusedLeftPositionOfLocationBarBackground(), expansion);
+
+        if (mExperimentalButtonAnimationRunning && ApiCompatibilityUtils.isLayoutRtl(this)) {
+            leftViewPosition -= getLocationBarBackgroundOffsetForExperimentalButton();
+        }
+
         return leftViewPosition;
     }
 
@@ -936,10 +979,39 @@
                 (int) MathUtils.interpolate(getViewBoundsRightOfLocationBar(visualState),
                         getFocusedRightPositionOfLocationBarBackground(), expansion);
 
+        if (mExperimentalButtonAnimationRunning && !ApiCompatibilityUtils.isLayoutRtl(this)) {
+            rightViewPosition += getLocationBarBackgroundOffsetForExperimentalButton();
+        }
+
         return rightViewPosition;
     }
 
     /**
+     * @return The location bar background position offset, for use when the experimental button
+     *         show/hide animation is running.
+     */
+    private int getLocationBarBackgroundOffsetForExperimentalButton() {
+        return (int) (getLocationBarWidthOffsetForExperimentalButton() * mLocBarWidthChangePercent);
+    }
+
+    /**
+     * @return The difference in the location bar width when the experimental button is hidden
+     *         rather than showing. This is effectively the width of the experimental button with
+     *         some adjustment to account for possible padding differences when the button
+     *         visibility changes.
+     */
+    private float getLocationBarWidthOffsetForExperimentalButton() {
+        float widthChange = mExperimentalButton.getWidth();
+
+        // When the experimental button is the only visible button after the location bar and the
+        // button is hidden mToolbarSidePadding is used for the padding after the location bar.
+        if (!isMenuButtonPresent()) {
+            widthChange -= mToolbarSidePadding;
+        }
+        return widthChange;
+    }
+
+    /**
      * @return The right drawing position for the location bar background when the location bar
      *         has focus.
      */
@@ -1003,12 +1075,32 @@
         int currentWidth = locationBarLayoutParams.width;
 
         float locationBarBaseTranslationX = mUnfocusedLocationBarLayoutLeft - currentLeftMargin;
+        if (mExperimentalButtonAnimationRunning) {
+            // When showing the button, we disable location bar relayout
+            // (mDisableLocationBarRelayout), so the location bar's left margin and
+            // mUnfocusedLocationBarLayoutLeft have not been updated to take into account the
+            // appearance of the experimental icon. The views to left of the location bar will
+            // be wider than mUnfocusedlocationBarLayoutLeft in RTL, so adjust the translation by
+            // that amount.
+            // When hiding the button, we force a relayout without the experimental toolbar button
+            // (mLayoutLocationBarWithoutExtraButton). mUnfocusedLocationBarLayoutLeft reflects
+            // the view bounds left of the location bar, which still includes the experimental
+            // button. The location bar left margin, however, has been adjusted to reflect its
+            // end value when the experimental button is fully hidden. The
+            // locationBarBaseTranslationX above accounts for the difference between
+            // mUnfocusedLocationBarLayoutLeft and the location bar's current left margin.
+            locationBarBaseTranslationX +=
+                    getViewBoundsLeftOfLocationBar(mVisualState) - mUnfocusedLocationBarLayoutLeft;
+        }
+
         boolean isLocationBarRtl = ApiCompatibilityUtils.isLayoutRtl(mLocationBar);
         if (isLocationBarRtl) {
             locationBarBaseTranslationX += mUnfocusedLocationBarLayoutWidth - currentWidth;
         }
 
-        locationBarBaseTranslationX *= 1f - mUrlExpansionPercent;
+        locationBarBaseTranslationX *= 1f
+                - (mExperimentalButtonAnimationRunning ? mLocBarWidthChangePercent
+                                                       : mUrlExpansionPercent);
 
         mLocationBarBackgroundNtpOffset.setEmpty();
         mLocationBarNtpOffsetLeft = 0;
@@ -1038,23 +1130,25 @@
         }
 
         mLocationBar.setTranslationX(locationBarTranslationX);
-        mUrlActionContainer.setTranslationX(getUrlActionsTranslationXForExpansionAnimation(
-                isLocationBarRtl, locationBarBaseTranslationX));
-        mLocationBar.setUrlFocusChangePercent(mUrlExpansionPercent);
+        if (!mExperimentalButtonAnimationRunning) {
+            mUrlActionContainer.setTranslationX(getUrlActionsTranslationXForExpansionAnimation(
+                    isLocationBarRtl, locationBarBaseTranslationX));
+            mLocationBar.setUrlFocusChangePercent(mUrlExpansionPercent);
 
-        // Only transition theme colors if in static tab mode that is not the NTP. In practice this
-        // only runs when you focus the omnibox on a web page.
-        if (!isLocationBarShownInNTP() && mTabSwitcherState == STATIC_TAB) {
-            int defaultColor = ColorUtils.getDefaultThemeColor(getResources(), isIncognito());
-            int defaultLocationBarColor = getLocationBarColorForToolbarColor(defaultColor);
-            int primaryColor = getToolbarDataProvider().getPrimaryColor();
-            int themedLocationBarColor = getLocationBarColorForToolbarColor(primaryColor);
+            // Only transition theme colors if in static tab mode that is not the NTP. In practice
+            // this only runs when you focus the omnibox on a web page.
+            if (!isLocationBarShownInNTP() && mTabSwitcherState == STATIC_TAB) {
+                int defaultColor = ColorUtils.getDefaultThemeColor(getResources(), isIncognito());
+                int defaultLocationBarColor = getLocationBarColorForToolbarColor(defaultColor);
+                int primaryColor = getToolbarDataProvider().getPrimaryColor();
+                int themedLocationBarColor = getLocationBarColorForToolbarColor(primaryColor);
 
-            updateToolbarBackground(ColorUtils.getColorWithOverlay(
-                    primaryColor, defaultColor, mUrlFocusChangePercent));
+                updateToolbarBackground(ColorUtils.getColorWithOverlay(
+                        primaryColor, defaultColor, mUrlFocusChangePercent));
 
-            updateModernLocationBarColor(ColorUtils.getColorWithOverlay(
-                    themedLocationBarColor, defaultLocationBarColor, mUrlFocusChangePercent));
+                updateModernLocationBarColor(ColorUtils.getColorWithOverlay(
+                        themedLocationBarColor, defaultLocationBarColor, mUrlFocusChangePercent));
+            }
         }
 
         // Force an invalidation of the location bar to properly handle the clipping of the URL
@@ -1441,7 +1535,7 @@
             // viewport used to draw the background.  During expansion transitions, compensation
             // is applied to increase the clip regions such that when the location bar converts
             // to the narrower collapsed layout the visible content is the same.
-            if (mUrlExpansionPercent != 1f) {
+            if (mUrlExpansionPercent != 1f && !mExperimentalButtonAnimationRunning) {
                 int leftDelta = mUnfocusedLocationBarLayoutLeft
                         - getViewBoundsLeftOfLocationBar(mVisualState);
                 int rightDelta = getViewBoundsRightOfLocationBar(mVisualState)
@@ -1461,6 +1555,13 @@
                     locationBarClipRight -= ViewCompat.getPaddingEnd(mLocationBar) * inversePercent;
                 }
             }
+            if (mExperimentalButtonAnimationRunning) {
+                if (ApiCompatibilityUtils.isLayoutRtl(mLocationBar)) {
+                    locationBarClipLeft += ViewCompat.getPaddingStart(mLocationBar);
+                } else {
+                    locationBarClipRight -= ViewCompat.getPaddingEnd(mLocationBar);
+                }
+            }
 
             // Clip the location bar child to the URL viewport calculated in onDraw.
             canvas.clipRect(
@@ -1969,6 +2070,19 @@
             animators.add(animator);
         }
 
+        if (mExperimentalButton != null && mExperimentalButton.getVisibility() != View.GONE) {
+            animator = ObjectAnimator.ofFloat(
+                    mExperimentalButton, TRANSLATION_X, toolbarButtonTranslationX);
+            animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
+            animator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
+            animators.add(animator);
+
+            animator = ObjectAnimator.ofFloat(mExperimentalButton, ALPHA, 0);
+            animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
+            animator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
+            animators.add(animator);
+        }
+
         animator = ObjectAnimator.ofFloat(mToolbarShadow, ALPHA, 0);
         animator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
         animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
@@ -2010,6 +2124,23 @@
             animators.add(animator);
         }
 
+        if (mExperimentalButton != null && mExperimentalButton.getVisibility() != View.GONE) {
+            // TODO(twellington): it's possible that the experimental button was shown while
+            // the url bar was focused, in which case the translation x and alpha animators
+            // are a no-op. Account for this case.
+            animator = ObjectAnimator.ofFloat(mExperimentalButton, TRANSLATION_X, 0);
+            animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
+            animator.setStartDelay(URL_CLEAR_FOCUS_EXPERIMENTAL_BUTTON_DELAY_MS);
+            animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+            animators.add(animator);
+
+            animator = ObjectAnimator.ofFloat(mExperimentalButton, ALPHA, 1);
+            animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
+            animator.setStartDelay(URL_CLEAR_FOCUS_EXPERIMENTAL_BUTTON_DELAY_MS);
+            animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+            animators.add(animator);
+        }
+
         for (int i = 0; i < mLocationBar.getChildCount(); i++) {
             View childView = mLocationBar.getChildAt(i);
             if (childView == mLocationBar.getFirstViewVisibleWhenFocused()) break;
@@ -2042,6 +2173,7 @@
             mUrlFocusLayoutAnimator.cancel();
             mUrlFocusLayoutAnimator = null;
         }
+        if (mExperimentalButtonAnimationRunning) mExperimentalButtonAnimator.end();
 
         List<Animator> animators = new ArrayList<>();
         if (hasFocus) {
@@ -2559,10 +2691,14 @@
             ViewStub viewStub = findViewById(R.id.experimental_button_stub);
             mExperimentalButton = (TintedImageButton) viewStub.inflate();
 
-            if (FeatureUtilities.isBottomToolbarEnabled()) {
-                mExperimentalButton.setPadding(0, 0, 0, 0);
-            }
+            if (!isMenuButtonPresent()) mExperimentalButton.setPadding(0, 0, 0, 0);
+            mExperimentalButtonTranslation = getResources().getDimensionPixelSize(
+                    R.dimen.toolbar_optional_button_animation_translation);
+            if (ApiCompatibilityUtils.isLayoutRtl(this)) mExperimentalButtonTranslation *= -1;
         } else {
+            if (mExperimentalButtonAnimationRunning) {
+                mExperimentalButtonAnimator.end();
+            }
             assert mExperimentalButton.getVisibility()
                     == View.GONE : "#disableExperimentalButton() should be called first.";
         }
@@ -2573,8 +2709,13 @@
         mExperimentalButton.setContentDescription(
                 getContext().getResources().getString(contentDescriptionResId));
         mExperimentalButton.setTint(mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
+
         if (mTabSwitcherState == STATIC_TAB) {
-            mExperimentalButton.setVisibility(View.VISIBLE);
+            if (!mUrlFocusChangeInProgress && !urlHasFocus()) {
+                runShowExperimentalButtonAnimation();
+            } else {
+                mExperimentalButton.setVisibility(View.VISIBLE);
+            }
         } else {
             mExperimentalButton.setVisibility(View.INVISIBLE);
         }
@@ -2585,24 +2726,158 @@
 
     @Override
     public void disableExperimentalButton() {
-        if (mExperimentalButton == null) return;
+        if (mExperimentalButton == null || mExperimentalButton.getVisibility() == View.GONE) {
+            return;
+        }
 
-        mExperimentalButton.setVisibility(View.GONE);
+        if (mTabSwitcherState == STATIC_TAB && !mUrlFocusChangeInProgress && !urlHasFocus()) {
+            runHideExperimentalButtonsAnimators();
+        } else {
+            mExperimentalButton.setVisibility(View.GONE);
+        }
+
         mBrowsingModeViews.remove(mExperimentalButton);
 
         getViewTreeObserver().addOnGlobalLayoutListener(mExperimentalButtonLayoutListener);
     }
 
+    /**
+     * Whether the menu button is visible. Used as a proxy for whether there are end toolbar
+     * buttons besides the experimental button.
+     */
+    private boolean isMenuButtonPresent() {
+        return mMenuButton != null;
+    }
+
     private void requestLayoutHostUpdateForExperimentalButton() {
         if (mLayoutUpdateHost != null) mLayoutUpdateHost.requestUpdate();
         getViewTreeObserver().removeOnGlobalLayoutListener(mExperimentalButtonLayoutListener);
     }
 
+    /**
+     * Runs an animation that fades in the experimental button while shortening the location bar
+     * background.
+     */
+    private void runShowExperimentalButtonAnimation() {
+        if (mExperimentalButtonAnimationRunning) mExperimentalButtonAnimator.end();
+
+        List<Animator> animators = new ArrayList<>();
+
+        mLocBarWidthChangePercent = 1.f;
+        Animator widthChangeAnimator =
+                ObjectAnimator.ofFloat(this, mLocBarWidthChangePercentProperty, 0.f);
+        widthChangeAnimator.setDuration(LOC_BAR_WIDTH_CHANGE_ANIMATION_DURATION_MS);
+        widthChangeAnimator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+        animators.add(widthChangeAnimator);
+
+        mExperimentalButton.setAlpha(0.f);
+        ObjectAnimator buttonAnimator =
+                ObjectAnimator.ofFloat(mExperimentalButton, View.ALPHA, 1.f);
+        buttonAnimator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+        buttonAnimator.setStartDelay(EXPERIMENTAL_ICON_ANIMATION_DELAY_MS);
+        buttonAnimator.setDuration(EXPERIMENTAL_ICON_ANIMATION_DURATION_MS);
+        animators.add(buttonAnimator);
+
+        mExperimentalButton.setTranslationX(mExperimentalButtonTranslation);
+        ObjectAnimator buttonTranslationAnimator =
+                ObjectAnimator.ofFloat(mExperimentalButton, View.TRANSLATION_X, 0);
+        buttonTranslationAnimator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+        buttonTranslationAnimator.setStartDelay(EXPERIMENTAL_ICON_ANIMATION_DELAY_MS);
+        buttonTranslationAnimator.setDuration(EXPERIMENTAL_ICON_ANIMATION_DURATION_MS);
+        animators.add(buttonTranslationAnimator);
+
+        mExperimentalButtonAnimator = new AnimatorSet();
+        mExperimentalButtonAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mDisableLocationBarRelayout = true;
+                mExperimentalButtonAnimationRunning = true;
+                mExperimentalButton.setVisibility(View.VISIBLE);
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                onExperimentalButtonAnimationEnd();
+                mDisableLocationBarRelayout = false;
+                mExperimentalButtonAnimationRunning = false;
+                requestLayout();
+            }
+        });
+        mExperimentalButtonAnimator.playTogether(animators);
+        mExperimentalButtonAnimator.start();
+    }
+
+    /**
+     * Runs an animation that fades out the experimental button while lengthening the location bar
+     * background.
+     */
+    private void runHideExperimentalButtonsAnimators() {
+        if (mExperimentalButtonAnimationRunning) mExperimentalButtonAnimator.end();
+
+        List<Animator> animators = new ArrayList<>();
+
+        mLocBarWidthChangePercent = 0.f;
+        Animator widthChangeAnimator =
+                ObjectAnimator.ofFloat(this, mLocBarWidthChangePercentProperty, 1.f);
+        widthChangeAnimator.setDuration(LOC_BAR_WIDTH_CHANGE_ANIMATION_DURATION_MS);
+        widthChangeAnimator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+        animators.add(widthChangeAnimator);
+
+        mExperimentalButton.setAlpha(1.f);
+        ObjectAnimator buttonAnimator =
+                ObjectAnimator.ofFloat(mExperimentalButton, View.ALPHA, 0.f);
+        buttonAnimator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
+        buttonAnimator.setDuration(EXPERIMENTAL_ICON_ANIMATION_DURATION_MS);
+        animators.add(buttonAnimator);
+
+        mExperimentalButton.setTranslationX(0);
+        ObjectAnimator buttonTranslationAnimator = ObjectAnimator.ofFloat(
+                mExperimentalButton, View.TRANSLATION_X, mExperimentalButtonTranslation);
+        buttonTranslationAnimator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
+        buttonTranslationAnimator.setDuration(EXPERIMENTAL_ICON_ANIMATION_DURATION_MS);
+        animators.add(buttonTranslationAnimator);
+
+        mExperimentalButtonAnimator = new AnimatorSet();
+        mExperimentalButtonAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mLayoutLocationBarWithoutExtraButton = true;
+                mExperimentalButtonAnimationRunning = true;
+                requestLayout();
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                onExperimentalButtonAnimationEnd();
+                mExperimentalButton.setVisibility(View.GONE);
+                mLayoutLocationBarWithoutExtraButton = false;
+                mExperimentalButtonAnimationRunning = false;
+            }
+        });
+        mExperimentalButtonAnimator.playTogether(animators);
+        mExperimentalButtonAnimator.start();
+    }
+
+    /**
+     * Resets the alpha and translation X for all views affected by the animations for showing or
+     * hiding buttons.
+     */
+    private void onExperimentalButtonAnimationEnd() {
+        mExperimentalButtonAnimator = null;
+        mExperimentalButton.setAlpha(1.f);
+        mExperimentalButton.setTranslationX(0);
+    }
+
     @VisibleForTesting
     public View getExperimentalButtonForTesting() {
         return mExperimentalButton;
     }
 
+    @VisibleForTesting
+    public void endExperimentalButtonAnimationForTesting() {
+        if (mExperimentalButtonAnimator != null) mExperimentalButtonAnimator.end();
+    }
+
     private void setTabSwitcherAnimationMenuDrawable() {
         mTabSwitcherAnimationMenuDrawable = ApiCompatibilityUtils.getDrawable(
                 getResources(), R.drawable.ic_more_vert_black_24dp);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialog.java
index 585f29d..d2c4413 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialog.java
@@ -84,10 +84,10 @@
      * Force the promo dialog to have a fully opaque background hiding any underlying content.
      */
     protected void forceOpaqueBackground() {
-        LayerDrawable background = new LayerDrawable(new Drawable[] {
-                new ColorDrawable(Color.WHITE),
-                new ColorDrawable(ApiCompatibilityUtils.getColor(
-                        getContext().getResources(), R.color.modal_dialog_scrim_color))});
+        LayerDrawable background = ApiCompatibilityUtils.createLayerDrawable(
+                new Drawable[] {new ColorDrawable(Color.WHITE),
+                        new ColorDrawable(ApiCompatibilityUtils.getColor(
+                                getContext().getResources(), R.color.modal_dialog_scrim_color))});
         mScrimView.setBackground(background);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ViewHighlighter.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ViewHighlighter.java
index fd10f30d..eb2ded88 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ViewHighlighter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ViewHighlighter.java
@@ -9,6 +9,7 @@
 import android.graphics.drawable.LayerDrawable;
 import android.view.View;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
 
@@ -49,9 +50,9 @@
             background = background.getConstantState().newDrawable(resources);
         }
 
-        LayerDrawable drawable =
-                new LayerDrawable(background == null ? new Drawable[] {pulseDrawable}
-                                                     : new Drawable[] {background, pulseDrawable});
+        LayerDrawable drawable = ApiCompatibilityUtils.createLayerDrawable(background == null
+                        ? new Drawable[] {pulseDrawable}
+                        : new Drawable[] {background, pulseDrawable});
         view.setBackground(drawable);
         view.setTag(R.id.highlight_state, true);
 
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 14b2c4c..3f1434fc 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -379,6 +379,7 @@
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabNavigationEventObserver.java",
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java",
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicy.java",
+  "java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java",
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java",
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java",
   "java/src/org/chromium/chrome/browser/customtabs/FirstMeaningfulPaintObserver.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java
index 8eb642c..dab21fd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java
@@ -528,7 +528,10 @@
                 "Toolbar button should be visible", View.VISIBLE, toolbarButton.getVisibility());
 
         // Simulate suggestions being cleared.
-        ThreadUtils.runOnUiThreadBlocking(() -> mMediator.clearState());
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            mMediator.clearState();
+            getToolbarPhone().endExperimentalButtonAnimationForTesting();
+        });
         assertEquals("Toolbar button should be gone", View.GONE, toolbarButton.getVisibility());
         assertEquals("Suggestions should be cleared", 0, mModel.getClusterList().getItemCount());
 
@@ -598,10 +601,8 @@
     }
 
     private View getToolbarButton(ChromeActivity activity) throws ExecutionException {
-        return ThreadUtils.runOnUiThreadBlocking(() -> {
-            return ((ToolbarPhone) activity.getToolbarManager().getToolbarLayout())
-                    .getExperimentalButtonForTesting();
-        });
+        return ThreadUtils.runOnUiThreadBlocking(
+                () -> { return getToolbarPhone(activity).getExperimentalButtonForTesting(); });
     }
 
     private void clickToolbarButton() throws ExecutionException {
@@ -641,6 +642,9 @@
         CriteriaHelper.pollUiThread(() -> {
             return mActivityTestRule.getActivity().getActivityTab().getUrl().equals(expectedUrl);
         });
+
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> getToolbarPhone().endExperimentalButtonAnimationForTesting());
     }
 
     private void dismissHelpBubble() {
@@ -650,4 +654,12 @@
             }
         });
     }
+
+    private ToolbarPhone getToolbarPhone() {
+        return getToolbarPhone(mActivityTestRule.getActivity());
+    }
+
+    private ToolbarPhone getToolbarPhone(ChromeActivity activity) {
+        return (ToolbarPhone) activity.getToolbarManager().getToolbarLayout();
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 19b4c32..e099558 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -1112,6 +1112,39 @@
 
     @Test
     @SmallTest
+    @RetryOnFailure
+    public void testSetTopBarContentView() throws Exception {
+        Intent intent = createMinimalCustomTabIntent();
+        mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
+
+        ThreadUtils.runOnUiThread(() -> {
+            CustomTabActivity cctActivity = mCustomTabActivityTestRule.getActivity();
+            View anyView = new View(cctActivity);
+            cctActivity.setTopBarContentView(anyView);
+            ViewGroup topBar = cctActivity.findViewById(R.id.topbar);
+            Assert.assertNotNull(topBar);
+            Assert.assertThat(anyView.getParent(), equalTo(topBar));
+        });
+    }
+
+    @Test
+    @SmallTest
+    @RetryOnFailure
+    public void testSetTopBarContentView_secondCallIsNoOp() throws Exception {
+        Intent intent = createMinimalCustomTabIntent();
+        mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
+
+        ThreadUtils.runOnUiThread(() -> {
+            CustomTabActivity cctActivity = mCustomTabActivityTestRule.getActivity();
+            View anyView = new View(cctActivity);
+            cctActivity.setTopBarContentView(anyView);
+            // Second call will not crash.
+            cctActivity.setTopBarContentView(anyView);
+        });
+    }
+
+    @Test
+    @SmallTest
     @Feature({"UiCatalogue"})
     public void testRemoteViews() throws Exception {
         Intent intent = createMinimalCustomTabIntent();
diff --git a/chrome/android/trichrome.gni b/chrome/android/trichrome.gni
new file mode 100644
index 0000000..7bd0c30
--- /dev/null
+++ b/chrome/android/trichrome.gni
@@ -0,0 +1,17 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/config.gni")
+
+trichrome_library_package = "org.chromium.trichromelibrary"
+trichrome_certdigest =
+    "1975b2f17177bc89a5dff31f9e64a6cae281a53dc1d1d59b1d147fe1c82afa00"
+
+trichrome_jinja_variables = [
+  "min_sdk_version=26",
+  "target_sdk_version=$android_sdk_version",
+  "trichrome_library=$trichrome_library_package",
+  "trichrome_version=$android_default_version_code",
+  "trichrome_certdigest=$trichrome_certdigest",
+]
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 54d47fc..742c10d 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -2662,6 +2662,12 @@
   <message name="IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_NOTIFICATION_DESCRIPTION" desc="Sub label for notification-enable toggle.">
     Enables the Assistant to show you notifications.
   </message>
+  <message name="IDS_SETTINGS_GOOGLE_ASSISTANT_LAUNCH_WITH_MIC_OPEN" desc="Title for a toggle that determines whether to open the microphone when launching the Assistant.">
+    Launch Assistant with microphone open
+  </message>
+  <message name="IDS_SETTINGS_GOOGLE_ASSISTANT_LAUNCH_WITH_MIC_OPEN_DESCRIPTION" desc="Sub label for launch-with-microphone-open toggle.">
+    Always launch the Assistant with microphone open.
+  </message>
   <message name="IDS_SETTINGS_GOOGLE_ASSISTANT_SETTINGS" desc="Title for a button that opens the Google Assistant app settings.">
     Google Assistant settings
   </message>
diff --git a/chrome/app_shim/chrome_main_app_mode_mac.mm b/chrome/app_shim/chrome_main_app_mode_mac.mm
index 6f345237..ae415b25 100644
--- a/chrome/app_shim/chrome_main_app_mode_mac.mm
+++ b/chrome/app_shim/chrome_main_app_mode_mac.mm
@@ -47,7 +47,7 @@
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/views/cocoa/bridge_factory_impl.h"
+#include "ui/views_bridge_mac/bridge_factory_impl.h"
 #include "ui/views_bridge_mac/mojo/bridge_factory.mojom.h"
 
 namespace {
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f54ffe17..632368c 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4506,6 +4506,8 @@
       "android/feed/feed_image_loader_bridge.h",
       "android/feed/feed_journal_bridge.cc",
       "android/feed/feed_journal_bridge.h",
+      "android/feed/feed_logging_bridge.cc",
+      "android/feed/feed_logging_bridge.h",
       "android/feed/feed_network_bridge.cc",
       "android/feed/feed_network_bridge.h",
       "android/feed/feed_offline_bridge.cc",
@@ -4786,6 +4788,7 @@
         "../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedContentBridge.java",
         "../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedImageLoaderBridge.java",
         "../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedJournalBridge.java",
+        "../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java",
         "../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNetworkBridge.java",
         "../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedOfflineBridge.java",
         "../android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java",
diff --git a/chrome/browser/android/feed/feed_logging_bridge.cc b/chrome/browser/android/feed/feed_logging_bridge.cc
new file mode 100644
index 0000000..f9ffc9e1
--- /dev/null
+++ b/chrome/browser/android/feed/feed_logging_bridge.cc
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/feed/feed_logging_bridge.h"
+
+#include <jni.h>
+
+#include "jni/FeedLoggingBridge_jni.h"
+
+namespace feed {
+
+using base::android::JavaRef;
+using base::android::JavaParamRef;
+
+static jlong JNI_FeedLoggingBridge_Init(JNIEnv* env,
+                                        const JavaParamRef<jobject>& j_this) {
+  FeedLoggingBridge* native_logging_bridge = new FeedLoggingBridge();
+  return reinterpret_cast<intptr_t>(native_logging_bridge);
+}
+
+FeedLoggingBridge::FeedLoggingBridge() = default;
+
+FeedLoggingBridge::~FeedLoggingBridge() = default;
+
+void FeedLoggingBridge::Destroy(JNIEnv* env, const JavaRef<jobject>& j_this) {
+  delete this;
+}
+
+void FeedLoggingBridge::OnOpenedWithContent(JNIEnv* j_env,
+                                            const JavaRef<jobject>& j_this,
+                                            const jint j_content_count) {}
+
+}  // namespace feed
diff --git a/chrome/browser/android/feed/feed_logging_bridge.h b/chrome/browser/android/feed/feed_logging_bridge.h
new file mode 100644
index 0000000..d264367a
--- /dev/null
+++ b/chrome/browser/android/feed/feed_logging_bridge.h
@@ -0,0 +1,32 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_FEED_FEED_LOGGING_BRIDGE_H_
+#define CHROME_BROWSER_ANDROID_FEED_FEED_LOGGING_BRIDGE_H_
+
+#include "base/android/scoped_java_ref.h"
+
+namespace feed {
+
+// Native counterpart of FeedLoggingBridge.java. Holds non-owning pointers
+// to native implementation, to which operations are delegated. This bridge is
+// instantiated, owned, and destroyed from Java.
+class FeedLoggingBridge {
+ public:
+  FeedLoggingBridge();
+  ~FeedLoggingBridge();
+
+  void Destroy(JNIEnv* j_env, const base::android::JavaRef<jobject>& j_this);
+
+  void OnOpenedWithContent(JNIEnv* j_env,
+                           const base::android::JavaRef<jobject>& j_this,
+                           const jint j_content_count);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FeedLoggingBridge);
+};
+
+}  // namespace feed
+
+#endif  // CHROME_BROWSER_ANDROID_FEED_FEED_LOGGING_BRIDGE_H_
diff --git a/chrome/browser/apps/platform_apps/api/BUILD.gn b/chrome/browser/apps/platform_apps/api/BUILD.gn
index 6cb17da..589307c 100644
--- a/chrome/browser/apps/platform_apps/api/BUILD.gn
+++ b/chrome/browser/apps/platform_apps/api/BUILD.gn
@@ -30,6 +30,10 @@
   ]
 
   deps = [
+    # TODO(https://crbug.com/883570): It'd be nice to have more APIs here
+    # extracted into their own BUILD files (so they are easy to audit, add, or
+    # remove), but any that depend on //chrome/browser:browser can't.
+    "//chrome/browser/apps/platform_apps/api/music_manager_private",
     "//chrome/browser/extensions",
     "//chrome/common/apps/platform_apps/api",
     "//extensions/browser",
diff --git a/chrome/browser/apps/platform_apps/api/music_manager_private/BUILD.gn b/chrome/browser/apps/platform_apps/api/music_manager_private/BUILD.gn
new file mode 100644
index 0000000..c543fd81
--- /dev/null
+++ b/chrome/browser/apps/platform_apps/api/music_manager_private/BUILD.gn
@@ -0,0 +1,41 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+import("//extensions/buildflags/buildflags.gni")
+import("//rlz/buildflags/buildflags.gni")
+
+assert(enable_extensions)
+
+source_set("music_manager_private") {
+  sources = [
+    "device_id.cc",
+    "device_id.h",
+    "device_id_chromeos.cc",
+    "device_id_linux.cc",
+    "device_id_mac.cc",
+    "device_id_win.cc",
+    "music_manager_private_api.cc",
+    "music_manager_private_api.h",
+  ]
+
+  deps = [
+    "//base",
+    "//chrome/common/apps/platform_apps/api",
+    "//content/public/browser",
+    "//extensions/browser",
+    "//rlz/buildflags",
+    "//crypto",
+  ]
+
+  if (is_chromeos) {
+    sources -= [ "device_id_linux.cc" ]
+
+    deps += [ "//chromeos" ]
+  }
+
+  if (enable_rlz_support) {
+    deps += [ "//rlz:rlz_lib" ]
+  }
+}
diff --git a/chrome/browser/apps/platform_apps/api/music_manager_private/device_id.cc b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id.cc
new file mode 100644
index 0000000..5352a0c
--- /dev/null
+++ b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id.cc
@@ -0,0 +1,195 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h"
+
+#include <stdint.h>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "content/public/browser/browser_thread.h"
+#include "crypto/hmac.h"
+
+namespace chrome_apps {
+namespace api {
+
+namespace {
+
+// Compute HMAC-SHA256(|key|, |text|) as a string.
+bool ComputeHmacSha256(const std::string& key,
+                       const std::string& text,
+                       std::string* signature_return) {
+  crypto::HMAC hmac(crypto::HMAC::SHA256);
+  const size_t digest_length = hmac.DigestLength();
+  std::vector<uint8_t> digest(digest_length);
+  bool result = hmac.Init(key) && hmac.Sign(text, &digest[0], digest.size());
+  if (result) {
+    *signature_return =
+        base::ToLowerASCII(base::HexEncode(digest.data(), digest.size()));
+  }
+  return result;
+}
+
+void GetRawDeviceIdCallback(const std::string& extension_id,
+                            const DeviceId::IdCallback& callback,
+                            const std::string& raw_device_id) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (raw_device_id.empty()) {
+    callback.Run("");
+    return;
+  }
+
+  std::string device_id;
+  if (!ComputeHmacSha256(raw_device_id, extension_id, &device_id)) {
+    DLOG(ERROR) << "Error while computing HMAC-SHA256 of device id.";
+    callback.Run("");
+    return;
+  }
+  callback.Run(device_id);
+}
+
+bool IsValidMacAddressImpl(const void* bytes, size_t size) {
+  const size_t MAC_LENGTH = 6;
+  const size_t OUI_LENGTH = 3;
+  struct InvalidMacEntry {
+    size_t size;
+    unsigned char address[MAC_LENGTH];
+  };
+
+  // VPN, virtualization, tethering, bluetooth, etc.
+  static InvalidMacEntry invalidAddresses[] = {
+      // Empty address
+      {MAC_LENGTH, {0, 0, 0, 0, 0, 0}},
+      // VMware
+      {OUI_LENGTH, {0x00, 0x50, 0x56}},
+      {OUI_LENGTH, {0x00, 0x05, 0x69}},
+      {OUI_LENGTH, {0x00, 0x0c, 0x29}},
+      {OUI_LENGTH, {0x00, 0x1c, 0x14}},
+      // VirtualBox
+      {OUI_LENGTH, {0x08, 0x00, 0x27}},
+      // PdaNet
+      {MAC_LENGTH, {0x00, 0x26, 0x37, 0xbd, 0x39, 0x42}},
+      // Cisco AnyConnect VPN
+      {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}},
+      // Marvell sometimes uses this as a dummy address
+      {MAC_LENGTH, {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
+      // Apple uses this across machines for Bluetooth ethernet adapters.
+      {MAC_LENGTH - 1, {0x65, 0x90, 0x07, 0x42, 0xf1}},
+      // Juniper uses this for their Virtual Adapter, the other 4 bytes are
+      // reassigned at every boot. 00-ff-xx is not assigned to anyone.
+      {2, {0x00, 0xff}},
+      // T-Mobile Wireless Ethernet
+      {MAC_LENGTH, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}},
+      // Generic Bluetooth device
+      {MAC_LENGTH, {0x00, 0x15, 0x83, 0x3d, 0x0a, 0x57}},
+      // RAS Async Adapter
+      {MAC_LENGTH, {0x20, 0x41, 0x53, 0x59, 0x4e, 0xff}},
+      // Qualcomm USB ethernet adapter
+      {MAC_LENGTH, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}},
+      // Windows VPN
+      {MAC_LENGTH, {0x00, 0x53, 0x45, 0x00, 0x00, 0x00}},
+      // Bluetooth
+      {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x08, 0x30}},
+      {MAC_LENGTH, {0x00, 0x1b, 0x10, 0x00, 0x2a, 0xec}},
+      {MAC_LENGTH, {0x00, 0x15, 0x83, 0x15, 0xa3, 0x10}},
+      {MAC_LENGTH, {0x00, 0x15, 0x83, 0x07, 0xC6, 0x5A}},
+      {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x02, 0x00}},
+      {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x02, 0xdd}},
+      // Ceton TV tuner
+      {MAC_LENGTH, {0x00, 0x22, 0x2c, 0xff, 0xff, 0xff}},
+      // Check Point VPN
+      {MAC_LENGTH, {0x54, 0x55, 0x43, 0x44, 0x52, 0x09}},
+      {MAC_LENGTH, {0x54, 0xEF, 0x14, 0x71, 0xE4, 0x0E}},
+      {MAC_LENGTH, {0x54, 0xBA, 0xC6, 0xFF, 0x74, 0x10}},
+      // Cisco VPN
+      {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}},
+      // Cisco VPN
+      {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x78, 0x00}},
+      // Intel USB cell modem
+      {MAC_LENGTH, {0x00, 0x1e, 0x10, 0x1f, 0x00, 0x01}},
+      // Microsoft tethering
+      {MAC_LENGTH, {0x80, 0x00, 0x60, 0x0f, 0xe8, 0x00}},
+      // Nortel VPN
+      {MAC_LENGTH, {0x44, 0x45, 0x53, 0x54, 0x42, 0x00}},
+      // AEP VPN
+      {MAC_LENGTH, {0x00, 0x30, 0x70, 0x00, 0x00, 0x01}},
+      // Positive VPN
+      {MAC_LENGTH, {0x00, 0x02, 0x03, 0x04, 0x05, 0x06}},
+      // Bluetooth
+      {MAC_LENGTH, {0x00, 0x15, 0x83, 0x0B, 0x13, 0xC0}},
+      // Kerio Virtual Network Adapter
+      {MAC_LENGTH, {0x44, 0x45, 0x53, 0x54, 0x4f, 0x53}},
+      // Sierra Wireless cell modems.
+      {OUI_LENGTH, {0x00, 0xA0, 0xD5}},
+      // FRITZ!web DSL
+      {MAC_LENGTH, {0x00, 0x04, 0x0E, 0xFF, 0xFF, 0xFF}},
+      // VirtualPC
+      {MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},
+      // Bluetooth
+      {MAC_LENGTH, {0x00, 0x1F, 0x81, 0x00, 0x01, 0x00}},
+      {MAC_LENGTH, {0x00, 0x30, 0x91, 0x10, 0x00, 0x26}},
+      {MAC_LENGTH, {0x00, 0x25, 0x00, 0x5A, 0xC3, 0xD0}},
+      {MAC_LENGTH, {0x00, 0x15, 0x83, 0x0C, 0xBF, 0xEB}},
+      // Huawei cell modem
+      {MAC_LENGTH, {0x58, 0x2C, 0x80, 0x13, 0x92, 0x63}},
+      // Fortinet VPN
+      {OUI_LENGTH, {0x00, 0x09, 0x0F}},
+      // Realtek
+      {MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x30}},
+      // Other rare dupes.
+      {MAC_LENGTH, {0x00, 0x11, 0xf5, 0x0d, 0x8a, 0xe8}},  // Atheros
+      {MAC_LENGTH, {0x00, 0x20, 0x07, 0x01, 0x16, 0x06}},  // Atheros
+      {MAC_LENGTH, {0x0d, 0x0b, 0x00, 0x00, 0xe0, 0x00}},  // Atheros
+      {MAC_LENGTH, {0x90, 0x4c, 0xe5, 0x0b, 0xc8, 0x8e}},  // Atheros
+      {MAC_LENGTH, {0x00, 0x1c, 0x23, 0x38, 0x49, 0xa4}},  // Broadcom
+      {MAC_LENGTH, {0x00, 0x12, 0x3f, 0x82, 0x7c, 0x32}},  // Broadcom
+      {MAC_LENGTH, {0x00, 0x11, 0x11, 0x32, 0xc3, 0x77}},  // Broadcom
+      {MAC_LENGTH, {0x00, 0x24, 0xd6, 0xae, 0x3e, 0x39}},  // Microsoft
+      {MAC_LENGTH, {0x00, 0x0f, 0xb0, 0x3a, 0xb4, 0x80}},  // Realtek
+      {MAC_LENGTH, {0x08, 0x10, 0x74, 0xa1, 0xda, 0x1b}},  // Realtek
+      {MAC_LENGTH, {0x00, 0x21, 0x9b, 0x2a, 0x0a, 0x9c}},  // Realtek
+  };
+
+  if (size != MAC_LENGTH) {
+    return false;
+  }
+
+  if (static_cast<const unsigned char*>(bytes)[0] & 0x02) {
+    // Locally administered.
+    return false;
+  }
+
+  for (size_t i = 0; i < arraysize(invalidAddresses); ++i) {
+    size_t count = invalidAddresses[i].size;
+    if (memcmp(invalidAddresses[i].address, bytes, count) == 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+// static
+void DeviceId::GetDeviceId(const std::string& extension_id,
+                           const IdCallback& callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  CHECK(!extension_id.empty());
+
+  // Forward call to platform specific implementation, then compute the HMAC
+  // in the callback.
+  GetRawDeviceId(base::Bind(&GetRawDeviceIdCallback, extension_id, callback));
+}
+
+// static
+bool DeviceId::IsValidMacAddress(const void* bytes, size_t size) {
+  return IsValidMacAddressImpl(bytes, size);
+}
+
+}  // namespace api
+}  // namespace chrome_apps
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id.h b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h
similarity index 87%
rename from chrome/browser/extensions/api/music_manager_private/device_id.h
rename to chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h
index 623a00b..8d82caa 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id.h
+++ b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id.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_EXTENSIONS_API_MUSIC_MANAGER_PRIVATE_DEVICE_ID_H_
-#define CHROME_BROWSER_EXTENSIONS_API_MUSIC_MANAGER_PRIVATE_DEVICE_ID_H_
+#ifndef CHROME_BROWSER_APPS_PLATFORM_APPS_API_MUSIC_MANAGER_PRIVATE_DEVICE_ID_H_
+#define CHROME_BROWSER_APPS_PLATFORM_APPS_API_MUSIC_MANAGER_PRIVATE_DEVICE_ID_H_
 
 #include <stddef.h>
 
@@ -12,7 +12,7 @@
 #include "base/bind.h"
 #include "base/task/task_traits.h"
 
-namespace extensions {
+namespace chrome_apps {
 namespace api {
 
 class DeviceId {
@@ -55,6 +55,6 @@
 };
 
 }  // namespace api
-}  // namespace extensions
+}  // namespace chrome_apps
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_MUSIC_MANAGER_PRIVATE_DEVICE_ID_H_
+#endif  // CHROME_BROWSER_APPS_PLATFORM_APPS_API_MUSIC_MANAGER_PRIVATE_DEVICE_ID_H_
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_chromeos.cc
similarity index 74%
rename from chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc
rename to chrome/browser/apps/platform_apps/api/music_manager_private/device_id_chromeos.cc
index f49e513..418e2a25 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc
+++ b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_chromeos.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/music_manager_private/device_id.h"
+#include "chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h"
 
 #include "chromeos/cryptohome/system_salt_getter.h"
 
-namespace extensions {
+namespace chrome_apps {
 namespace api {
 
 // static
@@ -15,4 +15,4 @@
 }
 
 }  // namespace api
-}  // namespace extensions
+}  // namespace chrome_apps
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_linux.cc b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_linux.cc
similarity index 88%
rename from chrome/browser/extensions/api/music_manager_private/device_id_linux.cc
rename to chrome/browser/apps/platform_apps/api/music_manager_private/device_id_linux.cc
index 9bcb8d3..6a0bc7e5 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_linux.cc
+++ b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_linux.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/music_manager_private/device_id.h"
+#include "chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h"
 
 #include <ifaddrs.h>
 #include <net/if.h>
@@ -25,24 +25,24 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 
-namespace {
+namespace chrome_apps {
+namespace api {
 
-using extensions::api::DeviceId;
+namespace {
 
 typedef base::Callback<bool(const void* bytes, size_t size)>
     IsValidMacAddressCallback;
 
 const char kDiskByUuidDirectoryName[] = "/dev/disk/by-uuid";
 const char* const kDeviceNames[] = {
-  "sda1", "hda1", "dm-0", "xvda1", "sda2", "hda2", "dm-1", "xvda2",
+    "sda1", "hda1", "dm-0", "xvda1", "sda2", "hda2", "dm-1", "xvda2",
 };
 // Fedora 15 uses biosdevname feature where Embedded ethernet uses the
 // "em" prefix and PCI cards use the p[0-9]c[0-9] format based on PCI
 // slot and card information.
 const char* const kNetDeviceNamePrefixes[] = {
-  "eth", "em", "en", "wl", "ww", "p0", "p1", "p2", "p3", "p4", "p5", "p6",
-  "p7", "p8", "p9", "wlan"
-};
+    "eth", "em", "en", "wl", "ww", "p0", "p1", "p2",
+    "p3",  "p4", "p5", "p6", "p7", "p8", "p9", "wlan"};
 
 // Map from device name to disk uuid
 typedef std::map<base::FilePath, base::FilePath> DiskEntries;
@@ -71,8 +71,7 @@
   // Look for first device name matching an entry of |kDeviceNames|.
   std::string result;
   for (size_t i = 0; i < arraysize(kDeviceNames); i++) {
-    DiskEntries::iterator it =
-        disk_uuids.find(base::FilePath(kDeviceNames[i]));
+    DiskEntries::iterator it = disk_uuids.find(base::FilePath(kDeviceNames[i]));
     if (it != disk_uuids.end()) {
       DVLOG(1) << "Returning uuid: \"" << it->second.value()
                << "\" for device \"" << it->first.value() << "\"";
@@ -86,10 +85,10 @@
   if (result.empty() && !error_logged) {
     error_logged = true;
     LOG(ERROR) << "Could not find appropriate disk uuid.";
-    for (DiskEntries::iterator it = disk_uuids.begin();
-        it != disk_uuids.end(); ++it) {
-      LOG(ERROR) << "  DeviceID=" << it->first.value() << ", uuid="
-                 << it->second.value();
+    for (DiskEntries::iterator it = disk_uuids.begin(); it != disk_uuids.end();
+         ++it) {
+      LOG(ERROR) << "  DeviceID=" << it->first.value()
+                 << ", uuid=" << it->second.value();
     }
   }
 
@@ -100,10 +99,9 @@
  public:
   explicit MacAddressProcessor(
       const IsValidMacAddressCallback& is_valid_mac_address)
-      : is_valid_mac_address_(is_valid_mac_address) {
-  }
+      : is_valid_mac_address_(is_valid_mac_address) {}
 
-  bool ProcessInterface(struct ifaddrs *ifaddr,
+  bool ProcessInterface(struct ifaddrs* ifaddr,
                         const char* const prefixes[],
                         size_t prefixes_count) {
     const int MAC_LENGTH = 6;
@@ -190,9 +188,6 @@
 
 }  // namespace
 
-namespace extensions {
-namespace api {
-
 // static
 void DeviceId::GetRawDeviceId(const IdCallback& callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -204,4 +199,4 @@
 }
 
 }  // namespace api
-}  // namespace extensions
+}  // namespace chrome_apps
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_mac.cc b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_mac.cc
similarity index 84%
rename from chrome/browser/extensions/api/music_manager_private/device_id_mac.cc
rename to chrome/browser/apps/platform_apps/api/music_manager_private/device_id_mac.cc
index 39d4cd23..2f9aebc 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_mac.cc
+++ b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_mac.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/music_manager_private/device_id.h"
+#include "chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h"
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <DiskArbitration/DADisk.h>
@@ -26,9 +26,10 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 
-namespace {
+namespace chrome_apps {
+namespace api {
 
-using extensions::api::DeviceId;
+namespace {
 
 const char kRootDirectory[] = "/";
 
@@ -83,8 +84,7 @@
   }
 
   CFUUIDRef volume_uuid = base::mac::GetValueFromDictionary<CFUUIDRef>(
-      disk_description,
-      kDADiskDescriptionVolumeUUIDKey);
+      disk_description, kDADiskDescriptionVolumeUUIDKey);
   if (volume_uuid == NULL) {
     VLOG(1) << "Error getting volume UUID of disk.";
     return std::string();
@@ -116,18 +116,14 @@
 class MacAddressProcessor {
  public:
   MacAddressProcessor(const IsValidMacAddressCallback& is_valid_mac_address)
-    : is_valid_mac_address_(is_valid_mac_address) {
-  }
+      : is_valid_mac_address_(is_valid_mac_address) {}
 
   bool ProcessNetworkController(io_object_t network_controller) {
     // Use the MAC address of the first network interface.
     bool keep_going = true;
     base::ScopedCFTypeRef<CFDataRef> mac_address_data(
-        static_cast<CFDataRef>(
-            IORegistryEntryCreateCFProperty(network_controller,
-                                            CFSTR(kIOMACAddress),
-                                            kCFAllocatorDefault,
-                                            0)));
+        static_cast<CFDataRef>(IORegistryEntryCreateCFProperty(
+            network_controller, CFSTR(kIOMACAddress), kCFAllocatorDefault, 0)));
     if (!mac_address_data)
       return keep_going;
 
@@ -136,18 +132,16 @@
     if (!is_valid_mac_address_.Run(mac_address, mac_address_size))
       return keep_going;
 
-    std::string mac_address_string = base::ToLowerASCII(base::HexEncode(
-        mac_address, mac_address_size));
+    std::string mac_address_string =
+        base::ToLowerASCII(base::HexEncode(mac_address, mac_address_size));
 
     base::ScopedCFTypeRef<CFStringRef> provider_class(
-        static_cast<CFStringRef>(
-            IORegistryEntryCreateCFProperty(network_controller,
-                                            CFSTR(kIOProviderClassKey),
-                                            kCFAllocatorDefault,
-                                            0)));
+        static_cast<CFStringRef>(IORegistryEntryCreateCFProperty(
+            network_controller, CFSTR(kIOProviderClassKey), kCFAllocatorDefault,
+            0)));
     if (provider_class) {
       if (CFStringCompare(provider_class, CFSTR("IOPCIDevice"), 0) ==
-              kCFCompareEqualTo) {
+          kCFCompareEqualTo) {
         // MAC address from built-in network card is always best choice.
         found_mac_address_ = mac_address_string;
         keep_going = false;
@@ -186,9 +180,7 @@
   }
 
   io_iterator_t iterator_ref;
-  kr = IOServiceGetMatchingServices(master_port,
-                                    match_classes,
-                                    &iterator_ref);
+  kr = IOServiceGetMatchingServices(master_port, match_classes, &iterator_ref);
   if (kr != KERN_SUCCESS) {
     LOG(ERROR) << "IOServiceGetMatchingServices failed: " << kr;
     return "";
@@ -203,8 +195,7 @@
       break;
 
     io_object_t controller_service_ref;
-    kr = IORegistryEntryGetParentEntry(interface_service,
-                                       kIOServicePlane,
+    kr = IORegistryEntryGetParentEntry(interface_service, kIOServicePlane,
                                        &controller_service_ref);
     if (kr != KERN_SUCCESS) {
       LOG(ERROR) << "IORegistryEntryGetParentEntry failed: " << kr;
@@ -236,9 +227,6 @@
 
 }  // namespace
 
-namespace extensions {
-namespace api {
-
 // static
 void DeviceId::GetRawDeviceId(const IdCallback& callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -250,4 +238,4 @@
 }
 
 }  // namespace api
-}  // namespace extensions
+}  // namespace chrome_apps
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_win.cc b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_win.cc
similarity index 86%
rename from chrome/browser/extensions/api/music_manager_private/device_id_win.cc
rename to chrome/browser/apps/platform_apps/api/music_manager_private/device_id_win.cc
index 7f1497bb..2ce3693 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_win.cc
+++ b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_win.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/music_manager_private/device_id.h"
+#include "chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h"
 
 // Note: The order of header includes is important, as we want both pre-Vista
 // and post-Vista data structures to be defined, specifically
@@ -33,9 +33,10 @@
 #include "rlz/lib/machine_id.h"
 #endif
 
-namespace {
+namespace chrome_apps {
+namespace api {
 
-using extensions::api::DeviceId;
+namespace {
 
 typedef base::Callback<bool(const void* bytes, size_t size)>
     IsValidMacAddressCallback;
@@ -43,9 +44,7 @@
 class MacAddressProcessor {
  public:
   MacAddressProcessor(const IsValidMacAddressCallback& is_valid_mac_address)
-    : is_valid_mac_address_(is_valid_mac_address),
-      found_index_(ULONG_MAX) {
-  }
+      : is_valid_mac_address_(is_valid_mac_address), found_index_(ULONG_MAX) {}
 
   // Iterate through the interfaces, looking for the valid MAC address with the
   // lowest IfIndex.
@@ -53,8 +52,7 @@
     if (address->IfType == IF_TYPE_TUNNEL)
       return;
 
-    ProcessPhysicalAddress(address->IfIndex,
-                           address->PhysicalAddress,
+    ProcessPhysicalAddress(address->IfIndex, address->PhysicalAddress,
                            address->PhysicalAddressLength);
   }
 
@@ -64,8 +62,7 @@
       return;
     }
 
-    ProcessPhysicalAddress(row->InterfaceIndex,
-                           row->PhysicalAddress,
+    ProcessPhysicalAddress(row->InterfaceIndex, row->PhysicalAddress,
                            row->PhysicalAddressLength);
   }
 
@@ -104,14 +101,13 @@
   PIP_ADAPTER_ADDRESSES adapterAddresses =
       reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
 
-  DWORD result = GetAdaptersAddresses(AF_UNSPEC, flags, 0,
-                                      adapterAddresses, &bufferSize);
+  DWORD result =
+      GetAdaptersAddresses(AF_UNSPEC, flags, 0, adapterAddresses, &bufferSize);
   if (result == ERROR_BUFFER_OVERFLOW) {
     buffer.resize(bufferSize);
-    adapterAddresses =
-        reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
-    result = GetAdaptersAddresses(AF_UNSPEC, flags, 0,
-                                  adapterAddresses, &bufferSize);
+    adapterAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
+    result = GetAdaptersAddresses(AF_UNSPEC, flags, 0, adapterAddresses,
+                                  &bufferSize);
   }
 
   if (result != NO_ERROR) {
@@ -133,8 +129,8 @@
   // This is available on Vista+ only.
   base::ScopedNativeLibrary library(base::FilePath(L"Iphlpapi.dll"));
 
-  typedef DWORD (NETIOAPI_API_ *GetIfTablePtr)(PMIB_IF_TABLE2*);
-  typedef void (NETIOAPI_API_ *FreeMibTablePtr)(PMIB_IF_TABLE2);
+  typedef DWORD(NETIOAPI_API_ * GetIfTablePtr)(PMIB_IF_TABLE2*);
+  typedef void(NETIOAPI_API_ * FreeMibTablePtr)(PMIB_IF_TABLE2);
 
   GetIfTablePtr getIfTable = reinterpret_cast<GetIfTablePtr>(
       library.GetFunctionPointer("GetIfTable2"));
@@ -145,7 +141,7 @@
     return "";
   }
 
-  PMIB_IF_TABLE2  ifTable = NULL;
+  PMIB_IF_TABLE2 ifTable = NULL;
   DWORD result = getIfTable(&ifTable);
   if (result != NO_ERROR || ifTable == NULL) {
     VLOG(ERROR) << "GetIfTable failed with error " << result;
@@ -208,9 +204,6 @@
 
 }  // namespace
 
-namespace extensions {
-namespace api {
-
 // static
 void DeviceId::GetRawDeviceId(const IdCallback& callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -222,4 +215,4 @@
 }
 
 }  // namespace api
-}  // namespace extensions
+}  // namespace chrome_apps
diff --git a/chrome/browser/extensions/api/music_manager_private/music_manager_private_api.cc b/chrome/browser/apps/platform_apps/api/music_manager_private/music_manager_private_api.cc
similarity index 65%
rename from chrome/browser/extensions/api/music_manager_private/music_manager_private_api.cc
rename to chrome/browser/apps/platform_apps/api/music_manager_private/music_manager_private_api.cc
index 08d2bca..9e050c2 100644
--- a/chrome/browser/extensions/api/music_manager_private/music_manager_private_api.cc
+++ b/chrome/browser/apps/platform_apps/api/music_manager_private/music_manager_private_api.cc
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/music_manager_private/music_manager_private_api.h"
+#include "chrome/browser/apps/platform_apps/api/music_manager_private/music_manager_private_api.h"
 
 #include <memory>
 
-#include "chrome/browser/extensions/api/music_manager_private/device_id.h"
+#include "base/bind.h"
+#include "base/values.h"
+#include "chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
@@ -15,28 +17,24 @@
 
 const char kDeviceIdNotSupported[] =
     "Device ID API is not supported on this platform.";
-
 }
 
-namespace extensions {
+namespace chrome_apps {
 namespace api {
 
 MusicManagerPrivateGetDeviceIdFunction::
-    MusicManagerPrivateGetDeviceIdFunction() {
-}
+    MusicManagerPrivateGetDeviceIdFunction() {}
 
 MusicManagerPrivateGetDeviceIdFunction::
-    ~MusicManagerPrivateGetDeviceIdFunction() {
-}
+    ~MusicManagerPrivateGetDeviceIdFunction() {}
 
 ExtensionFunction::ResponseAction
 MusicManagerPrivateGetDeviceIdFunction::Run() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DeviceId::GetDeviceId(
-      this->extension_id(),
-      base::Bind(
-          &MusicManagerPrivateGetDeviceIdFunction::DeviceIdCallback,
-          this));
+      extension_id(),
+      base::Bind(&MusicManagerPrivateGetDeviceIdFunction::DeviceIdCallback,
+                 this));
   // GetDeviceId will respond asynchronously.
   return RespondLater();
 }
@@ -51,5 +49,5 @@
   }
 }
 
-} // namespace api
-} // namespace extensions
+}  // namespace api
+}  // namespace chrome_apps
diff --git a/chrome/browser/extensions/api/music_manager_private/music_manager_private_api.h b/chrome/browser/apps/platform_apps/api/music_manager_private/music_manager_private_api.h
similarity index 65%
rename from chrome/browser/extensions/api/music_manager_private/music_manager_private_api.h
rename to chrome/browser/apps/platform_apps/api/music_manager_private/music_manager_private_api.h
index 0e61f0d2..a726b00 100644
--- a/chrome/browser/extensions/api/music_manager_private/music_manager_private_api.h
+++ b/chrome/browser/apps/platform_apps/api/music_manager_private/music_manager_private_api.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_MUSIC_MANAGER_PRIVATE_MUSIC_MANAGER_PRIVATE_API_H_
-#define CHROME_BROWSER_EXTENSIONS_API_MUSIC_MANAGER_PRIVATE_MUSIC_MANAGER_PRIVATE_API_H_
+#ifndef CHROME_BROWSER_APPS_PLATFORM_APPS_API_MUSIC_MANAGER_PRIVATE_MUSIC_MANAGER_PRIVATE_API_H_
+#define CHROME_BROWSER_APPS_PLATFORM_APPS_API_MUSIC_MANAGER_PRIVATE_MUSIC_MANAGER_PRIVATE_API_H_
 
 #include "extensions/browser/extension_function.h"
 
-namespace extensions {
+namespace chrome_apps {
 namespace api {
 
 class MusicManagerPrivateGetDeviceIdFunction
@@ -27,7 +27,7 @@
   void DeviceIdCallback(const std::string& device_id);
 };
 
-} // namespace api
-} // namespace extensions
+}  // namespace api
+}  // namespace chrome_apps
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_MUSIC_MANAGER_PRIVATE_MUSIC_MANAGER_PRIVATE_API_H_
+#endif  // CHROME_BROWSER_APPS_PLATFORM_APPS_API_MUSIC_MANAGER_PRIVATE_MUSIC_MANAGER_PRIVATE_API_H_
diff --git a/chrome/browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc b/chrome/browser/apps/platform_apps/api/music_manager_private/music_manager_private_browsertest.cc
similarity index 86%
rename from chrome/browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc
rename to chrome/browser/apps/platform_apps/api/music_manager_private/music_manager_private_browsertest.cc
index bd3cf0f..9382c7c1 100644
--- a/chrome/browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc
+++ b/chrome/browser/apps/platform_apps/api/music_manager_private/music_manager_private_browsertest.cc
@@ -10,13 +10,12 @@
 // Supported on all platforms, but on Windows only if RLZ is enabled.
 #if !defined(OS_WIN) || BUILDFLAG(ENABLE_RLZ)
 
-class MusicManagerPrivateTest : public extensions::PlatformAppBrowserTest {
-};
+using MusicManagerPrivateTest = extensions::PlatformAppBrowserTest;
 
 IN_PROC_BROWSER_TEST_F(MusicManagerPrivateTest, DeviceIdValueReturned) {
   ASSERT_TRUE(RunPlatformAppTest(
       "platform_apps/music_manager_private/device_id_value_returned"))
-          << message_;
+      << message_;
 }
 
 #endif
diff --git a/chrome/browser/background_fetch/background_fetch_browsertest.cc b/chrome/browser/background_fetch/background_fetch_browsertest.cc
index 270b052..8f7bc11a 100644
--- a/chrome/browser/background_fetch/background_fetch_browsertest.cc
+++ b/chrome/browser/background_fetch/background_fetch_browsertest.cc
@@ -144,6 +144,12 @@
     finished_processing_item_callback_ = std::move(callback);
   }
 
+  void set_delegate(BackgroundFetchDelegateImpl* delegate) {
+    delegate_ = delegate;
+  }
+
+  void PauseOnNextUpdate() { pause_ = true; }
+
   // OfflineContentProvider::Observer implementation:
   void OnItemsAdded(
       const OfflineContentProvider::OfflineItemList& items) override {
@@ -155,16 +161,34 @@
   void OnItemUpdated(const OfflineItem& item) override {
     if (item.state != offline_items_collection::OfflineItemState::IN_PROGRESS &&
         item.state != offline_items_collection::OfflineItemState::PENDING &&
-        finished_processing_item_callback_)
+        item.state != offline_items_collection::OfflineItemState::PAUSED &&
+        finished_processing_item_callback_) {
       std::move(finished_processing_item_callback_).Run(item);
+    }
+
+    if (pause_) {
+      if (item.state == offline_items_collection::OfflineItemState::PAUSED) {
+        Resume(item.id);
+        pause_ = false;
+      } else {
+        delegate_->PauseDownload(item.id);
+      }
+    }
+
     latest_item_ = item;
   }
 
   const OfflineItem& latest_item() const { return latest_item_; }
 
  private:
+  void Resume(const ContentId& id) {
+    delegate_->ResumeDownload(id, false /* has_user_gesture */);
+  }
+
   ItemsAddedCallback items_added_callback_;
   FinishedProcessingItemCallback finished_processing_item_callback_;
+  BackgroundFetchDelegateImpl* delegate_ = nullptr;
+  bool pause_ = false;
 
   OfflineItem latest_item_;
 
@@ -206,6 +230,13 @@
         ->AddObserver(offline_content_provider_observer_.get());
 
     SetUpBrowser(browser());
+
+    BackgroundFetchDelegateImpl* delegate =
+        static_cast<BackgroundFetchDelegateImpl*>(
+            active_browser_->profile()->GetBackgroundFetchDelegate());
+    DCHECK(delegate);
+
+    offline_content_provider_observer_->set_delegate(delegate);
   }
 
   void SetUpBrowser(Browser* browser) {
@@ -642,6 +673,12 @@
                        "New Failed Title!", base::CompareCase::SENSITIVE));
 }
 
+IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest, FetchCanBePausedAndResumed) {
+  offline_content_provider_observer_->PauseOnNextUpdate();
+  ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingMessage(
+      "RunFetchTillCompletion()", "backgroundfetchsuccess"));
+}
+
 IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest,
                        FetchRejectedWithoutPermission) {
   RevokeDownloadPermission();
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
index c782ea68..efa22ba2 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -73,8 +73,7 @@
     std::unique_ptr<content::BackgroundFetchDescription> fetch_description,
     const std::string& provider_namespace,
     bool is_off_the_record)
-    : cancelled(false),
-      offline_item(offline_items_collection::ContentId(
+    : offline_item(offline_items_collection::ContentId(
           provider_namespace,
           fetch_description->job_unique_id)),
       fetch_description(std::move(fetch_description)) {
@@ -125,6 +124,8 @@
     // response was an HTTP error, e.g. 404.
     offline_item.state = OfflineItemState::COMPLETE;
     offline_item.is_openable = true;
+  } else if (paused) {
+    offline_item.state = OfflineItemState::PAUSED;
   } else {
     offline_item.state = OfflineItemState::IN_PROGRESS;
   }
@@ -253,9 +254,6 @@
   DCHECK(job_details_map_.count(job_unique_id));
   DCHECK(!download_job_unique_id_map_.count(download_guid));
 
-  JobDetails& job_details = job_details_map_.find(job_unique_id)->second;
-  job_details.current_download_guids.insert(download_guid);
-
   download_job_unique_id_map_.emplace(download_guid, job_unique_id);
 
   download::DownloadParams params;
@@ -269,6 +267,22 @@
   params.traffic_annotation =
       net::MutableNetworkTrafficAnnotationTag(traffic_annotation);
 
+  JobDetails& job_details = job_details_map_.find(job_unique_id)->second;
+  if (job_details.paused) {
+    job_details.on_resume =
+        base::BindOnce(&BackgroundFetchDelegateImpl::StartDownload,
+                       GetWeakPtr(), job_unique_id, params);
+  } else {
+    StartDownload(job_unique_id, params);
+  }
+}
+
+void BackgroundFetchDelegateImpl::StartDownload(
+    const std::string& job_unique_id,
+    const download::DownloadParams& params) {
+  DCHECK(job_details_map_.count(job_unique_id));
+  JobDetails& job_details = job_details_map_.find(job_unique_id)->second;
+  job_details.current_download_guids.insert(params.guid);
   GetDownloadService()->StartDownload(params);
 }
 
@@ -520,12 +534,9 @@
     return;
 
   JobDetails& job_details = job_details_iter->second;
+  job_details.paused = true;
   for (auto& download_guid : job_details.current_download_guids)
     GetDownloadService()->PauseDownload(download_guid);
-
-  // TODO(delphick): Mark overall download job as paused so that future
-  // downloads are not started until resume. (Initially not a worry because only
-  // one download will be scheduled at a time).
 }
 
 void BackgroundFetchDelegateImpl::ResumeDownload(
@@ -536,10 +547,12 @@
     return;
 
   JobDetails& job_details = job_details_iter->second;
+  job_details.paused = false;
   for (auto& download_guid : job_details.current_download_guids)
     GetDownloadService()->ResumeDownload(download_guid);
 
-  // TODO(delphick): Start new downloads that weren't started because of pause.
+  if (job_details.on_resume)
+    std::move(job_details.on_resume).Run();
 }
 
 void BackgroundFetchDelegateImpl::GetItemById(
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.h b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
index 9d167e6..776b723 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.h
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
@@ -128,8 +128,8 @@
 
     void UpdateOfflineItem();
 
-    bool cancelled;
-    bool failed;
+    bool cancelled = false;
+    bool paused = false;
 
     // Set of DownloadService GUIDs that are currently downloading. They are
     // added by DownloadUrl and are removed when the download completes, fails
@@ -139,6 +139,8 @@
     offline_items_collection::OfflineItem offline_item;
     std::unique_ptr<content::BackgroundFetchDescription> fetch_description;
 
+    base::OnceClosure on_resume;
+
    private:
     // Whether we should report progress of the job in terms of size of
     // downloads or in terms of the number of files being downloaded.
@@ -147,6 +149,10 @@
     DISALLOW_COPY_AND_ASSIGN(JobDetails);
   };
 
+  // Starts a download according to |params| belonging to |job_unique_id|.
+  void StartDownload(const std::string& job_unique_id,
+                     const download::DownloadParams& params);
+
   // Updates the OfflineItem that controls the contents of download
   // notifications and notifies any OfflineContentProvider::Observer that was
   // registered with this instance.
diff --git a/chrome/browser/background_fetch/background_fetch_download_client.cc b/chrome/browser/background_fetch/background_fetch_download_client.cc
index 3d095d38..40f1d9c 100644
--- a/chrome/browser/background_fetch/background_fetch_download_client.cc
+++ b/chrome/browser/background_fetch/background_fetch_download_client.cc
@@ -31,7 +31,7 @@
     case download::Client::FailureReason::TIMEDOUT:
       return BackgroundFetchFailureReason::TIMEDOUT;
     case download::Client::FailureReason::UNKNOWN:
-      return BackgroundFetchFailureReason::UNKNOWN;
+      return BackgroundFetchFailureReason::FETCH_ERROR;
     case download::Client::FailureReason::ABORTED:
     case download::Client::FailureReason::CANCELLED:
       return BackgroundFetchFailureReason::CANCELLED;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 0451655..92039b7 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2564,18 +2564,18 @@
                                             "blocklist_additions");
 }
 
-net::URLRequestContext*
-ChromeContentBrowserClient::OverrideRequestContextForURL(
-    const GURL& url, content::ResourceContext* context) {
+net::CookieStore* ChromeContentBrowserClient::OverrideCookieStoreForURL(
+    const GURL& url,
+    content::ResourceContext* context) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   if (url.SchemeIs(extensions::kExtensionScheme)) {
     ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
-    return io_data->extensions_request_context();
+    return io_data->GetExtensionsCookieStore();
   }
 #endif
 
-  return NULL;
+  return nullptr;
 }
 
 scoped_refptr<network::SharedURLLoaderFactory>
@@ -4531,7 +4531,7 @@
     content::BrowserContext* browser_context,
     content::RenderFrameHost* frame,
     bool is_navigation,
-    const GURL& url,
+    const url::Origin& request_initiator,
     network::mojom::URLLoaderFactoryRequest* factory_request,
     bool* bypass_redirect_checks) {
   DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
@@ -4555,7 +4555,7 @@
 #endif
 
   use_proxy |= signin::ProxyingURLLoaderFactory::MaybeProxyRequest(
-      frame, is_navigation, url, factory_request);
+      frame, is_navigation, request_initiator, factory_request);
 
   return use_proxy;
 }
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index b3d1b5f..66d96ca 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -246,7 +246,7 @@
       const url::Origin& requesting_origin,
       const url::Origin& embedding_origin) override;
   std::string GetWebBluetoothBlocklist() override;
-  net::URLRequestContext* OverrideRequestContextForURL(
+  net::CookieStore* OverrideCookieStoreForURL(
       const GURL& url,
       content::ResourceContext* context) override;
   scoped_refptr<network::SharedURLLoaderFactory>
@@ -438,7 +438,7 @@
       content::BrowserContext* browser_context,
       content::RenderFrameHost* frame,
       bool is_navigation,
-      const GURL& url,
+      const url::Origin& request_initiator,
       network::mojom::URLLoaderFactoryRequest* factory_request,
       bool* bypass_redirect_checks) override;
   std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>>
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
index 759cc56..e60ee34 100644
--- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
+++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
@@ -32,11 +32,6 @@
   // Should be a no-op on ARC. This is managed on the Android side.
 }
 
-void ArcPictureInPictureWindowControllerImpl::ClickCustomControl(
-    const std::string& control_id) {
-  // Should be a no-op on ARC. This is managed on the Android side.
-}
-
 void ArcPictureInPictureWindowControllerImpl::SetPictureInPictureCustomControls(
     const std::vector<blink::PictureInPictureControlInfo>& info) {
   // Should be a no-op on ARC. This is managed on the Android side.
@@ -80,6 +75,11 @@
   return false;
 }
 
+void ArcPictureInPictureWindowControllerImpl::CustomControlPressed(
+    const std::string& control_id) {
+  // Should be a no-op on ARC. This is managed on the Android side.
+}
+
 void ArcPictureInPictureWindowControllerImpl::SetAlwaysHidePlayPauseButton(
     bool is_visible) {
   // Should be a no-op on ARC. This is managed on the Android side.
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
index c6316356..40fefe03 100644
--- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
+++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
@@ -36,7 +36,6 @@
   gfx::Size Show() override;
   void Close(bool should_pause_video) override;
   void OnWindowDestroyed() override;
-  void ClickCustomControl(const std::string& control_id) override;
   void SetPictureInPictureCustomControls(
       const std::vector<blink::PictureInPictureControlInfo>& info) override;
   void EmbedSurface(const viz::SurfaceId& surface_id,
@@ -46,6 +45,7 @@
   bool IsPlayerActive() override;
   content::WebContents* GetInitiatorWebContents() override;
   bool TogglePlayPause() override;
+  void CustomControlPressed(const std::string& control_id) override;
   void UpdatePlaybackState(bool is_playing,
                            bool reached_end_of_stream) override;
   void SetAlwaysHidePlayPauseButton(bool is_visible) override;
diff --git a/chrome/browser/chromeos/child_accounts/consumer_status_reporting_service.cc b/chrome/browser/chromeos/child_accounts/consumer_status_reporting_service.cc
index 920e2d4..e9e3531 100644
--- a/chrome/browser/chromeos/child_accounts/consumer_status_reporting_service.cc
+++ b/chrome/browser/chromeos/child_accounts/consumer_status_reporting_service.cc
@@ -94,6 +94,12 @@
   status_uploader_->ScheduleNextStatusUploadImmediately();
 }
 
+base::TimeDelta ConsumerStatusReportingService::GetChildScreenTime() const {
+  return const_cast<policy::DeviceStatusCollector*>(
+             status_uploader_->device_status_collector())
+      ->GetActiveChildScreenTime();
+}
+
 void ConsumerStatusReportingService::OnTimeLimitsPolicyChanged() {
   CreateStatusUploaderIfNeeded(user_cloud_policy_manager_->core()->client());
 }
diff --git a/chrome/browser/chromeos/child_accounts/consumer_status_reporting_service.h b/chrome/browser/chromeos/child_accounts/consumer_status_reporting_service.h
index 431c5cd3..0fed1d12 100644
--- a/chrome/browser/chromeos/child_accounts/consumer_status_reporting_service.h
+++ b/chrome/browser/chromeos/child_accounts/consumer_status_reporting_service.h
@@ -36,6 +36,9 @@
   ~ConsumerStatusReportingService() override;
   void RequestImmediateStatusReport();
 
+  // Get the child's usage time so far today.
+  base::TimeDelta GetChildScreenTime() const;
+
  private:
   // Creates new status uploader if parameters changed.
   void CreateStatusUploaderIfNeeded(policy::CloudPolicyClient* client);
diff --git a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
index 3c35b09..6732f6b 100644
--- a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
+++ b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
@@ -32,8 +32,6 @@
     base::TimeDelta::FromMinutes(5);
 constexpr base::TimeDelta kExitNotificationTimeout =
     base::TimeDelta::FromMinutes(1);
-constexpr base::TimeDelta kScreenTimeUsageUpdateFrequency =
-    base::TimeDelta::FromMinutes(1);
 
 // The notification id. All the time limit notifications share the same id so
 // that a subsequent notification can replace the previous one.
@@ -57,9 +55,6 @@
 
 // static
 void ScreenTimeController::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterTimePref(prefs::kCurrentScreenStartTime, base::Time());
-  registry->RegisterTimePref(prefs::kFirstScreenStartTime, base::Time());
-  registry->RegisterIntegerPref(prefs::kScreenTimeMinutesUsed, 0);
   registry->RegisterDictionaryPref(prefs::kUsageTimeLimit);
   registry->RegisterDictionaryPref(prefs::kScreenTimeLastState);
 }
@@ -79,18 +74,11 @@
 ScreenTimeController::~ScreenTimeController() {
   session_manager::SessionManager::Get()->RemoveObserver(this);
   system::TimezoneSettings::GetInstance()->RemoveObserver(this);
-  SaveScreenTimeProgressBeforeExit();
 }
 
-base::TimeDelta ScreenTimeController::GetScreenTimeDuration() const {
-  base::TimeDelta previous_duration = base::TimeDelta::FromMinutes(
-      pref_service_->GetInteger(prefs::kScreenTimeMinutesUsed));
-  if (current_screen_start_time_.is_null())
-    return previous_duration;
-
-  base::TimeDelta current_screen_duration =
-      base::Time::Now() - current_screen_start_time_;
-  return current_screen_duration + previous_duration;
+base::TimeDelta ScreenTimeController::GetScreenTimeDuration() {
+  return ConsumerStatusReportingServiceFactory::GetForBrowserContext(context_)
+      ->GetChildScreenTime();
 }
 
 void ScreenTimeController::CheckTimeLimit(const std::string& source) {
@@ -107,27 +95,8 @@
   const base::DictionaryValue* time_limit =
       pref_service_->GetDictionary(prefs::kUsageTimeLimit);
 
-  // Refresh the screen time usage when needed.
-  // |first_screen_start_time_| is retrieved from prefs::kFirstScreenStartTime
-  // which stores the timestamp of last screen time reset.
-  base::TimeDelta used_time = GetScreenTimeDuration();
-  base::Time reset_time = usage_time_limit::GetExpectedResetTime(
-      time_limit->CreateDeepCopy(), now, &time_zone);
-  if (reset_time - first_screen_start_time_ >= base::TimeDelta::FromDays(1)) {
-    VLOG(1) << "Reset screen time now.";
-    RefreshScreenLimit();
-    used_time = base::TimeDelta::FromMinutes(0);
-  } else {
-    VLOG(1) << "Scheduling screen reset timer in " << reset_time - now;
-    reset_screen_time_timer_.Start(
-        FROM_HERE, reset_time - now,
-        base::BindRepeating(&ScreenTimeController::CheckTimeLimit,
-                            base::Unretained(this),
-                            "reset_screen_time_timer_"));
-  }
-
   usage_time_limit::State state = usage_time_limit::GetState(
-      time_limit->CreateDeepCopy(), used_time, first_screen_start_time_, now,
+      time_limit->CreateDeepCopy(), GetScreenTimeDuration(), now, now,
       &time_zone, last_state);
   SaveCurrentStateToPref(state);
 
@@ -180,11 +149,15 @@
     }
   }
 
-  if (!state.next_state_change_time.is_null()) {
+  base::Time next_get_state_time =
+      std::min(state.next_state_change_time,
+               usage_time_limit::GetExpectedResetTime(
+                   time_limit->CreateDeepCopy(), now, &time_zone));
+  if (!next_get_state_time.is_null()) {
     VLOG(1) << "Scheduling state change timer in "
             << state.next_state_change_time - now;
     next_state_timer_.Start(
-        FROM_HERE, state.next_state_change_time - now,
+        FROM_HERE, next_get_state_time - now,
         base::BindRepeating(&ScreenTimeController::CheckTimeLimit,
                             base::Unretained(this), "next_state_timer_"));
   }
@@ -243,17 +216,6 @@
       ->Display(NotificationHandler::Type::TRANSIENT, *notification);
 }
 
-void ScreenTimeController::RefreshScreenLimit() {
-  base::Time now = base::Time::Now();
-  pref_service_->SetTime(prefs::kFirstScreenStartTime, now);
-  pref_service_->SetTime(prefs::kCurrentScreenStartTime, now);
-  pref_service_->SetInteger(prefs::kScreenTimeMinutesUsed, 0);
-  pref_service_->CommitPendingWrite();
-
-  first_screen_start_time_ = now;
-  current_screen_start_time_ = now;
-}
-
 void ScreenTimeController::OnPolicyChanged() {
   CheckTimeLimit("OnPolicyChanged");
 }
@@ -261,33 +223,12 @@
 void ScreenTimeController::ResetStateTimers() {
   VLOG(1) << "Stopping state timers";
   next_state_timer_.Stop();
-  reset_screen_time_timer_.Stop();
 }
 
 void ScreenTimeController::ResetInSessionTimers() {
   VLOG(1) << "Stopping in-session timers";
   warning_notification_timer_.Stop();
   exit_notification_timer_.Stop();
-  save_screen_time_timer_.Stop();
-}
-
-void ScreenTimeController::SaveScreenTimeProgressBeforeExit() {
-  VLOG(1) << "Saving screen time progress before exiting";
-  pref_service_->SetInteger(prefs::kScreenTimeMinutesUsed,
-                            GetScreenTimeDuration().InMinutes());
-  pref_service_->ClearPref(prefs::kCurrentScreenStartTime);
-  pref_service_->CommitPendingWrite();
-  current_screen_start_time_ = base::Time();
-  ResetInSessionTimers();
-}
-
-void ScreenTimeController::SaveScreenTimeProgressPeriodically() {
-  pref_service_->SetInteger(prefs::kScreenTimeMinutesUsed,
-                            GetScreenTimeDuration().InMinutes());
-  current_screen_start_time_ = base::Time::Now();
-  pref_service_->SetTime(prefs::kCurrentScreenStartTime,
-                         current_screen_start_time_);
-  pref_service_->CommitPendingWrite();
 }
 
 void ScreenTimeController::SaveCurrentStateToPref(
@@ -416,40 +357,9 @@
       UpdateTimeLimitsMessage(true /*visible*/, next_unlock_time_.value());
       next_unlock_time_.reset();
     }
-    SaveScreenTimeProgressBeforeExit();
+    ResetInSessionTimers();
   } else if (session_state == session_manager::SessionState::ACTIVE) {
-    base::Time now = base::Time::Now();
-    const base::Time first_screen_start_time =
-        pref_service_->GetTime(prefs::kFirstScreenStartTime);
-    if (first_screen_start_time.is_null()) {
-      pref_service_->SetTime(prefs::kFirstScreenStartTime, now);
-      first_screen_start_time_ = now;
-    } else {
-      first_screen_start_time_ = first_screen_start_time;
-    }
-
-    const base::Time current_screen_start_time =
-        pref_service_->GetTime(prefs::kCurrentScreenStartTime);
-    if (!current_screen_start_time.is_null() &&
-        current_screen_start_time < now &&
-        (now - current_screen_start_time) <
-            2 * kScreenTimeUsageUpdateFrequency) {
-      current_screen_start_time_ = current_screen_start_time;
-    } else {
-      // If kCurrentScreenStartTime is not set or it's been too long since the
-      // last update, set the time to now.
-      current_screen_start_time_ = now;
-    }
-    pref_service_->SetTime(prefs::kCurrentScreenStartTime,
-                           current_screen_start_time_);
-    pref_service_->CommitPendingWrite();
     CheckTimeLimit("OnSessionStateChanged");
-
-    save_screen_time_timer_.Start(
-        FROM_HERE, kScreenTimeUsageUpdateFrequency,
-        base::BindRepeating(
-            &ScreenTimeController::SaveScreenTimeProgressPeriodically,
-            base::Unretained(this)));
   }
 }
 
diff --git a/chrome/browser/chromeos/child_accounts/screen_time_controller.h b/chrome/browser/chromeos/child_accounts/screen_time_controller.h
index 40285a1e..cea35890 100644
--- a/chrome/browser/chromeos/child_accounts/screen_time_controller.h
+++ b/chrome/browser/chromeos/child_accounts/screen_time_controller.h
@@ -35,9 +35,9 @@
   explicit ScreenTimeController(content::BrowserContext* context);
   ~ScreenTimeController() override;
 
-  // Returns the screen time duration. This includes time in
-  // kScreenTimeMinutesUsed plus time passed since |current_screen_start_time_|.
-  base::TimeDelta GetScreenTimeDuration() const;
+  // Returns the child's screen time duration. This is how long the child has
+  // used the device today (since the last reset).
+  base::TimeDelta GetScreenTimeDuration();
 
  private:
   // The types of time limit notifications. |SCREEN_TIME| is used when the
@@ -66,9 +66,6 @@
   void ShowNotification(ScreenTimeController::TimeLimitNotificationType type,
                         const base::TimeDelta& time_remaining);
 
-  // Reset time tracking relevant prefs and local timestamps.
-  void RefreshScreenLimit();
-
   // Called when the policy of time limits changes.
   void OnPolicyChanged();
 
@@ -76,14 +73,6 @@
   void ResetStateTimers();
   void ResetInSessionTimers();
 
-  // Save the screen time progress when screen is locked, or user sign out or
-  // power down the device.
-  void SaveScreenTimeProgressBeforeExit();
-
-  // Save the screen time progress periodically in case of a crash or power
-  // outage.
-  void SaveScreenTimeProgressPeriodically();
-
   // Save the |state| to |prefs::kScreenTimeLastState|.
   void SaveCurrentStateToPref(const usage_time_limit::State& state);
 
@@ -104,26 +93,11 @@
   base::OneShotTimer warning_notification_timer_;
   base::OneShotTimer exit_notification_timer_;
 
-  // Called to record the current amount of time spent in-session.
-  base::RepeatingTimer save_screen_time_timer_;
-
   // Timers that are called when lock screen state change event happens, ie,
   // bedtime is over or the usage limit ends.
   base::OneShotTimer next_state_timer_;
   base::OneShotTimer reset_screen_time_timer_;
 
-  // Timestamp to keep track of the screen start time for the current active
-  // screen. This timestamp is periodically updated by
-  // SaveScreenTimeProgressPeriodically(), and is cleared when user exits the
-  // active screen(lock, sign out, shutdown).
-  base::Time current_screen_start_time_;
-
-  // Timestamp to keep track of the screen start time when user starts using
-  // the device for the first time of the day.
-  // Used to calculate the screen time limit and this will be refreshed by
-  // RefreshScreenLimit();
-  base::Time first_screen_start_time_;
-
   PrefChangeRegistrar pref_change_registrar_;
 
   // Used to update the time limits message, if any, when screen is locked.
diff --git a/chrome/browser/chromeos/extensions/autotest_private/DEPS b/chrome/browser/chromeos/extensions/autotest_private/DEPS
index 53fd62a1..1043b3e 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/DEPS
+++ b/chrome/browser/chromeos/extensions/autotest_private/DEPS
@@ -1,3 +1,10 @@
 include_rules = [
   "+chrome/browser/ui/views/crostini",
 ]
+
+specific_include_rules = {
+  "autotest_private_api\.cc": [
+    # TODO(mash): Remove the line below, http://crbug.com/557397
+    "+ash/shell.h",
+  ]
+}
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index 189fb40..7211d982 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -34,6 +34,8 @@
 #if defined(OS_CHROMEOS)
 #include "ash/public/interfaces/ash_message_center_controller.mojom.h"
 #include "ash/public/interfaces/constants.mojom.h"
+#include "ash/shell.h"
+#include "base/base64.h"
 #include "base/feature_list.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
@@ -842,6 +844,47 @@
 }
 #endif
 
+AutotestPrivateTakeScreenshotFunction::
+    ~AutotestPrivateTakeScreenshotFunction() = default;
+
+ExtensionFunction::ResponseAction AutotestPrivateTakeScreenshotFunction::Run() {
+  DVLOG(1) << "AutotestPrivateTakeScreenshotFunction";
+#if defined(OS_CHROMEOS)
+  auto grabber = std::make_unique<ui::ScreenshotGrabber>();
+  // TODO(mash): Fix for mash, http://crbug.com/557397
+  aura::Window* primary_root = ash::Shell::GetPrimaryRootWindow();
+  // Pass the ScreenshotGrabber to the callback so that it stays alive for the
+  // duration of the operation, it'll then get deallocated when the callback
+  // completes.
+  grabber->TakeScreenshot(
+      primary_root, primary_root->bounds(),
+      base::BindOnce(&AutotestPrivateTakeScreenshotFunction::ScreenshotTaken,
+                     this, base::Passed(&grabber)));
+  return RespondLater();
+#else
+  return RespondNow(Error(kOnlyAvailableOnChromeOSError));
+#endif
+}
+
+#if defined(OS_CHROMEOS)
+void AutotestPrivateTakeScreenshotFunction::ScreenshotTaken(
+    std::unique_ptr<ui::ScreenshotGrabber> grabber,
+    ui::ScreenshotResult screenshot_result,
+    scoped_refptr<base::RefCountedMemory> png_data) {
+  if (screenshot_result == ui::ScreenshotResult::SUCCESS) {
+    // Base64 encode the result so we can return it as a string.
+    std::string base64Png(png_data->front(),
+                          png_data->front() + png_data->size());
+    base::Base64Encode(base64Png, &base64Png);
+    Respond(OneArgument(std::make_unique<base::Value>(base64Png)));
+  } else {
+    Respond(Error(base::StrCat(
+        {"Error taking screenshot ",
+         base::NumberToString(static_cast<int>(screenshot_result))})));
+  }
+}
+#endif
+
 AutotestPrivateBootstrapMachineLearningServiceFunction::
     ~AutotestPrivateBootstrapMachineLearningServiceFunction() = default;
 
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
index 11f38f5..f2acf42d 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
@@ -16,6 +16,7 @@
 #include "ash/public/interfaces/ash_message_center_controller.mojom.h"
 #include "chrome/browser/chromeos/printing/cups_printers_manager.h"
 #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
+#include "ui/snapshot/screenshot_grabber.h"
 #endif
 
 namespace message_center {
@@ -310,6 +311,23 @@
   DISALLOW_COPY_AND_ASSIGN(AutotestPrivateRunCrostiniUninstallerFunction);
 };
 
+class AutotestPrivateTakeScreenshotFunction : public UIThreadExtensionFunction {
+ public:
+  AutotestPrivateTakeScreenshotFunction() = default;
+  DECLARE_EXTENSION_FUNCTION("autotestPrivate.takeScreenshot",
+                             AUTOTESTPRIVATE_TAKESCREENSHOT)
+
+ private:
+  ~AutotestPrivateTakeScreenshotFunction() override;
+  ResponseAction Run() override;
+#if defined(OS_CHROMEOS)
+  void ScreenshotTaken(std::unique_ptr<ui::ScreenshotGrabber> grabber,
+                       ui::ScreenshotResult screenshot_result,
+                       scoped_refptr<base::RefCountedMemory> png_data);
+#endif
+  DISALLOW_COPY_AND_ASSIGN(AutotestPrivateTakeScreenshotFunction);
+};
+
 class AutotestPrivateGetPrinterListFunction : public UIThreadExtensionFunction {
  public:
   AutotestPrivateGetPrinterListFunction() = default;
diff --git a/chrome/browser/chromeos/policy/app_install_event_log_uploader.h b/chrome/browser/chromeos/policy/app_install_event_log_uploader.h
index 813ac541e..b84edf2 100644
--- a/chrome/browser/chromeos/policy/app_install_event_log_uploader.h
+++ b/chrome/browser/chromeos/policy/app_install_event_log_uploader.h
@@ -80,7 +80,6 @@
   // request when the client registers, by asking the delegate to serialize logs
   // and with the exponential backoff reset to its minimum.
   void OnRegistrationStateChanged(CloudPolicyClient* client) override;
-  void OnRobotAuthCodesFetched(CloudPolicyClient* client) override {}
   void OnClientError(CloudPolicyClient* client) override {}
 
  private:
diff --git a/chrome/browser/chromeos/policy/device_status_collector.cc b/chrome/browser/chromeos/policy/device_status_collector.cc
index 4eb20f05..80fc32d3 100644
--- a/chrome/browser/chromeos/policy/device_status_collector.cc
+++ b/chrome/browser/chromeos/policy/device_status_collector.cc
@@ -459,7 +459,8 @@
   // represents the distance from midnight.
   ActivityStorage(PrefService* pref_service,
                   const std::string& pref_name,
-                  TimeDelta activity_day_start);
+                  TimeDelta activity_day_start,
+                  bool is_enterprise_reporting);
   ~ActivityStorage();
 
   // Adds an activity period. Accepts empty |active_user_email| if it should not
@@ -501,6 +502,7 @@
   void ProcessActivityPeriods(const base::DictionaryValue& activity_times,
                               const std::vector<std::string>& reporting_users,
                               base::DictionaryValue* const filtered_times);
+  void StoreChildScreenTime(Time activity_day_start, TimeDelta activity);
 
   // Determine the day key (milliseconds since epoch for corresponding
   // |day_start_| in UTC) for a given |timestamp|.
@@ -513,16 +515,21 @@
   // from midnight.
   const TimeDelta day_start_;
 
+  // Whether reporting is for enterprise or consumer.
+  bool is_enterprise_reporting_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(ActivityStorage);
 };
 
 DeviceStatusCollector::ActivityStorage::ActivityStorage(
     PrefService* pref_service,
     const std::string& pref_name,
-    TimeDelta activity_day_start)
+    TimeDelta activity_day_start,
+    bool is_enterprise_reporting)
     : pref_service_(pref_service),
       pref_name_(pref_name),
-      day_start_(activity_day_start) {
+      day_start_(activity_day_start),
+      is_enterprise_reporting_(is_enterprise_reporting) {
   DCHECK(pref_service_);
   const PrefService::PrefInitializationStatus pref_service_status =
       pref_service_->GetInitializationStatus();
@@ -554,6 +561,15 @@
     int previous_activity = 0;
     activity_times->GetInteger(key, &previous_activity);
     activity_times->SetInteger(key, previous_activity + activity);
+
+    // If the user is a child, the child screen time pref may need to be
+    // updated.
+    if (user_manager::UserManager::Get()->IsLoggedInAsChildUser() &&
+        !is_enterprise_reporting_) {
+      StoreChildScreenTime(day_start - TimeDelta::FromDays(1),
+                           TimeDelta::FromMilliseconds(activity));
+    }
+
     start = day_start;
   }
 }
@@ -705,6 +721,35 @@
   return out_time.ToJavaTime();
 }
 
+void DeviceStatusCollector::ActivityStorage::StoreChildScreenTime(
+    Time activity_day_start,
+    TimeDelta activity) {
+  DCHECK(user_manager::UserManager::Get()->IsLoggedInAsChildUser() &&
+         !is_enterprise_reporting_);
+
+  // Today's start time.
+  Time today_start = Time::Now().LocalMidnight() + day_start_;
+
+  TimeDelta previous_activity = TimeDelta::FromMilliseconds(
+      pref_service_->GetInteger(prefs::kChildScreenTimeMilliseconds));
+
+  // Reset screen time if it has not been reset today.
+  if (today_start > pref_service_->GetTime(prefs::kLastChildScreenTimeReset)) {
+    pref_service_->SetTime(prefs::kLastChildScreenTimeReset, Time::Now());
+    pref_service_->SetInteger(prefs::kChildScreenTimeMilliseconds, 0);
+    previous_activity = TimeDelta::FromSeconds(0);
+  }
+
+  // If this activity window belongs to the current day, the screen time pref
+  // should be updated.
+  if (activity_day_start >= today_start) {
+    pref_service_->SetInteger(prefs::kChildScreenTimeMilliseconds,
+                              (previous_activity + activity).InMilliseconds());
+    pref_service_->SetTime(prefs::kLastChildScreenTimeSaved, Time::Now());
+  }
+  pref_service_->CommitPendingWrite();
+}
+
 DeviceStatusCollector::DeviceStatusCollector(
     PrefService* pref_service,
     chromeos::system::StatisticsProvider* provider,
@@ -822,7 +867,7 @@
       pref_service_,
       (is_enterprise_reporting_ ? prefs::kDeviceActivityTimes
                                 : prefs::kUserActivityTimes),
-      activity_day_start);
+      activity_day_start, is_enterprise_reporting_);
 }
 
 DeviceStatusCollector::~DeviceStatusCollector() {
@@ -841,6 +886,18 @@
   registry->RegisterBooleanPref(prefs::kReportArcStatusEnabled, false);
   registry->RegisterDictionaryPref(prefs::kUserActivityTimes,
                                    std::make_unique<base::DictionaryValue>());
+  registry->RegisterTimePref(prefs::kLastChildScreenTimeReset, Time());
+  registry->RegisterTimePref(prefs::kLastChildScreenTimeSaved, Time());
+  registry->RegisterIntegerPref(prefs::kChildScreenTimeMilliseconds, 0);
+}
+
+TimeDelta DeviceStatusCollector::GetActiveChildScreenTime() {
+  if (!user_manager::UserManager::Get()->IsLoggedInAsChildUser())
+    return TimeDelta::FromSeconds(0);
+
+  UpdateChildUsageTime();
+  return TimeDelta::FromMilliseconds(
+      pref_service_->GetInteger(prefs::kChildScreenTimeMilliseconds));
 }
 
 void DeviceStatusCollector::CheckIdleState() {
@@ -929,7 +986,7 @@
 void DeviceStatusCollector::IdleStateCallback(ui::IdleState state) {
   // Do nothing if device activity reporting is disabled or if it's a child
   // account. Usage time for child accounts are calculated differently.
-  if (!report_activity_times_ ||
+  if (!report_activity_times_ || !is_enterprise_reporting_ ||
       user_manager::UserManager::Get()->IsLoggedInAsChildUser()) {
     return;
   }
@@ -1147,8 +1204,9 @@
 
 bool DeviceStatusCollector::GetActivityTimes(
     em::DeviceStatusReportRequest* status) {
-  if (user_manager::UserManager::Get()->IsLoggedInAsChildUser())
+  if (user_manager::UserManager::Get()->IsLoggedInAsChildUser()) {
     UpdateChildUsageTime();
+  }
 
   // If user reporting is off, data should be aggregated per day.
   // Signed-in user is reported in non-enterprise reporting.
diff --git a/chrome/browser/chromeos/policy/device_status_collector.h b/chrome/browser/chromeos/policy/device_status_collector.h
index ff72d58..8f1ae47 100644
--- a/chrome/browser/chromeos/policy/device_status_collector.h
+++ b/chrome/browser/chromeos/policy/device_status_collector.h
@@ -139,6 +139,10 @@
   // The total number of hardware resource usage samples cached internally.
   static const unsigned int kMaxResourceUsageSamples = 10;
 
+  // Returns the amount of time the child has used so far today. If the user is
+  // not a child or if there is no user logged in, it returns 0.
+  base::TimeDelta GetActiveChildScreenTime();
+
  protected:
   // Check whether the user has been idle for a certain period of time.
   virtual void CheckIdleState();
diff --git a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
index 5d1290e..772d2e6 100644
--- a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
@@ -64,6 +64,7 @@
 #include "chromeos/system/fake_statistics_provider.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/proto/device_management_backend.pb.h"
+#include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/user_manager/scoped_user_manager.h"
@@ -2436,6 +2437,9 @@
   ASSERT_EQ(1, device_status_.active_period_size());
   EXPECT_EQ(5 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
+  EXPECT_EQ(
+      5 * ActivePeriodMilliseconds(),
+      profile_pref_service_.GetInteger(prefs::kChildScreenTimeMilliseconds));
   EXPECT_EQ(user_account_id_.GetUserEmail(),
             device_status_.active_period(0).user_email());
 }
@@ -2458,6 +2462,9 @@
   ASSERT_EQ(1, device_status_.active_period_size());
   EXPECT_EQ(4 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
+  EXPECT_EQ(
+      4 * ActivePeriodMilliseconds(),
+      profile_pref_service_.GetInteger(prefs::kChildScreenTimeMilliseconds));
   EXPECT_EQ(user_account_id_.GetUserEmail(),
             device_status_.active_period(0).user_email());
 }
@@ -2482,6 +2489,9 @@
   ASSERT_EQ(1, device_status_.active_period_size());
   EXPECT_EQ(5 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
+  EXPECT_EQ(
+      5 * ActivePeriodMilliseconds(),
+      profile_pref_service_.GetInteger(prefs::kChildScreenTimeMilliseconds));
   EXPECT_EQ(user_account_id_.GetUserEmail(),
             device_status_.active_period(0).user_email());
 }
@@ -2519,6 +2529,9 @@
   GetStatus();
   EXPECT_EQ(12 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
+  EXPECT_EQ(
+      12 * ActivePeriodMilliseconds(),
+      profile_pref_service_.GetInteger(prefs::kChildScreenTimeMilliseconds));
 }
 
 TEST_F(ConsumerDeviceStatusCollectorTimeLimitEnabledTest,
@@ -2543,10 +2556,49 @@
   EXPECT_EQ(1, device_status_.active_period_size());
   EXPECT_EQ(5 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
+  EXPECT_EQ(
+      5 * ActivePeriodMilliseconds(),
+      profile_pref_service_.GetInteger(prefs::kChildScreenTimeMilliseconds));
 
   // Nothing should be written to local state, because it is only used for
   // enterprise reporting.
   EXPECT_TRUE(local_state_.GetDictionary(prefs::kDeviceActivityTimes)->empty());
 }
 
+TEST_F(ConsumerDeviceStatusCollectorTimeLimitEnabledTest,
+       ActivityCrossingMidnight) {
+  DeviceStateTransitions test_states[] = {
+      DeviceStateTransitions::kEnterSessionActive,
+      DeviceStateTransitions::kLeaveSessionActive};
+
+  // Set the baseline time to 15 seconds before midnight, so the activity is
+  // split between two days.
+  status_collector_->SetBaselineTime(Time::Now().LocalMidnight() -
+                                     TimeDelta::FromSeconds(15));
+
+  SimulateStateChanges(test_states,
+                       sizeof(test_states) / sizeof(DeviceStateTransitions));
+  GetStatus();
+  ASSERT_EQ(2, device_status_.active_period_size());
+
+  em::ActiveTimePeriod period0 = device_status_.active_period(0);
+  em::ActiveTimePeriod period1 = device_status_.active_period(1);
+  EXPECT_EQ(ActivePeriodMilliseconds() - 15000, period0.active_duration());
+  EXPECT_EQ(15000, period1.active_duration());
+
+  em::TimePeriod time_period0 = period0.time_period();
+  em::TimePeriod time_period1 = period1.time_period();
+
+  EXPECT_EQ(time_period0.end_timestamp(), time_period1.start_timestamp());
+
+  // Ensure that the start and end times for the period are a day apart.
+  EXPECT_EQ(time_period0.end_timestamp() - time_period0.start_timestamp(),
+            kMillisecondsPerDay);
+  EXPECT_EQ(time_period1.end_timestamp() - time_period1.start_timestamp(),
+            kMillisecondsPerDay);
+  EXPECT_EQ(
+      0.5 * ActivePeriodMilliseconds(),
+      profile_pref_service_.GetInteger(prefs::kChildScreenTimeMilliseconds));
+}
+
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
index 07710da03..6407191 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -551,7 +551,10 @@
     } else {
       domain_ = gaia::ExtractDomainName(gaia::CanonicalizeEmail(username));
       SetStep(STEP_ROBOT_AUTH_FETCH);
-      client_->FetchRobotAuthCodes(dm_auth_->Clone());
+      client_->FetchRobotAuthCodes(
+          dm_auth_->Clone(),
+          base::BindOnce(&EnrollmentHandlerChromeOS::OnRobotAuthCodesFetched,
+                         weak_ptr_factory_.GetWeakPtr()));
     }
   } else {
     ReportResult(EnrollmentStatus::ForValidationError(validator->status()));
@@ -559,11 +562,14 @@
 }
 
 void EnrollmentHandlerChromeOS::OnRobotAuthCodesFetched(
-    CloudPolicyClient* client) {
-  DCHECK_EQ(client_.get(), client);
+    DeviceManagementStatus status,
+    const std::string& auth_code) {
   CHECK_EQ(STEP_ROBOT_AUTH_FETCH, enrollment_step_);
-
-  if (client->robot_api_auth_code().empty()) {
+  if (status != DM_STATUS_SUCCESS) {
+    OnClientError(client_.get());
+    return;
+  }
+  if (auth_code.empty()) {
     // If the server doesn't provide an auth code, skip the robot auth setup.
     // This allows clients running against the test server to transparently skip
     // robot auth.
@@ -583,8 +589,8 @@
   // Use the system request context to avoid sending user cookies.
   gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
       g_browser_process->shared_url_loader_factory()));
-  gaia_oauth_client_->GetTokensFromAuthCode(
-      client_info, client->robot_api_auth_code(), 0 /* max_retries */, this);
+  gaia_oauth_client_->GetTokensFromAuthCode(client_info, auth_code,
+                                            0 /* max_retries */, this);
 }
 
 // GaiaOAuthClient::Delegate callback for OAuth2 refresh token fetched.
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
index a118ba93..ca92b25f 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
@@ -100,7 +100,6 @@
   // CloudPolicyClient::Observer:
   void OnPolicyFetched(CloudPolicyClient* client) override;
   void OnRegistrationStateChanged(CloudPolicyClient* client) override;
-  void OnRobotAuthCodesFetched(CloudPolicyClient* client) override;
   void OnClientError(CloudPolicyClient* client) override;
 
   // CloudPolicyStore::Observer:
@@ -211,6 +210,10 @@
   // Handles the policy validation result for the offline demo mode.
   void OnOfflinePolicyValidated(DeviceCloudPolicyValidator* validator);
 
+  // Handles the fetching auth codes for robot accounts during enrollment.
+  void OnRobotAuthCodesFetched(DeviceManagementStatus status,
+                               const std::string& auth_code);
+
   std::unique_ptr<DeviceCloudPolicyValidator> CreateValidator(
       std::unique_ptr<enterprise_management::PolicyFetchResponse> policy,
       const std::string& domain);
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc
index 89d3159..e96a469 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -1011,11 +1011,14 @@
       break;
     case DeviceSettingsService::STORE_VALIDATION_ERROR:
     case DeviceSettingsService::STORE_INVALID_POLICY:
-    case DeviceSettingsService::STORE_OPERATION_FAILED:
-      LOG(ERROR) << "Failed to retrieve cros policies. Reason: "
-                 << device_settings_service_->status();
+    case DeviceSettingsService::STORE_OPERATION_FAILED: {
+      DeviceSettingsService::Status status = device_settings_service_->status();
+      LOG(ERROR) << "Failed to retrieve cros policies. Reason: " << status
+                 << " (" << DeviceSettingsService::StatusToString(status)
+                 << ")";
       trusted_status_ = PERMANENTLY_UNTRUSTED;
       break;
+    }
   }
 
   // Notify the observers we are done.
diff --git a/chrome/browser/chromeos/settings/device_settings_service.cc b/chrome/browser/chromeos/settings/device_settings_service.cc
index 278656b..a6f9795 100644
--- a/chrome/browser/chromeos/settings/device_settings_service.cc
+++ b/chrome/browser/chromeos/settings/device_settings_service.cc
@@ -66,6 +66,25 @@
   return g_device_settings_service;
 }
 
+// static
+const char* DeviceSettingsService::StatusToString(Status status) {
+  switch (status) {
+    case STORE_SUCCESS:
+      return "SUCCESS";
+    case STORE_KEY_UNAVAILABLE:
+      return "KEY_UNAVAILABLE";
+    case STORE_OPERATION_FAILED:
+      return "OPERATION_FAILED";
+    case STORE_NO_POLICY:
+      return "NO_POLICY";
+    case STORE_INVALID_POLICY:
+      return "INVALID_POLICY";
+    case STORE_VALIDATION_ERROR:
+      return "VALIDATION_ERROR";
+  }
+  return "UNKNOWN";
+}
+
 DeviceSettingsService::DeviceSettingsService() {
   device_off_hours_controller_ =
       std::make_unique<policy::off_hours::DeviceOffHoursController>();
@@ -311,7 +330,8 @@
         device_settings_.swap(off_device_settings);
     }
   } else if (status != STORE_KEY_UNAVAILABLE) {
-    LOG(ERROR) << "Session manager operation failed: " << status;
+    LOG(ERROR) << "Session manager operation failed: " << status << " ("
+               << StatusToString(status) << ")";
   }
 
   public_key_ = scoped_refptr<PublicKey>(operation->public_key());
diff --git a/chrome/browser/chromeos/settings/device_settings_service.h b/chrome/browser/chromeos/settings/device_settings_service.h
index 9ee38b14..74d14559 100644
--- a/chrome/browser/chromeos/settings/device_settings_service.h
+++ b/chrome/browser/chromeos/settings/device_settings_service.h
@@ -97,6 +97,9 @@
   static void Shutdown();
   static DeviceSettingsService* Get();
 
+  // Returns a human-readable string describing |status|.
+  static const char* StatusToString(Status status);
+
   // Creates a device settings service instance. This is meant for unit tests,
   // production code uses the singleton returned by Get() above.
   DeviceSettingsService();
diff --git a/chrome/browser/chromeos/settings/session_manager_operation.cc b/chrome/browser/chromeos/settings/session_manager_operation.cc
index 831e5673..5532af2 100644
--- a/chrome/browser/chromeos/settings/session_manager_operation.cc
+++ b/chrome/browser/chromeos/settings/session_manager_operation.cc
@@ -213,7 +213,10 @@
     device_settings_ = std::move(validator->payload());
     ReportResult(DeviceSettingsService::STORE_SUCCESS);
   } else {
-    LOG(ERROR) << "Policy validation failed: " << validator->status();
+    LOG(ERROR) << "Policy validation failed: " << validator->status() << " ("
+               << policy::DeviceCloudPolicyValidator::StatusToString(
+                      validator->status())
+               << ")";
     ReportResult(DeviceSettingsService::STORE_VALIDATION_ERROR);
   }
 }
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 32b520fb..8e96597 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -260,14 +260,6 @@
     "api/metrics_private/chrome_metrics_private_delegate.h",
     "api/module/module.cc",
     "api/module/module.h",
-    "api/music_manager_private/device_id.cc",
-    "api/music_manager_private/device_id.h",
-    "api/music_manager_private/device_id_chromeos.cc",
-    "api/music_manager_private/device_id_linux.cc",
-    "api/music_manager_private/device_id_mac.cc",
-    "api/music_manager_private/device_id_win.cc",
-    "api/music_manager_private/music_manager_private_api.cc",
-    "api/music_manager_private/music_manager_private_api.h",
     "api/networking_private/networking_private_credentials_getter_chromeos.cc",
     "api/networking_private/networking_private_ui_delegate_chromeos.cc",
     "api/networking_private/networking_private_ui_delegate_chromeos.h",
@@ -986,7 +978,6 @@
       "updater/local_extension_cache.h",
     ]
 
-    sources -= [ "api/music_manager_private/device_id_linux.cc" ]
     if (use_dbus) {
       configs += [ "//build/config/linux/dbus" ]
     }
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id.cc b/chrome/browser/extensions/api/music_manager_private/device_id.cc
deleted file mode 100644
index 08de538..0000000
--- a/chrome/browser/extensions/api/music_manager_private/device_id.cc
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/api/music_manager_private/device_id.h"
-
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "content/public/browser/browser_thread.h"
-#include "crypto/hmac.h"
-
-namespace {
-
-using extensions::api::DeviceId;
-
-// Compute HMAC-SHA256(|key|, |text|) as a string.
-bool ComputeHmacSha256(const std::string& key,
-                       const std::string& text,
-                       std::string* signature_return) {
-  crypto::HMAC hmac(crypto::HMAC::SHA256);
-  const size_t digest_length = hmac.DigestLength();
-  std::vector<uint8_t> digest(digest_length);
-  bool result = hmac.Init(key) &&
-      hmac.Sign(text, &digest[0], digest.size());
-  if (result) {
-    *signature_return = base::ToLowerASCII(
-        base::HexEncode(digest.data(), digest.size()));
-  }
-  return result;
-}
-
-void GetRawDeviceIdCallback(const std::string& extension_id,
-                            const DeviceId::IdCallback& callback,
-                            const std::string& raw_device_id) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  if (raw_device_id.empty()) {
-    callback.Run("");
-    return;
-  }
-
-  std::string device_id;
-  if (!ComputeHmacSha256(raw_device_id, extension_id, &device_id)) {
-    DLOG(ERROR) << "Error while computing HMAC-SHA256 of device id.";
-    callback.Run("");
-    return;
-  }
-  callback.Run(device_id);
-}
-
-bool IsValidMacAddressImpl(const void* bytes, size_t size) {
-  const size_t MAC_LENGTH = 6;
-  const size_t OUI_LENGTH = 3;
-  struct InvalidMacEntry {
-      size_t size;
-      unsigned char address[MAC_LENGTH];
-  };
-
-  // VPN, virtualization, tethering, bluetooth, etc.
-  static InvalidMacEntry invalidAddresses[] = {
-    // Empty address
-    {MAC_LENGTH, {0, 0, 0, 0, 0, 0}},
-    // VMware
-    {OUI_LENGTH, {0x00, 0x50, 0x56}},
-    {OUI_LENGTH, {0x00, 0x05, 0x69}},
-    {OUI_LENGTH, {0x00, 0x0c, 0x29}},
-    {OUI_LENGTH, {0x00, 0x1c, 0x14}},
-    // VirtualBox
-    {OUI_LENGTH, {0x08, 0x00, 0x27}},
-    // PdaNet
-    {MAC_LENGTH, {0x00, 0x26, 0x37, 0xbd, 0x39, 0x42}},
-    // Cisco AnyConnect VPN
-    {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}},
-    // Marvell sometimes uses this as a dummy address
-    {MAC_LENGTH, {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
-    // Apple uses this across machines for Bluetooth ethernet adapters.
-    {MAC_LENGTH-1, {0x65, 0x90, 0x07, 0x42, 0xf1}},
-    // Juniper uses this for their Virtual Adapter, the other 4 bytes are
-    // reassigned at every boot. 00-ff-xx is not assigned to anyone.
-    {2, {0x00, 0xff}},
-    // T-Mobile Wireless Ethernet
-    {MAC_LENGTH, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}},
-    // Generic Bluetooth device
-    {MAC_LENGTH, {0x00, 0x15, 0x83, 0x3d, 0x0a, 0x57}},
-    // RAS Async Adapter
-    {MAC_LENGTH, {0x20, 0x41, 0x53, 0x59, 0x4e, 0xff}},
-    // Qualcomm USB ethernet adapter
-    {MAC_LENGTH, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}},
-    // Windows VPN
-    {MAC_LENGTH, {0x00, 0x53, 0x45, 0x00, 0x00, 0x00}},
-    // Bluetooth
-    {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x08, 0x30}},
-    {MAC_LENGTH, {0x00, 0x1b, 0x10, 0x00, 0x2a, 0xec}},
-    {MAC_LENGTH, {0x00, 0x15, 0x83, 0x15, 0xa3, 0x10}},
-    {MAC_LENGTH, {0x00, 0x15, 0x83, 0x07, 0xC6, 0x5A}},
-    {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x02, 0x00}},
-    {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x02, 0xdd}},
-    // Ceton TV tuner
-    {MAC_LENGTH, {0x00, 0x22, 0x2c, 0xff, 0xff, 0xff}},
-    // Check Point VPN
-    {MAC_LENGTH, {0x54, 0x55, 0x43, 0x44, 0x52, 0x09}},
-    {MAC_LENGTH, {0x54, 0xEF, 0x14, 0x71, 0xE4, 0x0E}},
-    {MAC_LENGTH, {0x54, 0xBA, 0xC6, 0xFF, 0x74, 0x10}},
-    // Cisco VPN
-    {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}},
-    // Cisco VPN
-    {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x78, 0x00}},
-    // Intel USB cell modem
-    {MAC_LENGTH, {0x00, 0x1e, 0x10, 0x1f, 0x00, 0x01}},
-    // Microsoft tethering
-    {MAC_LENGTH, {0x80, 0x00, 0x60, 0x0f, 0xe8, 0x00}},
-    // Nortel VPN
-    {MAC_LENGTH, {0x44, 0x45, 0x53, 0x54, 0x42, 0x00}},
-    // AEP VPN
-    {MAC_LENGTH, {0x00, 0x30, 0x70, 0x00, 0x00, 0x01}},
-    // Positive VPN
-    {MAC_LENGTH, {0x00, 0x02, 0x03, 0x04, 0x05, 0x06}},
-    // Bluetooth
-    {MAC_LENGTH, {0x00, 0x15, 0x83, 0x0B, 0x13, 0xC0}},
-    // Kerio Virtual Network Adapter
-    {MAC_LENGTH, {0x44, 0x45, 0x53, 0x54, 0x4f, 0x53}},
-    // Sierra Wireless cell modems.
-    {OUI_LENGTH, {0x00, 0xA0, 0xD5}},
-    // FRITZ!web DSL
-    {MAC_LENGTH, {0x00, 0x04, 0x0E, 0xFF, 0xFF, 0xFF}},
-    // VirtualPC
-    {MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},
-    // Bluetooth
-    {MAC_LENGTH, {0x00, 0x1F, 0x81, 0x00, 0x01, 0x00}},
-    {MAC_LENGTH, {0x00, 0x30, 0x91, 0x10, 0x00, 0x26}},
-    {MAC_LENGTH, {0x00, 0x25, 0x00, 0x5A, 0xC3, 0xD0}},
-    {MAC_LENGTH, {0x00, 0x15, 0x83, 0x0C, 0xBF, 0xEB}},
-    // Huawei cell modem
-    {MAC_LENGTH, {0x58, 0x2C, 0x80, 0x13, 0x92, 0x63}},
-    // Fortinet VPN
-    {OUI_LENGTH, {0x00, 0x09, 0x0F}},
-    // Realtek
-    {MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x30}},
-    // Other rare dupes.
-    {MAC_LENGTH, {0x00, 0x11, 0xf5, 0x0d, 0x8a, 0xe8}}, // Atheros
-    {MAC_LENGTH, {0x00, 0x20, 0x07, 0x01, 0x16, 0x06}}, // Atheros
-    {MAC_LENGTH, {0x0d, 0x0b, 0x00, 0x00, 0xe0, 0x00}}, // Atheros
-    {MAC_LENGTH, {0x90, 0x4c, 0xe5, 0x0b, 0xc8, 0x8e}}, // Atheros
-    {MAC_LENGTH, {0x00, 0x1c, 0x23, 0x38, 0x49, 0xa4}}, // Broadcom
-    {MAC_LENGTH, {0x00, 0x12, 0x3f, 0x82, 0x7c, 0x32}}, // Broadcom
-    {MAC_LENGTH, {0x00, 0x11, 0x11, 0x32, 0xc3, 0x77}}, // Broadcom
-    {MAC_LENGTH, {0x00, 0x24, 0xd6, 0xae, 0x3e, 0x39}}, // Microsoft
-    {MAC_LENGTH, {0x00, 0x0f, 0xb0, 0x3a, 0xb4, 0x80}}, // Realtek
-    {MAC_LENGTH, {0x08, 0x10, 0x74, 0xa1, 0xda, 0x1b}}, // Realtek
-    {MAC_LENGTH, {0x00, 0x21, 0x9b, 0x2a, 0x0a, 0x9c}}, // Realtek
-  };
-
-  if (size != MAC_LENGTH) {
-    return false;
-  }
-
-  if (static_cast<const unsigned char *>(bytes)[0] & 0x02) {
-    // Locally administered.
-    return false;
-  }
-
-  for (size_t i = 0; i < arraysize(invalidAddresses); ++i) {
-    size_t count = invalidAddresses[i].size;
-    if (memcmp(invalidAddresses[i].address, bytes, count) == 0) {
-        return false;
-    }
-  }
-  return true;
-}
-
-}  // namespace
-
-namespace extensions {
-namespace api {
-
-// static
-void DeviceId::GetDeviceId(const std::string& extension_id,
-                           const IdCallback& callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  CHECK(!extension_id.empty());
-
-  // Forward call to platform specific implementation, then compute the HMAC
-  // in the callback.
-  GetRawDeviceId(base::Bind(&GetRawDeviceIdCallback, extension_id, callback));
-}
-
-// static
-bool DeviceId::IsValidMacAddress(const void* bytes, size_t size) {
-  return IsValidMacAddressImpl(bytes, size);
-}
-
-}  // namespace api
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
index 8b975a1f..892ea52 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
@@ -224,7 +224,7 @@
     entry.index = base::checked_cast<int>(i);
     entry.num_characters_in_password = form->password_value.length();
 
-    if (!form->federation_origin.unique()) {
+    if (!form->federation_origin.opaque()) {
       entry.federation_text.reset(new std::string(l10n_util::GetStringFUTF8(
           IDS_PASSWORDS_VIA_FEDERATION,
           base::UTF8ToUTF16(form->federation_origin.host()))));
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index cda1e33..43ced6b4 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -371,6 +371,8 @@
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)[arc::prefs::kVoiceInteractionNotificationEnabled] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)[arc::prefs::kVoiceInteractionLaunchWithMicOpen] =
+      settings_api::PrefType::PREF_TYPE_BOOLEAN;
 
   // Misc.
   (*s_whitelist)[::prefs::kUse24HourClock] =
diff --git a/chrome/browser/extensions/data_deleter.cc b/chrome/browser/extensions/data_deleter.cc
index cbecc61..06aa322 100644
--- a/chrome/browser/extensions/data_deleter.cc
+++ b/chrome/browser/extensions/data_deleter.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_special_storage_policy.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_io_data.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -37,10 +38,9 @@
 
 namespace {
 
-void ClearCookiesOnIOThread(scoped_refptr<net::URLRequestContextGetter> context,
+void ClearCookiesOnIOThread(base::OnceCallback<net::CookieStore*()> getter,
                             const GURL& origin) {
-  net::CookieStore* cookie_store =
-      context->GetURLRequestContext()->cookie_store();
+  net::CookieStore* cookie_store = std::move(getter).Run();
   net::CookieDeletionInfo delete_info;
   delete_info.host = origin.host();
   cookie_store->DeleteAllMatchingInfoAsync(std::move(delete_info),
@@ -76,10 +76,8 @@
     // TODO(rdsmith): Mojoify this call and get rid of the thread hopping.
     base::PostTaskWithTraits(
         FROM_HERE, {BrowserThread::IO},
-        base::BindOnce(
-            &ClearCookiesOnIOThread,
-            base::WrapRefCounted(profile->GetRequestContextForExtensions()),
-            origin));
+        base::BindOnce(&ClearCookiesOnIOThread,
+                       profile->GetExtensionsCookieStoreGetter(), origin));
   } else {
     // We don't need to worry about the media request context because that
     // shares the same cookie store as the main request context.
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 08225a9..73308a7 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -4848,9 +4848,8 @@
   std::string origin_id = storage::GetIdentifierFromOrigin(ext_url);
 
   // Set a cookie for the extension.
-  net::CookieStore* cookie_store = profile()->GetRequestContextForExtensions()
-                                            ->GetURLRequestContext()
-                                            ->cookie_store();
+  net::CookieStore* cookie_store =
+      profile()->GetExtensionsCookieStoreGetter().Run();
   ASSERT_TRUE(cookie_store);
   net::CookieOptions options;
   cookie_store->SetCookieWithOptionsAsync(
diff --git a/chrome/browser/media/android/cdm/media_drm_storage_factory.cc b/chrome/browser/media/android/cdm/media_drm_storage_factory.cc
index fa0e074..37cfd33 100644
--- a/chrome/browser/media/android/cdm/media_drm_storage_factory.cc
+++ b/chrome/browser/media/android/cdm/media_drm_storage_factory.cc
@@ -35,7 +35,7 @@
   PrefService* pref_service = profile->GetPrefs();
   DCHECK(pref_service) << "PrefService not available.";
 
-  if (render_frame_host->GetLastCommittedOrigin().unique()) {
+  if (render_frame_host->GetLastCommittedOrigin().opaque()) {
     DVLOG(1) << __func__ << ": Unique origin.";
     return;
   }
diff --git a/chrome/browser/media/cdm_storage_id.cc b/chrome/browser/media/cdm_storage_id.cc
index 9aaf614..ebfee13 100644
--- a/chrome/browser/media/cdm_storage_id.cc
+++ b/chrome/browser/media/cdm_storage_id.cc
@@ -55,7 +55,7 @@
     return {};
   }
 
-  if (origin.unique()) {
+  if (origin.opaque()) {
     DLOG(ERROR) << "Unexpected origin: " << origin;
     return {};
   }
diff --git a/chrome/browser/media/router/presentation/presentation_service_delegate_impl.cc b/chrome/browser/media/router/presentation/presentation_service_delegate_impl.cc
index 2c53c9a5..af1f0ea2 100644
--- a/chrome/browser/media/router/presentation/presentation_service_delegate_impl.cc
+++ b/chrome/browser/media/router/presentation/presentation_service_delegate_impl.cc
@@ -68,7 +68,7 @@
     const content::PresentationRequest& request2) {
   return request1.render_frame_host_id == request2.render_frame_host_id &&
          request1.presentation_urls == request2.presentation_urls &&
-         ((request1.frame_origin.unique() && request2.frame_origin.unique()) ||
+         ((request1.frame_origin.opaque() && request2.frame_origin.opaque()) ||
           (request1.frame_origin == request2.frame_origin));
 }
 
diff --git a/chrome/browser/net/chrome_url_request_context_getter.cc b/chrome/browser/net/chrome_url_request_context_getter.cc
index 8d44a53..eca8e53 100644
--- a/chrome/browser/net/chrome_url_request_context_getter.cc
+++ b/chrome/browser/net/chrome_url_request_context_getter.cc
@@ -63,20 +63,6 @@
   content::URLRequestInterceptorScopedVector request_interceptors_;
 };
 
-// Factory that creates the URLRequestContext for extensions.
-class FactoryForExtensions : public ChromeURLRequestContextFactory {
- public:
-  explicit FactoryForExtensions(const ProfileIOData* profile_io_data)
-      : profile_io_data_(profile_io_data) {}
-
-  net::URLRequestContext* Create() override {
-    return profile_io_data_->GetExtensionsRequestContext();
-  }
-
- private:
-  const ProfileIOData* const profile_io_data_;
-};
-
 // Factory that creates the URLRequestContext for a given isolated app.
 class FactoryForIsolatedApp : public ChromeURLRequestContextFactory {
  public:
@@ -254,15 +240,6 @@
 
 // static
 scoped_refptr<ChromeURLRequestContextGetter>
-ChromeURLRequestContextGetter::CreateForExtensions(
-    Profile* profile,
-    const ProfileIOData* profile_io_data) {
-  return ChromeURLRequestContextGetter::CreateAndInit(
-      std::make_unique<FactoryForExtensions>(profile_io_data));
-}
-
-// static
-scoped_refptr<ChromeURLRequestContextGetter>
 ChromeURLRequestContextGetter::CreateForIsolatedApp(
     Profile* profile,
     const ProfileIOData* profile_io_data,
diff --git a/chrome/browser/net/chrome_url_request_context_getter.h b/chrome/browser/net/chrome_url_request_context_getter.h
index a870e0dd..b17941e 100644
--- a/chrome/browser/net/chrome_url_request_context_getter.h
+++ b/chrome/browser/net/chrome_url_request_context_getter.h
@@ -53,12 +53,6 @@
       Profile* profile,
       const ProfileIOData* profile_io_data);
 
-  // Create an instance for an original profile for extensions. This is expected
-  // to get called on UI thread.
-  static scoped_refptr<ChromeURLRequestContextGetter> CreateForExtensions(
-      Profile* profile,
-      const ProfileIOData* profile_io_data);
-
   // Create an instance for an original profile for an app with isolated
   // storage. This is expected to get called on UI thread.
   static scoped_refptr<ChromeURLRequestContextGetter> CreateForIsolatedApp(
diff --git a/chrome/browser/notifications/notification_channels_provider_android.cc b/chrome/browser/notifications/notification_channels_provider_android.cc
index 76fa6c7..56710d2e 100644
--- a/chrome/browser/notifications/notification_channels_provider_android.cc
+++ b/chrome/browser/notifications/notification_channels_provider_android.cc
@@ -326,7 +326,7 @@
   InitCachedChannels();
 
   url::Origin origin = url::Origin::Create(GURL(primary_pattern.ToString()));
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   const std::string origin_string = origin.Serialize();
 
   ContentSetting setting = content_settings::ValueToContentSetting(value);
@@ -386,7 +386,7 @@
     return base::Time();
   }
   url::Origin origin = url::Origin::Create(GURL(primary_pattern.ToString()));
-  if (origin.unique())
+  if (origin.opaque())
     return base::Time();
   const std::string origin_string = origin.Serialize();
 
@@ -425,7 +425,7 @@
     const content_settings::Rule& rule) {
   url::Origin origin =
       url::Origin::Create(GURL(rule.primary_pattern.ToString()));
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   const std::string origin_string = origin.Serialize();
   ContentSetting content_setting =
       content_settings::ValueToContentSetting(rule.value.get());
diff --git a/chrome/browser/password_manager/credential_android.cc b/chrome/browser/password_manager/credential_android.cc
index 31d730f..c5a68d0 100644
--- a/chrome/browser/password_manager/credential_android.cc
+++ b/chrome/browser/password_manager/credential_android.cc
@@ -22,7 +22,7 @@
           ? password_form.origin.GetOrigin().spec()
           : std::string();
   std::string federation =
-      password_form.federation_origin.unique()
+      password_form.federation_origin.opaque()
           ? std::string()
           : l10n_util::GetStringFUTF8(
                 IDS_PASSWORDS_VIA_FEDERATION,
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.cc b/chrome/browser/password_manager/native_backend_gnome_x.cc
index 1fcc156..e52bc04 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x.cc
@@ -321,7 +321,7 @@
       "avatar_url", form.icon_url.spec().c_str(),
       // We serialize unique origins as "", in order to make other systems that
       // read from the login database happy. https://crbug.com/591310
-      "federation_url", form.federation_origin.unique()
+      "federation_url", form.federation_origin.opaque()
           ? ""
           : form.federation_origin.Serialize().c_str(),
       "should_skip_zero_click", form.skip_zero_click,
diff --git a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
index 22ae222..42181269 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
@@ -476,7 +476,7 @@
     // We serialize unique origins as "", in order to make other systems that
     // read from the login database happy. https://crbug.com/591310
     CheckStringAttribute(item, "federation_url",
-                         form.federation_origin.unique()
+                         form.federation_origin.opaque()
                              ? ""
                              : form.federation_origin.Serialize());
     CheckUint32Attribute(item, "should_skip_zero_click", form.skip_zero_click);
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x.cc b/chrome/browser/password_manager/native_backend_kwallet_x.cc
index 75ec1c8..a323b10 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x.cc
+++ b/chrome/browser/password_manager/native_backend_kwallet_x.cc
@@ -274,7 +274,7 @@
     pickle->WriteString(form->icon_url.spec());
     // We serialize unique origins as "", in order to make other systems that
     // read from the login database happy. https://crbug.com/591310
-    pickle->WriteString(form->federation_origin.unique()
+    pickle->WriteString(form->federation_origin.opaque()
                             ? std::string()
                             : form->federation_origin.Serialize());
     pickle->WriteBool(form->skip_zero_click);
diff --git a/chrome/browser/password_manager/native_backend_libsecret.cc b/chrome/browser/password_manager/native_backend_libsecret.cc
index a73e77a..3426c52e 100644
--- a/chrome/browser/password_manager/native_backend_libsecret.cc
+++ b/chrome/browser/password_manager/native_backend_libsecret.cc
@@ -352,7 +352,7 @@
       "avatar_url", form.icon_url.spec().c_str(),
       // We serialize unique origins as "", in order to make other systems that
       // read from the login database happy. https://crbug.com/591310
-      "federation_url", form.federation_origin.unique()
+      "federation_url", form.federation_origin.opaque()
           ? ""
           : form.federation_origin.Serialize().c_str(),
       "should_skip_zero_click", form.skip_zero_click,
diff --git a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc b/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
index e8b2e05..bbd34bb5 100644
--- a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
@@ -420,7 +420,7 @@
     // We serialize unique origins as "", in order to make other systems that
     // read from the login database happy. https://crbug.com/591310
     CheckStringAttribute(item, "federation_url",
-                         form.federation_origin.unique()
+                         form.federation_origin.opaque()
                              ? ""
                              : form.federation_origin.Serialize());
     CheckUint32Attribute(item, "should_skip_zero_click", form.skip_zero_click);
diff --git a/chrome/browser/password_manager/save_password_infobar_delegate_android.cc b/chrome/browser/password_manager/save_password_infobar_delegate_android.cc
index 6918854..16ffbc9 100644
--- a/chrome/browser/password_manager/save_password_infobar_delegate_android.cc
+++ b/chrome/browser/password_manager/save_password_infobar_delegate_android.cc
@@ -57,7 +57,7 @@
   base::string16 message;
   gfx::Range message_link_range = gfx::Range();
   PasswordTitleType type =
-      form_to_save_->GetPendingCredentials().federation_origin.unique()
+      form_to_save_->GetPendingCredentials().federation_origin.opaque()
           ? PasswordTitleType::SAVE_PASSWORD
           : PasswordTitleType::SAVE_ACCOUNT;
   GetSavePasswordDialogTitleTextAndLinkRange(
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index b770088..bc5b09a 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -56,7 +56,6 @@
   MOCK_METHOD0(Show, gfx::Size());
   MOCK_METHOD1(Close, void(bool));
   MOCK_METHOD0(OnWindowDestroyed, void());
-  MOCK_METHOD1(ClickCustomControl, void(const std::string&));
   MOCK_METHOD1(SetPictureInPictureCustomControls,
                void(const std::vector<blink::PictureInPictureControlInfo>&));
   MOCK_METHOD2(EmbedSurface, void(const viz::SurfaceId&, const gfx::Size&));
@@ -66,6 +65,7 @@
   MOCK_METHOD0(GetInitiatorWebContents, content::WebContents*());
   MOCK_METHOD2(UpdatePlaybackState, void(bool, bool));
   MOCK_METHOD0(TogglePlayPause, bool());
+  MOCK_METHOD1(CustomControlPressed, void(const std::string&));
   MOCK_METHOD1(SetAlwaysHidePlayPauseButton, void(bool));
 
  private:
@@ -427,8 +427,7 @@
   std::string control_id = "Test custom control ID";
   base::string16 expected_title = base::ASCIIToUTF16(control_id);
 
-  static_cast<OverlayWindowViews*>(overlay_window)
-      ->ClickCustomControl(control_id);
+  window_controller()->CustomControlPressed(control_id);
 
   EXPECT_EQ(expected_title,
             content::TitleWatcher(active_web_contents, expected_title)
@@ -466,8 +465,7 @@
 
   base::string16 expected_title = base::ASCIIToUTF16(kControlId);
 
-  static_cast<OverlayWindowViews*>(overlay_window)
-      ->ClickCustomControl(kControlId);
+  window_controller()->CustomControlPressed(kControlId);
   EXPECT_EQ(expected_title,
             content::TitleWatcher(active_web_contents, expected_title)
                 .WaitAndGetTitle());
@@ -507,8 +505,7 @@
 
   base::string16 left_expected_title = base::ASCIIToUTF16(kLeftControlId);
 
-  static_cast<OverlayWindowViews*>(overlay_window)
-      ->ClickCustomControl(kLeftControlId);
+  window_controller()->CustomControlPressed(kLeftControlId);
   EXPECT_EQ(left_expected_title,
             content::TitleWatcher(active_web_contents, left_expected_title)
                 .WaitAndGetTitle());
@@ -548,8 +545,7 @@
 
   base::string16 right_expected_title = base::ASCIIToUTF16(kRightControlId);
 
-  static_cast<OverlayWindowViews*>(overlay_window)
-      ->ClickCustomControl(kRightControlId);
+  window_controller()->CustomControlPressed(kRightControlId);
   EXPECT_EQ(right_expected_title,
             content::TitleWatcher(active_web_contents, right_expected_title)
                 .WaitAndGetTitle());
diff --git a/chrome/browser/plugins/plugin_info_host_impl.cc b/chrome/browser/plugins/plugin_info_host_impl.cc
index a19f5d4f..989d5d0 100644
--- a/chrome/browser/plugins/plugin_info_host_impl.cc
+++ b/chrome/browser/plugins/plugin_info_host_impl.cc
@@ -479,7 +479,7 @@
       g_browser_process->rappor_service();
   if (!rappor_service)
     return;
-  if (main_frame_origin.unique())
+  if (main_frame_origin.opaque())
     return;
 
   if (mime_type != content::kFlashPluginSwfMimeType &&
diff --git a/chrome/browser/policy/test/policy_testserver.py b/chrome/browser/policy/test/policy_testserver.py
index 4e53926..c78440b 100644
--- a/chrome/browser/policy/test/policy_testserver.py
+++ b/chrome/browser/policy/test/policy_testserver.py
@@ -53,8 +53,11 @@
   "available_licenses" : {
       "annual": 10,
       "perpetual": 20
-   }
-
+   },
+   "token_enrollment": {
+      "token": "abcd-ef01-123123123",
+      "username": "admin@example.com"
+   },
 }
 
 """
@@ -391,6 +394,18 @@
 
     return None
 
+  def CheckEnrollmentToken(self):
+    """Extracts the enrollment token from the request and returns it. The token
+    is GoogleEnrollmentToken token from an Authorization header. Returns None
+    if no token is present.
+    """
+    match = re.match('GoogleEnrollmentToken auth=(\\w+)',
+                     self.headers.getheader('Authorization', ''))
+    if match:
+      return match.group(1)
+
+    return None
+
   def ProcessRegister(self, msg):
     """Handles a register request.
 
@@ -403,15 +418,26 @@
     Returns:
       A tuple of HTTP status code and response data to send to the client.
     """
-    # Check the auth token and device ID.
-    auth = self.CheckGoogleLogin()
-    if not auth:
-      return (403, 'No authorization')
-
+    enrollment_token = self.CheckEnrollmentToken()
     policy = self.server.GetPolicies()
-    if ('managed_users' not in policy):
-      return (500, 'Error in config - no managed users')
-    username = self.server.ResolveUser(auth)
+    if enrollment_token:
+      if ((not policy['token_enrollment']) or
+          (not policy['token_enrollment']['token']) or
+          (not policy['token_enrollment']['username'])):
+        return (500, 'Error in config - no token-based enrollment')
+      if policy['token_enrollment']['token'] != enrollment_token:
+        return (403, 'Invalid enrollment token')
+      username = policy['token_enrollment']['username']
+    else:
+      # Check the auth token and device ID.
+      auth = self.CheckGoogleLogin()
+      if not auth:
+        return (403, 'No authorization')
+
+      if ('managed_users' not in policy):
+        return (500, 'Error in config - no managed users')
+      username = self.server.ResolveUser(auth)
+
     if ('*' not in policy['managed_users'] and
         username not in policy['managed_users']):
       return (403, 'Unmanaged')
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc
index 323c79a0..062c4fc 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.cc
+++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -308,7 +308,7 @@
   std::string legacy_device_id;
 #if defined(OS_WIN) && BUILDFLAG(ENABLE_RLZ)
   // This is used by
-  // chrome/browser/extensions/api/music_manager_private/device_id_win.cc
+  // chrome/browser/apps/platform_apps/api/music_manager_private/device_id_win.cc
   // but that API is private (http://crbug.com/276485) and other platforms are
   // not available synchronously.
   // As part of improving pref metrics on other platforms we may want to find
diff --git a/chrome/browser/printing/print_preview_message_handler.cc b/chrome/browser/printing/print_preview_message_handler.cc
index bc90f2b..37b7d6d 100644
--- a/chrome/browser/printing/print_preview_message_handler.cc
+++ b/chrome/browser/printing/print_preview_message_handler.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/memory/read_only_shared_memory_region.h"
@@ -31,6 +32,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "printing/nup_parameters.h"
+#include "printing/page_setup.h"
 #include "printing/print_job_constants.h"
 #include "printing/print_settings.h"
 
@@ -63,25 +65,6 @@
   return page_number >= 0 && page_number < page_count;
 }
 
-// Checks whether |printable_area| can be used to form a valid symmetrical
-// printable area, so that margin_left equals margin_right, and margin_top
-// equals margin_bottom.  For example if
-// printable_area.x() * 2 >= page_size.width(), then the
-// content_width = page_size.width() - 2 * printable_area.x() would be zero or
-// negative, which is invalid.
-// |page_size| is the physical page size that includes margins.
-bool IsValidPrintableArea(const gfx::Size& page_size,
-                          const gfx::Rect& printable_area) {
-  return !printable_area.IsEmpty() && printable_area.x() >= 0 &&
-         printable_area.y() >= 0 &&
-         printable_area.right() <= page_size.width() &&
-         printable_area.bottom() <= page_size.height() &&
-         printable_area.x() * 2 < page_size.width() &&
-         printable_area.y() * 2 < page_size.height() &&
-         printable_area.right() * 2 > page_size.width() &&
-         printable_area.bottom() * 2 > page_size.height();
-}
-
 }  // namespace
 
 PrintPreviewMessageHandler::PrintPreviewMessageHandler(
@@ -360,7 +343,7 @@
       std::vector<base::ReadOnlySharedMemoryRegion> pdf_page_regions =
           print_preview_ui->TakePagesForNupConvert();
 
-      gfx::Rect printable_area = GetSymmetricalPrintableArea(
+      gfx::Rect printable_area = PageSetup::GetSymmetricalPrintableArea(
           print_preview_ui->page_size(), print_preview_ui->printable_area());
       if (printable_area.IsEmpty())
         return;
@@ -421,7 +404,7 @@
     auto* client = PdfNupConverterClient::FromWebContents(web_contents());
     DCHECK(client);
 
-    gfx::Rect printable_area = GetSymmetricalPrintableArea(
+    gfx::Rect printable_area = PageSetup::GetSymmetricalPrintableArea(
         print_preview_ui->page_size(), print_preview_ui->printable_area());
     if (printable_area.IsEmpty())
       return;
@@ -490,24 +473,4 @@
   return handled;
 }
 
-// static
-gfx::Rect PrintPreviewMessageHandler::GetSymmetricalPrintableArea(
-    const gfx::Size& page_size,
-    const gfx::Rect& printable_area) {
-  if (!IsValidPrintableArea(page_size, printable_area))
-    return gfx::Rect();
-
-  int left_right_margin =
-      std::max(printable_area.x(), page_size.width() - printable_area.right());
-  int top_bottom_margin = std::max(
-      printable_area.y(), page_size.height() - printable_area.bottom());
-  int width = page_size.width() - 2 * left_right_margin;
-  int height = page_size.height() - 2 * top_bottom_margin;
-
-  gfx::Rect symmetrical_printable_area = gfx::Rect(page_size);
-  symmetrical_printable_area.ClampToCenteredSize(gfx::Size(width, height));
-
-  return symmetrical_printable_area;
-}
-
 }  // namespace printing
diff --git a/chrome/browser/printing/print_preview_message_handler.h b/chrome/browser/printing/print_preview_message_handler.h
index cf88ffc..8e3dd31c 100644
--- a/chrome/browser/printing/print_preview_message_handler.h
+++ b/chrome/browser/printing/print_preview_message_handler.h
@@ -32,7 +32,6 @@
 
 namespace gfx {
 class Rect;
-class Size;
 }
 
 namespace printing {
@@ -50,11 +49,6 @@
   bool OnMessageReceived(const IPC::Message& message,
                          content::RenderFrameHost* render_frame_host) override;
 
-  // Gets a symmetrical printable area.  It is defined as a static function to
-  // make writing unit tests easier.
-  static gfx::Rect GetSymmetricalPrintableArea(const gfx::Size& page_size,
-                                               const gfx::Rect& printable_area);
-
  private:
   friend class content::WebContentsUserData<PrintPreviewMessageHandler>;
 
diff --git a/chrome/browser/printing/print_preview_message_handler_unittest.cc b/chrome/browser/printing/print_preview_message_handler_unittest.cc
deleted file mode 100644
index c8401fc2..0000000
--- a/chrome/browser/printing/print_preview_message_handler_unittest.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/printing/print_preview_message_handler.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace printing {
-
-using PrintPreviewMessageHandlerTest = testing::Test;
-
-TEST_F(PrintPreviewMessageHandlerTest, GetSymmetricalPrintableArea) {
-  gfx::Rect printable_area =
-      PrintPreviewMessageHandler::GetSymmetricalPrintableArea(
-          gfx::Size(612, 792), gfx::Rect(0, 0, 560, 750));
-  EXPECT_EQ(gfx::Rect(52, 42, 508, 708), printable_area);
-
-  printable_area = PrintPreviewMessageHandler::GetSymmetricalPrintableArea(
-      gfx::Size(612, 792), gfx::Rect(50, 60, 550, 700));
-  EXPECT_EQ(gfx::Rect(50, 60, 512, 672), printable_area);
-
-  printable_area = PrintPreviewMessageHandler::GetSymmetricalPrintableArea(
-      gfx::Size(612, 792), gfx::Rect(-1, 60, 520, 700));
-  EXPECT_EQ(gfx::Rect(), printable_area);
-  printable_area = PrintPreviewMessageHandler::GetSymmetricalPrintableArea(
-      gfx::Size(612, 792), gfx::Rect(50, -1, 520, 700));
-  EXPECT_EQ(gfx::Rect(), printable_area);
-  printable_area = PrintPreviewMessageHandler::GetSymmetricalPrintableArea(
-      gfx::Size(612, 792), gfx::Rect(100, 60, 520, 700));
-  EXPECT_EQ(gfx::Rect(), printable_area);
-  printable_area = PrintPreviewMessageHandler::GetSymmetricalPrintableArea(
-      gfx::Size(612, 792), gfx::Rect(50, 100, 520, 700));
-  EXPECT_EQ(gfx::Rect(), printable_area);
-  printable_area = PrintPreviewMessageHandler::GetSymmetricalPrintableArea(
-      gfx::Size(612, 792), gfx::Rect(400, 60, 212, 700));
-  EXPECT_EQ(gfx::Rect(), printable_area);
-  printable_area = PrintPreviewMessageHandler::GetSymmetricalPrintableArea(
-      gfx::Size(612, 792), gfx::Rect(40, 600, 212, 192));
-  EXPECT_EQ(gfx::Rect(), printable_area);
-}
-
-}  // namespace printing
diff --git a/chrome/browser/profiles/gaia_info_update_service.cc b/chrome/browser/profiles/gaia_info_update_service.cc
index cb9fb5cd..368e124 100644
--- a/chrome/browser/profiles/gaia_info_update_service.cc
+++ b/chrome/browser/profiles/gaia_info_update_service.cc
@@ -43,6 +43,12 @@
       IdentityManagerFactory::GetForProfile(profile_);
   identity_manager->AddObserver(this);
 
+  if (!identity_manager->HasPrimaryAccount()) {
+    // Handle the case when the primary account was cleared while loading the
+    // profile, before the |GAIAInfoUpdateService| is created.
+    OnUsernameChanged(std::string());
+  }
+
   PrefService* prefs = profile_->GetPrefs();
   last_updated_ = base::Time::FromInternalValue(
       prefs->GetInt64(prefs::kProfileGAIAInfoUpdateTime));
diff --git a/chrome/browser/profiles/gaia_info_update_service_unittest.cc b/chrome/browser/profiles/gaia_info_update_service_unittest.cc
index 667a504..da425fe 100644
--- a/chrome/browser/profiles/gaia_info_update_service_unittest.cc
+++ b/chrome/browser/profiles/gaia_info_update_service_unittest.cc
@@ -70,9 +70,28 @@
 };
 
 // TODO(anthonyvd) : remove ProfileInfoCacheTest from the test fixture.
-class GAIAInfoUpdateServiceTest : public ProfileInfoCacheTest {
+class GAIAInfoUpdateServiceTestBase : public ProfileInfoCacheTest {
  protected:
-  GAIAInfoUpdateServiceTest() : profile_(NULL) {
+  explicit GAIAInfoUpdateServiceTestBase(bool create_gaia_info_service_on_setup)
+      : create_gaia_info_service_on_setup_(create_gaia_info_service_on_setup) {}
+  ~GAIAInfoUpdateServiceTestBase() override = default;
+
+  void SetUp() override {
+    ProfileInfoCacheTest::SetUp();
+    if (create_gaia_info_service_on_setup_) {
+      service_.reset(new NiceMock<GAIAInfoUpdateServiceMock>(profile()));
+      downloader_.reset(new NiceMock<ProfileDownloaderMock>(service()));
+    }
+  };
+
+  void TearDown() override {
+    if (downloader_)
+      downloader_.reset();
+    if (service_) {
+      service_->Shutdown();
+      service_.reset();
+    }
+    ProfileInfoCacheTest::TearDown();
   }
 
   Profile* profile() {
@@ -157,27 +176,36 @@
     EXPECT_EQ(given_name, entry->GetGAIAGivenName());
   }
 
- private:
-  void SetUp() override;
-  void TearDown() override;
-
-  Profile* profile_;
+  const bool create_gaia_info_service_on_setup_;
+  Profile* profile_ = nullptr;
   std::unique_ptr<NiceMock<GAIAInfoUpdateServiceMock>> service_;
   std::unique_ptr<NiceMock<ProfileDownloaderMock>> downloader_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GAIAInfoUpdateServiceTestBase);
 };
 
-void GAIAInfoUpdateServiceTest::SetUp() {
-  ProfileInfoCacheTest::SetUp();
-  service_.reset(new NiceMock<GAIAInfoUpdateServiceMock>(profile()));
-  downloader_.reset(new NiceMock<ProfileDownloaderMock>(service()));
-}
+class GAIAInfoUpdateServiceTest : public GAIAInfoUpdateServiceTestBase {
+ public:
+  GAIAInfoUpdateServiceTest()
+      : GAIAInfoUpdateServiceTestBase(
+            /*create_gaia_info_service_on_setup_=*/true) {}
+  ~GAIAInfoUpdateServiceTest() override = default;
 
-void GAIAInfoUpdateServiceTest::TearDown() {
-  downloader_.reset();
-  service_->Shutdown();
-  service_.reset();
-  ProfileInfoCacheTest::TearDown();
-}
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GAIAInfoUpdateServiceTest);
+};
+
+class GAIAInfoUpdateServiceMiscTest : public GAIAInfoUpdateServiceTestBase {
+ public:
+  GAIAInfoUpdateServiceMiscTest()
+      : GAIAInfoUpdateServiceTestBase(
+            /*create_gaia_info_service_on_setup_=*/false) {}
+  ~GAIAInfoUpdateServiceMiscTest() override = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GAIAInfoUpdateServiceMiscTest);
+};
 
 }  // namespace
 
@@ -363,4 +391,23 @@
   EXPECT_EQ(kLocalAvatarIndex, entry->GetAvatarIconIndex());
 }
 
+TEST_F(GAIAInfoUpdateServiceMiscTest, ClearGaiaInfoOnStartup) {
+  // Simulate a state where the profile entry has GAIA related information
+  // when there is not primary account set.
+  EXPECT_FALSE(
+      IdentityManagerFactory::GetForProfile(profile())->HasPrimaryAccount());
+  ASSERT_EQ(1u, storage()->GetNumberOfProfiles());
+  ProfileAttributesEntry* entry = storage()->GetAllProfilesAttributes().front();
+  entry->SetGAIAName(base::UTF8ToUTF16("foo"));
+  entry->SetGAIAGivenName(base::UTF8ToUTF16("Pat Foo"));
+  gfx::Image gaia_picture = gfx::test::CreateImage(256, 256);
+  entry->SetGAIAPicture(&gaia_picture);
+
+  // Verify that creating the GAIAInfoUpdateService resets the GAIA related
+  // profile attributes if the profile no longer has a primary account.
+  service_.reset(new NiceMock<GAIAInfoUpdateServiceMock>(profile()));
+  EXPECT_TRUE(entry->GetGAIAName().empty());
+  EXPECT_TRUE(entry->GetGAIAGivenName().empty());
+  EXPECT_FALSE(entry->GetGAIAPicture());
+}
 #endif
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 193b8cf0..901dcbe 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -393,9 +393,14 @@
   return GetDefaultStoragePartition(this)->GetURLRequestContext();
 }
 
-net::URLRequestContextGetter*
-    OffTheRecordProfileImpl::GetRequestContextForExtensions() {
-  return io_data_->GetExtensionsRequestContextGetter().get();
+base::OnceCallback<net::CookieStore*()>
+OffTheRecordProfileImpl::GetExtensionsCookieStoreGetter() {
+  return base::BindOnce(
+      [](content::ResourceContext* context) {
+        auto* io_data = ProfileIOData::FromResourceContext(context);
+        return io_data->GetExtensionsCookieStore();
+      },
+      GetResourceContext());
 }
 
 scoped_refptr<network::SharedURLLoaderFactory>
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h
index 77f24ffa..c8faf0c 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.h
+++ b/chrome/browser/profiles/off_the_record_profile_impl.h
@@ -56,7 +56,8 @@
   const PrefService* GetPrefs() const override;
   PrefService* GetOffTheRecordPrefs() override;
   net::URLRequestContextGetter* GetRequestContext() override;
-  net::URLRequestContextGetter* GetRequestContextForExtensions() override;
+  base::OnceCallback<net::CookieStore*()> GetExtensionsCookieStoreGetter()
+      override;
   scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
   net::URLRequestContextGetter* CreateRequestContext(
       content::ProtocolHandlerMap* protocol_handlers,
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.cc b/chrome/browser/profiles/off_the_record_profile_io_data.cc
index fe5fee3..de26825 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.cc
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.cc
@@ -105,17 +105,6 @@
 }
 
 scoped_refptr<ChromeURLRequestContextGetter>
-OffTheRecordProfileIOData::Handle::GetExtensionsRequestContextGetter() const {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  LazyInitialize();
-  if (!extensions_request_context_getter_.get()) {
-    extensions_request_context_getter_ =
-        ChromeURLRequestContextGetter::CreateForExtensions(profile_, io_data_);
-  }
-  return extensions_request_context_getter_;
-}
-
-scoped_refptr<ChromeURLRequestContextGetter>
 OffTheRecordProfileIOData::Handle::GetIsolatedAppRequestContextGetter(
     const base::FilePath& partition_path,
     bool in_memory) const {
@@ -205,9 +194,6 @@
   for (; iter != app_request_context_getter_map_.end(); ++iter)
     context_getters->push_back(iter->second);
 
-  if (extensions_request_context_getter_.get())
-    context_getters->push_back(extensions_request_context_getter_);
-
   if (main_request_context_getter_.get())
     context_getters->push_back(main_request_context_getter_);
 
@@ -241,22 +227,17 @@
 void OffTheRecordProfileIOData::OnMainRequestContextCreated(
     ProfileParams* profile_params) const {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-  InitializeExtensionsRequestContext(profile_params);
+  InitializeExtensionsCookieStore(profile_params);
 #endif
 }
 
-void OffTheRecordProfileIOData::
-    InitializeExtensionsRequestContext(ProfileParams* profile_params) const {
-  // All we care about for extensions is the cookie store. For incognito, we
-  // use a non-persistent cookie store.
-  net::URLRequestContext* extensions_context = extensions_request_context();
-
+void OffTheRecordProfileIOData::InitializeExtensionsCookieStore(
+    ProfileParams* profile_params) const {
   content::CookieStoreConfig cookie_config;
   // Enable cookies for chrome-extension URLs.
   cookie_config.cookieable_schemes.push_back(extensions::kExtensionScheme);
   extensions_cookie_store_ = content::CreateCookieStore(
       cookie_config, profile_params->io_thread->net_log());
-  extensions_context->set_cookie_store(extensions_cookie_store_.get());
 }
 
 net::URLRequestContext*
@@ -281,3 +262,7 @@
   NOTREACHED();
   return NULL;
 }
+
+net::CookieStore* OffTheRecordProfileIOData::GetExtensionsCookieStore() const {
+  return extensions_cookie_store_.get();
+}
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.h b/chrome/browser/profiles/off_the_record_profile_io_data.h
index 8b915d0..6c86ef5 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.h
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.h
@@ -53,8 +53,6 @@
         content::ProtocolHandlerMap* protocol_handlers,
         content::URLRequestInterceptorScopedVector request_interceptors) const;
     scoped_refptr<ChromeURLRequestContextGetter>
-        GetExtensionsRequestContextGetter() const;
-    scoped_refptr<ChromeURLRequestContextGetter>
         GetIsolatedAppRequestContextGetter(
             const base::FilePath& partition_path,
             bool in_memory) const;
@@ -88,8 +86,6 @@
     // ProfileIOData instance is deleted.
     mutable scoped_refptr<ChromeURLRequestContextGetter>
         main_request_context_getter_;
-    mutable scoped_refptr<ChromeURLRequestContextGetter>
-        extensions_request_context_getter_;
     mutable ChromeURLRequestContextGetterMap
         app_request_context_getter_map_;
     OffTheRecordProfileIOData* const io_data_;
@@ -112,7 +108,7 @@
                               request_interceptors) const override;
   void OnMainRequestContextCreated(
       ProfileParams* profile_params) const override;
-  void InitializeExtensionsRequestContext(
+  void InitializeExtensionsCookieStore(
       ProfileParams* profile_params) const override;
   net::URLRequestContext* InitializeMediaRequestContext(
       net::URLRequestContext* original_context,
@@ -122,6 +118,7 @@
   net::URLRequestContext* AcquireIsolatedMediaRequestContext(
       net::URLRequestContext* app_context,
       const StoragePartitionDescriptor& partition_descriptor) const override;
+  net::CookieStore* GetExtensionsCookieStore() const override;
 
   mutable std::unique_ptr<net::CookieStore> extensions_cookie_store_;
 
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 6309ea2..e52b848 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -197,9 +197,10 @@
   // Returns the main request context.
   virtual net::URLRequestContextGetter* GetRequestContext() = 0;
 
-  // Returns the request context used for extension-related requests.  This
-  // is only used for a separate cookie store currently.
-  virtual net::URLRequestContextGetter* GetRequestContextForExtensions() = 0;
+  // Returns a callback (which must be executed on the IO thread) that returns
+  // the cookie store for the chrome-extensions:// scheme.
+  virtual base::OnceCallback<net::CookieStore*()>
+  GetExtensionsCookieStoreGetter() = 0;
 
   // Returns the main URLLoaderFactory.
   virtual scoped_refptr<network::SharedURLLoaderFactory>
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 0dd40e7..5012debc 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -1068,8 +1068,14 @@
   return GetDefaultStoragePartition(this)->GetURLRequestContext();
 }
 
-net::URLRequestContextGetter* ProfileImpl::GetRequestContextForExtensions() {
-  return io_data_.GetExtensionsRequestContextGetter().get();
+base::OnceCallback<net::CookieStore*()>
+ProfileImpl::GetExtensionsCookieStoreGetter() {
+  return base::BindOnce(
+      [](content::ResourceContext* context) {
+        auto* io_data = ProfileIOData::FromResourceContext(context);
+        return io_data->GetExtensionsCookieStore();
+      },
+      GetResourceContext());
 }
 
 scoped_refptr<network::SharedURLLoaderFactory>
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index a016448..b7cbdf1 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -133,7 +133,8 @@
   PrefService* GetOffTheRecordPrefs() override;
   PrefService* GetReadOnlyOffTheRecordPrefs() override;
   net::URLRequestContextGetter* GetRequestContext() override;
-  net::URLRequestContextGetter* GetRequestContextForExtensions() override;
+  base::OnceCallback<net::CookieStore*()> GetExtensionsCookieStoreGetter()
+      override;
   scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
   bool IsSameProfile(Profile* profile) override;
   base::Time GetStartTime() const override;
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index 8bad0ec..3bd55049 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -269,17 +269,6 @@
 }
 
 scoped_refptr<ChromeURLRequestContextGetter>
-ProfileImplIOData::Handle::GetExtensionsRequestContextGetter() const {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  LazyInitialize();
-  if (!extensions_request_context_getter_.get()) {
-    extensions_request_context_getter_ =
-        ChromeURLRequestContextGetter::CreateForExtensions(profile_, io_data_);
-  }
-  return extensions_request_context_getter_;
-}
-
-scoped_refptr<ChromeURLRequestContextGetter>
 ProfileImplIOData::Handle::CreateIsolatedAppRequestContextGetter(
     const base::FilePath& partition_path,
     bool in_memory,
@@ -396,9 +385,6 @@
   for (; iter != app_request_context_getter_map_.end(); ++iter)
     context_getters->push_back(iter->second);
 
-  if (extensions_request_context_getter_.get())
-    context_getters->push_back(extensions_request_context_getter_);
-
   if (media_request_context_getter_.get())
     context_getters->push_back(media_request_context_getter_);
 
@@ -481,7 +467,7 @@
   DCHECK(lazy_params_);
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-  InitializeExtensionsRequestContext(profile_params);
+  InitializeExtensionsCookieStore(profile_params);
 #endif
 
   MaybeDeleteMediaCache(lazy_params_->media_cache_path);
@@ -494,12 +480,8 @@
   lazy_params_.reset();
 }
 
-void ProfileImplIOData::
-    InitializeExtensionsRequestContext(ProfileParams* profile_params) const {
-  // The extensions context only serves to hold onto the extensions cookie
-  // store.
-  net::URLRequestContext* extensions_context = extensions_request_context();
-
+void ProfileImplIOData::InitializeExtensionsCookieStore(
+    ProfileParams* profile_params) const {
   content::CookieStoreConfig cookie_config(
       lazy_params_->extensions_cookie_path,
       lazy_params_->restore_old_session_cookies,
@@ -507,10 +489,8 @@
   cookie_config.crypto_delegate = cookie_config::GetCookieCryptoDelegate();
   // Enable cookies for chrome-extension URLs.
   cookie_config.cookieable_schemes.push_back(extensions::kExtensionScheme);
-  cookie_config.channel_id_service = extensions_context->channel_id_service();
   extensions_cookie_store_ = content::CreateCookieStore(
       cookie_config, profile_params->io_thread->net_log());
-  extensions_context->set_cookie_store(extensions_cookie_store_.get());
 }
 
 net::URLRequestContext* ProfileImplIOData::InitializeMediaRequestContext(
@@ -579,3 +559,7 @@
   DCHECK(media_request_context);
   return media_request_context;
 }
+
+net::CookieStore* ProfileImplIOData::GetExtensionsCookieStore() const {
+  return extensions_cookie_store_.get();
+}
diff --git a/chrome/browser/profiles/profile_impl_io_data.h b/chrome/browser/profiles/profile_impl_io_data.h
index 0f6ab9b..fb9fdfbb 100644
--- a/chrome/browser/profiles/profile_impl_io_data.h
+++ b/chrome/browser/profiles/profile_impl_io_data.h
@@ -73,8 +73,6 @@
     scoped_refptr<ChromeURLRequestContextGetter>
         GetMediaRequestContextGetter() const;
     scoped_refptr<ChromeURLRequestContextGetter>
-        GetExtensionsRequestContextGetter() const;
-    scoped_refptr<ChromeURLRequestContextGetter>
         GetIsolatedMediaRequestContextGetter(
             const base::FilePath& partition_path,
             bool in_memory) const;
@@ -103,8 +101,6 @@
         main_request_context_getter_;
     mutable scoped_refptr<ChromeURLRequestContextGetter>
         media_request_context_getter_;
-    mutable scoped_refptr<ChromeURLRequestContextGetter>
-        extensions_request_context_getter_;
     mutable ChromeURLRequestContextGetterMap app_request_context_getter_map_;
     mutable ChromeURLRequestContextGetterMap
         isolated_media_request_context_getter_map_;
@@ -149,7 +145,7 @@
                               request_interceptors) const override;
   void OnMainRequestContextCreated(
       ProfileParams* profile_params) const override;
-  void InitializeExtensionsRequestContext(
+  void InitializeExtensionsCookieStore(
       ProfileParams* profile_params) const override;
   net::URLRequestContext* InitializeMediaRequestContext(
       net::URLRequestContext* original_context,
@@ -159,6 +155,7 @@
   net::URLRequestContext* AcquireIsolatedMediaRequestContext(
       net::URLRequestContext* app_context,
       const StoragePartitionDescriptor& partition_descriptor) const override;
+  net::CookieStore* GetExtensionsCookieStore() const override;
 
   // Returns a net::ReportingService, if reporting should be enabled. Otherwise,
   // returns nullptr.
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 11fe1a0..e9104165 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -632,11 +632,6 @@
   if (domain_reliability_monitor_unowned_)
     domain_reliability_monitor_unowned_->Shutdown();
 
-  // TODO(ajwong): These AssertNoURLRequests() calls are unnecessary since they
-  // are already done in the URLRequestContext destructor.
-  if (extensions_request_context_)
-    extensions_request_context_->AssertNoURLRequests();
-
   current_context = 0;
   for (URLRequestContextMap::iterator it =
            isolated_media_request_context_map_.begin();
@@ -749,11 +744,6 @@
   return context;
 }
 
-net::URLRequestContext* ProfileIOData::GetExtensionsRequestContext() const {
-  DCHECK(initialized_);
-  return extensions_request_context_.get();
-}
-
 net::URLRequestContext* ProfileIOData::GetIsolatedAppRequestContext(
     IOThread* io_thread,
     net::URLRequestContext* main_context,
@@ -967,10 +957,6 @@
 
   account_consistency_ = profile_params_->account_consistency;
 
-  // Create extension request context.  Only used for cookies.
-  extensions_request_context_.reset(new net::URLRequestContext());
-  extensions_request_context_->set_name("extensions");
-
   // Take ownership over these parameters.
   cookie_settings_ = profile_params_->cookie_settings;
   host_content_settings_map_ = profile_params_->host_content_settings_map;
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index 8a7b8a2..2a89b541 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -137,7 +137,7 @@
 
   net::URLRequestContext* GetMainRequestContext() const;
   net::URLRequestContext* GetMediaRequestContext() const;
-  net::URLRequestContext* GetExtensionsRequestContext() const;
+  virtual net::CookieStore* GetExtensionsCookieStore() const = 0;
   net::URLRequestContext* GetIsolatedAppRequestContext(
       IOThread* io_thread,
       net::URLRequestContext* main_context,
@@ -167,10 +167,6 @@
   bool IsSyncEnabled() const;
   bool SyncHasAuthError() const;
 
-  net::URLRequestContext* extensions_request_context() const {
-    return extensions_request_context_.get();
-  }
-
   BooleanPrefMember* safe_browsing_enabled() const {
     return &safe_browsing_enabled_;
   }
@@ -501,8 +497,8 @@
   virtual void OnMainRequestContextCreated(
       ProfileParams* profile_params) const = 0;
 
-  // Initializes the RequestContext for extensions.
-  virtual void InitializeExtensionsRequestContext(
+  // Initializes the cookie store for extensions.
+  virtual void InitializeExtensionsCookieStore(
       ProfileParams* profile_params) const = 0;
 
   // Does an on-demand initialization of a media RequestContext for the given
@@ -599,7 +595,6 @@
   mutable network::URLRequestContextOwner main_request_context_owner_;
   mutable net::URLRequestContext* main_request_context_;
 
-  mutable std::unique_ptr<net::URLRequestContext> extensions_request_context_;
   // One URLRequestContext per isolated app for main and media requests.
   mutable URLRequestContextMap app_request_context_map_;
   mutable URLRequestContextMap isolated_media_request_context_map_;
diff --git a/chrome/browser/profiles/profiles_state.cc b/chrome/browser/profiles/profiles_state.cc
index 31daf61..8122aca 100644
--- a/chrome/browser/profiles/profiles_state.cc
+++ b/chrome/browser/profiles/profiles_state.cc
@@ -15,6 +15,7 @@
 #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/signin_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/pref_names.h"
@@ -157,11 +158,13 @@
                           base::UTF16ToUTF8(new_profile_name));
 }
 
-std::vector<std::string> GetSecondaryAccountsForProfile(
-    Profile* profile,
-    const std::string& primary_account) {
+std::vector<std::string> GetSecondaryAccountsForSignedInProfile(
+    Profile* profile) {
   std::vector<std::string> accounts =
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->GetAccounts();
+  std::string primary_account =
+      SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedAccountId();
+  DCHECK(!primary_account.empty());
 
   // The vector returned by ProfileOAuth2TokenService::GetAccounts() contains
   // the primary account too, so we need to remove it from the list.
diff --git a/chrome/browser/profiles/profiles_state.h b/chrome/browser/profiles/profiles_state.h
index b0be81cb..bc66518 100644
--- a/chrome/browser/profiles/profiles_state.h
+++ b/chrome/browser/profiles/profiles_state.h
@@ -69,12 +69,10 @@
 void UpdateProfileName(Profile* profile,
                        const base::string16& new_profile_name);
 
-// Returns the list of secondary accounts for a specific |profile|, which is
-// all the email addresses associated with the profile that are not equal to
-// the |primary_account|.
-std::vector<std::string> GetSecondaryAccountsForProfile(
-    Profile* profile,
-    const std::string& primary_account);
+// Returns the list of secondary accounts for a specific
+// |profile|. Note that the profile must be signed in.
+std::vector<std::string> GetSecondaryAccountsForSignedInProfile(
+    Profile* profile);
 #endif  // !defined(OS_CHROMEOS)
 
 // Returns whether the |browser|'s profile is a non-incognito or guest profile.
diff --git a/chrome/browser/resources/print_preview/data/destination.js b/chrome/browser/resources/print_preview/data/destination.js
index c291d64..92543b7b 100644
--- a/chrome/browser/resources/print_preview/data/destination.js
+++ b/chrome/browser/resources/print_preview/data/destination.js
@@ -163,9 +163,24 @@
 };
 
 /**
+ * Enumeration of duplex modes used by Chromium.
+ * This has to coincide with |printing::DuplexModeRestriction| as defined in
+ * printing/backend/printing_restrictions.h
+ * @enum {number}
+ */
+print_preview.DuplexModeRestriction = {
+  NONE: 0x0,
+  SIMPLEX: 0x1,
+  LONG_EDGE: 0x2,
+  SHORT_EDGE: 0x4,
+  DUPLEX: 0x6
+};
+
+/**
  * Policies affecting a destination.
  * @typedef {{
- *   allowedColorModes: ?number,
+ *   allowedColorModes: ?print_preview.ColorMode,
+ *   allowedDuplexModes: ?print_preview.DuplexModeRestriction,
  * }}
  */
 print_preview.Policies;
@@ -780,8 +795,7 @@
     }
 
     /**
-     * @return {?number} Color mode set by policy. Valid values are |null|,
-           |print_preview.ColorMode.COLOR| and |print_preview.ColorMode.GRAY|.
+     * @return {?print_preview.ColorMode} Color mode set by policy.
      * @private
      */
     colorPolicy_() {
@@ -791,6 +805,17 @@
     }
 
     /**
+     * @return {print_preview.DuplexModeRestriction} Duplex modes allowed by
+     *     policy.
+     * @private
+     */
+    duplexPolicy_() {
+      return this.policies && this.policies.allowedDuplexModes ?
+          this.policies.allowedDuplexModes :
+          print_preview.DuplexModeRestriction.NONE;
+    }
+
+    /**
      * @return {boolean} Whether the printer supports both black and white and
      *     color printing.
      */
@@ -809,22 +834,35 @@
       return hasColor && hasMonochrome;
     }
 
-    /**
-     * @return {boolean} Whether the printer color mode is set by policy.
-     */
+    /** @return {boolean} Whether the printer color mode is set by policy. */
     get isColorManaged() {
       return !!this.colorPolicy_();
     }
 
-    /**
-     * @return {?boolean} Value for color setting set by policy.
-     */
+    /** @return {?boolean} Value of color setting given by policy. */
     get colorPolicyValue() {
       return this.colorPolicy_() ?
           this.colorPolicy_() == print_preview.ColorMode.COLOR :
           null;
     }
 
+    /** @return {boolean} Whether the printer duplex mode is set by policy. */
+    get isDuplexManaged() {
+      return !!this.duplexPolicy_();
+    }
+
+    /** @return {?boolean} Value for duplex setting given by policy. */
+    get duplexPolicyValue() {
+      switch (this.duplexPolicy_()) {
+        case print_preview.DuplexModeRestriction.NONE:
+          return null;
+        case print_preview.DuplexModeRestriction.SIMPLEX:
+          return false;
+        default:
+          return true;
+      }
+    }
+
     /**
      * @param {boolean} isColor Whether to use a color printing mode.
      * @return {Object} Selected color option.
diff --git a/chrome/browser/resources/print_preview/new/model.js b/chrome/browser/resources/print_preview/new/model.js
index c4a473f0..064d31b2c 100644
--- a/chrome/browser/resources/print_preview/new/model.js
+++ b/chrome/browser/resources/print_preview/new/model.js
@@ -364,14 +364,18 @@
     this.set('settings.collate.available', !!caps && !!(caps.collate));
     this.set('settings.layout.available', this.isLayoutAvailable_(caps));
     this.set('settings.color.available', this.destination.hasColorCapability);
+
     if (this.destination.isColorManaged) {
       // |this.setSetting| does nothing if policy is present.
       // We want to set the value nevertheless so we call |this.set| directly.
       this.set('settings.color.value', this.destination.colorPolicyValue);
     }
-
     this.set('settings.color.setByPolicy', this.destination.isColorManaged);
 
+    if (this.destination.isDuplexManaged)
+      this.set('settings.duplex.value', this.destination.duplexPolicyValue);
+    this.set('settings.duplex.setByPolicy', this.destination.isDuplexManaged);
+
     this.set(
         'settings.dpi.available',
         !!caps && !!caps.dpi && !!caps.dpi.option &&
diff --git a/chrome/browser/resources/print_preview/new/settings_section.html b/chrome/browser/resources/print_preview/new/settings_section.html
index bd2ad8bc..90b09f8c 100644
--- a/chrome/browser/resources/print_preview/new/settings_section.html
+++ b/chrome/browser/resources/print_preview/new/settings_section.html
@@ -56,7 +56,7 @@
       }
 
       iron-icon {
-        fill: var(--google-grey-600);
+        fill: var(--google-grey-refresh-700);
         flex: 0;
         min-width: var(--policy-icon-size);
       }
diff --git a/chrome/browser/resources/settings/downloads_page/smb_shares_page.html b/chrome/browser/resources/settings/downloads_page/smb_shares_page.html
index aff446c..584488a 100644
--- a/chrome/browser/resources/settings/downloads_page/smb_shares_page.html
+++ b/chrome/browser/resources/settings/downloads_page/smb_shares_page.html
@@ -18,7 +18,7 @@
     <div class="settings-box first">
       <div class="start">
         <span>$i18n{smbSharesLearnMoreLabel}</span>
-        <a href="http://support.google.com" target="_blank">
+        <a href="$i18n{smbSharesLearnMoreURL}" target="_blank">
           $i18n{learnMore}
         </a>
         <div class="secondary" hidden="false">
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
index e87f2d0f..6892117 100644
--- a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
+++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
@@ -36,14 +36,18 @@
             label="$i18n{googleAssistantEnableHotword}"
             sub-label="$i18n{googleAssistantEnableHotwordDescription}">
         </settings-toggle-button>
-      </template>
-      <template is="dom-if" if="[[assistantFeatureEnabled_]]">
         <settings-toggle-button id="googleAssistantNotificationEnable"
             class="continuation indented"
             pref="{{prefs.settings.voice_interaction.notification.enabled}}"
             label="$i18n{googleAssistantEnableNotification}"
             sub-label="$i18n{googleAssistantEnableNotificationDescription}">
         </settings-toggle-button>
+        <settings-toggle-button id="googleAssistantLaunchWithMicOpen"
+            class="continuation indented"
+            pref="{{prefs.settings.voice_interaction.launch_with_mic_open}}"
+            label="$i18n{googleAssistantLaunchWithMicOpen}"
+            sub-label="$i18n{googleAssistantLaunchWithMicOpenDescription}">
+        </settings-toggle-button>
       </template>
       <div id="googleAssistantSettings" class="settings-box"
           on-click="onGoogleAssistantSettingsTapped_" actionable>
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
index 34b0f02..d16fd33 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
@@ -239,13 +239,14 @@
 // static
 bool AdvancedProtectionStatusManager::IsUnderAdvancedProtection(
     Profile* profile) {
-  // Advanced protection is off for incognito mode.
-  if (profile->IsOffTheRecord())
-    return false;
+  Profile* original_profile =
+      profile->IsOffTheRecord() ? profile->GetOriginalProfile() : profile;
 
-  return AdvancedProtectionStatusManagerFactory::GetInstance()
-      ->GetForBrowserContext(static_cast<content::BrowserContext*>(profile))
-      ->is_under_advanced_protection();
+  return original_profile &&
+         AdvancedProtectionStatusManagerFactory::GetInstance()
+             ->GetForBrowserContext(
+                 static_cast<content::BrowserContext*>(original_profile))
+             ->is_under_advanced_protection();
 }
 
 bool AdvancedProtectionStatusManager::IsPrimaryAccount(
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager.h b/chrome/browser/safe_browsing/advanced_protection_status_manager.h
index a5c943f5..1892245 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager.h
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager.h
@@ -17,8 +17,10 @@
 
 // Responsible for keeping track of advanced protection status of the sign-in
 // profile.
-// Note that for profile that is not signed-in or is in incognito mode, we
-// consider it NOT under advanced protection.
+// Note that for profile that is not signed-in, we consider it NOT under
+// advanced protection.
+// For incognito profile Chrome returns users' advanced protection status
+// of its original profile.
 class AdvancedProtectionStatusManager : public KeyedService,
                                         public AccountTrackerService::Observer,
                                         public SigninManagerBase::Observer {
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc b/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc
index 10f146f..9b649fba 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc
@@ -51,9 +51,4 @@
   return true;
 }
 
-bool AdvancedProtectionStatusManagerFactory::ServiceIsNULLWhileTesting() const {
-  // TODO(jialiul): Change this to 'false' when this class is wired into Chrome.
-  return true;
-}
-
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h b/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h
index fe7fd2c5..3ed3aa1 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h
@@ -36,7 +36,6 @@
   KeyedService* BuildServiceInstanceFor(
       content::BrowserContext* context) const override;
   bool ServiceIsCreatedWithBrowserContext() const override;
-  bool ServiceIsNULLWhileTesting() const override;
 
   DISALLOW_COPY_AND_ASSIGN(AdvancedProtectionStatusManagerFactory);
 };
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager_unittest.cc b/chrome/browser/safe_browsing/advanced_protection_status_manager_unittest.cc
index 98d3929..ca0b7df 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager_unittest.cc
@@ -225,8 +225,8 @@
       prefs::kAdvancedProtectionLastRefreshInUs,
       base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
 
-  // Simulates the situation where user signed in long time ago, thus
-  // has no advanced protection status.
+  // Simulates the situation where the user has already signed in and is
+  // under advanced protection.
   std::string account_id =
       SignIn("gaia_id", "email", /* is_under_advanced_protection = */ true);
   AdvancedProtectionStatusManager aps_manager(
@@ -241,6 +241,44 @@
   aps_manager.UnsubscribeFromSigninEvents();
 }
 
+TEST_F(AdvancedProtectionStatusManagerTest,
+       AlreadySignedInAndUnderAPIncognito) {
+  testing_profile_->GetPrefs()->SetInt64(
+      prefs::kAdvancedProtectionLastRefreshInUs,
+      base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
+
+  // Simulates the situation where the user has already signed in and is
+  // under advanced protection.
+  std::string account_id =
+      SignIn("gaia_id", "email", /* is_under_advanced_protection = */ true);
+
+  // Incognito profile should share the advanced protection status with the
+  // original profile.
+  EXPECT_TRUE(AdvancedProtectionStatusManager::IsUnderAdvancedProtection(
+      testing_profile_->GetOffTheRecordProfile()));
+  EXPECT_TRUE(AdvancedProtectionStatusManager::IsUnderAdvancedProtection(
+      testing_profile_.get()));
+}
+
+TEST_F(AdvancedProtectionStatusManagerTest,
+       AlreadySignedInAndNotUnderAPIncognito) {
+  testing_profile_->GetPrefs()->SetInt64(
+      prefs::kAdvancedProtectionLastRefreshInUs,
+      base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
+
+  // Simulates the situation where the user has already signed in and is
+  // NOT under advanced protection.
+  std::string account_id =
+      SignIn("gaia_id", "email", /* is_under_advanced_protection = */ false);
+
+  // Incognito profile should share the advanced protection status with the
+  // original profile.
+  EXPECT_FALSE(AdvancedProtectionStatusManager::IsUnderAdvancedProtection(
+      testing_profile_->GetOffTheRecordProfile()));
+  EXPECT_FALSE(AdvancedProtectionStatusManager::IsUnderAdvancedProtection(
+      testing_profile_.get()));
+}
+
 TEST_F(AdvancedProtectionStatusManagerTest, StayInAdvancedProtection) {
   base::Time last_update = base::Time::Now();
   testing_profile_->GetPrefs()->SetInt64(
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
index e9fdc24f1..d535dec4 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
@@ -18,12 +18,11 @@
 #include "chrome/browser/safe_browsing/download_protection/download_url_sb_client.h"
 #include "chrome/browser/safe_browsing/download_protection/ppapi_download_request.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/safe_browsing/binary_feature_extractor.h"
 #include "chrome/common/url_constants.h"
 #include "components/google/core/common/google_util.h"
 #include "components/safe_browsing/common/safebrowsing_switches.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -31,6 +30,7 @@
 #include "content/public/browser/web_contents.h"
 #include "net/base/url_util.h"
 #include "net/cert/x509_util.h"
+#include "services/identity/public/cpp/identity_manager.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 using content::BrowserThread;
@@ -493,11 +493,11 @@
 void DownloadProtectionService::OnDangerousDownloadOpened(
     const download::DownloadItem* item,
     Profile* profile) {
-  const SigninManagerBase* signin_manager =
-      SigninManagerFactory::GetForProfileIfExists(profile);
-  std::string username =
-      signin_manager ? signin_manager->GetAuthenticatedAccountInfo().email
-                     : std::string();
+  identity::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfileIfExists(profile);
+  std::string username = identity_manager
+                             ? identity_manager->GetPrimaryAccountInfo().email
+                             : std::string();
 
   std::string raw_digest_sha256 = item->GetHash();
   extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
index a985d93..d6215cc 100644
--- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
+++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
@@ -442,7 +442,7 @@
 bool ProxyingURLLoaderFactory::MaybeProxyRequest(
     content::RenderFrameHost* render_frame_host,
     bool is_navigation,
-    const GURL& url,
+    const url::Origin& request_initiator,
     network::mojom::URLLoaderFactoryRequest* factory_request) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
@@ -452,7 +452,8 @@
 
   // This proxy should only be installed for subresource requests from a frame
   // that is rendering the GAIA signon realm.
-  if (!render_frame_host || !gaia::IsGaiaSignonRealm(url.GetOrigin())) {
+  if (!render_frame_host ||
+      !gaia::IsGaiaSignonRealm(request_initiator.GetURL())) {
     return false;
   }
 
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.h b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.h
index 9dd6228..6d0028f 100644
--- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.h
+++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.h
@@ -50,7 +50,7 @@
   static bool MaybeProxyRequest(
       content::RenderFrameHost* render_frame_host,
       bool is_navigation,
-      const GURL& url,
+      const url::Origin& request_initiator,
       network::mojom::URLLoaderFactoryRequest* factory_request);
 
   // network::mojom::URLLoaderFactory:
diff --git a/chrome/browser/site_details.cc b/chrome/browser/site_details.cc
index e4dafde..69bb8bd 100644
--- a/chrome/browser/site_details.cc
+++ b/chrome/browser/site_details.cc
@@ -151,7 +151,7 @@
       url::Origin origin = frame->GetLastCommittedOrigin();
       GURL site = SiteInstance::GetSiteForURL(
           context,
-          origin.unique() ? frame->GetLastCommittedURL() : origin.GetURL());
+          origin.opaque() ? frame->GetLastCommittedURL() : origin.GetURL());
 
       bool should_isolate = ShouldIsolate(context, scenario, site);
 
diff --git a/chrome/browser/subresource_filter/subresource_filter_special_subframe_navigations_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_special_subframe_navigations_browsertest.cc
index 677ac1b..d33a061 100644
--- a/chrome/browser/subresource_filter/subresource_filter_special_subframe_navigations_browsertest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_special_subframe_navigations_browsertest.cc
@@ -83,7 +83,7 @@
         return rfh->GetLastCommittedURL().scheme_piece() == url::kDataScheme;
       }));
   ASSERT_NE(target, nullptr);
-  EXPECT_TRUE(target->GetLastCommittedOrigin().unique());
+  EXPECT_TRUE(target->GetLastCommittedOrigin().opaque());
   EXPECT_FALSE(WasParsedScriptElementLoaded(target));
 }
 
diff --git a/chrome/browser/task_manager/task_manager_browsertest.cc b/chrome/browser/task_manager/task_manager_browsertest.cc
index 8eec3f3..7d8cdab3 100644
--- a/chrome/browser/task_manager/task_manager_browsertest.cc
+++ b/chrome/browser/task_manager/task_manager_browsertest.cc
@@ -677,7 +677,13 @@
   ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("title1.html")));
 }
 
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, SentDataObserved) {
+#if defined(MEMORY_SANITIZER)
+// This tests times out when MSan is enabled. See https://crbug.com/890313.
+#define MAYBE_SentDataObserved DISABLED_SentDataObserved
+#else
+#define MAYBE_SentDataObserved SentDataObserved
+#endif
+IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_SentDataObserved) {
   ShowTaskManager();
   GURL test_gurl = embedded_test_server()->GetURL("/title1.html");
 
@@ -709,7 +715,13 @@
             model()->GetColumnValue(ColumnSpecifier::TOTAL_NETWORK_USE, 0));
 }
 
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, TotalSentDataObserved) {
+#if defined(MEMORY_SANITIZER)
+// This tests times out when MSan is enabled. See https://crbug.com/890313.
+#define MAYBE_TotalSentDataObserved DISABLED_TotalSentDataObserved
+#else
+#define MAYBE_TotalSentDataObserved TotalSentDataObserved
+#endif
+IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_TotalSentDataObserved) {
   ShowTaskManager();
   GURL test_gurl = embedded_test_server()->GetURL("/title1.html");
 
diff --git a/chrome/browser/ui/android/bluetooth_chooser_android.cc b/chrome/browser/ui/android/bluetooth_chooser_android.cc
index 0c567a81..0bf18ee 100644
--- a/chrome/browser/ui/android/bluetooth_chooser_android.cc
+++ b/chrome/browser/ui/android/bluetooth_chooser_android.cc
@@ -29,7 +29,7 @@
     : web_contents_(content::WebContents::FromRenderFrameHost(frame)),
       event_handler_(event_handler) {
   const url::Origin origin = frame->GetLastCommittedOrigin();
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
 
   base::android::ScopedJavaLocalRef<jobject> window_android =
       web_contents_->GetNativeView()->GetWindowAndroid()->GetJavaObject();
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_icon_loader.cc b/chrome/browser/ui/app_list/crostini/crostini_app_icon_loader.cc
index 5e8c231..0411c72 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_icon_loader.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_icon_loader.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/app_list/crostini/crostini_app_icon_loader.h"
 
-#include "ash/public/cpp/app_list/app_list_config.h"
 #include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
 #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -36,9 +35,8 @@
   if (icon_map_.find(app_id) != icon_map_.end())
     return;
 
-  std::unique_ptr<CrostiniAppIcon> icon = std::make_unique<CrostiniAppIcon>(
-      profile(), app_id,
-      app_list::AppListConfig::instance().grid_icon_dimension(), this);
+  std::unique_ptr<CrostiniAppIcon> icon =
+      std::make_unique<CrostiniAppIcon>(profile(), app_id, icon_size(), this);
   icon->image_skia().EnsureRepsForSupportedScales();
   icon_map_[app_id] = std::move(icon);
   UpdateImage(app_id);
diff --git a/chrome/browser/ui/app_list/test/fake_profile.cc b/chrome/browser/ui/app_list/test/fake_profile.cc
index 97ef0aa..d662941 100644
--- a/chrome/browser/ui/app_list/test/fake_profile.cc
+++ b/chrome/browser/ui/app_list/test/fake_profile.cc
@@ -160,8 +160,9 @@
   return nullptr;
 }
 
-net::URLRequestContextGetter* FakeProfile::GetRequestContextForExtensions() {
-  return nullptr;
+base::OnceCallback<net::CookieStore*()>
+FakeProfile::GetExtensionsCookieStoreGetter() {
+  return base::BindOnce([]() -> net::CookieStore* { return nullptr; });
 }
 
 bool FakeProfile::IsSameProfile(Profile* profile) {
diff --git a/chrome/browser/ui/app_list/test/fake_profile.h b/chrome/browser/ui/app_list/test/fake_profile.h
index 97e5e65..40f5bb60 100644
--- a/chrome/browser/ui/app_list/test/fake_profile.h
+++ b/chrome/browser/ui/app_list/test/fake_profile.h
@@ -76,7 +76,8 @@
   const PrefService* GetPrefs() const override;
   PrefService* GetOffTheRecordPrefs() override;
   net::URLRequestContextGetter* GetRequestContext() override;
-  net::URLRequestContextGetter* GetRequestContextForExtensions() override;
+  base::OnceCallback<net::CookieStore*()> GetExtensionsCookieStoreGetter()
+      override;
   bool IsSameProfile(Profile* profile) override;
   base::Time GetStartTime() const override;
   base::FilePath last_selected_directory() override;
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
index d4937b7639..2f02ced1 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
@@ -547,6 +547,10 @@
     case BubbleType::INACTIVE:
       NOTREACHED();
   }
+
+  if (observer_for_testing_) {
+    observer_for_testing_->OnBubbleShown();
+  }
 }
 
 void SaveCardBubbleControllerImpl::UpdateIcon() {
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
index 8eb14300..cd77a61d 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
@@ -30,6 +30,13 @@
       public content::WebContentsObserver,
       public content::WebContentsUserData<SaveCardBubbleControllerImpl> {
  public:
+  // An observer class used by browsertests that gets notified whenever
+  // particular actions occur.
+  class ObserverForTest {
+   public:
+    virtual void OnBubbleShown() = 0;
+  };
+
   ~SaveCardBubbleControllerImpl() override;
 
   // Sets up the controller for local save and shows the bubble.
@@ -121,6 +128,7 @@
 
  private:
   friend class content::WebContentsUserData<SaveCardBubbleControllerImpl>;
+  friend class SaveCardBubbleViewsBrowserTestBase;
 
   void FetchAccountInfo();
 
@@ -131,6 +139,11 @@
 
   void OpenUrl(const GURL& url);
 
+  // For testing.
+  void SetEventObserverForTesting(ObserverForTest* observer) {
+    observer_for_testing_ = observer;
+  }
+
   // The web_contents associated with this controller.
   content::WebContents* web_contents_;
 
@@ -184,6 +197,9 @@
   // The security level for the current context.
   security_state::SecurityLevel security_level_;
 
+  // Observer for when a bubble is created. Initialized only during tests.
+  ObserverForTest* observer_for_testing_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(SaveCardBubbleControllerImpl);
 };
 
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index d4901768..602715e 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -173,7 +173,7 @@
   std::string link_destination(chrome::kChromeUIContentSettingsURL);
   // TODO(https://crbug.com/444047): Site Details should work with file:// urls
   // when this bug is fixed, so add it to the whitelist when that happens.
-  if (!site_origin.unique() && (url.SchemeIsHTTPOrHTTPS() ||
+  if (!site_origin.opaque() && (url.SchemeIsHTTPOrHTTPS() ||
                                 url.SchemeIs(extensions::kExtensionScheme))) {
     std::string origin_string = site_origin.Serialize();
     url::RawCanonOutputT<char> percent_encoded_origin;
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa_views_mac.mm b/chrome/browser/ui/cocoa/browser_window_cocoa_views_mac.mm
index ecfa2bbe..286231c 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa_views_mac.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa_views_mac.mm
@@ -4,13 +4,8 @@
 
 #import "chrome/browser/ui/cocoa/browser_window_views_mac.h"
 
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
 
-BrowserWindowController* BrowserWindowControllerForWindow(NSWindow* window) {
-  return [BrowserWindowController browserWindowControllerForWindow:window];
-}
-
 TabWindowController* TabWindowControllerForWindow(NSWindow* window) {
   return [TabWindowController tabWindowControllerForWindow:window];
 }
diff --git a/chrome/browser/ui/cocoa/browser_window_views_mac.h b/chrome/browser/ui/cocoa/browser_window_views_mac.h
index 24c0170d..c85d389 100644
--- a/chrome/browser/ui/cocoa/browser_window_views_mac.h
+++ b/chrome/browser/ui/cocoa/browser_window_views_mac.h
@@ -12,14 +12,9 @@
 // visible here (or in any files that import this header). Declare a protocol
 // instead that describes the dependencies needed outside of Cocoa-specific
 // code.
-@class BrowserWindowController;
 @class NSWindow;
 @class TabWindowController;
 
-// Returns the BrowserWindowController backing a Cocoa browser window. Always
-// returns nil if |window| is a views browser window.
-BrowserWindowController* BrowserWindowControllerForWindow(NSWindow* window);
-
 // Returns the TabWindowController backing a Cocoa browser window. Always
 // returns nil if |window| is a views browser window.
 TabWindowController* TabWindowControllerForWindow(NSWindow* window);
diff --git a/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm b/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm
index ccb704dc..c08891c 100644
--- a/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm
+++ b/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm
@@ -31,18 +31,6 @@
   if (!window)
     return NO;
 
-  // Logic for handling Cocoa windows.
-  BrowserWindowController* controller =
-      BrowserWindowControllerForWindow(window);
-  if (controller) {
-    if ([controller respondsToSelector:@selector
-                    (handledByExtensionCommand:priority:)]) {
-      if ([controller handledByExtensionCommand:event priority:priority])
-        return YES;
-    }
-    return NO;
-  }
-
   // Logic for handling Views windows.
   //
   // There are 3 ways for extensions to register accelerators in Views:
diff --git a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_views.mm b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_views.mm
index 0a449de..33bc698 100644
--- a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_views.mm
+++ b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_views.mm
@@ -5,7 +5,7 @@
 #import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_views.h"
 
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#include "ui/views/cocoa/bridged_native_widget.h"
+#include "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 @implementation FullscreenToolbarControllerViews
 
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller_browsertest.mm b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller_browsertest.mm
index 63a214e3..7066deb 100644
--- a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller_browsertest.mm
@@ -21,7 +21,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "testing/gtest_mac.h"
-#include "ui/views/cocoa/window_touch_bar_delegate.h"
+#include "ui/views_bridge_mac/window_touch_bar_delegate.h"
 
 // TODO(spqchan): Write tests that will check for page load and bookmark
 // updates.
diff --git a/chrome/browser/ui/desktop_ios_promotion/sms_service_factory.cc b/chrome/browser/ui/desktop_ios_promotion/sms_service_factory.cc
index cab95dc1..2a630a3c 100644
--- a/chrome/browser/ui/desktop_ios_promotion/sms_service_factory.cc
+++ b/chrome/browser/ui/desktop_ios_promotion/sms_service_factory.cc
@@ -7,8 +7,6 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/desktop_ios_promotion/sms_service.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
index 5474840..9561463 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
@@ -469,7 +469,7 @@
           state_ == password_manager::ui::PENDING_PASSWORD_STATE) &&
          IsSyncUser(GetProfile()) &&
          // TODO(crbug.com/862269): Remove when "Smart Lock" is gone.
-         pending_password_.federation_origin.unique();
+         pending_password_.federation_origin.opaque();
 }
 
 const base::string16& ManagePasswordsBubbleModel::GetCurrentUsername() const {
@@ -532,7 +532,7 @@
   PasswordTitleType type =
       state_ == password_manager::ui::PENDING_PASSWORD_UPDATE_STATE
           ? PasswordTitleType::UPDATE_PASSWORD
-          : (pending_password_.federation_origin.unique()
+          : (pending_password_.federation_origin.opaque()
                  ? PasswordTitleType::SAVE_PASSWORD
                  : PasswordTitleType::SAVE_ACCOUNT);
   GetSavePasswordDialogTitleTextAndLinkRange(
diff --git a/chrome/browser/ui/passwords/manage_passwords_view_utils.cc b/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
index c1f86f4..338d09e7 100644
--- a/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
@@ -56,7 +56,7 @@
 std::pair<base::string16, base::string16> GetCredentialLabelsForAccountChooser(
     const autofill::PasswordForm& form) {
   base::string16 federation;
-  if (!form.federation_origin.unique()) {
+  if (!form.federation_origin.opaque()) {
     federation = l10n_util::GetStringFUTF16(
         IDS_PASSWORDS_VIA_FEDERATION,
         base::UTF8ToUTF16(form.federation_origin.host()));
diff --git a/chrome/browser/ui/views/autofill/dialog_view_ids.h b/chrome/browser/ui/views/autofill/dialog_view_ids.h
index d76f6d3..4f298d5 100644
--- a/chrome/browser/ui/views/autofill/dialog_view_ids.h
+++ b/chrome/browser/ui/views/autofill/dialog_view_ids.h
@@ -22,6 +22,9 @@
   SIGN_IN_PROMO_VIEW,        // Contains the sign-in promo view
   MANAGE_CARDS_VIEW,         // The manage cards view
 
+  // The sub-view that contains the sign-in button in the promo.
+  SIGN_IN_VIEW,
+
   // The following are views::LabelButton objects (clickable).
   OK_BUTTON,            // Can say [Save], [Next], [Confirm],
                         // or [Done] depending on context
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
index 13b5bbc..54005152 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
@@ -205,9 +205,10 @@
   return view;
 }
 
-void SaveCardBubbleViews::SetFootnoteViewForTesting(
-    views::View* footnote_view) {
+void SaveCardBubbleViews::InitFootnoteView(views::View* footnote_view) {
+  DCHECK(!footnote_view_);
   footnote_view_ = footnote_view;
+  footnote_view_->set_id(DialogViewId::FOOTNOTE_VIEW);
 }
 
 void SaveCardBubbleViews::AssignIdsToDialogClientView() {
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.h b/chrome/browser/ui/views/autofill/save_card_bubble_views.h
index 008c1c0f..692015bb 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views.h
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.h
@@ -83,8 +83,8 @@
   // footnote.
   virtual std::unique_ptr<views::View> CreateMainContentView();
 
-  // Set the footnote view so that its accessible for testing.
-  void SetFootnoteViewForTesting(views::View* footnote_view);
+  // Called by sub-classes to initialize |footnote_view_|.
+  virtual void InitFootnoteView(views::View* footnote_view);
 
   SaveCardBubbleController* controller() {
     return controller_;
@@ -101,11 +101,7 @@
   ~SaveCardBubbleViews() override;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(SaveCardBubbleViewsFullFormBrowserTest,
-                           Upload_ClickingCloseClosesBubble);
-  FRIEND_TEST_ALL_PREFIXES(
-      SaveCardBubbleViewsFullFormBrowserTest,
-      Upload_DecliningUploadDoesNotLogUserAcceptedCardOriginUMA);
+  friend class SaveCardBubbleViewsBrowserTestBase;
 
   views::View* footnote_view_ = nullptr;
 
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc
index 053d17c..21d9b8c 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
 #include <string>
 
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/metrics/user_action_tester.h"
 #include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -13,6 +15,7 @@
 #include "chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.h"
 #include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/autofill/core/common/autofill_features.h"
+#include "components/signin/core/browser/signin_buildflags.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "ui/views/bubble/bubble_frame_view.h"
@@ -21,6 +24,14 @@
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/window/dialog_client_view.h"
 
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+#include "chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h"
+#endif
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/ui/settings_window_manager_chromeos.h"
+#endif
+
 using base::Bucket;
 using testing::ElementsAre;
 
@@ -94,17 +105,24 @@
 
   // Clicking [Save] should accept and close it.
   base::HistogramTester histogram_tester;
+  base::UserActionTester user_action_tester;
   ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON);
   // UMA should have recorded bubble acceptance.
   histogram_tester.ExpectUniqueSample(
       "Autofill.SaveCreditCardPrompt.Local.FirstShow",
       AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, 1);
-  // The sign-in promo should not be shown because the experiment is disabled.
-  // TODO(crbug/855186): Add test that checks that sign-in promo is not showing.
+
+  // No bubble should be showing and no sign-in impression should have been
+  // recorded.
+  EXPECT_EQ(nullptr, GetSaveCardBubbleViews());
+  EXPECT_FALSE(GetSaveCardIconView()->visible());
+  EXPECT_EQ(0, user_action_tester.GetActionCount(
+                   "Signin_Impression_FromSaveCardBubble"));
 }
 
 // Tests the sign in promo bubble. Ensures that clicking the [Save] button
 // on the local save bubble successfully causes the sign in promo to show.
+#if !defined(OS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
                        Local_ClickingSaveShowsSigninPromo) {
   // Enable the sign-in promo.
@@ -126,11 +144,24 @@
   EXPECT_TRUE(
       FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_LOCAL)->visible());
 
+  // Adding an event observer to the controller so we can wait for the bubble to
+  // show.
+  AddEventObserverToController();
+  ReduceAnimationTime();
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+
   // Click [Save] should close the offer-to-save bubble
   // and pop up the sign-in promo.
-  // TODO(crbug/855186): Add test that checks that sign-in promo shows after
-  // clicking save.
+  base::UserActionTester user_action_tester;
+  ClickOnDialogViewWithId(DialogViewId::OK_BUTTON);
+  WaitForObservedEvent();
+
+  // Sign-in promo should be showing and user actions should have recorded
+  // impression.
+  EXPECT_TRUE(
+      FindViewInBubbleById(DialogViewId::SIGN_IN_PROMO_VIEW)->visible());
 }
+#endif
 
 // Tests the sign in promo bubble. Ensures that the sign-in promo
 // is not shown when the user is signed-in and syncing, even if
@@ -161,11 +192,381 @@
 
   // Click [Save] should close the offer-to-save bubble
   // but no sign-in promo should show because user is signed in.
+  base::UserActionTester user_action_tester;
   ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON);
-  // TODO(crbug/855186): Add test that checks that sign-in promo
-  // is not showing.
+
+  // No bubble should be showing and no sign-in impression should have been
+  // recorded.
+  EXPECT_EQ(nullptr, GetSaveCardBubbleViews());
+  EXPECT_EQ(0, user_action_tester.GetActionCount(
+                   "Signin_Impression_FromSaveCardBubble"));
 }
 
+// Tests the sign in promo bubble. Ensures that signin impression is recorded
+// when promo is shown.
+#if !defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       Local_Metrics_SigninImpressionSigninPromo) {
+  // Enable the sign-in promo.
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillSaveCardSignInAfterLocalSave);
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsDeclines();
+
+  // Submitting the form and having Payments decline offering to save should
+  // show the local save bubble.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence(
+      {DialogEvent::REQUESTED_UPLOAD_SAVE,
+       DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE,
+       DialogEvent::OFFERED_LOCAL_SAVE});
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+
+  // Adding an event observer to the controller so we can wait for the bubble to
+  // show.
+  AddEventObserverToController();
+  ReduceAnimationTime();
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+
+  // Click [Save] should close the offer-to-save bubble
+  // and pop up the sign-in promo.
+  base::UserActionTester user_action_tester;
+  ClickOnDialogViewWithId(DialogViewId::OK_BUTTON);
+  WaitForObservedEvent();
+
+  // User actions should have recorded impression.
+  EXPECT_EQ(1, user_action_tester.GetActionCount(
+                   "Signin_Impression_FromSaveCardBubble"));
+}
+#endif
+
+// Tests the sign in promo bubble. Ensures that signin action is recorded when
+// user accepts promo.
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       Local_Metrics_AcceptingSigninPromo) {
+  // Enable the sign-in promo.
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillSaveCardSignInAfterLocalSave);
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsDeclines();
+
+  // Submitting the form and having Payments decline offering to save should
+  // show the local save bubble.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence(
+      {DialogEvent::REQUESTED_UPLOAD_SAVE,
+       DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE,
+       DialogEvent::OFFERED_LOCAL_SAVE});
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+
+  // Adding an event observer to the controller so we can wait for the bubble to
+  // show.
+  AddEventObserverToController();
+  ReduceAnimationTime();
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+
+  // Click [Save] should close the offer-to-save bubble
+  // and pop up the sign-in promo.
+  base::UserActionTester user_action_tester;
+  ClickOnDialogViewWithId(DialogViewId::OK_BUTTON);
+  WaitForObservedEvent();
+
+  // Click on [Sign in] button.
+  ClickOnDialogView(static_cast<DiceBubbleSyncPromoView*>(
+                        FindViewInBubbleById(DialogViewId::SIGN_IN_VIEW))
+                        ->GetSigninButtonForTesting());
+
+  // User actions should have recorded impression and click.
+  EXPECT_EQ(1, user_action_tester.GetActionCount(
+                   "Signin_Impression_FromSaveCardBubble"));
+  EXPECT_EQ(
+      1, user_action_tester.GetActionCount("Signin_Signin_FromSaveCardBubble"));
+}
+#endif
+
+// Tests the manage cards bubble. Ensures that it shows up by clicking the
+// credit card icon.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       Local_ClickingIconShowsManageCards) {
+  // Enable the sign-in promo.
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillSaveCardSignInAfterLocalSave);
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsDeclines();
+
+  // Submitting the form and having Payments decline offering to save should
+  // show the local save bubble.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence(
+      {DialogEvent::REQUESTED_UPLOAD_SAVE,
+       DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE,
+       DialogEvent::OFFERED_LOCAL_SAVE});
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+
+  // Adding an event observer to the controller so we can wait for the bubble to
+  // show.
+  AddEventObserverToController();
+  ReduceAnimationTime();
+
+#if !defined(OS_CHROMEOS)
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+#endif
+
+  // Click [Save] should close the offer-to-save bubble and show "Card saved"
+  // animation -- followed by the sign-in promo (if not on Chrome OS).
+  ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON);
+
+#if !defined(OS_CHROMEOS)
+  // Wait for and then close the promo.
+  WaitForObservedEvent();
+  ClickOnCloseButton();
+#endif
+
+  // Open up Manage Cards prompt.
+  base::HistogramTester histogram_tester;
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+  ClickOnView(GetSaveCardIconView());
+  WaitForObservedEvent();
+
+  // Bubble should be showing.
+  EXPECT_TRUE(FindViewInBubbleById(DialogViewId::MANAGE_CARDS_VIEW)->visible());
+  histogram_tester.ExpectUniqueSample("Autofill.ManageCardsPrompt.Local",
+                                      AutofillMetrics::MANAGE_CARDS_SHOWN, 1);
+}
+
+// Tests the manage cards bubble. Ensures that clicking the [Manage cards]
+// button redirects properly.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       Local_ManageCardsButtonRedirects) {
+  // Enable the sign-in promo.
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillSaveCardSignInAfterLocalSave);
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsDeclines();
+
+  // Submitting the form and having Payments decline offering to save should
+  // show the local save bubble.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence(
+      {DialogEvent::REQUESTED_UPLOAD_SAVE,
+       DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE,
+       DialogEvent::OFFERED_LOCAL_SAVE});
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+
+  // Adding an event observer to the controller so we can wait for the bubble to
+  // show.
+  AddEventObserverToController();
+  ReduceAnimationTime();
+
+#if !defined(OS_CHROMEOS)
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+#endif
+
+  // Click [Save] should close the offer-to-save bubble and show "Card saved"
+  // animation -- followed by the sign-in promo (if not on Chrome OS).
+  ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON);
+
+#if !defined(OS_CHROMEOS)
+  // Wait for and then close the promo.
+  WaitForObservedEvent();
+  ClickOnCloseButton();
+#endif
+
+  // Open up Manage Cards prompt.
+  base::HistogramTester histogram_tester;
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+  ClickOnView(GetSaveCardIconView());
+  WaitForObservedEvent();
+
+  // Click on the redirect button.
+  ClickOnDialogViewWithId(DialogViewId::MANAGE_CARDS_BUTTON);
+
+#if defined(OS_CHROMEOS)
+  // ChromeOS should have opened up the settings window.
+  EXPECT_TRUE(
+      chrome::SettingsWindowManager::GetInstance()->FindBrowserForProfile(
+          browser()->profile()));
+#else
+  // Otherwise, another tab should have opened.
+  EXPECT_EQ(2, browser()->tab_strip_model()->count());
+#endif
+
+  // Metrics should have been recorded correctly.
+  EXPECT_THAT(
+      histogram_tester.GetAllSamples("Autofill.ManageCardsPrompt.Local"),
+      ElementsAre(Bucket(AutofillMetrics::MANAGE_CARDS_SHOWN, 1),
+                  Bucket(AutofillMetrics::MANAGE_CARDS_MANAGE_CARDS, 1)));
+}
+
+// Tests the manage cards bubble. Ensures that clicking the [Done]
+// button closes the bubble.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       Local_ManageCardsDoneButtonClosesBubble) {
+  // Enable the sign-in promo.
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillSaveCardSignInAfterLocalSave);
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsDeclines();
+
+  // Submitting the form and having Payments decline offering to save should
+  // show the local save bubble.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence(
+      {DialogEvent::REQUESTED_UPLOAD_SAVE,
+       DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE,
+       DialogEvent::OFFERED_LOCAL_SAVE});
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+
+  // Adding an event observer to the controller so we can wait for the bubble to
+  // show.
+  AddEventObserverToController();
+  ReduceAnimationTime();
+
+#if !defined(OS_CHROMEOS)
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+#endif
+
+  // Click [Save] should close the offer-to-save bubble and show "Card saved"
+  // animation -- followed by the sign-in promo (if not on Chrome OS).
+  ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON);
+
+#if !defined(OS_CHROMEOS)
+  // Wait for and then close the promo.
+  WaitForObservedEvent();
+  ClickOnCloseButton();
+#endif
+
+  // Open up Manage Cards prompt.
+  base::HistogramTester histogram_tester;
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+  ClickOnView(GetSaveCardIconView());
+  WaitForObservedEvent();
+
+  // Click on the [Done] button.
+  ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON);
+
+  // No bubble should be showing now and metrics should be recorded correctly.
+  EXPECT_EQ(nullptr, GetSaveCardBubbleViews());
+  EXPECT_THAT(
+      histogram_tester.GetAllSamples("Autofill.ManageCardsPrompt.Local"),
+      ElementsAre(Bucket(AutofillMetrics::MANAGE_CARDS_SHOWN, 1),
+                  Bucket(AutofillMetrics::MANAGE_CARDS_DONE, 1)));
+}
+
+// Tests the manage cards bubble. Ensures that sign-in impression is recorded
+// correctly.
+#if !defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       Local_Metrics_SigninImpressionManageCards) {
+  // Enable the sign-in promo.
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillSaveCardSignInAfterLocalSave);
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsDeclines();
+
+  // Submitting the form and having Payments decline offering to save should
+  // show the local save bubble.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence(
+      {DialogEvent::REQUESTED_UPLOAD_SAVE,
+       DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE,
+       DialogEvent::OFFERED_LOCAL_SAVE});
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+
+  // Adding an event observer to the controller so we can wait for the bubble to
+  // show.
+  AddEventObserverToController();
+  ReduceAnimationTime();
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+
+  // Click [Save] should close the offer-to-save bubble
+  // and pop up the sign-in promo.
+  base::UserActionTester user_action_tester;
+  ClickOnDialogViewWithId(DialogViewId::OK_BUTTON);
+  WaitForObservedEvent();
+
+  // Close promo.
+  ClickOnCloseButton();
+
+  // Open up Manage Cards prompt.
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+  ClickOnView(GetSaveCardIconView());
+  WaitForObservedEvent();
+
+  // User actions should have recorded impression.
+  EXPECT_EQ(1, user_action_tester.GetActionCount(
+                   "Signin_Impression_FromManageCardsBubble"));
+}
+#endif
+
+// Tests the Manage Cards bubble. Ensures that signin action is recorded when
+// user accepts footnote promo.
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       Local_Metrics_AcceptingFootnotePromoManageCards) {
+  // Enable the sign-in promo.
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillSaveCardSignInAfterLocalSave);
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsDeclines();
+
+  // Submitting the form and having Payments decline offering to save should
+  // show the local save bubble.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence(
+      {DialogEvent::REQUESTED_UPLOAD_SAVE,
+       DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE,
+       DialogEvent::OFFERED_LOCAL_SAVE});
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+
+  // Adding an event observer to the controller so we can wait for the bubble to
+  // show.
+  AddEventObserverToController();
+  ReduceAnimationTime();
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+
+  // Click [Save] should close the offer-to-save bubble
+  // and pop up the sign-in promo.
+  base::UserActionTester user_action_tester;
+  ClickOnDialogViewWithId(DialogViewId::OK_BUTTON);
+  WaitForObservedEvent();
+
+  // Close promo.
+  ClickOnCloseButton();
+
+  // Open up Manage Cards prompt.
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+  ClickOnView(GetSaveCardIconView());
+  WaitForObservedEvent();
+
+  // Click on [Sign in] button in footnote.
+  ClickOnDialogView(static_cast<DiceBubbleSyncPromoView*>(
+                        FindViewInBubbleById(DialogViewId::FOOTNOTE_VIEW))
+                        ->GetSigninButtonForTesting());
+
+  // User actions should have recorded impression and click.
+  EXPECT_EQ(1, user_action_tester.GetActionCount(
+                   "Signin_Impression_FromManageCardsBubble"));
+  EXPECT_EQ(1, user_action_tester.GetActionCount(
+                   "Signin_Signin_FromManageCardsBubble"));
+}
+#endif
+
 // Tests the local save bubble. Ensures that the Harmony version of the bubble
 // does not have a [No thanks] button (it has an [X] Close button instead.)
 IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
@@ -300,8 +701,7 @@
 
   // Clicking the [X] close button should dismiss the bubble.
   base::HistogramTester histogram_tester;
-  ClickOnDialogViewAndWait(
-      GetSaveCardBubbleViews()->GetBubbleFrameView()->GetCloseButtonForTest());
+  ClickOnCloseButton();
 }
 
 // Tests the upload save bubble. Ensures that the bubble does not surface the
@@ -814,8 +1214,7 @@
   EXPECT_TRUE(FindViewInBubbleById(DialogViewId::FOOTNOTE_VIEW)->visible());
 
   // Clicking the [X] close button should dismiss the bubble.
-  ClickOnDialogViewAndWait(
-      GetSaveCardBubbleViews()->GetBubbleFrameView()->GetCloseButtonForTest());
+  ClickOnCloseButton();
 
   // Ensure that UMA was logged correctly.
   histogram_tester.ExpectUniqueSample(
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc
index 841ee5e8..86cfa810 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc
@@ -7,6 +7,7 @@
 #include <list>
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "chrome/browser/signin/account_fetcher_service_factory.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
@@ -16,9 +17,13 @@
 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
 #include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/autofill/dialog_view_ids.h"
 #include "chrome/browser/ui/views/autofill/save_card_bubble_views.h"
+#include "chrome/browser/ui/views/autofill/save_card_icon_view.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
 #include "components/autofill/core/browser/credit_card_save_manager.h"
@@ -134,6 +139,11 @@
     event_waiter_->OnEvent(DialogEvent::SENT_UPLOAD_CARD_REQUEST);
 }
 
+void SaveCardBubbleViewsBrowserTestBase::OnBubbleShown() {
+  if (event_waiter_)
+    event_waiter_->OnEvent(DialogEvent::BUBBLE_SHOWN);
+}
+
 void SaveCardBubbleViewsBrowserTestBase::SetUpInProcessBrowserTestFixture() {
   will_create_browser_context_services_subscription_ =
       BrowserContextDependencyManager::GetInstance()
@@ -336,6 +346,18 @@
                                          net::HTTP_INTERNAL_SERVER_ERROR);
 }
 
+void SaveCardBubbleViewsBrowserTestBase::ClickOnView(views::View* view) {
+  DCHECK(view);
+  ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+                         ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                         ui::EF_LEFT_MOUSE_BUTTON);
+  view->OnMousePressed(pressed);
+  ui::MouseEvent released_event = ui::MouseEvent(
+      ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(),
+      ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+  view->OnMouseReleased(released_event);
+}
+
 void SaveCardBubbleViewsBrowserTestBase::ClickOnDialogView(views::View* view) {
   GetSaveCardBubbleViews()
       ->GetDialogClientView()
@@ -346,16 +368,7 @@
                                                ->non_client_view()
                                                ->frame_view());
   bubble_frame_view->ResetViewShownTimeStampForTesting();
-
-  DCHECK(view);
-  ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
-                         ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
-                         ui::EF_LEFT_MOUSE_BUTTON);
-  view->OnMousePressed(pressed);
-  ui::MouseEvent released_event = ui::MouseEvent(
-      ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(),
-      ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
-  view->OnMouseReleased(released_event);
+  ClickOnView(view);
 }
 
 void SaveCardBubbleViewsBrowserTestBase::ClickOnDialogViewAndWait(
@@ -407,6 +420,13 @@
   return specified_view;
 }
 
+void SaveCardBubbleViewsBrowserTestBase::ClickOnCloseButton() {
+  SaveCardBubbleViews* save_card_bubble_views = GetSaveCardBubbleViews();
+  DCHECK(save_card_bubble_views);
+  ClickOnDialogViewAndWait(
+      save_card_bubble_views->GetBubbleFrameView()->GetCloseButtonForTest());
+}
+
 SaveCardBubbleViews*
 SaveCardBubbleViewsBrowserTestBase::GetSaveCardBubbleViews() {
   SaveCardBubbleControllerImpl* save_card_bubble_controller_impl =
@@ -420,11 +440,31 @@
   return static_cast<SaveCardBubbleViews*>(save_card_bubble_view);
 }
 
+SaveCardIconView* SaveCardBubbleViewsBrowserTestBase::GetSaveCardIconView() {
+  if (!browser())
+    return nullptr;
+  LocationBarView* location_bar_view =
+      static_cast<LocationBarView*>(browser()->window()->GetLocationBar());
+  DCHECK(location_bar_view->save_credit_card_icon_view());
+  return location_bar_view->save_credit_card_icon_view();
+}
+
 content::WebContents*
 SaveCardBubbleViewsBrowserTestBase::GetActiveWebContents() {
   return browser()->tab_strip_model()->GetActiveWebContents();
 }
 
+void SaveCardBubbleViewsBrowserTestBase::AddEventObserverToController() {
+  SaveCardBubbleControllerImpl* save_card_bubble_controller_impl =
+      SaveCardBubbleControllerImpl::FromWebContents(GetActiveWebContents());
+  DCHECK(save_card_bubble_controller_impl);
+  save_card_bubble_controller_impl->SetEventObserverForTesting(this);
+}
+
+void SaveCardBubbleViewsBrowserTestBase::ReduceAnimationTime() {
+  GetSaveCardIconView()->ReduceAnimationTimeForTesting();
+}
+
 void SaveCardBubbleViewsBrowserTestBase::ResetEventWaiterForSequence(
     std::list<DialogEvent> event_sequence) {
   event_waiter_ =
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.h b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.h
index 4c8e110..481d931 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.h
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.h
@@ -13,8 +13,10 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h"
 #include "chrome/browser/ui/views/autofill/dialog_view_ids.h"
 #include "chrome/browser/ui/views/autofill/save_card_bubble_views.h"
+#include "chrome/browser/ui/views/autofill/save_card_icon_view.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/autofill/core/browser/credit_card_save_manager.h"
 #include "components/autofill/core/browser/test_event_waiter.h"
@@ -36,7 +38,8 @@
 // need to show and interact with the offer-to-save bubble.
 class SaveCardBubbleViewsBrowserTestBase
     : public InProcessBrowserTest,
-      public CreditCardSaveManager::ObserverForTest {
+      public CreditCardSaveManager::ObserverForTest,
+      public SaveCardBubbleControllerImpl::ObserverForTest {
  public:
   // Various events that can be waited on by the DialogEventWaiter.
   enum DialogEvent : int {
@@ -44,6 +47,7 @@
     REQUESTED_UPLOAD_SAVE,
     RECEIVED_GET_UPLOAD_DETAILS_RESPONSE,
     SENT_UPLOAD_CARD_REQUEST,
+    BUBBLE_SHOWN
   };
 
  protected:
@@ -63,6 +67,9 @@
   void OnReceivedGetUploadDetailsResponse() override;
   void OnSentUploadCardRequest() override;
 
+  // SaveCardBubbleControllerImpl::ObserverForTest:
+  void OnBubbleShown() override;
+
   // BrowserTestBase:
   void SetUpInProcessBrowserTestFixture() override;
 
@@ -90,9 +97,12 @@
   void SetUploadDetailsRpcServerError();
 
   // Clicks on the given views::View*.
+  void ClickOnView(views::View* view);
+
+  // Clicks on the given dialog views::View*.
   void ClickOnDialogView(views::View* view);
 
-  // Clicks on the given views::View* and waits for the dialog to close.
+  // Clicks on the given dialog views::View* and waits for the dialog to close.
   void ClickOnDialogViewAndWait(views::View* view);
 
   // Clicks on a view from within the dialog.
@@ -104,11 +114,26 @@
   // Returns the views::View* that was previously assigned the id |view_id|.
   views::View* FindViewInBubbleById(DialogViewId view_id);
 
+  // Assert that there is a SaveCardBubbleViews bubble open, then click on the
+  // [X] button.
+  void ClickOnCloseButton();
+
   // Gets the views::View* instance of the save credit card bubble.
   SaveCardBubbleViews* GetSaveCardBubbleViews();
 
+  // Gets the views::View* instance of the credit card icon.
+  SaveCardIconView* GetSaveCardIconView();
+
   content::WebContents* GetActiveWebContents();
 
+  // Adding an observer to the controller so we know when the sign-in promo
+  // shows after the animation.
+  void AddEventObserverToController();
+
+  // Reduces the animation time to one millisecond so that the test does not
+  // take long.
+  void ReduceAnimationTime();
+
   // Resets the event waiter for a given |event_sequence|.
   void ResetEventWaiterForSequence(std::list<DialogEvent> event_sequence);
   // Wait for the event(s) passed to ResetEventWaiter*() to occur.
diff --git a/chrome/browser/ui/views/autofill/save_card_icon_view.h b/chrome/browser/ui/views/autofill/save_card_icon_view.h
index 409d85ed..9fd90f1 100644
--- a/chrome/browser/ui/views/autofill/save_card_icon_view.h
+++ b/chrome/browser/ui/views/autofill/save_card_icon_view.h
@@ -38,6 +38,8 @@
   const gfx::VectorIcon& GetVectorIcon() const override;
 
  private:
+  friend class SaveCardBubbleViewsBrowserTestBase;
+
   SaveCardBubbleControllerImpl* GetController() const;
 
   // gfx::AnimationDelegate:
diff --git a/chrome/browser/ui/views/autofill/save_card_manage_cards_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_manage_cards_bubble_views.cc
index 6891ab9e..80a01bf 100644
--- a/chrome/browser/ui/views/autofill/save_card_manage_cards_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/save_card_manage_cards_bubble_views.cc
@@ -35,7 +35,7 @@
   if (!controller()->ShouldShowSignInPromo())
     return nullptr;
 
-  views::View* footnote_view_ = nullptr;
+  views::View* promo_view = nullptr;
 
   Profile* profile = controller()->GetProfile();
   sync_promo_delegate_ =
@@ -44,7 +44,7 @@
           signin_metrics::AccessPoint::ACCESS_POINT_MANAGE_CARDS_BUBBLE);
   if (AccountConsistencyModeManager::IsDiceEnabledForProfile(profile)) {
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
-    footnote_view_ = new DiceBubbleSyncPromoView(
+    promo_view = new DiceBubbleSyncPromoView(
         profile, sync_promo_delegate_.get(),
         signin_metrics::AccessPoint::ACCESS_POINT_MANAGE_CARDS_BUBBLE,
         IDS_AUTOFILL_SIGNIN_PROMO_MESSAGE, IDS_AUTOFILL_SYNC_PROMO_MESSAGE,
@@ -53,15 +53,15 @@
     NOTREACHED();
 #endif
   } else {
-    footnote_view_ = new BubbleSyncPromoView(
+    promo_view = new BubbleSyncPromoView(
         sync_promo_delegate_.get(),
         signin_metrics::AccessPoint::ACCESS_POINT_MANAGE_CARDS_BUBBLE,
         IDS_AUTOFILL_SIGNIN_PROMO_LINK_DICE_DISABLED,
         IDS_AUTOFILL_SIGNIN_PROMO_MESSAGE_DICE_DISABLED);
   }
 
-  SetFootnoteViewForTesting(footnote_view_);
-  return footnote_view_;
+  InitFootnoteView(promo_view);
+  return promo_view;
 }
 
 views::View* SaveCardManageCardsBubbleViews::CreateExtraView() {
diff --git a/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.cc
index 78c721ba..d7a89ab 100644
--- a/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/autofill/save_card_offer_bubble_views.h"
 
+#include <memory>
+
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/app/vector_icons/vector_icons.h"
@@ -56,12 +58,11 @@
   if (controller()->GetLegalMessageLines().empty())
     return nullptr;
 
-  footnote_view_ =
+  legal_message_view_ =
       new LegalMessageView(controller()->GetLegalMessageLines(), this);
-  footnote_view_->set_id(DialogViewId::FOOTNOTE_VIEW);
 
-  SetFootnoteViewForTesting(footnote_view_);
-  return footnote_view_;
+  InitFootnoteView(legal_message_view_);
+  return legal_message_view_;
 }
 
 bool SaveCardOfferBubbleViews::Accept() {
@@ -101,7 +102,7 @@
   if (!controller())
     return;
 
-  footnote_view_->OnLinkClicked(label, range, web_contents_);
+  legal_message_view_->OnLinkClicked(label, range, web_contents_);
 }
 
 void SaveCardOfferBubbleViews::ContentsChanged(
diff --git a/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.h b/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.h
index b68ee32..fe71f2ec 100644
--- a/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.h
+++ b/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.h
@@ -55,7 +55,7 @@
 
   views::Textfield* cardholder_name_textfield_ = nullptr;
 
-  LegalMessageView* footnote_view_ = nullptr;
+  LegalMessageView* legal_message_view_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(SaveCardOfferBubbleViews);
 };
diff --git a/chrome/browser/ui/views/autofill/save_card_sign_in_promo_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_sign_in_promo_bubble_views.cc
index 8efd4143..2ddd989 100644
--- a/chrome/browser/ui/views/autofill/save_card_sign_in_promo_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/save_card_sign_in_promo_bubble_views.cc
@@ -48,6 +48,7 @@
       provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL)));
   view->set_id(DialogViewId::SIGN_IN_PROMO_VIEW);
 
+  std::unique_ptr<views::View> signin_view;
   Profile* profile = controller()->GetProfile();
   sync_promo_delegate_ =
       std::make_unique<SaveCardSignInPromoBubbleViews::SyncPromoDelegate>(
@@ -55,19 +56,21 @@
           signin_metrics::AccessPoint::ACCESS_POINT_SAVE_CARD_BUBBLE);
   if (AccountConsistencyModeManager::IsDiceEnabledForProfile(profile)) {
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
-    view->AddChildView(new DiceBubbleSyncPromoView(
+    signin_view = std::make_unique<DiceBubbleSyncPromoView>(
         profile, sync_promo_delegate_.get(),
-        signin_metrics::AccessPoint::ACCESS_POINT_SAVE_CARD_BUBBLE));
+        signin_metrics::AccessPoint::ACCESS_POINT_SAVE_CARD_BUBBLE);
 #else
     NOTREACHED();
 #endif
   } else {
-    view->AddChildView(new BubbleSyncPromoView(
+    signin_view = std::make_unique<BubbleSyncPromoView>(
         sync_promo_delegate_.get(),
         signin_metrics::AccessPoint::ACCESS_POINT_SAVE_CARD_BUBBLE,
         IDS_AUTOFILL_SIGNIN_PROMO_LINK_DICE_DISABLED,
-        IDS_AUTOFILL_SIGNIN_PROMO_MESSAGE_DICE_DISABLED));
+        IDS_AUTOFILL_SIGNIN_PROMO_MESSAGE_DICE_DISABLED);
   }
+  signin_view->set_id(DialogViewId::SIGN_IN_VIEW);
+  view->AddChildView(signin_view.release());
   return view;
 }
 
diff --git a/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h b/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h
index 2a6fd6b..60f986c 100644
--- a/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h
+++ b/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h
@@ -64,6 +64,9 @@
   void OnMouseEntered(const ui::MouseEvent& event) override;
   void OnMouseExited(const ui::MouseEvent& event) override;
   gfx::Rect GetBubbleBounds() override;
+  void UpdateHighlightedButton(bool highlighted) override {
+    // Do nothing: the anchor for promo bubbles should not highlight.
+  }
 
   // Starts a timer to close the promo bubble.
   void StartAutoCloseTimer(base::TimeDelta auto_close_duration);
diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.mm b/chrome/browser/ui/views/frame/browser_frame_mac.mm
index bca3621..30e91604 100644
--- a/chrome/browser/ui/views/frame/browser_frame_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_frame_mac.mm
@@ -18,7 +18,7 @@
 #include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #import "ui/base/cocoa/window_size_constants.h"
-#import "ui/views/cocoa/window_touch_bar_delegate.h"
+#import "ui/views_bridge_mac/window_touch_bar_delegate.h"
 
 namespace {
 
diff --git a/chrome/browser/ui/views/frame/browser_native_widget_window_mac.h b/chrome/browser/ui/views/frame/browser_native_widget_window_mac.h
index ee8dd6bb..5d98387 100644
--- a/chrome/browser/ui/views/frame/browser_native_widget_window_mac.h
+++ b/chrome/browser/ui/views/frame/browser_native_widget_window_mac.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NATIVE_WIDGET_WINDOW_MAC_H_
 #define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NATIVE_WIDGET_WINDOW_MAC_H_
 
-#import "ui/views/cocoa/native_widget_mac_nswindow.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
 
 @interface BrowserNativeWidgetWindow : NativeWidgetMacNSWindow
 @end
diff --git a/chrome/browser/ui/views/frame/native_widget_mac_frameless_nswindow.h b/chrome/browser/ui/views/frame/native_widget_mac_frameless_nswindow.h
index 9b7ac0b..52b054b 100644
--- a/chrome/browser/ui/views/frame/native_widget_mac_frameless_nswindow.h
+++ b/chrome/browser/ui/views/frame/native_widget_mac_frameless_nswindow.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_NATIVE_WIDGET_MAC_FRAMELESS_NSWINDOW_H_
 #define CHROME_BROWSER_UI_VIEWS_FRAME_NATIVE_WIDGET_MAC_FRAMELESS_NSWINDOW_H_
 
-#import "ui/views/cocoa/native_widget_mac_nswindow.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
 
 // Overrides contentRect <-> frameRect conversion methods to keep them equal to
 // each other, even for windows that do not use NSBorderlessWindowMask. This
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
index c49a812..48ec85b 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -538,6 +538,10 @@
   slide_animation_.Reset(show_label);
 }
 
+void IconLabelBubbleView::ReduceAnimationTimeForTesting() {
+  slide_animation_.SetSlideDuration(1);
+}
+
 void IconLabelBubbleView::PauseAnimation() {
   if (slide_animation_.is_animating()) {
     // If the user clicks while we're animating, the bubble arrow will be
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
index 7fb9872..c6e9984 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
@@ -185,6 +185,10 @@
   // currently paused.
   bool is_animation_paused() const { return is_animation_paused_; }
 
+  // Reduces the slide duration to 1ms such that animation still follows
+  // through in the code but is short enough that it is essentially skipped.
+  void ReduceAnimationTimeForTesting();
+
  private:
   // Spacing between the image and the label.
   int GetInternalSpacing() const;
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index 189a2c7..ff12066 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -734,10 +734,10 @@
     TogglePlayPause();
 
   if (sender == first_custom_controls_view_.get())
-    controller_->ClickCustomControl(first_custom_controls_view_->id());
+    controller_->CustomControlPressed(first_custom_controls_view_->id());
 
   if (sender == second_custom_controls_view_.get())
-    controller_->ClickCustomControl(second_custom_controls_view_->id());
+    controller_->CustomControlPressed(second_custom_controls_view_->id());
 }
 
 gfx::Rect OverlayWindowViews::GetCloseControlsBounds() {
@@ -780,10 +780,6 @@
   play_pause_controls_view_->SetToggled(is_active);
 }
 
-void OverlayWindowViews::ClickCustomControl(const std::string& control_id) {
-  controller_->ClickCustomControl(control_id);
-}
-
 views::ToggleImageButton*
 OverlayWindowViews::play_pause_controls_view_for_testing() const {
   return play_pause_controls_view_.get();
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h
index 81f1830..e1c7f5a0 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -66,9 +66,6 @@
   gfx::Rect GetFirstCustomControlsBounds();
   gfx::Rect GetSecondCustomControlsBounds();
 
-  // Send the message that a custom control on |this| has been clicked.
-  void ClickCustomControl(const std::string& control_id);
-
   views::ToggleImageButton* play_pause_controls_view_for_testing() const;
   views::View* controls_parent_view_for_testing() const;
 
diff --git a/chrome/browser/ui/views/passwords/password_items_view.cc b/chrome/browser/ui/views/passwords/password_items_view.cc
index 68c13b6a..0a9e791 100644
--- a/chrome/browser/ui/views/passwords/password_items_view.cc
+++ b/chrome/browser/ui/views/passwords/password_items_view.cc
@@ -126,7 +126,7 @@
     int federation_message_id,
     bool are_passwords_revealed) {
   base::string16 text =
-      form.federation_origin.unique()
+      form.federation_origin.opaque()
           ? form.password_value
           : l10n_util::GetStringFUTF16(
                 federation_message_id,
@@ -134,9 +134,9 @@
   auto label = std::make_unique<views::Label>(text, CONTEXT_BODY_TEXT_LARGE,
                                               STYLE_SECONDARY);
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  if (form.federation_origin.unique() && !are_passwords_revealed)
+  if (form.federation_origin.opaque() && !are_passwords_revealed)
     label->SetObscured(true);
-  if (!form.federation_origin.unique())
+  if (!form.federation_origin.opaque())
     label->SetElideBehavior(gfx::ELIDE_HEAD);
 
   return label;
diff --git a/chrome/browser/ui/views/passwords/password_pending_view.cc b/chrome/browser/ui/views/passwords/password_pending_view.cc
index a69c46a..bcc79b01 100644
--- a/chrome/browser/ui/views/passwords/password_pending_view.cc
+++ b/chrome/browser/ui/views/passwords/password_pending_view.cc
@@ -232,7 +232,7 @@
             .release();
   }
 
-  const bool is_password_credential = password_form.federation_origin.unique();
+  const bool is_password_credential = password_form.federation_origin.opaque();
   if (is_password_credential) {
     password_view_button_ =
         CreatePasswordViewButton(this, are_passwords_revealed_).release();
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
index 6131232..c96cdef 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -1425,25 +1425,24 @@
       profiles::kAvatarBubbleAccountsBackgroundColor));
   views::GridLayout* layout = CreateSingleColumnLayout(view, menu_width_);
 
-  Profile* profile = browser_->profile();
-  std::string primary_account =
-      SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedAccountId();
-  DCHECK(!primary_account.empty());
-  std::vector<std::string> accounts =
-      profiles::GetSecondaryAccountsForProfile(profile, primary_account);
-
   // Get state of authentication error, if any.
+  Profile* profile = browser_->profile();
   std::string error_account_id = GetAuthErrorAccountId(profile);
 
   // The primary account should always be listed first.
   // TODO(rogerta): we still need to further differentiate the primary account
   // from the others in the UI, so more work is likely required here:
   // crbug.com/311124.
+  std::string primary_account =
+      SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedAccountId();
+  DCHECK(!primary_account.empty());
   CreateAccountButton(layout, primary_account, true,
                       error_account_id == primary_account, menu_width_);
-  for (size_t i = 0; i < accounts.size(); ++i)
-    CreateAccountButton(layout, accounts[i], false,
-                        error_account_id == accounts[i], menu_width_);
+  for (const std::string& account :
+       profiles::GetSecondaryAccountsForSignedInProfile(profile)) {
+    CreateAccountButton(layout, account, false, error_account_id == account,
+                        menu_width_);
+  }
 
   ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
   const int vertical_spacing =
diff --git a/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.cc b/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.cc
index 67ff5cc..9cbd5311 100644
--- a/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.cc
+++ b/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.cc
@@ -110,6 +110,10 @@
   NOTREACHED();
 }
 
+views::View* DiceBubbleSyncPromoView::GetSigninButtonForTesting() {
+  return signin_button_view_ ? signin_button_view_->signin_button() : nullptr;
+}
+
 void DiceBubbleSyncPromoView::EnableSync(
     bool is_default_promo_account,
     const base::Optional<AccountInfo>& account) {
diff --git a/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h b/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h
index 187f519..1d8ff96 100644
--- a/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h
+++ b/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h
@@ -52,6 +52,9 @@
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
+  // Returns the sign-in button.
+  views::View* GetSigninButtonForTesting();
+
  private:
   // Used to enable sync in the DiceAccountsMenu and when |signin_button_| is
   // pressed.
diff --git a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc
index 9f9cbaf..6be9bd9 100644
--- a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc
+++ b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc
@@ -38,8 +38,10 @@
 
   const web_modal::WebContentsModalDialogManager* manager =
       web_modal::WebContentsModalDialogManager::FromWebContents(web_contents_);
-  if (manager && manager->IsDialogActive())
+  if (manager && manager->IsDialogActive()) {
     manager->FocusTopmostDialog();
+    return true;
+  }
 
   return false;
 }
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
index cd2cb8ea..956a6b38 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
@@ -187,6 +187,9 @@
       policies.SetInteger(
           printing::kAllowedColorModes,
           profile_->GetPrefs()->GetInteger(prefs::kPrintingAllowedColorModes));
+      policies.SetInteger(
+          printing::kAllowedDuplexModes,
+          profile_->GetPrefs()->GetInteger(prefs::kPrintingAllowedDuplexModes));
       // fetch settings on the blocking pool and invoke callback.
       FetchCapabilities(std::move(printer), std::move(policies), std::move(cb));
       return;
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 6dbb63a..bc10d2f 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -852,6 +852,8 @@
 #if defined(OS_CHROMEOS)
   html_source->AddBoolean("enableNativeSmbSetting",
                           base::FeatureList::IsEnabled(features::kNativeSmb));
+  html_source->AddString("smbSharesLearnMoreURL",
+                         GetHelpUrlWithBoard(chrome::kSmbSharesLearnMoreURL));
 #endif
 }
 
@@ -2181,6 +2183,10 @@
        IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_NOTIFICATION},
       {"googleAssistantEnableNotificationDescription",
        IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_NOTIFICATION_DESCRIPTION},
+      {"googleAssistantLaunchWithMicOpen",
+       IDS_SETTINGS_GOOGLE_ASSISTANT_LAUNCH_WITH_MIC_OPEN},
+      {"googleAssistantLaunchWithMicOpenDescription",
+       IDS_SETTINGS_GOOGLE_ASSISTANT_LAUNCH_WITH_MIC_OPEN_DESCRIPTION},
       {"googleAssistantSettings", IDS_SETTINGS_GOOGLE_ASSISTANT_SETTINGS},
   };
   AddLocalizedStringsBulk(html_source, localized_strings,
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc
index 04422c78..554ec6a 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -123,7 +123,7 @@
 bool PatternAppliesToSingleOrigin(const ContentSettingPatternSource& pattern) {
   const GURL url(pattern.primary_pattern.ToString());
   // Default settings and other patterns apply to multiple origins.
-  if (url::Origin::Create(url).unique())
+  if (url::Origin::Create(url).opaque())
     return false;
   // Embedded content settings only when |url| is embedded in another origin, so
   // ignore non-wildcard secondary patterns that are different to the primary.
diff --git a/chrome/browser/ui/webui/site_settings_helper.cc b/chrome/browser/ui/webui/site_settings_helper.cc
index f7cfefa..457f8350 100644
--- a/chrome/browser/ui/webui/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/site_settings_helper.cc
@@ -318,7 +318,7 @@
     const GURL& url,
     const extensions::ExtensionRegistry* extension_registry) {
   const url::Origin origin = url::Origin::Create(url);
-  if (origin.unique())
+  if (origin.opaque())
     return url.spec();
 
   std::string display_name =
diff --git a/chrome/browser/vr/webxr_vr_transition_browser_test.cc b/chrome/browser/vr/webxr_vr_transition_browser_test.cc
index fda129fb..106544ba 100644
--- a/chrome/browser/vr/webxr_vr_transition_browser_test.cc
+++ b/chrome/browser/vr/webxr_vr_transition_browser_test.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/vr/test/webvr_browser_test.h"
+
+#include "build/build_config.h"
 #include "chrome/browser/vr/test/webxr_vr_browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 
@@ -78,8 +80,14 @@
 
 // Tests that WebVR does not return any devices if OpenVR support is disabled.
 // Since WebVR isn't actually used, we can remove the GPU requirement.
+#if defined(OS_WIN)
+#define MAYBE_TestWebVrNoDevicesWithoutOpenVr \
+  DISABLED_TestWebVrNoDevicesWithoutOpenVr
+#else
+#define MAYBE_TestWebVrNoDevicesWithoutOpenVr TestWebVrNoDevicesWithoutOpenVr
+#endif
 IN_PROC_BROWSER_TEST_F(WebVrBrowserTestOpenVrDisabled,
-                       TestWebVrNoDevicesWithoutOpenVr) {
+                       MAYBE_TestWebVrNoDevicesWithoutOpenVr) {
   LoadUrlAndAwaitInitialization(GetHtmlTestFile("generic_webvr_page"));
   EXPECT_FALSE(XrDeviceFound())
       << "Found a VRDisplay even with OpenVR disabled";
diff --git a/chrome/chrome_cleaner/BUILD.gn b/chrome/chrome_cleaner/BUILD.gn
index 840d269..389300fb9 100644
--- a/chrome/chrome_cleaner/BUILD.gn
+++ b/chrome/chrome_cleaner/BUILD.gn
@@ -33,6 +33,7 @@
 
     # Tests from sub-directories.
     "//chrome/chrome_cleaner/chrome_utils:unittest_sources",
+    "//chrome/chrome_cleaner/components:unittest_sources",
     "//chrome/chrome_cleaner/http:unittest_sources",
     "//chrome/chrome_cleaner/interfaces/typemaps:unittest_sources",
     "//chrome/chrome_cleaner/ipc:unittest_sources",
diff --git a/chrome/chrome_cleaner/components/BUILD.gn b/chrome/chrome_cleaner/components/BUILD.gn
new file mode 100644
index 0000000..3a9bf1fb
--- /dev/null
+++ b/chrome/chrome_cleaner/components/BUILD.gn
@@ -0,0 +1,85 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("crx_file") {
+  sources = [
+    "crx_file.cc",
+    "crx_file.h",
+  ]
+
+  deps = [
+    "//base",
+    "//components/chrome_cleaner/public/constants:constants",
+  ]
+}
+
+source_set("components") {
+  sources = [
+    "component_api.h",
+    "component_manager.cc",
+    "component_manager.h",
+    "component_unpacker.cc",
+    "component_unpacker.h",
+    "recovery_component.cc",
+    "recovery_component.h",
+    "system_report_component.cc",
+    "system_report_component.h",
+    "system_restore_point_component.cc",
+    "system_restore_point_component.h",
+  ]
+
+  deps = [
+    ":crx_file",
+    "//base:base",
+    "//chrome/chrome_cleaner/chrome_utils:chrome_util_lib",
+    "//chrome/chrome_cleaner/chrome_utils:extensions_util_lib",
+    "//chrome/chrome_cleaner/constants:common_strings",
+    "//chrome/chrome_cleaner/constants:uws_id",
+    "//chrome/chrome_cleaner/http:http",
+    "//chrome/chrome_cleaner/http:http_status_codes",
+    "//chrome/chrome_cleaner/json_parser",
+    "//chrome/chrome_cleaner/logging:common",
+    "//chrome/chrome_cleaner/logging:scoped_timed_task_logger",
+    "//chrome/chrome_cleaner/logging/proto:shared_data_proto",
+    "//chrome/chrome_cleaner/os:cleaner_os",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//chrome/chrome_cleaner/pup_data:pup_data_base",
+    "//components/chrome_cleaner/public/constants:constants",
+    "//crypto:crypto",
+    "//third_party/zlib/google:zip",
+    "//url:url",
+  ]
+}
+
+source_set("unittest_sources") {
+  testonly = true
+
+  sources = [
+    "component_manager_unittest.cc",
+    "recovery_component_unittest.cc",
+    "system_report_component_unittest.cc",
+    "system_restore_point_component_unittest.cc",
+  ]
+
+  deps = [
+    ":components",
+    "//base",
+    "//base/test:test_support",
+    "//chrome/chrome_cleaner/chrome_utils:chrome_util_lib",
+    "//chrome/chrome_cleaner/constants:common_strings",
+    "//chrome/chrome_cleaner/constants:uws_id",
+    "//chrome/chrome_cleaner/http:mock_http_agent_factory",
+    "//chrome/chrome_cleaner/json_parser",
+    "//chrome/chrome_cleaner/logging:cleaner_logging",
+    "//chrome/chrome_cleaner/logging/proto:chrome_cleaner_report_proto",
+    "//chrome/chrome_cleaner/os:cleaner_os",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//chrome/chrome_cleaner/test:test_branding_header",
+    "//chrome/chrome_cleaner/test:test_component",
+    "//chrome/chrome_cleaner/test:test_pup_data",
+    "//chrome/chrome_cleaner/test:test_util",
+    "//components/chrome_cleaner/public/constants",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/chrome_cleaner/components/DEPS b/chrome/chrome_cleaner/components/DEPS
new file mode 100644
index 0000000..4394973
--- /dev/null
+++ b/chrome/chrome_cleaner/components/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/zlib/google",
+]
diff --git a/chrome/chrome_cleaner/components/component_api.h b/chrome/chrome_cleaner/components/component_api.h
new file mode 100644
index 0000000..fd06746
--- /dev/null
+++ b/chrome/chrome_cleaner/components/component_api.h
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_CLEANER_COMPONENTS_COMPONENT_API_H_
+#define CHROME_CHROME_CLEANER_COMPONENTS_COMPONENT_API_H_
+
+#include <vector>
+
+#include "chrome/chrome_cleaner/constants/uws_id.h"
+#include "components/chrome_cleaner/public/constants/result_codes.h"
+
+namespace chrome_cleaner {
+
+class RebooterAPI;
+
+// This class is used to register components that are to be executed by the main
+// controller either before the scanner or after the cleaner.
+class ComponentAPI {
+ public:
+  virtual ~ComponentAPI() {}
+
+  // Called before the scanning starts. Components may need to consult the
+  // command line to identify if this is a post-reboot scan.
+  virtual void PreScan() = 0;
+
+  // Called after scanning. |found_pups| contains the ids of the found pups.
+  virtual void PostScan(const std::vector<UwSId>& found_pups) = 0;
+
+  // Called before cleanup starts.
+  virtual void PreCleanup() = 0;
+
+  // Called after the final cleanup. |result_code| can be used to identify if
+  // a post-reboot removal will be needed, or other status that might be useful
+  // to the component. |rebooter| is specified in case the component needs to
+  // specify command line arguments for the post-reboot run so that the
+  // |PostValidation| call below can take some decisions based on it. |rebooter|
+  // can be null in tests.
+  virtual void PostCleanup(ResultCode result_code, RebooterAPI* rebooter) = 0;
+
+  // Called after the post reboot run scanner is done validating the cleanup.
+  virtual void PostValidation(ResultCode result_code) = 0;
+
+  // Called when the final dialog window is closed. As above, |result_code| can
+  // be used to tell the result of the run (i.e., whether a cleanup was needed
+  // or not). Since this happens after users had a chance to look at the logs to
+  // decide whether they want to opt-out or not, any logging done here won't be
+  // uploaded back to Google.
+  virtual void OnClose(ResultCode result_code) = 0;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_COMPONENTS_COMPONENT_API_H_
diff --git a/chrome/chrome_cleaner/components/component_manager.cc b/chrome/chrome_cleaner/components/component_manager.cc
new file mode 100644
index 0000000..87cf1fd
--- /dev/null
+++ b/chrome/chrome_cleaner/components/component_manager.cc
@@ -0,0 +1,186 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/components/component_manager.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/run_loop.h"
+#include "base/task/post_task.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/chrome_cleaner/components/component_api.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+// A set of factory functions to create the calls to code to be executed in
+// worker threads. Since the code to loop through the components is the same
+// for all calls, it was extracted in the |PostComponentTasks| method. So the
+// public API methods must specify which function to call on the components.
+// Since the component pointer must be the first argument, and we can't pre-pend
+// args to bound calls, the public API methods sends a bound version of these
+// factory functions so that |PostComponentTasks| can call them to get the
+// closure by passing the component pointer to them. The component pointer
+// must be the last argument to these factory functions so that the other
+// arguments are pre-bound by the public API methods when they call
+// |PostComponentTasks| (e.g., |found_pups|).
+base::OnceClosure BindPreScan(ComponentAPI* component) {
+  return base::BindOnce(&ComponentAPI::PreScan, base::Unretained(component));
+}
+
+base::OnceClosure BindPostScan(const std::vector<UwSId>& found_pups,
+                               ComponentAPI* component) {
+  return base::BindOnce(&ComponentAPI::PostScan, base::Unretained(component),
+                        found_pups);
+}
+
+base::OnceClosure BindPreCleanup(ComponentAPI* component) {
+  return base::BindOnce(&ComponentAPI::PreCleanup, base::Unretained(component));
+}
+
+base::OnceClosure BindPostCleanup(ResultCode result_code,
+                                  RebooterAPI* rebooter,
+                                  ComponentAPI* component) {
+  return base::BindOnce(&ComponentAPI::PostCleanup, base::Unretained(component),
+                        result_code, rebooter);
+}
+
+}  // namespace
+
+ComponentManager::ComponentManager(ComponentManagerDelegate* delegate)
+    : delegate_(delegate) {
+  DCHECK(delegate_);
+}
+
+ComponentManager::~ComponentManager() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Make sure |CloseAllComponents| was called. IT can't be called from here
+  // because it needs the result code. The components will still be released by
+  // the scoped vector, but their OnClose won't be called if
+  // |CloseAllComponents| wasn't called.
+  DCHECK(!cancelable_task_tracker_.HasTrackedTasks());
+  DCHECK(components_.empty());
+  DCHECK(done_callback_.is_null());
+}
+
+void ComponentManager::AddComponent(std::unique_ptr<ComponentAPI> component) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Components can't be added while tasks are in flight.
+  DCHECK(!cancelable_task_tracker_.HasTrackedTasks());
+  DCHECK(done_callback_.is_null());
+  DCHECK_EQ(0UL, num_tasks_pending_);
+
+  components_.push_back(std::move(component));
+}
+
+void ComponentManager::PreScan() {
+  // No task should be pending when any method from the ComponentsAPI are
+  // called.
+  DCHECK(done_callback_.is_null());
+  done_callback_ = base::BindOnce(&ComponentManagerDelegate::PreScanDone,
+                                  base::Unretained(delegate_));
+  PostComponentTasks(base::BindRepeating(&BindPreScan), "PreScan");
+}
+
+void ComponentManager::PostScan(const std::vector<UwSId>& found_pups) {
+  DCHECK(done_callback_.is_null());
+  done_callback_ = base::BindOnce(&ComponentManagerDelegate::PostScanDone,
+                                  base::Unretained(delegate_));
+  PostComponentTasks(base::BindRepeating(&BindPostScan, found_pups),
+                     "PostScan");
+}
+
+void ComponentManager::PreCleanup() {
+  DCHECK(done_callback_.is_null());
+  done_callback_ = base::BindOnce(&ComponentManagerDelegate::PreCleanupDone,
+                                  base::Unretained(delegate_));
+  PostComponentTasks(base::BindRepeating(&BindPreCleanup), "PreCleanup");
+}
+
+void ComponentManager::PostCleanup(ResultCode result_code,
+                                   RebooterAPI* rebooter) {
+  DCHECK(done_callback_.is_null());
+  done_callback_ = base::BindOnce(&ComponentManagerDelegate::PostCleanupDone,
+                                  base::Unretained(delegate_));
+  PostComponentTasks(
+      base::BindRepeating(&BindPostCleanup, result_code, rebooter),
+      "PostCleanup");
+}
+
+void ComponentManager::PostValidation(ResultCode result_code) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!cancelable_task_tracker_.HasTrackedTasks());
+  DCHECK_EQ(0UL, num_tasks_pending_);
+
+  for (auto& component : components_)
+    component->PostValidation(result_code);
+}
+
+void ComponentManager::CloseAllComponents(ResultCode result_code) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (num_tasks_pending_ > 0) {
+    cancelable_task_tracker_.TryCancelAll();
+    while (cancelable_task_tracker_.HasTrackedTasks())
+      base::RunLoop().RunUntilIdle();
+    done_callback_.Reset();
+  } else {
+    DCHECK(!cancelable_task_tracker_.HasTrackedTasks());
+  }
+
+  for (auto& component : components_)
+    component->OnClose(result_code);
+  components_.clear();
+}
+
+void ComponentManager::PostComponentTasks(
+    const base::RepeatingCallback<base::OnceClosure(ComponentAPI*)>
+        component_task,
+    const char* method_name) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!cancelable_task_tracker_.HasTrackedTasks());
+  DCHECK_EQ(0UL, num_tasks_pending_);
+
+  if (components_.empty()) {
+    DCHECK(!done_callback_.is_null());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  std::move(done_callback_));
+    return;
+  }
+
+  // Allow blocking operations, such as file operations, in the component task.
+  // This is allowed since there is no UI for it to block.
+  auto task_runner = base::CreateTaskRunnerWithTraits(base::MayBlock());
+  for (auto& component : components_) {
+    if (cancelable_task_tracker_.PostTaskAndReply(
+            task_runner.get(), FROM_HERE,
+            component_task.Run(component.get()),  // This returns a Closure.
+            base::BindOnce(&ComponentManager::TaskCompleted,
+                           base::Unretained(this))) ==
+        base::CancelableTaskTracker::kBadTaskId) {
+      PLOG(ERROR) << "Failed to run component's method: " << method_name;
+    } else {
+      // The reply task is never called synchronously, so it's OK to increment
+      // the number of tasks pending after the task was posted.
+      ++num_tasks_pending_;
+    }
+  }
+}
+
+void ComponentManager::TaskCompleted() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_GT(num_tasks_pending_, 0UL);
+
+  if (--num_tasks_pending_ == 0) {
+    // The callback must be run asynchronously so that the task tracker is not
+    // on the call stack anymore in cases where the callback ends up calling
+    // CloseAllComponents.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  std::move(done_callback_));
+  }
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/components/component_manager.h b/chrome/chrome_cleaner/components/component_manager.h
new file mode 100644
index 0000000..c707c601
--- /dev/null
+++ b/chrome/chrome_cleaner/components/component_manager.h
@@ -0,0 +1,100 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_CLEANER_COMPONENTS_COMPONENT_MANAGER_H_
+#define CHROME_CHROME_CLEANER_COMPONENTS_COMPONENT_MANAGER_H_
+
+#include <vector>
+
+#include "base/sequence_checker.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "chrome/chrome_cleaner/components/component_api.h"
+#include "chrome/chrome_cleaner/constants/uws_id.h"
+#include "chrome/chrome_cleaner/os/rebooter_api.h"
+#include "components/chrome_cleaner/public/constants/result_codes.h"
+
+namespace chrome_cleaner {
+
+// A delegate API to be called back when all requested tasks are completed.
+class ComponentManagerDelegate {
+ public:
+  virtual ~ComponentManagerDelegate() {}
+  virtual void PreScanDone() = 0;
+  virtual void PostScanDone() = 0;
+  virtual void PreCleanupDone() = 0;
+  virtual void PostCleanupDone() = 0;
+};
+
+// This class is used to register components that are to be executed by the main
+// controller either before the scanner or after the cleaner.
+class ComponentManager {
+ public:
+  // |delegate| must outlive the ComponentManager.
+  explicit ComponentManager(ComponentManagerDelegate* delegate);
+
+  // |CloseAllComponents| must be called before deleting the component manager.
+  // Self cleanup is NOT supported!
+  ~ComponentManager();
+
+  // Add a new component. The ComponentManager takes ownership of the component.
+  // This method can't be called while there is an active call to the
+  // ComponentsAPI methods below that has not been completed by a call to
+  // |delegate_| yet.
+  void AddComponent(std::unique_ptr<ComponentAPI> component);
+
+  // All ComponentsAPI methods are duplicated here. Each of these calls run
+  // asynchronously and call their respective counterpart on |delegate_|. There
+  // can only be one of these calls active at a time. Callers must wait for
+  // |delegate_| to be called back before attempting other calls on this API.
+  void PreScan();
+  void PostScan(const std::vector<UwSId>& found_pups);
+  void PreCleanup();
+  void PostCleanup(ResultCode result_code, RebooterAPI* rebooter);
+  // This call is synchronous so doesn't have an equivalent done call on the
+  // delegate. TODO(csharp): This is confusing, fix it! b/23372645.
+  void PostValidation(ResultCode result_code);
+
+  // Call OnClose on all components and then destroy them. Any pending component
+  // tasks will be canceled and any pending threads will be joined. |delegate_|
+  // won't be called, even if there was a pending task. This must absolutely
+  // be called before the object is destroyed.
+  void CloseAllComponents(ResultCode result_code);
+
+  // Return the number of pending tasks. Mainly used by tests.
+  size_t num_tasks_pending() const { return num_tasks_pending_; }
+
+ private:
+  // Common code to post tasks to the worker threads. |component_task| is called
+  // to create the closure that will run in the worker threads for each
+  // component. |method_name| is used for logging.
+  void PostComponentTasks(const base::RepeatingCallback<
+                              base::OnceClosure(ComponentAPI*)> component_task,
+                          const char* method_name);
+
+  // Called back on the main thread when a task is completed. When the last task
+  // completes, run |done_callback_| asynchronously to avoid re-entrance.
+  void TaskCompleted();
+
+  // The components that are to be called before / after the scan / cleanup.
+  std::vector<std::unique_ptr<ComponentAPI>> components_;
+
+  // The task tracker that can be used to cancel pending tasks.
+  base::CancelableTaskTracker cancelable_task_tracker_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  // The delegate to be called when tasks are completed.
+  ComponentManagerDelegate* delegate_;
+
+  // The closure to callback once all tasks completed. This always contains a
+  // call to |delegate_|.
+  base::OnceClosure done_callback_;
+
+  // The number of pending tasks that have not called |TaskCompleted| yet.
+  size_t num_tasks_pending_ = 0;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_COMPONENTS_COMPONENT_MANAGER_H_
diff --git a/chrome/chrome_cleaner/components/component_manager_unittest.cc b/chrome/chrome_cleaner/components/component_manager_unittest.cc
new file mode 100644
index 0000000..9efa7623
--- /dev/null
+++ b/chrome/chrome_cleaner/components/component_manager_unittest.cc
@@ -0,0 +1,197 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/components/component_manager.h"
+
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/chrome_cleaner/components/component_api.h"
+#include "chrome/chrome_cleaner/test/test_component.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+const UwSId kFakePupId = 42;
+
+// This delegate validates that calls were made, and also interrupt the
+// currently running message loop, waiting for the delegate methods to be
+// called.
+class TestComponentManagerDelegate : public ComponentManagerDelegate {
+ public:
+  struct Calls {
+    bool pre_scan = false;
+    bool post_scan = false;
+    bool pre_cleanup = false;
+    bool post_cleanup = false;
+  };
+  explicit TestComponentManagerDelegate(Calls* calls) : calls_(calls) {}
+
+  void set_quit_closure(base::OnceClosure quit_closure) {
+    quit_closure_ = std::move(quit_closure);
+  }
+
+  // ComponentManagerDelegate
+  void PreScanDone() override {
+    calls_->pre_scan = true;
+    if (quit_closure_)
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                    std::move(quit_closure_));
+  }
+  void PostScanDone() override {
+    calls_->post_scan = true;
+    if (quit_closure_)
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                    std::move(quit_closure_));
+  }
+  void PreCleanupDone() override {
+    calls_->pre_cleanup = true;
+    if (quit_closure_)
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                    std::move(quit_closure_));
+  }
+  void PostCleanupDone() override {
+    calls_->post_cleanup = true;
+    if (quit_closure_)
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                    std::move(quit_closure_));
+  }
+
+ private:
+  Calls* calls_;
+  base::OnceClosure quit_closure_;
+};
+
+}  // namespace
+
+TEST(ComponentManagerTest, Empty) {
+  base::test::ScopedTaskEnvironment scoped_task_environment;
+
+  TestComponentManagerDelegate::Calls calls;
+  TestComponentManagerDelegate delegate(&calls);
+  ComponentManager component_manager(&delegate);
+
+  base::RunLoop run_loop1;
+  delegate.set_quit_closure(run_loop1.QuitWhenIdleClosure());
+  component_manager.PreScan();
+  run_loop1.Run();
+  EXPECT_TRUE(calls.pre_scan);
+  calls.pre_scan = false;
+  EXPECT_FALSE(calls.post_scan);
+  EXPECT_FALSE(calls.pre_cleanup);
+  EXPECT_FALSE(calls.post_cleanup);
+
+  base::RunLoop run_loop2;
+  delegate.set_quit_closure(run_loop2.QuitWhenIdleClosure());
+  component_manager.PostScan(std::vector<UwSId>());
+  run_loop2.Run();
+  EXPECT_FALSE(calls.pre_scan);
+  EXPECT_TRUE(calls.post_scan);
+  calls.post_scan = false;
+  EXPECT_FALSE(calls.pre_cleanup);
+  EXPECT_FALSE(calls.post_cleanup);
+
+  base::RunLoop run_loop3;
+  delegate.set_quit_closure(run_loop3.QuitWhenIdleClosure());
+  component_manager.PreCleanup();
+  run_loop3.Run();
+  EXPECT_FALSE(calls.pre_scan);
+  EXPECT_FALSE(calls.post_scan);
+  EXPECT_TRUE(calls.pre_cleanup);
+  calls.pre_cleanup = false;
+  EXPECT_FALSE(calls.post_cleanup);
+
+  base::RunLoop run_loop4;
+  delegate.set_quit_closure(run_loop4.QuitWhenIdleClosure());
+  component_manager.PostCleanup(RESULT_CODE_SUCCESS, nullptr);
+  run_loop4.Run();
+  EXPECT_FALSE(calls.pre_scan);
+  EXPECT_FALSE(calls.post_scan);
+  EXPECT_FALSE(calls.pre_cleanup);
+  EXPECT_TRUE(calls.post_cleanup);
+
+  // Nothing to validate, just make sure it can be called.
+  component_manager.CloseAllComponents(RESULT_CODE_FAILED);
+}
+
+TEST(ComponentManagerTest, All) {
+  base::test::ScopedTaskEnvironment scoped_task_environment;
+
+  TestComponentManagerDelegate::Calls delegate_calls;
+  TestComponentManagerDelegate delegate(&delegate_calls);
+  ComponentManager component_manager(&delegate);
+
+  TestComponent::Calls component_calls;
+  component_manager.AddComponent(
+      std::make_unique<TestComponent>(&component_calls));
+
+  base::RunLoop run_loop1;
+  delegate.set_quit_closure(run_loop1.QuitWhenIdleClosure());
+  component_manager.PreScan();
+  run_loop1.Run();
+  EXPECT_TRUE(delegate_calls.pre_scan);
+  EXPECT_TRUE(component_calls.pre_scan);
+
+  base::RunLoop run_loop2;
+  delegate.set_quit_closure(run_loop2.QuitWhenIdleClosure());
+  std::vector<UwSId> pup_ids;
+  pup_ids.push_back(kFakePupId);
+  component_manager.PostScan(pup_ids);
+  run_loop2.Run();
+  EXPECT_TRUE(delegate_calls.post_scan);
+  EXPECT_TRUE(component_calls.post_scan);
+  ASSERT_EQ(1UL, component_calls.post_scan_found_pups.size());
+  EXPECT_EQ(kFakePupId, component_calls.post_scan_found_pups[0]);
+
+  base::RunLoop run_loop3;
+  delegate.set_quit_closure(run_loop3.QuitWhenIdleClosure());
+  component_manager.PreCleanup();
+  run_loop3.Run();
+  EXPECT_TRUE(delegate_calls.pre_cleanup);
+  EXPECT_TRUE(component_calls.pre_cleanup);
+
+  base::RunLoop run_loop4;
+  delegate.set_quit_closure(run_loop4.QuitWhenIdleClosure());
+  component_manager.PostCleanup(RESULT_CODE_SUCCESS, nullptr);
+  run_loop4.Run();
+  EXPECT_TRUE(delegate_calls.post_cleanup);
+  EXPECT_TRUE(component_calls.post_cleanup);
+  EXPECT_EQ(RESULT_CODE_SUCCESS, component_calls.result_code);
+  component_calls.result_code = RESULT_CODE_INVALID;
+
+  component_manager.PostValidation(RESULT_CODE_FAILED);
+  EXPECT_TRUE(component_calls.post_validation);
+  EXPECT_EQ(RESULT_CODE_FAILED, component_calls.result_code);
+
+  component_manager.CloseAllComponents(RESULT_CODE_CANCELED);
+  EXPECT_TRUE(component_calls.on_close);
+  EXPECT_TRUE(component_calls.destroyed);
+  EXPECT_EQ(RESULT_CODE_CANCELED, component_calls.result_code);
+}
+
+TEST(ComponentManagerTest, Interrupt) {
+  base::test::ScopedTaskEnvironment scoped_task_environment;
+
+  TestComponentManagerDelegate::Calls delegate_calls;
+  TestComponentManagerDelegate delegate(&delegate_calls);
+  ComponentManager component_manager(&delegate);
+
+  TestComponent::Calls component_calls;
+  for (size_t i = 0; i < 1000; ++i) {
+    component_manager.AddComponent(
+        std::make_unique<TestComponent>(&component_calls));
+  }
+
+  component_manager.PreScan();
+  EXPECT_FALSE(delegate_calls.pre_scan);
+  component_manager.CloseAllComponents(RESULT_CODE_INVALID);
+  EXPECT_FALSE(delegate_calls.pre_scan);
+  // We rely on test harness leak detector to make sure TestComponents were
+  // properly destroyed.
+  EXPECT_GT(component_manager.num_tasks_pending(), 0UL);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/components/component_unpacker.cc b/chrome/chrome_cleaner/components/component_unpacker.cc
new file mode 100644
index 0000000..7989b63
--- /dev/null
+++ b/chrome/chrome_cleaner/components/component_unpacker.cc
@@ -0,0 +1,122 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Stolen from chrome/browser/component_updater/component_unpacker.cc
+
+#include "chrome/chrome_cleaner/components/component_unpacker.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "chrome/chrome_cleaner/components/crx_file.h"
+#include "chrome/chrome_cleaner/os/file_path_sanitization.h"
+#include "crypto/secure_hash.h"
+#include "crypto/signature_verifier.h"
+#include "third_party/zlib/google/zip.h"
+
+using crypto::SecureHash;
+
+namespace chrome_cleaner {
+
+namespace {
+
+// This class makes sure that the CRX digital signature is valid and well
+// formed.
+class CRXValidator {
+ public:
+  explicit CRXValidator(FILE* crx_file) : valid_(false) {
+    CrxFile::Header header;
+    size_t len = fread(&header, 1, sizeof(header), crx_file);
+    if (len < sizeof(header))
+      return;
+
+    CrxFile::Error error;
+    std::unique_ptr<CrxFile> crx(CrxFile::Parse(header, &error));
+    if (!crx.get())
+      return;
+    DCHECK(!CrxFile::HeaderIsDelta(header));
+
+    std::vector<uint8_t> key(header.key_size);
+    len = fread(&key[0], sizeof(uint8_t), header.key_size, crx_file);
+    if (len < header.key_size)
+      return;
+
+    std::vector<uint8_t> signature(header.signature_size);
+    len =
+        fread(&signature[0], sizeof(uint8_t), header.signature_size, crx_file);
+    if (len < header.signature_size)
+      return;
+
+    crypto::SignatureVerifier verifier;
+    if (!verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1,
+                             signature, key)) {
+      // Signature verification initialization failed. This is most likely
+      // caused by a public key in the wrong format (should encode algorithm).
+      return;
+    }
+
+    const size_t kBufSize = 8 * 1024;
+    std::vector<uint8_t> buf(kBufSize);
+    while ((len = fread(buf.data(), 1, kBufSize, crx_file)) > 0)
+      verifier.VerifyUpdate(buf);
+
+    if (!verifier.VerifyFinal())
+      return;
+
+    public_key_.swap(key);
+    valid_ = true;
+  }
+
+  bool valid() const { return valid_; }
+
+  const std::vector<uint8_t>& public_key() const { return public_key_; }
+
+ private:
+  bool valid_;
+  std::vector<uint8_t> public_key_;
+};
+
+}  // namespace
+
+ComponentUnpacker::ComponentUnpacker(const std::vector<uint8_t>& pk_hash,
+                                     const base::FilePath& path)
+    : pk_hash_(pk_hash), path_(path) {}
+
+bool ComponentUnpacker::Unpack(const base::FilePath& ouput_folder) {
+  return Verify() && zip::Unzip(path_, ouput_folder);
+}
+
+bool ComponentUnpacker::Verify() {
+  if (pk_hash_.empty() || path_.empty())
+    return false;
+  // First, validate the CRX header and signature. As of today this is SHA1 with
+  // RSA 1024.
+  base::ScopedFILE file(base::OpenFile(path_, "rb"));
+  if (!file.get())
+    return false;
+  CRXValidator validator(file.get());
+  file.reset();
+  if (!validator.valid())
+    return false;
+
+  // File is valid and the digital signature matches. Now make sure the public
+  // key hash matches the expected hash. If they do we fully trust this CRX.
+  uint8_t hash[32] = {};
+  std::unique_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256));
+  sha256->Update(&(validator.public_key()[0]), validator.public_key().size());
+  sha256->Finish(hash, base::size(hash));
+
+  if (!std::equal(pk_hash_.begin(), pk_hash_.end(), hash)) {
+    LOG(WARNING) << "Hash mismatch: " << SanitizePath(path_);
+    return false;
+  }
+  return true;
+}
+
+ComponentUnpacker::~ComponentUnpacker() {}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/components/component_unpacker.h b/chrome/chrome_cleaner/components/component_unpacker.h
new file mode 100644
index 0000000..34260a8
--- /dev/null
+++ b/chrome/chrome_cleaner/components/component_unpacker.h
@@ -0,0 +1,52 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Stolen from chrome/browser/component_updater/component_unpacker.h
+
+#ifndef CHROME_CHROME_CLEANER_COMPONENTS_COMPONENT_UNPACKER_H_
+#define CHROME_CHROME_CLEANER_COMPONENTS_COMPONENT_UNPACKER_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+
+namespace chrome_cleaner {
+
+// In charge of unpacking the component CRX package and verifying that it is
+// well formed and the cryptographic signature is correct.
+//
+// This class is inspired by and overlaps with code in the extension's
+// SandboxedUnpacker.
+// The main differences are:
+// - The public key hash is full SHA256.
+// - Does not use a sandboxed unpacker. A valid component is fully trusted.
+class ComponentUnpacker {
+ public:
+  // Constructs an unpacker for a specific component unpacking operation.
+  // |pk_hash| is the expected public key SHA256 hash. |path| is the current
+  // location of the CRX.
+  ComponentUnpacker(const std::vector<uint8_t>& pk_hash,
+                    const base::FilePath& path);
+  virtual ~ComponentUnpacker();
+
+  // Unpack the file to the provided folder. Return true on success.
+  bool Unpack(const base::FilePath& ouput_folder);
+
+ private:
+  // The first step of unpacking is to verify the file. Return false if an
+  // error is encountered, the file is malformed, or the file is incorrectly
+  // signed.
+  bool Verify();
+
+  std::vector<uint8_t> pk_hash_;
+  base::FilePath path_;
+
+  DISALLOW_COPY_AND_ASSIGN(ComponentUnpacker);
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_COMPONENTS_COMPONENT_UNPACKER_H_
diff --git a/chrome/chrome_cleaner/components/crx_file.cc b/chrome/chrome_cleaner/components/crx_file.cc
new file mode 100644
index 0000000..abad50a
--- /dev/null
+++ b/chrome/chrome_cleaner/components/crx_file.cc
@@ -0,0 +1,87 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Stolen from extensions/common/crx_file.cc
+// TODO(crbug.com/889575): The above file no longer exists. It's been
+// refactored and now lives in components/crx_file. Should pull in that
+// component directly.
+
+#include "chrome/chrome_cleaner/components/crx_file.h"
+
+#include "base/memory/ptr_util.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+// The current version of the crx format.
+static const uint32_t kCurrentVersion = 2;
+
+// The current version of the crx diff format.
+static const uint32_t kCurrentDiffVersion = 0;
+
+// The maximum size the crx parser will tolerate for a public key.
+static const uint32_t kMaxPublicKeySize = 1 << 16;
+
+// The maximum size the crx parser will tolerate for a signature.
+static const uint32_t kMaxSignatureSize = 1 << 16;
+
+}  // namespace
+
+// The magic string embedded in the header.
+const char kCrxFileHeaderMagic[] = "Cr24";
+const char kCrxDiffFileHeaderMagic[] = "CrOD";
+
+std::unique_ptr<CrxFile> CrxFile::Parse(const CrxFile::Header& header,
+                                        CrxFile::Error* error) {
+  if (HeaderIsValid(header, error))
+    return base::WrapUnique<CrxFile>(new CrxFile(header));
+  return nullptr;
+}
+
+std::unique_ptr<CrxFile> CrxFile::Create(const uint32_t key_size,
+                                         const uint32_t signature_size,
+                                         CrxFile::Error* error) {
+  CrxFile::Header header;
+  memcpy(&header.magic, kCrxFileHeaderMagic, kCrxFileHeaderMagicSize);
+  header.version = kCurrentVersion;
+  header.key_size = key_size;
+  header.signature_size = signature_size;
+  if (HeaderIsValid(header, error))
+    return base::WrapUnique<CrxFile>(new CrxFile(header));
+  return nullptr;
+}
+
+CrxFile::CrxFile(const Header& header) : header_(header) {}
+
+bool CrxFile::HeaderIsDelta(const CrxFile::Header& header) {
+  return !strncmp(kCrxDiffFileHeaderMagic, header.magic, sizeof(header.magic));
+}
+
+bool CrxFile::HeaderIsValid(const CrxFile::Header& header,
+                            CrxFile::Error* error) {
+  bool valid = false;
+  bool diffCrx = false;
+  if (!strncmp(kCrxDiffFileHeaderMagic, header.magic, sizeof(header.magic)))
+    diffCrx = true;
+  if (strncmp(kCrxFileHeaderMagic, header.magic, sizeof(header.magic)) &&
+      !diffCrx)
+    *error = kWrongMagic;
+  else if (header.version != kCurrentVersion &&
+           !(diffCrx && header.version == kCurrentDiffVersion))
+    *error = kInvalidVersion;
+  else if (header.key_size > kMaxPublicKeySize)
+    *error = kInvalidKeyTooLarge;
+  else if (header.key_size == 0)
+    *error = kInvalidKeyTooSmall;
+  else if (header.signature_size > kMaxSignatureSize)
+    *error = kInvalidSignatureTooLarge;
+  else if (header.signature_size == 0)
+    *error = kInvalidSignatureTooSmall;
+  else
+    valid = true;
+  return valid;
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/components/crx_file.h b/chrome/chrome_cleaner/components/crx_file.h
new file mode 100644
index 0000000..363586ac
--- /dev/null
+++ b/chrome/chrome_cleaner/components/crx_file.h
@@ -0,0 +1,81 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Stolen from extensions/common/crx_file.h
+
+#ifndef CHROME_CHROME_CLEANER_COMPONENTS_CRX_FILE_H_
+#define CHROME_CHROME_CLEANER_COMPONENTS_CRX_FILE_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <memory>
+
+namespace chrome_cleaner {
+
+// CRX files have a header that includes a magic key, version number, and
+// some signature sizing information. Use CrxFile object to validate whether
+// the header is valid or not.
+class CrxFile {
+ public:
+  // The size of the magic character sequence at the beginning of each crx
+  // file, in bytes. This should be a multiple of 4.
+  static const size_t kCrxFileHeaderMagicSize = 4;
+
+  // This header is the first data at the beginning of an extension. Its
+  // contents are purposely 32-bit aligned so that it can just be slurped into
+  // a struct without manual parsing.
+  struct Header {
+    char magic[kCrxFileHeaderMagicSize];
+    uint32_t version;
+    uint32_t key_size;        // The size of the public key, in bytes.
+    uint32_t signature_size;  // The size of the signature, in bytes.
+    // An ASN.1-encoded PublicKeyInfo structure follows.
+    // The signature follows.
+  };
+
+  enum Error {
+    kWrongMagic,
+    kInvalidVersion,
+    kInvalidKeyTooLarge,
+    kInvalidKeyTooSmall,
+    kInvalidSignatureTooLarge,
+    kInvalidSignatureTooSmall,
+  };
+
+  // Construct a new CRX file header object with bytes of a header
+  // read from a CRX file. If a null std::unique_ptr is returned, |error|
+  // contains an error code with additional information.
+  static std::unique_ptr<CrxFile> Parse(const Header& header, Error* error);
+
+  // Construct a new header for the given key and signature sizes.
+  // Returns a null std::unique_ptr if erroneous values of |key_size| and/or
+  // |signature_size| are provided. |error| contains an error code with
+  // additional information.
+  // Use this constructor and then .header() to obtain the Header
+  // for writing out to a CRX file.
+  static std::unique_ptr<CrxFile> Create(const uint32_t key_size,
+                                         const uint32_t signature_size,
+                                         Error* error);
+
+  // Returns the header structure for writing out to a CRX file.
+  const Header& header() const { return header_; }
+
+  // Checks a valid |header| to determine whether or not the CRX represents a
+  // differential CRX.
+  static bool HeaderIsDelta(const Header& header);
+
+ private:
+  Header header_;
+
+  // Constructor is private. Clients should use static factory methods above.
+  explicit CrxFile(const Header& header);
+
+  // Checks the |header| for validity and returns true if the values are valid.
+  // If false is returned, more detailed error code is returned in |error|.
+  static bool HeaderIsValid(const Header& header, Error* error);
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_COMPONENTS_CRX_FILE_H_
diff --git a/chrome/chrome_cleaner/components/recovery_component.cc b/chrome/chrome_cleaner/components/recovery_component.cc
new file mode 100644
index 0000000..cc75282
--- /dev/null
+++ b/chrome/chrome_cleaner/components/recovery_component.cc
@@ -0,0 +1,289 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/components/recovery_component.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/command_line.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/process/kill.h"
+#include "base/process/launch.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "chrome/chrome_cleaner/components/component_unpacker.h"
+#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
+#include "chrome/chrome_cleaner/http/http_agent.h"
+#include "chrome/chrome_cleaner/http/http_agent_factory.h"
+#include "chrome/chrome_cleaner/http/http_response.h"
+#include "chrome/chrome_cleaner/http/http_status_codes.h"
+#include "chrome/chrome_cleaner/pup_data/pup_data.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+const char kComponentDownloadUrl[] =
+    "https://clients2.google.com/service/update2/crx?response=redirect&os=win"
+    "&arch=x86&installsource=swreporter&x=id%3Dnpdjjkjlcidkjlamlmmdelcjbcpdjocm"
+    "%26v%3D0.0.0.0%26uc";
+
+// CRX hash. The extension id is: npdjjkjlcidkjlamlmmdelcjbcpdjocm.
+const uint8_t kSha2Hash[] = {0xdf, 0x39, 0x9a, 0x9b, 0x28, 0x3a, 0x9b, 0x0c,
+                             0xbc, 0xc3, 0x4b, 0x29, 0x12, 0xf3, 0x9e, 0x2c,
+                             0x19, 0x7a, 0x71, 0x4b, 0x0a, 0x7c, 0x80, 0x1c,
+                             0xf6, 0x29, 0x7c, 0x0a, 0x5f, 0xea, 0x67, 0xb7};
+
+// Name of the executable file as well as the command line arg to use for Foil.
+const wchar_t kChromeRecoveryExe[] = L"ChromeRecovery.exe";
+const char kChromeRecoveryArg[] = "/installsource swreporter";
+
+const int kDownloadCrxWaitTimeInMin = 2;
+const int kExecutionCrxWaitTimeInMin = 1;
+
+const HttpAgentFactory* current_http_agent_factory{nullptr};
+
+constexpr net::NetworkTrafficAnnotationTag kComponentDownloadTrafficAnnotation =
+    net::DefineNetworkTrafficAnnotation("download_recovery_component", R"(
+          semantics {
+            sender: "Chrome Cleanup"
+            description:
+              "Chrome on Windows is able to detect and remove software that "
+              "violates Google's Unwanted Software Policy "
+              "(https://www.google.com/about/unwanted-software-policy.html). "
+              "When potentially unwanted software is detected and the user "
+              "accepts Chrome's offer to remove it, as part of the cleanup "
+              "Chrome sends a request to Google to download the Chrome "
+              "Recovery component, which can repair the Chrome update system "
+              "to ensure that unwanted software does not block Chrome from "
+              "getting security updates."
+            trigger:
+              "The user either accepted a prompt to remove unwanted software, "
+              "or went to \"Clean up computer\" in the settings page and chose "
+              "to \"Find and remove harmful software\"."
+            data: "None"
+            destination: GOOGLE_OWNED_SERVICE
+          }
+          policy {
+            cookies_allowed: NO
+            setting:
+              "Chrome Cleanup is offered in \"Reset and clean up\" in settings "
+              "under Advanced and never happens without explicit user consent. "
+            chrome_policy {
+              ChromeCleanupEnabled {
+                ChromeCleanupEnabled: false
+              }
+            }
+          }
+          )");
+
+bool SaveHttpResponseDataToFile(const base::FilePath& file_path,
+                                chrome_cleaner::HttpResponse* response) {
+  base::File file(file_path,
+                  base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+
+  uint32_t count = RecoveryComponent::kReadDataFromResponseBufferSize;
+  std::vector<char> buffer(count);
+  while (true) {
+    if (!response->ReadData(buffer.data(), &count)) {
+      LOG(ERROR) << "ReadData failed";
+      return false;
+    } else if (!count) {
+      break;
+    }
+
+    if (file.WriteAtCurrentPos(buffer.data(), base::checked_cast<int>(count)) ==
+        -1) {
+      PLOG(ERROR) << "WriteAtCurrentPos";
+      return false;
+    }
+  }
+
+  return true;
+}
+
+const HttpAgentFactory* GetHttpAgentFactory() {
+  // This is "leaked" on purpose to avoid static destruction order woes.
+  // Neither HttpAgentFactory nor its parent classes dtors do any work.
+  static HttpAgentFactory* http_agent_factory = new HttpAgentFactory();
+
+  if (!current_http_agent_factory) {
+    current_http_agent_factory = http_agent_factory;
+  }
+
+  return current_http_agent_factory;
+}
+
+}  // namespace
+
+// static
+bool RecoveryComponent::IsAvailable() {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+// Only add the recovery component in official builds, unless it's forced, and
+// not if it's explicitly disabled.
+#if defined(CHROME_CLEANER_OFFICIAL_BUILD)
+  return !command_line->HasSwitch(kNoRecoveryComponentSwitch);
+#else
+  return command_line->HasSwitch(kForceRecoveryComponentSwitch);
+#endif
+}
+
+RecoveryComponent::RecoveryComponent()
+    : recovery_io_thread_("RecoveryComponentIO"),
+      done_expanding_crx_(base::WaitableEvent::ResetPolicy::MANUAL,
+                          base::WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+// static
+void RecoveryComponent::SetHttpAgentFactoryForTesting(
+    const HttpAgentFactory* factory) {
+  current_http_agent_factory = factory;
+}
+
+void RecoveryComponent::PreScan() {
+  bool success = recovery_io_thread_.StartWithOptions(
+      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
+  DCHECK(success) << "Can't start File Thread!";
+
+  recovery_io_thread_.task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&RecoveryComponent::FetchOnIOThread,
+                                base::Unretained(this)));
+}
+
+void RecoveryComponent::PostScan(const std::vector<UwSId>& found_pups) {
+  // If there won't be any cleanup, then run the recovery component now.
+  if (!PUPData::HasFlaggedPUP(found_pups, &PUPData::HasRemovalFlag)) {
+    Run();
+  }
+}
+
+void RecoveryComponent::PreCleanup() {}
+
+void RecoveryComponent::PostCleanup(ResultCode result_code,
+                                    RebooterAPI* rebooter) {
+  if (result_code == RESULT_CODE_PENDING_REBOOT) {
+    LOG(INFO) << "Not executing ChromeRecovery before reboot.";
+    return;
+  }
+  Run();
+}
+
+void RecoveryComponent::PostValidation(ResultCode result_code) {
+  PreScan();
+  Run();
+}
+
+void RecoveryComponent::Run() {
+  DCHECK(!ran_);
+  ran_ = true;
+  // We must make sure that the crx expansion is complete.
+  if (!done_expanding_crx_.TimedWait(
+          base::TimeDelta::FromMinutes(kDownloadCrxWaitTimeInMin))) {
+    LOG(WARNING) << "Timed out waiting for crx expansion completion.";
+    return;
+  }
+
+  if (!component_path_.IsValid()) {
+    LOG(WARNING) << "No access to the component path.";
+    return;
+  }
+
+  base::FilePath chrome_recovery(
+      component_path_.GetPath().Append(kChromeRecoveryExe));
+  DCHECK(base::PathExists(chrome_recovery));
+
+  base::CommandLine recovery_command_line(chrome_recovery);
+  recovery_command_line.AppendArg(kChromeRecoveryArg);
+  base::Process recovery_process =
+      base::LaunchProcess(recovery_command_line, base::LaunchOptions());
+  if (!recovery_process.IsValid()) {
+    LOG(WARNING) << "Failed to launch " << kChromeRecoveryExe << " "
+                 << kChromeRecoveryArg;
+    return;
+  }
+
+  int exit_code = -1;
+  bool success = recovery_process.WaitForExitWithTimeout(
+      base::TimeDelta::FromMinutes(kExecutionCrxWaitTimeInMin), &exit_code);
+  LOG_IF(INFO, success) << "ChromeRecovery returned code: " << exit_code;
+  PLOG_IF(ERROR, !success) << "ChromeRecovery failed to start in time.";
+}
+
+void RecoveryComponent::OnClose(ResultCode result_code) {}
+
+void RecoveryComponent::UnpackComponent(const base::FilePath& crx_file) {
+  std::vector<uint8_t> pk_hash;
+  pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]);
+
+  ComponentUnpacker unpacker(pk_hash, crx_file);
+  bool success = unpacker.Unpack(component_path_.GetPath());
+  DCHECK(success) << "Failed to unpack component.";
+}
+
+void RecoveryComponent::FetchOnIOThread() {
+  DCHECK_EQ(base::MessageLoop::current(), recovery_io_thread_.message_loop());
+  std::unique_ptr<chrome_cleaner::HttpAgent> http_agent =
+      GetHttpAgentFactory()->CreateHttpAgent();
+
+  LOG(INFO) << "Sending request to download Recovery Component.";
+  const GURL download_url(kComponentDownloadUrl);
+  std::unique_ptr<chrome_cleaner::HttpResponse> http_response = http_agent->Get(
+      base::UTF8ToWide(download_url.host()),
+      base::checked_cast<uint16_t>(download_url.EffectiveIntPort()),
+      base::UTF8ToWide(download_url.PathForRequest()),
+      download_url.SchemeIsCryptographic(),
+      L"",  // No extra headers.
+      kComponentDownloadTrafficAnnotation);
+
+  // Make sure to signal the event when this method returns.
+  base::ScopedClosureRunner set_event(
+      base::BindOnce(base::IgnoreResult(&base::WaitableEvent::Signal),
+                     base::Unretained(&done_expanding_crx_)));
+
+  if (!http_response.get()) {
+    LOG(WARNING) << "Recovery Component failed to download (no response)";
+    return;
+  }
+
+  uint16_t status_code = 0;
+  if (!http_response->GetStatusCode(&status_code) ||
+      status_code != static_cast<uint16_t>(HttpStatus::kOk)) {
+    LOG(WARNING) << "Recovery Component failed to download. Response: "
+                 << status_code;
+    return;
+  }
+
+  LOG(INFO) << "Recovery Component successfully downloaded.";
+
+  base::FilePath crx_file;
+  if (!base::CreateTemporaryFile(&crx_file)) {
+    LOG(ERROR) << "Failed to create temporary file to save crx";
+    return;
+  }
+
+  base::ScopedClosureRunner delete_file(
+      base::BindOnce(base::IgnoreResult(&base::DeleteFile), crx_file, false));
+
+  if (!SaveHttpResponseDataToFile(crx_file, http_response.get())) {
+    LOG(WARNING) << "Failed to save downloaded recovery component";
+    return;
+  }
+
+  if (component_path_.CreateUniqueTempDir())
+    UnpackComponent(crx_file);
+  else
+    NOTREACHED() << "Couldn't create a temp dir?";
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/components/recovery_component.h b/chrome/chrome_cleaner/components/recovery_component.h
new file mode 100644
index 0000000..cb58dee5
--- /dev/null
+++ b/chrome/chrome_cleaner/components/recovery_component.h
@@ -0,0 +1,80 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_CLEANER_COMPONENTS_RECOVERY_COMPONENT_H_
+#define CHROME_CHROME_CLEANER_COMPONENTS_RECOVERY_COMPONENT_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "chrome/chrome_cleaner/components/component_api.h"
+#include "url/gurl.h"
+
+namespace chrome_cleaner {
+
+class HttpAgentFactory;
+
+// This class starts downloading the recovery component before the scanner
+// starts, and it runs it after the cleaner completed, except if a reboot is
+// pending.
+class RecoveryComponent : public ComponentAPI {
+ public:
+  // Return true when the recovery component is available for the current build
+  // and command line flags combination.
+  static bool IsAvailable();
+
+  RecoveryComponent();
+  ~RecoveryComponent() override = default;
+
+  // Replace the HttpAgent factory with a new factory. Passing in an empty
+  // factory (nullptr) will reset to the default factory. Exposed so tests can
+  // create mock HttpAgent objects. This method is not thread-safe.
+  static void SetHttpAgentFactoryForTesting(const HttpAgentFactory* factory);
+
+  // ComponentAPI methods.
+  void PreScan() override;
+  void PostScan(const std::vector<UwSId>& found_pups) override;
+  void PreCleanup() override;
+  void PostCleanup(ResultCode result_code, RebooterAPI* rebooter) override;
+  void PostValidation(ResultCode result_code) override;
+  void OnClose(ResultCode result_code) override;
+
+  // Exposed for testing. The size of the buffer used when reading data from the
+  // response.
+  static const size_t kReadDataFromResponseBufferSize = 8192;
+
+ protected:
+  // Try to run the recovery component if it's ready, or wait for it. Protected
+  // virtual to test the logic of the public methods.
+  virtual void Run();
+
+  // A protected abstraction of the unpacking so that tests can override it.
+  virtual void UnpackComponent(const base::FilePath& crx_file);
+
+  // Return when |FetchOnIOThread| is done. Mainly used by tests.
+  void WaitForDoneExpandingCrxForTest() { done_expanding_crx_.Wait(); }
+
+ private:
+  // The fetch must be done on the IO thread as it's synchronous.
+  void FetchOnIOThread();
+
+  // Thread on which the recovery component is fetched, and the CRX is unpacked.
+  base::Thread recovery_io_thread_;
+
+  // Where the downloaded CRX was unzipped.
+  base::ScopedTempDir component_path_;
+
+  // Signaled when the expansion of the crx is complete.
+  base::WaitableEvent done_expanding_crx_;
+
+  // To check whether the component already ran or not.
+  bool ran_ = false;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_COMPONENTS_RECOVERY_COMPONENT_H_
diff --git a/chrome/chrome_cleaner/components/recovery_component_unittest.cc b/chrome/chrome_cleaner/components/recovery_component_unittest.cc
new file mode 100644
index 0000000..71ff18a
--- /dev/null
+++ b/chrome/chrome_cleaner/components/recovery_component_unittest.cc
@@ -0,0 +1,186 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/components/recovery_component.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/message_loop/message_loop.h"
+#include "base/test/test_simple_task_runner.h"
+#include "chrome/chrome_cleaner/http/mock_http_agent_factory.h"
+#include "chrome/chrome_cleaner/test/test_pup_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+const UwSId kRemovableUwSId = 42;
+const UwSId kReportOnlyUwSId = 21;
+
+}  // namespace
+
+class TestRecoveryComponent : public RecoveryComponent {
+ public:
+  TestRecoveryComponent() = default;
+
+  using RecoveryComponent::WaitForDoneExpandingCrxForTest;
+
+  bool run_called() const { return run_called_; }
+  bool unpack_component_called() const { return unpack_component_called_; }
+  const std::string& crx_file_contents() const { return crx_file_contents_; }
+
+ protected:
+  // RecoveryComponent.
+  void Run() override { run_called_ = true; }
+  void UnpackComponent(const base::FilePath& crx_file) override {
+    unpack_component_called_ = true;
+
+    if (base::PathExists(crx_file)) {
+      ASSERT_TRUE(base::ReadFileToString(crx_file, &crx_file_contents_));
+    }
+  }
+
+ private:
+  bool run_called_{false};
+  bool unpack_component_called_{false};
+  std::string crx_file_contents_;
+};
+
+class RecoveryComponentTest : public testing::Test {
+ public:
+  void SetUp() override {
+    RecoveryComponent::SetHttpAgentFactoryForTesting(factory_.get());
+  }
+
+  void TearDown() override {
+    RecoveryComponent::SetHttpAgentFactoryForTesting(nullptr);
+  }
+
+ protected:
+  RecoveryComponentTest() : task_runner_(new base::TestSimpleTaskRunner) {}
+
+  // A message loop is needed for the current task runner to be available.
+  base::MessageLoopForUI ui_message_loop_;
+
+  // The recover component under test. This declaration must be after the
+  // |ui_message_loop_| because the |RecoveryComponent| constructor needs
+  // a reference to the current run loop.
+  TestRecoveryComponent recovery_component_;
+
+  // A task runner and a URL fetcher factory are necessary to test URL requests.
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+
+  MockHttpAgentConfig config_;
+  std::unique_ptr<HttpAgentFactory> factory_{
+      std::make_unique<MockHttpAgentFactory>(&config_)};
+};
+
+TEST_F(RecoveryComponentTest, Success) {
+  MockHttpAgentConfig::Calls calls(HttpStatus::kOk);
+  config_.AddCalls(calls);
+
+  recovery_component_.PreScan();
+  recovery_component_.WaitForDoneExpandingCrxForTest();
+  EXPECT_TRUE(recovery_component_.unpack_component_called());
+}
+
+TEST_F(RecoveryComponentTest, Failure) {
+  MockHttpAgentConfig::Calls calls(HttpStatus::kOk);
+  calls.request_succeeds = false;
+  config_.AddCalls(calls);
+
+  recovery_component_.PreScan();
+  recovery_component_.WaitForDoneExpandingCrxForTest();
+  EXPECT_FALSE(recovery_component_.unpack_component_called());
+}
+
+TEST_F(RecoveryComponentTest, CrxDataSavedToDisk) {
+  const std::string test_data = "test data";
+
+  MockHttpAgentConfig::Calls calls(HttpStatus::kOk);
+  calls.read_data_result = test_data;
+  config_.AddCalls(calls);
+
+  recovery_component_.PreScan();
+  recovery_component_.WaitForDoneExpandingCrxForTest();
+  EXPECT_TRUE(recovery_component_.unpack_component_called());
+  EXPECT_EQ(test_data, recovery_component_.crx_file_contents());
+}
+
+TEST_F(RecoveryComponentTest, CrxDataPartiallySavedToDisk) {
+  // Ensure the buffer is large enough, so a second buffer needs to be read.
+  const std::string test_data =
+      std::string(RecoveryComponent::kReadDataFromResponseBufferSize + 1, 'x');
+
+  MockHttpAgentConfig::Calls calls(HttpStatus::kOk);
+  calls.read_data_result = test_data;
+  calls.read_data_success_sequence.push_back(true);
+  calls.read_data_success_sequence.push_back(false);
+  config_.AddCalls(calls);
+
+  recovery_component_.PreScan();
+  recovery_component_.WaitForDoneExpandingCrxForTest();
+  EXPECT_FALSE(recovery_component_.unpack_component_called());
+}
+
+TEST_F(RecoveryComponentTest, RunCalledForRemovablePUP) {
+  const UwSId kRemovableUwSId = 42;
+  std::vector<UwSId> found_pups;
+  TestPUPData test_pup_data;
+
+  // When a removable PUP was found, the post scan shouldn't run, it should
+  // wait for the post-cleanup.
+  test_pup_data.AddPUP(kRemovableUwSId, PUPData::FLAGS_ACTION_REMOVE, nullptr,
+                       PUPData::kMaxFilesToRemoveSmallUwS);
+  found_pups.push_back(kRemovableUwSId);
+  recovery_component_.PostScan(found_pups);
+  EXPECT_FALSE(recovery_component_.run_called());
+  recovery_component_.PostCleanup(RESULT_CODE_SUCCESS, nullptr);
+  EXPECT_TRUE(recovery_component_.run_called());
+}
+
+TEST_F(RecoveryComponentTest, RunCalledForNoPUPs) {
+  std::vector<UwSId> found_pups;
+  TestPUPData test_pup_data;
+
+  // When no PUPs are found, the post scan should run, but not the post-cleanup.
+  found_pups.clear();
+  recovery_component_.PostScan(found_pups);
+  EXPECT_TRUE(recovery_component_.run_called());
+}
+
+TEST_F(RecoveryComponentTest, RunCalledForReportOnlyUwS) {
+  std::vector<UwSId> found_pups;
+  TestPUPData test_pup_data;
+
+  // When only report only PUPs are found, the post scan should run, but not the
+  // post-cleanup.
+  test_pup_data.AddPUP(kReportOnlyUwSId, PUPData::FLAGS_NONE, nullptr,
+                       PUPData::kMaxFilesToRemoveSmallUwS);
+  found_pups.push_back(kReportOnlyUwSId);
+  recovery_component_.PostScan(found_pups);
+  EXPECT_TRUE(recovery_component_.run_called());
+}
+
+TEST_F(RecoveryComponentTest, RunNotCalledPreReboot) {
+  std::vector<UwSId> found_pups;
+  TestPUPData test_pup_data;
+
+  // And finally, when a reboot will be needed, none should call run.
+  test_pup_data.AddPUP(kRemovableUwSId, PUPData::FLAGS_ACTION_REMOVE, nullptr,
+                       PUPData::kMaxFilesToRemoveSmallUwS);
+  found_pups.push_back(kRemovableUwSId);
+  recovery_component_.PostScan(found_pups);
+  EXPECT_FALSE(recovery_component_.run_called());
+  recovery_component_.PostCleanup(RESULT_CODE_PENDING_REBOOT, nullptr);
+  EXPECT_FALSE(recovery_component_.run_called());
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/components/system_report_component.cc b/chrome/chrome_cleaner/components/system_report_component.cc
new file mode 100644
index 0000000..fbb003e
--- /dev/null
+++ b/chrome/chrome_cleaner/components/system_report_component.cc
@@ -0,0 +1,835 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/components/system_report_component.h"
+
+#include <windows.h>
+
+#include <psapi.h>
+#include <stdint.h>
+#include <winhttp.h>
+#include <wrl/client.h>
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/command_line.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/process/process_iterator.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "base/win/registry.h"
+#include "base/win/scoped_bstr.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_variant.h"
+#include "base/win/windows_version.h"
+#include "chrome/chrome_cleaner/chrome_utils/chrome_util.h"
+#include "chrome/chrome_cleaner/chrome_utils/extensions_util.h"
+#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
+#include "chrome/chrome_cleaner/constants/common_registry_names.h"
+#include "chrome/chrome_cleaner/json_parser/json_parser_api.h"
+#include "chrome/chrome_cleaner/logging/logging_service_api.h"
+#include "chrome/chrome_cleaner/logging/proto/shared_data.pb.h"
+#include "chrome/chrome_cleaner/logging/scoped_timed_task_logger.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "chrome/chrome_cleaner/os/file_path_sanitization.h"
+#include "chrome/chrome_cleaner/os/layered_service_provider_wrapper.h"
+#include "chrome/chrome_cleaner/os/nt_internals.h"
+#include "chrome/chrome_cleaner/os/pre_fetched_paths.h"
+#include "chrome/chrome_cleaner/os/process.h"
+#include "chrome/chrome_cleaner/os/registry_util.h"
+#include "chrome/chrome_cleaner/os/scoped_disable_wow64_redirection.h"
+#include "chrome/chrome_cleaner/os/scoped_service_handle.h"
+#include "chrome/chrome_cleaner/os/system_util.h"
+#include "chrome/chrome_cleaner/os/system_util_cleaner.h"
+#include "chrome/chrome_cleaner/os/task_scheduler.h"
+#include "components/chrome_cleaner/public/constants/constants.h"
+
+using base::WaitableEvent;
+
+namespace chrome_cleaner {
+namespace {
+
+// The initial number of services when enumerating services.
+const unsigned int kInitialNumberOfServices = 100;
+
+const wchar_t kServicesKeyPath[] = L"system\\currentcontrolset\\services\\";
+
+const wchar_t kAbsolutePrefix[] = L"\\??\\";
+const wchar_t kSystemRootPrefix[] = L"\\systemroot\\";
+
+const wchar_t kNameServerPath[] =
+    L"system\\currentcontrolset\\services\\tcpip\\parameters\\interfaces";
+const wchar_t kNameServer[] = L"nameserver";
+
+const bool kHasFileInformation = true;
+const bool kNoFileInformation = false;
+
+struct RegistryKey {
+  HKEY hkey;
+  const wchar_t* key_path;
+};
+
+struct RegistryValue {
+  HKEY hkey;
+  const wchar_t* key_path;
+  const wchar_t* value_name;
+};
+
+const RegistryKey startup_registry_keys[] = {
+    {HKEY_LOCAL_MACHINE, L"software\\microsoft\\windows\\currentversion\\run"},
+    {HKEY_CURRENT_USER, L"software\\microsoft\\windows\\currentversion\\run"},
+    {HKEY_LOCAL_MACHINE,
+     L"software\\microsoft\\windows\\currentversion\\runonce"},
+    {HKEY_CURRENT_USER,
+     L"software\\microsoft\\windows\\currentversion\\runonce"},
+    {HKEY_LOCAL_MACHINE,
+     L"software\\microsoft\\windows\\currentversion\\runonceex"},
+    {HKEY_CURRENT_USER,
+     L"software\\microsoft\\windows\\currentversion\\runonceex"},
+    {HKEY_LOCAL_MACHINE,
+     L"software\\microsoft\\windows\\currentversion\\runservices"},
+    {HKEY_CURRENT_USER,
+     L"software\\microsoft\\windows\\currentversion\\runservices"},
+    {HKEY_LOCAL_MACHINE,
+     L"software\\microsoft\\windows\\currentversion\\runservicesonce"},
+    {HKEY_CURRENT_USER,
+     L"software\\microsoft\\windows\\currentversion\\runservicesonce"}};
+
+const RegistryValue system_path_values[] = {
+    {HKEY_LOCAL_MACHINE, L"system\\currentcontrolset\\control\\session manager",
+     L"bootexecute"},
+    {HKEY_LOCAL_MACHINE, L"system\\currentcontrolset\\control\\session manager",
+     L"setupexecute"},
+    {HKEY_LOCAL_MACHINE, kAppInitDllsKeyPath, kAppInitDllsValueName},
+    {HKEY_LOCAL_MACHINE, L"system\\currentcontrolset\\control\\session manager",
+     L"appcertdlls"}};
+
+const RegistryValue system_values[] = {
+    {HKEY_LOCAL_MACHINE,
+     L"software\\policies\\microsoft\\windows\\windowsupdate",
+     L"disablewindowsupdateaccess"}};
+
+const RegistryKey extension_policy_keys[] = {
+    {HKEY_LOCAL_MACHINE, kChromePoliciesWhitelistKeyPath},
+    {HKEY_CURRENT_USER, kChromePoliciesWhitelistKeyPath},
+    {HKEY_LOCAL_MACHINE, kChromePoliciesForcelistKeyPath},
+    {HKEY_CURRENT_USER, kChromePoliciesForcelistKeyPath},
+    {HKEY_LOCAL_MACHINE, kChromiumPoliciesWhitelistKeyPath},
+    {HKEY_CURRENT_USER, kChromiumPoliciesWhitelistKeyPath},
+    {HKEY_LOCAL_MACHINE, kChromiumPoliciesForcelistKeyPath},
+    {HKEY_CURRENT_USER, kChromiumPoliciesForcelistKeyPath}};
+
+const int64_t kParseAttemptTimeoutMilliseconds = 10000;
+
+// Expand an executable path as if the launch process directory was the
+// windows folder. This is used to resolve kernel module path.
+bool ExpandToAbsolutePathFromWindowsFolder(const base::FilePath& path,
+                                           base::FilePath* output) {
+  DCHECK(output);
+  if (path.IsAbsolute()) {
+    *output = path;
+    return true;
+  }
+
+  // Retrieve the system folder path.
+  base::FilePath system_folder =
+      PreFetchedPaths::GetInstance()->GetWindowsFolder();
+
+  base::FilePath absolute_path = system_folder.Append(path);
+  if (base::PathExists(absolute_path)) {
+    *output = absolute_path;
+    return true;
+  }
+
+  LOG(ERROR) << "Cannot determine absolute path: file does not exist.";
+  return false;
+}
+
+void RetrieveDetailedFileInformationFromCommandLine(
+    const base::string16& content,
+    internal::FileInformation* file_information,
+    bool* white_listed) {
+  // Handle the case where |content| contains only an executable path.
+  base::FilePath expanded_path(
+      ExtractExecutablePathFromRegistryContent(content));
+  if (base::PathExists(expanded_path)) {
+    RetrieveDetailedFileInformation(expanded_path, file_information,
+                                    white_listed);
+    return;
+  }
+
+  // Fallback using the original path.
+  RetrieveDetailedFileInformation(base::FilePath(content), file_information,
+                                  white_listed);
+}
+
+void ReportRegistryValue(const RegKeyPath& key_path,
+                         const wchar_t* name,
+                         const base::string16& content,
+                         bool has_file_information) {
+  DCHECK(name);
+  if (content.empty())
+    return;
+
+  internal::FileInformation file_information;
+  if (has_file_information) {
+    bool white_listed = false;
+    RetrieveDetailedFileInformationFromCommandLine(content, &file_information,
+                                                   &white_listed);
+    if (white_listed)
+      return;
+  }
+
+  internal::RegistryValue registry_value = {};
+  std::vector<internal::FileInformation> file_informations;
+  registry_value.key_path = key_path.FullPath();
+  registry_value.value_name = name;
+  registry_value.data = content;
+
+  if (has_file_information)
+    file_informations.push_back(file_information);
+
+  LoggingServiceAPI::GetInstance()->AddRegistryValue(registry_value,
+                                                     file_informations);
+}
+
+void ReportRegistryValues(const RegistryValue* report_data,
+                          size_t report_data_length,
+                          REGSAM access_mask,
+                          bool has_file_information) {
+  DCHECK(report_data);
+  for (size_t offset = 0; offset < report_data_length; ++offset) {
+    // Retrieve the content of the registry value.
+    base::string16 content;
+    const RegKeyPath key_path(report_data[offset].hkey,
+                              report_data[offset].key_path, access_mask);
+    RegistryError error;
+    if (!ReadRegistryValue(key_path, report_data[offset].value_name, &content,
+                           nullptr, &error)) {
+      LOG_IF(WARNING, error != RegistryError::VALUE_NOT_FOUND)
+          << "Failed to read string registry value: '" << key_path.FullPath()
+          << "\\" << report_data[offset].value_name << "', error: '"
+          << static_cast<int>(error) << "'.";
+      continue;
+    }
+    ReportRegistryValue(key_path, report_data[offset].value_name, content,
+                        has_file_information);
+  }
+}
+
+void ReportRegistryKeys(const RegistryKey* report_data,
+                        size_t length,
+                        REGSAM access_mask,
+                        bool has_file_information) {
+  DCHECK(report_data);
+  for (size_t offset = 0; offset < length; ++offset) {
+    // Enumerate values from the current registry key.
+    base::win::RegistryValueIterator values_it(
+        report_data[offset].hkey, report_data[offset].key_path, access_mask);
+    for (; values_it.Valid(); ++values_it) {
+      base::string16 content;
+      GetRegistryValueAsString(values_it.Value(), values_it.ValueSize(),
+                               values_it.Type(), &content);
+      RegKeyPath key_path(report_data[offset].hkey,
+                          report_data[offset].key_path);
+      ReportRegistryValue(
+          key_path, values_it.Name(), content,
+          // File information should only be text.
+          has_file_information && (values_it.Type() == REG_SZ ||
+                                   values_it.Type() == REG_EXPAND_SZ ||
+                                   values_it.Type() == REG_MULTI_SZ));
+    }
+  }
+}
+
+// Reports nameservers i.e.
+// system\currentcontrolset\services\tcpip\parameters\interfaces\*\nameserver
+void ReportNameServer(REGSAM access_mask) {
+  base::win::RegistryKeyIterator keys_it(HKEY_LOCAL_MACHINE, kNameServerPath,
+                                         access_mask);
+  // Check each key at this path.
+  for (; keys_it.Valid(); ++keys_it) {
+    const base::string16 full_path =
+        base::StrCat({kNameServerPath, L"\\", keys_it.Name()});
+
+    base::string16 content;
+    uint32_t content_type = REG_NONE;
+    const RegKeyPath nameserver_key_path(HKEY_LOCAL_MACHINE, full_path.c_str(),
+                                         access_mask);
+    // Check to see if this key has a nameserver value who's content is non
+    // empty.
+    if (!ReadRegistryValue(nameserver_key_path, kNameServer, &content,
+                           &content_type, nullptr) ||
+        content_type != REG_SZ || content.empty()) {
+      continue;
+    }
+
+    ReportRegistryValue(nameserver_key_path, kNameServer, content,
+                        kNoFileInformation);
+  }
+}
+
+void ReportAppInitDllsTargets(REGSAM access_mask) {
+  base::string16 content;
+  uint32_t content_type = REG_NONE;
+  const RegKeyPath appinit_dlls_key_path(HKEY_LOCAL_MACHINE,
+                                         kAppInitDllsKeyPath, access_mask);
+  if (!ReadRegistryValue(appinit_dlls_key_path, kAppInitDllsValueName, &content,
+                         &content_type, nullptr) ||
+      content_type != REG_SZ) {
+    return;
+  }
+
+  base::string16 delimiters(PUPData::kCommonDelimiters,
+                            PUPData::kCommonDelimitersLength);
+  std::vector<base::string16> entries = base::SplitString(
+      content, delimiters, base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+  bool white_listed = false;
+
+  internal::RegistryValue registry_value = {};
+  std::vector<internal::FileInformation> file_informations;
+  registry_value.key_path = appinit_dlls_key_path.FullPath();
+  registry_value.value_name = kAppInitDllsValueName;
+  registry_value.data = content;
+
+  for (const auto& entry : entries) {
+    base::string16 long_path;
+    ConvertToLongPath(entry, &long_path);
+    base::FilePath expanded_path(
+        ExpandEnvPathAndWow64Path(base::FilePath(long_path)));
+    internal::FileInformation file_information;
+    RetrieveDetailedFileInformation(expanded_path, &file_information,
+                                    &white_listed);
+    if (!white_listed)
+      file_informations.push_back(file_information);
+  }
+  LoggingServiceAPI::GetInstance()->AddRegistryValue(registry_value,
+                                                     file_informations);
+}
+
+void ReportRegistry(REGSAM access_mask) {
+  // Report on startup keys/values.
+  ReportRegistryKeys(startup_registry_keys, base::size(startup_registry_keys),
+                     access_mask, kHasFileInformation);
+  ReportRegistryValues(system_path_values, base::size(system_path_values),
+                       access_mask, kHasFileInformation);
+  ReportRegistryValues(system_values, base::size(system_values), access_mask,
+                       kNoFileInformation);
+
+  // Report on extension policy keys.
+  ReportRegistryKeys(extension_policy_keys, base::size(extension_policy_keys),
+                     access_mask, kNoFileInformation);
+  ReportAppInitDllsTargets(access_mask);
+  ReportNameServer(access_mask);
+}
+
+void ReportRegistry() {
+  ReportRegistry(KEY_WOW64_32KEY);
+  if (IsX64Architecture())
+    ReportRegistry(KEY_WOW64_64KEY);
+}
+
+void ReportFoldersUnderPath(const base::FilePath& path, const wchar_t* prefix) {
+  base::FileEnumerator folder_enum(path, false,
+                                   base::FileEnumerator::DIRECTORIES);
+  for (base::FilePath folder = folder_enum.Next(); !folder.empty();
+       folder = folder_enum.Next()) {
+    LoggingServiceAPI::GetInstance()->AddInstalledProgram(folder);
+  }
+}
+
+void ReportInstalledPrograms() {
+  static unsigned int install_paths[] = {
+      base::DIR_PROGRAM_FILES,     base::DIR_PROGRAM_FILESX86,
+      base::DIR_PROGRAM_FILES6432, base::DIR_APP_DATA,
+      base::DIR_LOCAL_APP_DATA,    base::DIR_COMMON_APP_DATA,
+  };
+  std::set<base::FilePath> path_processed;
+  for (size_t path = 0; path < base::size(install_paths); ++path) {
+    base::FilePath install_path;
+    bool success = base::PathService::Get(install_paths[path], &install_path);
+    if (!success) {
+      LOG(ERROR) << "Can't get path from PathService.";
+      continue;
+    }
+    if (path_processed.insert(install_path).second)
+      ReportFoldersUnderPath(install_path, L"Program:");
+  }
+}
+
+void ReportRunningProcesses() {
+  base::ProcessIterator iter(nullptr);
+  while (const base::ProcessEntry* entry = iter.NextProcessEntry()) {
+    base::win::ScopedHandle handle(
+        ::OpenProcess(PROCESS_QUERY_INFORMATION, false, entry->pid()));
+    base::string16 exec_path;
+    if (handle.IsValid() &&
+        GetProcessExecutablePath(handle.Get(), &exec_path)) {
+      internal::FileInformation file_information;
+      bool white_listed = false;
+      RetrieveDetailedFileInformation(base::FilePath(exec_path),
+                                      &file_information, &white_listed);
+      if (!white_listed) {
+        LoggingServiceAPI::GetInstance()->AddProcess(entry->exe_file(),
+                                                     file_information);
+      }
+    } else {
+      LOG(WARNING) << "Unable to query process: '" << entry->exe_file() << "'";
+    }
+  }
+}
+
+bool RetrieveExecutablePathFromPid(DWORD pid, base::FilePath* path) {
+  DCHECK(path);
+  base::win::ScopedHandle process_handle(
+      ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
+
+  base::string16 exe_path;
+  if (!GetProcessExecutablePath(process_handle.Get(), &exe_path))
+    return false;
+
+  *path = base::FilePath(exe_path);
+  return true;
+}
+
+bool RetrieveExecutablePathFromServiceName(const wchar_t* service_name,
+                                           base::FilePath* service_path) {
+  DCHECK(service_name);
+  DCHECK(service_path);
+  base::string16 subkey_path(kServicesKeyPath);
+  subkey_path += service_name;
+
+  base::string16 content;
+  if (!ReadRegistryValue(RegKeyPath(HKEY_LOCAL_MACHINE, subkey_path.c_str()),
+                         L"imagepath", &content, nullptr, nullptr)) {
+    return false;
+  }
+
+  base::FilePath file_path = base::FilePath(content);
+  // Convert a NT native form ("\Device\HarddiskVolumeXX\...") to the
+  // equivalent path that starts with a drive letter ("C:\...").
+  base::FilePath dos_file_path;
+  if (base::DevicePathToDriveLetterPath(file_path, &dos_file_path)) {
+    file_path = dos_file_path;
+  } else if (base::StartsWith(file_path.value(), kAbsolutePrefix,
+                              base::CompareCase::INSENSITIVE_ASCII)) {
+    // Remove the prefix "\??\" in front of the path.
+    file_path = base::FilePath(
+        file_path.value().substr(base::size(kAbsolutePrefix) - 1));
+  } else if (base::StartsWith(file_path.value(), kSystemRootPrefix,
+                              base::CompareCase::INSENSITIVE_ASCII)) {
+    // Remove the prefix "\systemroot\" in front of the path. The path
+    // will be resolved from the system folder.
+    file_path = base::FilePath(
+        file_path.value().substr(base::size(kSystemRootPrefix) - 1));
+  }
+
+  // For relative path, resolve them from %systemroot%.
+  base::FilePath absolute_file_path;
+  if (ExpandToAbsolutePathFromWindowsFolder(file_path, &absolute_file_path))
+    file_path = absolute_file_path;
+
+  *service_path = file_path;
+  return true;
+}
+
+void ReportRunningServices(DWORD services_type) {
+  ScopedScHandle service_manager;
+  service_manager.Set(::OpenSCManager(
+      nullptr, nullptr, SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT));
+  if (!service_manager.IsValid()) {
+    PLOG(ERROR) << "Cannot open service manager.";
+    return;
+  }
+
+  std::vector<uint8_t> buffer(kInitialNumberOfServices *
+                              sizeof(ENUM_SERVICE_STATUS_PROCESS));
+  ULONG number_of_service = 0;
+  while (true) {
+    ULONG more_bytes_needed = 0;
+    if (::EnumServicesStatusEx(service_manager.Get(), SC_ENUM_PROCESS_INFO,
+                               services_type, SERVICE_ACTIVE, &buffer[0],
+                               buffer.size(), &more_bytes_needed,
+                               &number_of_service, nullptr, nullptr) != FALSE) {
+      break;
+    }
+
+    if (::GetLastError() == ERROR_MORE_DATA) {
+      buffer.resize(buffer.size() + more_bytes_needed);
+    } else {
+      PLOG(ERROR) << "Cannot enumerate running services.";
+      return;
+    }
+  }
+
+  LPENUM_SERVICE_STATUS_PROCESS services =
+      reinterpret_cast<LPENUM_SERVICE_STATUS_PROCESS>(&buffer[0]);
+  for (size_t i = 0; i < number_of_service; i++) {
+    base::FilePath service_path;
+    bool service_found = false;
+    if (services[i].ServiceStatusProcess.dwProcessId != 0) {
+      service_found = RetrieveExecutablePathFromPid(
+          services[i].ServiceStatusProcess.dwProcessId, &service_path);
+    } else {
+      service_found = RetrieveExecutablePathFromServiceName(
+          services[i].lpServiceName, &service_path);
+    }
+    if (service_found) {
+      internal::FileInformation file_information;
+      bool white_listed = false;
+      RetrieveDetailedFileInformation(service_path, &file_information,
+                                      &white_listed);
+
+      if (!white_listed) {
+        LoggingServiceAPI::GetInstance()->AddService(services[i].lpDisplayName,
+                                                     services[i].lpServiceName,
+                                                     file_information);
+      }
+    }
+  }
+}
+
+void ReportScheduledTasks() {
+  std::unique_ptr<TaskScheduler> task_scheduler(
+      TaskScheduler::CreateInstance());
+  std::vector<base::string16> task_names;
+  if (!task_scheduler->GetTaskNameList(&task_names)) {
+    LOG(ERROR) << "Failed to enumerate scheduled tasks.";
+    return;
+  }
+
+  for (const auto& task_name : task_names) {
+    TaskScheduler::TaskInfo task_info;
+    if (!task_scheduler->GetTaskInfo(task_name.c_str(), &task_info)) {
+      LOG(ERROR) << "Failed to get info for task '" << task_name << "'";
+      continue;
+    }
+    std::vector<internal::FileInformation> actions;
+    for (size_t action = 0; action < task_info.exec_actions.size(); ++action) {
+      bool white_listed = false;
+      internal::FileInformation file_information;
+      RetrieveDetailedFileInformation(
+          task_info.exec_actions[action].application_path, &file_information,
+          &white_listed);
+      if (!white_listed)
+        actions.push_back(file_information);
+    }
+    LoggingServiceAPI::GetInstance()->AddScheduledTask(
+        task_name, task_info.description, actions);
+  }
+}
+
+// Report the file paths of all DLLs loaded into the process with |pid|. The
+// |prefix| is prepended to the log line to qualify the running process.
+// |paths_reported| contains already reported paths to avoid duplication.
+// Reported paths are added to |paths_reported|.
+void ReportLoadedModules(DWORD pid,
+                         const wchar_t* prefix,
+                         ModuleHost host,
+                         std::set<base::FilePath>* paths_reported) {
+  DCHECK(prefix);
+  DCHECK(paths_reported);
+  base::win::ScopedHandle snapshot(
+      ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid));
+  if (!snapshot.Get())
+    return;
+
+  MODULEENTRY32 module = {sizeof(module)};
+  if (!::Module32First(snapshot.Get(), &module))
+    return;
+
+  do {
+    base::FilePath file_path(module.szExePath);
+    if (!paths_reported->insert(file_path).second) {
+      // File details are already reported.
+      continue;
+    }
+
+    internal::FileInformation file_information;
+    bool white_listed = false;
+    RetrieveDetailedFileInformation(file_path, &file_information,
+                                    &white_listed);
+    if (!white_listed) {
+      LoggingServiceAPI::GetInstance()->AddLoadedModule(module.szModule, host,
+                                                        file_information);
+    }
+  } while (::Module32Next(snapshot.Get(), &module));
+}
+
+void ReportLoadedModulesOfCurrentProcess() {
+  std::set<base::FilePath> paths_reported;
+  ReportLoadedModules(::GetCurrentProcessId(), L"CCT",
+                      ModuleHost::CHROME_CLEANUP_TOOL, &paths_reported);
+}
+
+// Report the DLLs for every running process |executable|. DLLs are reported
+// only once.
+void ReportLoadedModulesOfRunningProcesses(const wchar_t* executable,
+                                           ModuleHost host) {
+  DCHECK(executable);
+
+  // |paths_reported| is used to avoid duplicate report of the same path for
+  // different running chrome processes.
+  std::set<base::FilePath> paths_reported;
+  base::NamedProcessIterator iter(executable, nullptr);
+  while (const base::ProcessEntry* entry = iter.NextProcessEntry())
+    ReportLoadedModules(entry->pid(), executable, host, &paths_reported);
+}
+
+void ReportLayeredServiceProviders() {
+  LSPPathToGUIDs providers;
+  GetLayeredServiceProviders(LayeredServiceProviderWrapper(), &providers);
+  for (LSPPathToGUIDs::const_iterator provider = providers.begin();
+       provider != providers.end(); ++provider) {
+    const base::FilePath& path = provider->first;
+
+    internal::FileInformation file_information;
+    bool white_listed = false;
+    RetrieveDetailedFileInformationFromCommandLine(
+        path.value(), &file_information, &white_listed);
+
+    if (!white_listed) {
+      std::vector<base::string16> logged_guids;
+      const std::set<GUID, GUIDLess>& guids = provider->second;
+      for (std::set<GUID, GUIDLess>::const_iterator guid = guids.begin();
+           guid != guids.end(); ++guid) {
+        base::string16 guid_str;
+        GUIDToString(*guid, &guid_str);
+        logged_guids.push_back(guid_str);
+      }
+      LoggingServiceAPI::GetInstance()->AddLayeredServiceProvider(
+          logged_guids, file_information);
+    }
+  }
+}
+
+void ReportProxySettingsInformation() {
+  // Retrieve the default Internet Explorer proxy configuration for the current
+  // user.
+  WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_proxy_info;
+  if (::WinHttpGetIEProxyConfigForCurrentUser(&ie_proxy_info)) {
+    // Report proxy information when it's not the default configuration.
+    if (ie_proxy_info.lpszProxy || ie_proxy_info.lpszProxyBypass ||
+        ie_proxy_info.lpszAutoConfigUrl || ie_proxy_info.fAutoDetect) {
+      base::string16 config =
+          (ie_proxy_info.lpszProxy ? ie_proxy_info.lpszProxy : L"");
+      base::string16 bypass =
+          (ie_proxy_info.lpszProxyBypass ? ie_proxy_info.lpszProxyBypass : L"");
+      base::string16 autoconfig =
+          (ie_proxy_info.lpszAutoConfigUrl ? ie_proxy_info.lpszAutoConfigUrl
+                                           : L"");
+      LoggingServiceAPI::GetInstance()->SetWinInetProxySettings(
+          config, bypass, autoconfig, ie_proxy_info.fAutoDetect != FALSE);
+    }
+
+    if (ie_proxy_info.lpszProxy)
+      ::GlobalFree(ie_proxy_info.lpszProxy);
+    if (ie_proxy_info.lpszProxyBypass)
+      ::GlobalFree(ie_proxy_info.lpszProxyBypass);
+    if (ie_proxy_info.lpszAutoConfigUrl)
+      ::GlobalFree(ie_proxy_info.lpszAutoConfigUrl);
+  }
+
+  // Retrieve the default WinHTTP proxy configuration from the registry.
+  WINHTTP_PROXY_INFO proxy_info;
+  if (::WinHttpGetDefaultProxyConfiguration(&proxy_info)) {
+    const char* access_type = nullptr;
+    switch (proxy_info.dwAccessType) {
+      case WINHTTP_ACCESS_TYPE_NO_PROXY:
+        access_type = "no proxy";
+        break;
+      case WINHTTP_ACCESS_TYPE_DEFAULT_PROXY:
+        access_type = "default proxy";
+        break;
+      case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
+        access_type = "named proxy";
+        break;
+      default:
+        access_type = "unknown";
+        break;
+    }
+
+    // Report proxy information when it's not the default configuration.
+    if (proxy_info.dwAccessType != WINHTTP_ACCESS_TYPE_NO_PROXY ||
+        proxy_info.lpszProxy || proxy_info.lpszProxyBypass) {
+      base::string16 config =
+          (proxy_info.lpszProxy ? proxy_info.lpszProxy : L"");
+      base::string16 bypass =
+          (proxy_info.lpszProxyBypass ? proxy_info.lpszProxyBypass : L"");
+      LoggingServiceAPI::GetInstance()->SetWinHttpProxySettings(config, bypass);
+    }
+
+    if (proxy_info.lpszProxy)
+      ::GlobalFree(proxy_info.lpszProxy);
+    if (proxy_info.lpszProxyBypass)
+      ::GlobalFree(proxy_info.lpszProxyBypass);
+  }
+}
+
+void ReportForcelistExtensions() {
+  std::vector<ExtensionPolicyRegistryEntry> policies;
+  GetExtensionForcelistRegistryPolicies(&policies);
+
+  for (const ExtensionPolicyRegistryEntry& policy : policies) {
+    LoggingServiceAPI::GetInstance()->AddInstalledExtension(
+        policy.extension_id,
+        ExtensionInstallMethod::POLICY_EXTENSION_FORCELIST);
+  }
+}
+
+void ReportInstalledExtensions(JsonParserAPI* json_parser) {
+  DCHECK(json_parser);
+  // TODO(proberge): Temporarily allowing syncing to avoid crashes in debug
+  // mode. This isn't catastrophic since the cleanup tool doesn't have a UI and
+  // the system report is collected at the end of the process. We also assert
+  // blocking is allowed here since it will block the thread.
+  base::AssertBlockingAllowed();
+  base::ScopedAllowBaseSyncPrimitivesForTesting allow_sync;
+
+  ReportForcelistExtensions();
+
+  std::vector<ExtensionPolicyRegistryEntry> extension_settings_policies;
+  WaitableEvent extension_settings_done(
+      WaitableEvent::ResetPolicy::MANUAL,
+      WaitableEvent::InitialState::NOT_SIGNALED);
+  GetExtensionSettingsForceInstalledExtensions(
+      json_parser, &extension_settings_policies, &extension_settings_done);
+
+  std::vector<ExtensionPolicyFile> master_preferences_policies;
+  WaitableEvent master_preferences_done(
+      WaitableEvent::ResetPolicy::MANUAL,
+      WaitableEvent::InitialState::NOT_SIGNALED);
+  GetMasterPreferencesExtensions(json_parser, &master_preferences_policies,
+                                 &master_preferences_done);
+
+  std::vector<ExtensionPolicyFile> default_extension_policies;
+  WaitableEvent default_extensions_done(
+      WaitableEvent::ResetPolicy::MANUAL,
+      WaitableEvent::InitialState::NOT_SIGNALED);
+  GetNonWhitelistedDefaultExtensions(json_parser, &default_extension_policies,
+                                     &default_extensions_done);
+
+  // Wait for all asynchronous parsing to be done
+  const base::TimeTicks end_time =
+      base::TimeTicks::Now() +
+      base::TimeDelta::FromMilliseconds(kParseAttemptTimeoutMilliseconds);
+  extension_settings_done.TimedWaitUntil(end_time);
+  master_preferences_done.TimedWaitUntil(end_time);
+  default_extensions_done.TimedWaitUntil(end_time);
+
+  // Log extensions that were found
+  for (const ExtensionPolicyRegistryEntry& policy : extension_settings_policies)
+    LoggingServiceAPI::GetInstance()->AddInstalledExtension(
+        policy.extension_id, ExtensionInstallMethod::POLICY_EXTENSION_SETTINGS);
+
+  for (const ExtensionPolicyFile& policy : master_preferences_policies)
+    LoggingServiceAPI::GetInstance()->AddInstalledExtension(
+        policy.extension_id, ExtensionInstallMethod::POLICY_MASTER_PREFERENCES);
+
+  for (const ExtensionPolicyFile& policy : default_extension_policies)
+    LoggingServiceAPI::GetInstance()->AddInstalledExtension(
+        policy.extension_id, ExtensionInstallMethod::DEFAULT_APPS_EXTENSION);
+}
+
+}  // namespace
+
+SystemReportComponent::SystemReportComponent(JsonParserAPI* json_parser)
+    : created_report_(false), json_parser_(json_parser) {}
+
+void SystemReportComponent::PreScan() {}
+
+void SystemReportComponent::PostScan(const std::vector<UwSId>& found_pups) {
+  // If no removable UwS was found, we should collect the detailed system report
+  // now since there won't be a post-cleanup called.
+  if (found_pups.size() == 0 ||
+      !PUPData::HasFlaggedPUP(found_pups, &PUPData::HasRemovalFlag))
+    CreateFullSystemReport();
+}
+
+void SystemReportComponent::PreCleanup() {}
+
+void SystemReportComponent::PostCleanup(ResultCode result_code,
+                                        RebooterAPI* rebooter) {
+  // If the user cancels the cleanup, don't collect system information since the
+  // old UI quits without giving the user a chance to opt out of uploading this.
+  if (result_code == RESULT_CODE_CANCELED)
+    return;
+
+  CreateFullSystemReport();
+}
+
+void SystemReportComponent::PostValidation(ResultCode result_code) {}
+
+void SystemReportComponent::OnClose(ResultCode result_code) {}
+
+void SystemReportComponent::CreateFullSystemReport() {
+  LoggingServiceAPI* logging_service = LoggingServiceAPI::GetInstance();
+
+  // Don't collect a system report if we've already collected one
+  if (created_report_)
+    return;
+
+  // Don't collect a system report if logs won't be uploaded.
+  if (!logging_service->uploads_enabled()) {
+    // TODO(proberge): Remove this by EOQ4 2018.
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(kDumpRawLogsSwitch)) {
+      ReportInstalledExtensions(json_parser_);
+      created_report_ = true;
+    }
+
+    return;
+  }
+
+  logging_service->SetDetailedSystemReport(true);
+
+  ScopedTimedTaskLogger scoped_timed_task_logger(
+      "Logging detailed system report");
+  // Make sure this process has the debug privilege to allow opening more
+  // running processes. If we have to obtain it, be sure to drop it again to
+  // leave the system in the state we found it. Some unit tests depend on not
+  // having debug privileges.
+  base::ScopedClosureRunner release_debug_rights;
+  if (!HasDebugRightsPrivileges() && AcquireDebugRightsPrivileges()) {
+    release_debug_rights.ReplaceClosure(
+        base::BindOnce(base::IgnoreResult(&ReleaseDebugRightsPrivileges)));
+  }
+
+  ReportLoadedModulesOfCurrentProcess();
+  ReportLoadedModulesOfRunningProcesses(L"chrome.exe", ModuleHost::CHROME);
+  ReportRunningProcesses();
+  ReportRunningServices(SERVICE_WIN32);
+  {
+    // The wow64 redirection must be disabled because path are reported as
+    // viewed by the kernel.
+    ScopedDisableWow64Redirection wow64_disabled;
+    ReportRunningServices(SERVICE_DRIVER);
+  }
+  ReportRegistry();
+  ReportScheduledTasks();
+  ReportInstalledPrograms();
+  ReportLayeredServiceProviders();
+  ReportProxySettingsInformation();
+  ReportInstalledExtensions(json_parser_);
+
+  created_report_ = true;
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/components/system_report_component.h b/chrome/chrome_cleaner/components/system_report_component.h
new file mode 100644
index 0000000..4ec3665
--- /dev/null
+++ b/chrome/chrome_cleaner/components/system_report_component.h
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_CLEANER_COMPONENTS_SYSTEM_REPORT_COMPONENT_H_
+#define CHROME_CHROME_CLEANER_COMPONENTS_SYSTEM_REPORT_COMPONENT_H_
+
+#include <vector>
+
+#include "chrome/chrome_cleaner/components/component_api.h"
+#include "chrome/chrome_cleaner/json_parser/json_parser_api.h"
+
+namespace chrome_cleaner {
+
+// This class manages the production of a system information report.
+class SystemReportComponent : public ComponentAPI {
+ public:
+  explicit SystemReportComponent(JsonParserAPI* json_parser);
+
+  // ComponentAPI methods.
+  void PreScan() override;
+  void PostScan(const std::vector<UwSId>& found_pups) override;
+  void PreCleanup() override;
+  void PostCleanup(ResultCode result_code, RebooterAPI* rebooter) override;
+  void PostValidation(ResultCode result_code) override;
+  void OnClose(ResultCode result_code) override;
+
+  void CreateFullSystemReport();
+
+  // Only exposed for tests.
+  bool created_report() { return created_report_; }
+
+ private:
+  bool created_report_;
+  JsonParserAPI* json_parser_;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_COMPONENTS_SYSTEM_REPORT_COMPONENT_H_
diff --git a/chrome/chrome_cleaner/components/system_report_component_unittest.cc b/chrome/chrome_cleaner/components/system_report_component_unittest.cc
new file mode 100644
index 0000000..e3244778
--- /dev/null
+++ b/chrome/chrome_cleaner/components/system_report_component_unittest.cc
@@ -0,0 +1,601 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/components/system_report_component.h"
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/lazy_instance.h"
+#include "base/path_service.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_command_line.h"
+#include "base/test/scoped_path_override.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/test/test_timeouts.h"
+#include "base/win/registry.h"
+#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
+#include "chrome/chrome_cleaner/constants/uws_id.h"
+#include "chrome/chrome_cleaner/json_parser/test_json_parser.h"
+#include "chrome/chrome_cleaner/logging/cleaner_logging_service.h"
+#include "chrome/chrome_cleaner/logging/logging_service_api.h"
+#include "chrome/chrome_cleaner/logging/proto/chrome_cleaner_report.pb.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "chrome/chrome_cleaner/os/file_path_sanitization.h"
+#include "chrome/chrome_cleaner/os/pre_fetched_paths.h"
+#include "chrome/chrome_cleaner/os/registry_util.h"
+#include "chrome/chrome_cleaner/test/test_file_util.h"
+#include "chrome/chrome_cleaner/test/test_pup_data.h"
+#include "chrome/chrome_cleaner/test/test_util.h"
+#include "components/chrome_cleaner/public/constants/constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_cleaner {
+namespace {
+
+using google::protobuf::RepeatedPtrField;
+using InstalledExtension =
+    ChromeCleanerReport::SystemReport::InstalledExtension;
+using base::WaitableEvent;
+
+const int kExtensionIdLength = 32;
+
+const wchar_t kRunKeyPath[] =
+    L"software\\microsoft\\windows\\currentversion\\run";
+const wchar_t kRunTestName[] = L"test_chrome_cleanup_tool";
+const wchar_t kRunTestValue[] = L"chrome_cleanup_tool.exe";
+
+const wchar_t kNameServerKeyPath[] =
+    L"system\\currentcontrolset\\services\\tcpip\\parameters\\interfaces\\"
+    L"fishy";
+const wchar_t kNameServerName[] = L"nameserver";
+const wchar_t kNameServerValue[] = L"8.8.4.4";
+const wchar_t kFakeProgramFolder[] = L"FakeProgram";
+const char kFakeProgram[] = "FakeProgram";
+const wchar_t kFakeAppDataProgramFolder[] = L"FakeAppDataProgram";
+const char kFakeAppDataProgram[] = "FakeAppDataProgram";
+
+const char kExtensionPoliciesNonExistent[] =
+    "software\\policies\\google\\chrome\\";
+
+struct ReportTestData {
+  HKEY hkey;
+  const wchar_t* key_path;
+  const wchar_t* name;
+  const wchar_t* value;
+};
+
+const ReportTestData kExtensionPolicyEmpty{
+    HKEY_LOCAL_MACHINE, kChromePoliciesWhitelistKeyPath, L"test1", L""};
+
+constexpr base::char16 kTestExtensionId1[] =
+    L"ababababcdcdcdcdefefefefghghghgh";
+constexpr base::char16 kTestExtensionId1WithUpdateUrl[] =
+    L"ababababcdcdcdcdefefefefghghghgh;https://clients2.google.com/service/"
+    L"update2/crx";
+constexpr base::char16 kTestExtensionId2[] =
+    L"aaaabbbbccccddddeeeeffffgggghhhh";
+constexpr base::char16 kTestExtensionId2WithUpdateUrl[] =
+    L"aaaabbbbccccddddeeeeffffgggghhhh;https://clients2.google.com/service/"
+    L"update2/crx";
+
+const ReportTestData extension_policies[] = {
+    {HKEY_LOCAL_MACHINE, kChromePoliciesWhitelistKeyPath, L"test1",
+     kTestExtensionId1},
+    {HKEY_CURRENT_USER, kChromePoliciesWhitelistKeyPath, L"test2",
+     kTestExtensionId1},
+    {HKEY_LOCAL_MACHINE, kChromePoliciesForcelistKeyPath, L"test3",
+     kTestExtensionId2WithUpdateUrl},
+    {HKEY_CURRENT_USER, kChromePoliciesForcelistKeyPath, L"test4",
+     kTestExtensionId2WithUpdateUrl},
+    {HKEY_LOCAL_MACHINE, kChromiumPoliciesWhitelistKeyPath, L"test5",
+     kTestExtensionId1},
+    {HKEY_CURRENT_USER, kChromiumPoliciesWhitelistKeyPath, L"test6",
+     kTestExtensionId1},
+    {HKEY_LOCAL_MACHINE, kChromiumPoliciesForcelistKeyPath, L"test7",
+     kTestExtensionId2WithUpdateUrl},
+    {HKEY_CURRENT_USER, kChromiumPoliciesForcelistKeyPath, L"test8",
+     kTestExtensionId2WithUpdateUrl},
+};
+
+const ReportTestData extension_forcelist_policies[] = {
+    {HKEY_LOCAL_MACHINE, kChromePoliciesForcelistKeyPath, L"test1",
+     kTestExtensionId1WithUpdateUrl},
+    {HKEY_CURRENT_USER, kChromePoliciesForcelistKeyPath, L"test2",
+     kTestExtensionId2WithUpdateUrl},
+};
+
+const UwSId kFakePupId = 42;
+
+const wchar_t kFakeChromeFolder[] = L"google\\chrome\\application\\42.12.34.56";
+
+const char kDefaultExtensionsJson[] = R"(
+    {
+      "ababababcdcdcdcdefefefefghghghgh" : {
+        "external_update_url": "https://clients2.google.com/service/update2/crx"
+      },
+      "aaaabbbbccccddddeeeeffffgggghhhh" : {
+        "external_update_url": "https://clients2.google.com/service/update2/crx"
+      }
+    })";
+// Don't include the null-terminator in the length.
+const int kDefaultExtensionsJsonSize = sizeof(kDefaultExtensionsJson) - 1;
+
+// ExtensionSettings that has two force_installed extensions and two not.
+const wchar_t kExtensionSettingsJson[] =
+    LR"(
+    {
+      "ababababcdcdcdcdefefefefghghghgh": {
+        "installation_mode": "force_installed",
+        "update_url":"https://clients2.google.com/service/update2/crx"
+      },
+      "aaaabbbbccccddddeeeeffffgggghhhh": {
+        "installation_mode": "force_installed",
+        "update_url":"https://clients2.google.com/service/update2/crx"
+      },
+      "extensionwithinstallmodeblockeda": {
+        "installation_mode": "blocked",
+        "update_url":"https://clients2.google.com/service/update2/crx"
+      },
+      "extensionwithnosettingsabcdefghi": {}
+    })";
+const ReportTestData extension_settings_entry = {
+    HKEY_LOCAL_MACHINE, kChromePoliciesKeyPath, L"ExtensionSettings",
+    kExtensionSettingsJson};
+
+const wchar_t kChromeExePath[] = L"google\\chrome\\application";
+const wchar_t kMasterPreferencesFileName[] = L"master_preferences";
+const char kMasterPreferencesJson[] =
+    R"(
+    {
+      "homepage": "http://dev.chromium.org/",
+      "extensions": {
+        "settings": {
+          "ababababcdcdcdcdefefefefghghghgh": {
+            "location": 1,
+            "manifest": {
+              "name": "Test extension"
+            }
+          },
+          "aaaabbbbccccddddeeeeffffgggghhhh": {
+            "location": 1,
+            "manifest": {
+              "name": "Another one"
+            }
+          }
+        }
+      }
+    })";
+
+class SystemReportComponentTest : public testing::Test {
+ public:
+  SystemReportComponentTest() : component_(&json_parser_) {}
+
+  void SetUp() override {
+    cleaner_logging_service_ = CleanerLoggingService::GetInstance();
+    cleaner_logging_service_->Initialize(nullptr);
+    cleaner_logging_service_->EnableUploads(true, /*registry_logger=*/nullptr);
+    LoggingServiceAPI::SetInstanceForTesting(cleaner_logging_service_);
+    registry_override_.OverrideRegistry(HKEY_CURRENT_USER);
+    registry_override_.OverrideRegistry(HKEY_LOCAL_MACHINE);
+  }
+
+  void TearDown() override {
+    LoggingServiceAPI::SetInstanceForTesting(nullptr);
+    cleaner_logging_service_->Terminate();
+  }
+
+  ChromeCleanerReport GetChromeCleanerReport() {
+    ChromeCleanerReport report;
+    CHECK(report.ParseFromString(cleaner_logging_service_->RawReportContent()));
+    return report;
+  }
+
+  TestJsonParser json_parser_;
+  SystemReportComponent component_;
+  CleanerLoggingService* cleaner_logging_service_ = nullptr;
+  registry_util::RegistryOverrideManager registry_override_;
+};
+
+template <typename Component>
+bool SomeComponentContainsPath(const RepeatedPtrField<Component>& components,
+                               const base::FilePath& path) {
+  const std::string name = path.BaseName().MaybeAsASCII();
+  const std::string sanitized_path = base::UTF16ToUTF8(SanitizePath(path));
+  for (const auto component : components) {
+    if (component.name() == name &&
+        component.file_information().path() == sanitized_path) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool InstalledProgramCollected(
+    const RepeatedPtrField<ChromeCleanerReport::SystemReport::InstalledProgram>&
+        programs,
+    const std::string& folder_name) {
+  const std::string lower_case_folder_name = base::ToLowerASCII(folder_name);
+  for (const auto& program : programs) {
+    if (program.folder_information().path().find(lower_case_folder_name) !=
+        std::string::npos) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool RegistryEntryCollected(
+    const RepeatedPtrField<RegistryValue>& registry_values,
+    const std::string& key_path,
+    const std::string& value_name,
+    const std::string& data) {
+  for (const auto& registry_value : registry_values) {
+    if (StringContainsCaseInsensitive(registry_value.key_path(), key_path) &&
+        registry_value.value_name() == value_name &&
+        registry_value.data() == data) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool RegistryKeyCollected(
+    const RepeatedPtrField<RegistryValue>& registry_values,
+    const std::string& key_path) {
+  for (const auto& registry_value : registry_values) {
+    if (StringContainsCaseInsensitive(registry_value.key_path(), key_path))
+      return true;
+  }
+  return false;
+}
+
+// Returns whether |reported_extensions| contains an entry for an extension with
+// |extension_id| and |install_method|.
+bool InstalledExtensionReported(
+    const RepeatedPtrField<InstalledExtension>& reported_extensions,
+    const std::wstring& extension_id,
+    ExtensionInstallMethod install_method) {
+  for (const auto& installed_extension : reported_extensions) {
+    if (installed_extension.extension_id() == base::WideToUTF8(extension_id) &&
+        installed_extension.install_method() == install_method) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
+TEST_F(SystemReportComponentTest, PreScan_NoDetailedReport) {
+  component_.PreScan();
+  EXPECT_FALSE(component_.created_report());
+}
+
+TEST_F(SystemReportComponentTest, PostScanNoUwS_DetailedReport) {
+  std::vector<UwSId> found_pups;
+  component_.PostScan(found_pups);
+  EXPECT_TRUE(component_.created_report());
+}
+
+TEST_F(SystemReportComponentTest, PostScanNonRemovalableUwS_DetailedReport) {
+  TestPUPData test_pup_data;
+  test_pup_data.AddPUP(kFakePupId, PUPData::FLAGS_NONE, nullptr,
+                       PUPData::kMaxFilesToRemoveSmallUwS);
+  std::vector<UwSId> found_pups;
+  found_pups.push_back(kFakePupId);
+  component_.PostScan(found_pups);
+  EXPECT_TRUE(component_.created_report());
+}
+
+TEST_F(SystemReportComponentTest, PostScanRemovalableUwS_NoDetailedReport) {
+  TestPUPData test_pup_data;
+  test_pup_data.AddPUP(kFakePupId, PUPData::FLAGS_ACTION_REMOVE, nullptr,
+                       PUPData::kMaxFilesToRemoveSmallUwS);
+  std::vector<UwSId> found_pups;
+  found_pups.push_back(kFakePupId);
+  component_.PostScan(found_pups);
+  EXPECT_FALSE(component_.created_report());
+}
+
+TEST_F(SystemReportComponentTest, PreCleanup_NoDetailedReport) {
+  component_.PreCleanup();
+  EXPECT_FALSE(component_.created_report());
+}
+
+TEST_F(SystemReportComponentTest, PostCleanup_DetailedReport) {
+  component_.PostCleanup(RESULT_CODE_SUCCESS, nullptr);
+  EXPECT_TRUE(component_.created_report());
+}
+
+TEST_F(SystemReportComponentTest, PostCleanup_canceled_NoDetailedReport) {
+  component_.PostCleanup(RESULT_CODE_CANCELED, nullptr);
+  EXPECT_FALSE(component_.created_report());
+}
+
+TEST_F(SystemReportComponentTest, PostValidation_NoDetailedReport) {
+  component_.PostValidation(RESULT_CODE_SUCCESS);
+  EXPECT_FALSE(component_.created_report());
+}
+
+TEST_F(SystemReportComponentTest, OnClose_NoDetailedReport) {
+  component_.OnClose(RESULT_CODE_SUCCESS);
+  EXPECT_FALSE(component_.created_report());
+}
+
+TEST_F(SystemReportComponentTest, DisableUploads) {
+  cleaner_logging_service_->EnableUploads(false, nullptr);
+
+  component_.CreateFullSystemReport();
+  EXPECT_FALSE(component_.created_report());
+}
+
+TEST_F(SystemReportComponentTest, NoRepeatedCollections) {
+  component_.CreateFullSystemReport();
+  EXPECT_TRUE(component_.created_report());
+
+  // Clear the report and ensure it isn't populated again, since
+  // |created_report| is still true.
+  EXPECT_LT(0, GetChromeCleanerReport().system_report().processes_size());
+  cleaner_logging_service_->Terminate();
+  cleaner_logging_service_->Initialize(/*registry_logger=*/nullptr);
+  EXPECT_EQ(0, GetChromeCleanerReport().system_report().processes_size());
+  component_.CreateFullSystemReport();
+  EXPECT_EQ(0, GetChromeCleanerReport().system_report().processes_size());
+}
+
+TEST_F(SystemReportComponentTest, DetectFakePrograms) {
+  base::ScopedPathOverride program_files_override(base::DIR_PROGRAM_FILES);
+  base::FilePath program_files_dir;
+  ASSERT_TRUE(
+      base::PathService::Get(base::DIR_PROGRAM_FILES, &program_files_dir));
+
+  base::ScopedPathOverride appdata_override(base::DIR_LOCAL_APP_DATA);
+  base::FilePath appdata_dir;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_LOCAL_APP_DATA, &appdata_dir));
+
+  // Setup a fake program installation folder.
+  base::FilePath fake_program_dir(program_files_dir.Append(kFakeProgramFolder));
+  ASSERT_TRUE(base::CreateDirectoryAndGetError(fake_program_dir, nullptr));
+  ASSERT_TRUE(CreateFileInFolder(fake_program_dir, L"fake.exe"));
+
+  base::FilePath fake_appdata_dir(
+      appdata_dir.Append(kFakeAppDataProgramFolder));
+  ASSERT_TRUE(base::CreateDirectoryAndGetError(fake_appdata_dir, nullptr));
+  ASSERT_TRUE(CreateFileInFolder(fake_appdata_dir, L"fake.exe"));
+
+  // Setup a fake runonce keys.
+  base::win::RegKey run_once(HKEY_CURRENT_USER, kRunKeyPath, KEY_WRITE);
+  ASSERT_TRUE(run_once.Valid());
+  ASSERT_EQ(run_once.WriteValue(kRunTestName, kRunTestValue), ERROR_SUCCESS);
+
+  component_.CreateFullSystemReport();
+
+  ChromeCleanerReport report = GetChromeCleanerReport();
+  const auto& system_report = report.system_report();
+
+  const base::FilePath module_path =
+      PreFetchedPaths::GetInstance()->GetExecutablePath();
+  EXPECT_TRUE(
+      SomeComponentContainsPath(system_report.loaded_modules(), module_path));
+
+  EXPECT_TRUE(
+      SomeComponentContainsPath(system_report.processes(), module_path));
+
+  EXPECT_TRUE(RegistryEntryCollected(
+      system_report.registry_values(), base::UTF16ToASCII(kRunKeyPath),
+      base::UTF16ToASCII(kRunTestName), base::UTF16ToASCII(kRunTestValue)));
+
+  EXPECT_TRUE(InstalledProgramCollected(system_report.installed_programs(),
+                                        kFakeProgram));
+  EXPECT_TRUE(InstalledProgramCollected(system_report.installed_programs(),
+                                        kFakeAppDataProgram));
+}
+
+TEST_F(SystemReportComponentTest, ReportNameServer) {
+  // Setup a fake key that triggers nameserver check.
+  base::win::RegKey nameserver_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            nameserver_key.Create(HKEY_LOCAL_MACHINE, kNameServerKeyPath,
+                                  KEY_ALL_ACCESS));
+  ASSERT_TRUE(nameserver_key.Valid());
+  ASSERT_EQ(nameserver_key.WriteValue(kNameServerName, kNameServerValue),
+            ERROR_SUCCESS);
+
+  component_.CreateFullSystemReport();
+
+  EXPECT_TRUE(RegistryEntryCollected(
+      GetChromeCleanerReport().system_report().registry_values(),
+      base::UTF16ToASCII(kNameServerKeyPath),
+      base::UTF16ToASCII(kNameServerName),
+      base::UTF16ToASCII(kNameServerValue)));
+}
+
+TEST_F(SystemReportComponentTest, ReportNameServerBadValue) {
+  // Setup a fake key that triggers nameserver check.
+  base::win::RegKey nameserver_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            nameserver_key.Create(HKEY_LOCAL_MACHINE, kNameServerKeyPath,
+                                  KEY_ALL_ACCESS));
+  ASSERT_TRUE(nameserver_key.Valid());
+  ASSERT_EQ(nameserver_key.WriteValue(kNameServerName, L""), ERROR_SUCCESS);
+
+  component_.CreateFullSystemReport();
+
+  EXPECT_FALSE(RegistryKeyCollected(
+      GetChromeCleanerReport().system_report().registry_values(),
+      base::UTF16ToASCII(kNameServerKeyPath)));
+}
+
+TEST_F(SystemReportComponentTest, ReportNameServerNonExistent) {
+  component_.CreateFullSystemReport();
+
+  EXPECT_FALSE(RegistryKeyCollected(
+      GetChromeCleanerReport().system_report().registry_values(),
+      base::UTF16ToASCII(kNameServerKeyPath)));
+}
+
+TEST_F(SystemReportComponentTest, ReportExtensionPolicies) {
+  for (const auto& extension_policy : extension_policies) {
+    base::win::RegKey policy_key;
+    ASSERT_EQ(ERROR_SUCCESS,
+              policy_key.Create(extension_policy.hkey,
+                                extension_policy.key_path, KEY_ALL_ACCESS));
+    ASSERT_TRUE(policy_key.Valid());
+    ASSERT_EQ(
+        policy_key.WriteValue(extension_policy.name, extension_policy.value),
+        ERROR_SUCCESS);
+  }
+
+  component_.CreateFullSystemReport();
+
+  ChromeCleanerReport report = GetChromeCleanerReport();
+  const auto& system_report = report.system_report();
+  for (const auto& extension_policy : extension_policies) {
+    EXPECT_TRUE(
+        RegistryEntryCollected(system_report.registry_values(),
+                               base::UTF16ToASCII(extension_policy.key_path),
+                               base::UTF16ToASCII(extension_policy.name),
+                               base::UTF16ToASCII(extension_policy.value)));
+  }
+}
+
+TEST_F(SystemReportComponentTest, ReportExtensionPoliciesBadValue) {
+  base::win::RegKey policy_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            policy_key.Create(kExtensionPolicyEmpty.hkey,
+                              kExtensionPolicyEmpty.key_path, KEY_ALL_ACCESS));
+  ASSERT_TRUE(policy_key.Valid());
+  ASSERT_EQ(policy_key.WriteValue(kExtensionPolicyEmpty.name,
+                                  kExtensionPolicyEmpty.value),
+            ERROR_SUCCESS);
+  component_.CreateFullSystemReport();
+  EXPECT_FALSE(RegistryKeyCollected(
+      GetChromeCleanerReport().system_report().registry_values(),
+      base::UTF16ToASCII(kExtensionPolicyEmpty.key_path)));
+}
+
+TEST_F(SystemReportComponentTest, ReportExtensionPoliciesNonExistent) {
+  component_.CreateFullSystemReport();
+
+  EXPECT_FALSE(RegistryKeyCollected(
+      GetChromeCleanerReport().system_report().registry_values(),
+      kExtensionPoliciesNonExistent));
+}
+
+TEST_F(SystemReportComponentTest, ReportForcelistExtensions) {
+  for (const ReportTestData& policy : extension_forcelist_policies) {
+    base::win::RegKey policy_key;
+    ASSERT_EQ(ERROR_SUCCESS,
+              policy_key.Create(policy.hkey, policy.key_path, KEY_ALL_ACCESS));
+    ASSERT_TRUE(policy_key.Valid());
+    ASSERT_EQ(ERROR_SUCCESS, policy_key.WriteValue(policy.name, policy.value));
+  }
+
+  base::test::ScopedCommandLine scoped_command_line;
+  component_.CreateFullSystemReport();
+  ChromeCleanerReport report = GetChromeCleanerReport();
+
+  for (const ReportTestData& expected : extension_forcelist_policies) {
+    std::wstring policy_value(expected.value);
+    EXPECT_TRUE(InstalledExtensionReported(
+        report.system_report().installed_extensions(),
+        policy_value.substr(0, kExtensionIdLength),
+        ExtensionInstallMethod::POLICY_EXTENSION_FORCELIST));
+  }
+}
+
+TEST_F(SystemReportComponentTest, ReportDefaultExtensions) {
+  // Set up a fake default extensions JSON file.
+  base::ScopedPathOverride program_files_x86_override(
+      base::DIR_PROGRAM_FILESX86);
+  base::ScopedPathOverride program_files_override(base::DIR_PROGRAM_FILES);
+  base::FilePath program_files_dir;
+  ASSERT_TRUE(
+      base::PathService::Get(base::DIR_PROGRAM_FILES, &program_files_dir));
+
+  base::FilePath fake_apps_dir(
+      program_files_dir.Append(kFakeChromeFolder).Append(L"default_apps"));
+  ASSERT_TRUE(base::CreateDirectoryAndGetError(fake_apps_dir, nullptr));
+
+  base::FilePath default_extensions_file =
+      fake_apps_dir.Append(L"external_extensions.json");
+  CreateFileWithContent(default_extensions_file, kDefaultExtensionsJson,
+                        kDefaultExtensionsJsonSize);
+  ASSERT_TRUE(base::PathExists(default_extensions_file));
+
+  base::test::ScopedCommandLine scoped_command_line;
+  component_.CreateFullSystemReport();
+  ChromeCleanerReport report = GetChromeCleanerReport();
+
+  EXPECT_EQ(2, report.system_report().installed_extensions().size());
+  EXPECT_TRUE(InstalledExtensionReported(
+      report.system_report().installed_extensions(), kTestExtensionId1,
+      ExtensionInstallMethod::DEFAULT_APPS_EXTENSION));
+  EXPECT_TRUE(InstalledExtensionReported(
+      report.system_report().installed_extensions(), kTestExtensionId2,
+      ExtensionInstallMethod::DEFAULT_APPS_EXTENSION));
+}
+
+TEST_F(SystemReportComponentTest, ReportExtensionSettings) {
+  // Set up a fake ExtensionSettings registry key.
+  base::win::RegKey settings_key;
+  ASSERT_EQ(
+      ERROR_SUCCESS,
+      settings_key.Create(extension_settings_entry.hkey,
+                          extension_settings_entry.key_path, KEY_ALL_ACCESS));
+  DCHECK(settings_key.Valid());
+  ASSERT_EQ(ERROR_SUCCESS,
+            settings_key.WriteValue(extension_settings_entry.name,
+                                    extension_settings_entry.value));
+
+  base::test::ScopedCommandLine scoped_command_line;
+  component_.CreateFullSystemReport();
+  ChromeCleanerReport report = GetChromeCleanerReport();
+
+  EXPECT_TRUE(InstalledExtensionReported(
+      report.system_report().installed_extensions(), kTestExtensionId1,
+      ExtensionInstallMethod::POLICY_EXTENSION_SETTINGS));
+  EXPECT_TRUE(InstalledExtensionReported(
+      report.system_report().installed_extensions(), kTestExtensionId2,
+      ExtensionInstallMethod::POLICY_EXTENSION_SETTINGS));
+}
+
+TEST_F(SystemReportComponentTest, ReportMasterPreferencesExtensions) {
+  // Set up a fake master preferences file
+  base::ScopedPathOverride program_files_x86_override(
+      base::DIR_PROGRAM_FILESX86);
+  base::ScopedPathOverride program_files_override(base::DIR_PROGRAM_FILES);
+  base::FilePath program_files_dir;
+  ASSERT_TRUE(
+      base::PathService::Get(base::DIR_PROGRAM_FILES, &program_files_dir));
+
+  base::FilePath chrome_dir(program_files_dir.Append(kChromeExePath));
+  ASSERT_TRUE(base::CreateDirectoryAndGetError(chrome_dir, nullptr));
+
+  base::FilePath master_preferences =
+      chrome_dir.Append(kMasterPreferencesFileName);
+  CreateFileWithContent(master_preferences, kMasterPreferencesJson,
+                        sizeof(kMasterPreferencesJson) - 1);
+  ASSERT_TRUE(base::PathExists(master_preferences));
+
+  base::test::ScopedCommandLine scoped_command_line;
+  component_.CreateFullSystemReport();
+  ChromeCleanerReport report = GetChromeCleanerReport();
+
+  EXPECT_EQ(2, report.system_report().installed_extensions().size());
+  EXPECT_TRUE(InstalledExtensionReported(
+      report.system_report().installed_extensions(), kTestExtensionId1,
+      ExtensionInstallMethod::POLICY_MASTER_PREFERENCES));
+  EXPECT_TRUE(InstalledExtensionReported(
+      report.system_report().installed_extensions(), kTestExtensionId2,
+      ExtensionInstallMethod::POLICY_MASTER_PREFERENCES));
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/components/system_restore_point_component.cc b/chrome/chrome_cleaner/components/system_restore_point_component.cc
new file mode 100644
index 0000000..3128469f
--- /dev/null
+++ b/chrome/chrome_cleaner/components/system_restore_point_component.cc
@@ -0,0 +1,191 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/components/system_restore_point_component.h"
+
+#include <stdint.h>
+#include <windows.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/win/registry.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+const wchar_t* kSystemRestoreKey =
+    L"Software\\Microsoft\\Windows NT\\CurrentVersion\\SystemRestore";
+const wchar_t* kSystemRestoreFrequencyWin8 =
+    L"SystemRestorePointCreationFrequency";
+const int64_t kInvalidSequenceNumber = -1;
+// Name of the restore point library.
+const wchar_t kRestorePointClientLibrary[] = L"srclient.dll";
+
+}  // namespace
+
+namespace chrome_cleaner {
+
+SystemRestorePointComponent::SystemRestorePointComponent(
+    const base::string16& product_fullname)
+    : set_restore_point_info_fn_(nullptr),
+      remove_restore_point_info_fn_(nullptr),
+      sequence_number_(kInvalidSequenceNumber),
+      product_fullname_(product_fullname) {
+  base::NativeLibraryLoadError error;
+  srclient_dll_ = base::LoadNativeLibrary(
+      base::FilePath(kRestorePointClientLibrary), &error);
+  if (!srclient_dll_) {
+    PLOG(ERROR) << "Failed to load the restore point library, error="
+                << error.code;
+  } else {
+    // Force the DLL to stay loaded until program termination.
+    base::NativeLibrary module_handle = nullptr;
+    if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN,
+                              kRestorePointClientLibrary, &module_handle)) {
+      PLOG(ERROR) << "Failed to pin the restore point library.";
+      return;
+    }
+    DCHECK_EQ(srclient_dll_, module_handle);
+    set_restore_point_info_fn_ = reinterpret_cast<SetRestorePointInfoWFn>(
+        base::GetFunctionPointerFromNativeLibrary(srclient_dll_,
+                                                  "SRSetRestorePointW"));
+    remove_restore_point_info_fn_ = reinterpret_cast<RemoveRestorePointFn>(
+        base::GetFunctionPointerFromNativeLibrary(srclient_dll_,
+                                                  "SRRemoveRestorePoint"));
+  }
+
+  if (!set_restore_point_info_fn_)
+    LOG(ERROR) << "Unable to find System Restore Point library.";
+}
+
+void SystemRestorePointComponent::PreScan() {}
+
+void SystemRestorePointComponent::PostScan(
+    const std::vector<UwSId>& found_pups) {}
+
+void SystemRestorePointComponent::PreCleanup() {
+  // It is not ok to call SRSetRestorePoint recursively. Make sure this is the
+  // first call.
+  DCHECK_EQ(sequence_number_, kInvalidSequenceNumber);
+  if (!set_restore_point_info_fn_)
+    return;
+
+  // On Windows8, a registry value needs to be created in order for restore
+  // points to be deterministically created. Attempt to create this value, but
+  // continue with the restore point anyway even if doing so fails. See
+  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa378941.aspx for
+  // more information.
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+    base::win::RegKey system_restore_key(HKEY_LOCAL_MACHINE, kSystemRestoreKey,
+                                         KEY_SET_VALUE | KEY_QUERY_VALUE);
+    if (system_restore_key.Valid() &&
+        !system_restore_key.HasValue(kSystemRestoreFrequencyWin8)) {
+      system_restore_key.WriteValue(kSystemRestoreFrequencyWin8,
+                                    static_cast<DWORD>(0));
+    }
+  }
+
+  // Take a system restore point before doing anything else.
+  RESTOREPOINTINFO restore_point_spec = {};
+  STATEMGRSTATUS state_manager_status = {};
+
+  restore_point_spec.dwEventType = BEGIN_SYSTEM_CHANGE;
+  // MSDN documents few of the available values here. Use APPLICATION_INSTALL
+  // since that seems closest from the documented ones. The header file
+  // mentions a CHECKPOINT type which looks interesting, but let's stay on the
+  // beaten path for now.
+  restore_point_spec.dwRestorePtType = APPLICATION_INSTALL;
+  restore_point_spec.llSequenceNumber = 0;
+  wcsncpy(restore_point_spec.szDescription, product_fullname_.c_str(),
+          base::size(restore_point_spec.szDescription));
+
+  if (set_restore_point_info_fn_(&restore_point_spec, &state_manager_status)) {
+    sequence_number_ = state_manager_status.llSequenceNumber;
+  } else {
+    if (state_manager_status.nStatus == ERROR_SERVICE_DISABLED) {
+      LOG(WARNING) << "System Restore is disabled.";
+    } else {
+      LOG(ERROR) << "Failed to start System Restore service, error: "
+                 << state_manager_status.nStatus;
+    }
+  }
+}
+
+void SystemRestorePointComponent::PostCleanup(ResultCode result_code,
+                                              RebooterAPI* rebooter) {
+  if (!set_restore_point_info_fn_ || sequence_number_ == kInvalidSequenceNumber)
+    return;
+
+  RESTOREPOINTINFO restore_point_spec = {};
+  STATEMGRSTATUS state_manager_status = {};
+
+  restore_point_spec.dwEventType = END_SYSTEM_CHANGE;
+  restore_point_spec.llSequenceNumber = sequence_number_;
+
+  if (result_code == RESULT_CODE_SUCCESS ||
+      result_code == RESULT_CODE_PENDING_REBOOT ||
+      result_code == RESULT_CODE_POST_REBOOT_SUCCESS ||
+      result_code == RESULT_CODE_POST_REBOOT_ELEVATION_DENIED) {
+    // Success! For now... Commit the restore point.
+    restore_point_spec.dwRestorePtType = APPLICATION_INSTALL;
+
+    if (!SetRestorePointInfoWrapper(&restore_point_spec,
+                                    &state_manager_status)) {
+      LOG(ERROR) << "Failed to commit System Restore point, error: "
+                 << state_manager_status.nStatus;
+    }
+  } else {
+    // No mutations were made, either because we found nothing, the user
+    // canceled or an error occurred. Abort the restore point.
+    restore_point_spec.dwRestorePtType = CANCELLED_OPERATION;
+
+    if (!SetRestorePointInfoWrapper(&restore_point_spec,
+                                    &state_manager_status)) {
+      LOG(ERROR) << "Failed to cancel System Restore point, error: "
+                 << state_manager_status.nStatus;
+    }
+
+    // I have observed, at least on Win8, that cancelling the restore point
+    // still leaves it behind, so explicitly remove it as well.
+    if (remove_restore_point_info_fn_ &&
+        !RemoveRestorePointWrapper(sequence_number_)) {
+      LOG(ERROR) << "Failed to remove cancelled Restore point.";
+    }
+  }
+}
+
+void SystemRestorePointComponent::PostValidation(ResultCode result_code) {}
+
+void SystemRestorePointComponent::OnClose(ResultCode result_code) {}
+
+bool SystemRestorePointComponent::IsLoadedRestorePointLibrary() {
+  base::NativeLibrary module_handle = nullptr;
+  if (!::GetModuleHandleExW(0, kRestorePointClientLibrary, &module_handle)) {
+    PLOG(ERROR) << "Restore point library no longer present.";
+    return false;
+  }
+  DCHECK_EQ(srclient_dll_, module_handle);
+  return true;
+}
+
+bool SystemRestorePointComponent::SetRestorePointInfoWrapper(
+    PRESTOREPOINTINFOW info,
+    PSTATEMGRSTATUS status) {
+  if (!set_restore_point_info_fn_ ||
+      !SystemRestorePointComponent::IsLoadedRestorePointLibrary()) {
+    return false;
+  }
+  return set_restore_point_info_fn_(info, status) != FALSE;
+}
+
+bool SystemRestorePointComponent::RemoveRestorePointWrapper(DWORD sequence) {
+  if (!remove_restore_point_info_fn_ ||
+      !SystemRestorePointComponent::IsLoadedRestorePointLibrary()) {
+    return false;
+  }
+  return remove_restore_point_info_fn_(sequence) != FALSE;
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/components/system_restore_point_component.h b/chrome/chrome_cleaner/components/system_restore_point_component.h
new file mode 100644
index 0000000..d261f59
--- /dev/null
+++ b/chrome/chrome_cleaner/components/system_restore_point_component.h
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_CLEANER_COMPONENTS_SYSTEM_RESTORE_POINT_COMPONENT_H_
+#define CHROME_CHROME_CLEANER_COMPONENTS_SYSTEM_RESTORE_POINT_COMPONENT_H_
+
+#include <windows.h>
+
+#include <srrestoreptapi.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/native_library.h"
+#include "base/strings/string16.h"
+#include "chrome/chrome_cleaner/components/component_api.h"
+
+namespace chrome_cleaner {
+
+// This class manages the setting and clearing of a system restore point.
+class SystemRestorePointComponent : public ComponentAPI {
+ public:
+  explicit SystemRestorePointComponent(const base::string16& product_fullname);
+
+  // ComponentAPI methods.
+  void PreScan() override;
+  void PostScan(const std::vector<UwSId>& found_pups) override;
+  void PreCleanup() override;
+  void PostCleanup(ResultCode result_code, RebooterAPI* rebooter) override;
+  void PostValidation(ResultCode result_code) override;
+  void OnClose(ResultCode result_code) override;
+
+ protected:
+  // The below typedefs and members have protected visibility for testing.
+  typedef BOOL(WINAPI* SetRestorePointInfoWFn)(PRESTOREPOINTINFOW,
+                                               PSTATEMGRSTATUS);
+  typedef BOOL(WINAPI* RemoveRestorePointFn)(DWORD);
+
+  SetRestorePointInfoWFn set_restore_point_info_fn_;
+  RemoveRestorePointFn remove_restore_point_info_fn_;
+
+ private:
+  // Perform internal sanity checks to validate the presence of the restore
+  // point library.
+  bool IsLoadedRestorePointLibrary();
+  // Safe wrappers to dynamic calls to the restore point library.
+  bool SetRestorePointInfoWrapper(PRESTOREPOINTINFOW, PSTATEMGRSTATUS);
+  bool RemoveRestorePointWrapper(DWORD);
+
+  base::NativeLibrary srclient_dll_;
+  int64_t sequence_number_;
+  base::string16 product_fullname_;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_COMPONENTS_SYSTEM_RESTORE_POINT_COMPONENT_H_
diff --git a/chrome/chrome_cleaner/components/system_restore_point_component_unittest.cc b/chrome/chrome_cleaner/components/system_restore_point_component_unittest.cc
new file mode 100644
index 0000000..c013635
--- /dev/null
+++ b/chrome/chrome_cleaner/components/system_restore_point_component_unittest.cc
@@ -0,0 +1,127 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/components/system_restore_point_component.h"
+
+#include "base/synchronization/lock.h"
+#include "base/test/test_reg_util_win.h"
+#include "chrome/chrome_cleaner/test/test_branding.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// TODO(robertshield): Figure out how to test this. Near as I can tell the
+// only way to enumerate RestorePoints is via WMI, which is 12 kinds of ugh.
+
+namespace chrome_cleaner {
+
+namespace {
+
+constexpr DWORD kFakeSeqNumber = 42U;
+bool g_set_called = false;
+bool g_remove_called = false;
+
+base::Lock* SharedLock() {
+  static base::Lock lock;
+  return &lock;
+}
+
+BOOL WINAPI FakeSetRestorePointInfoWFn(RESTOREPOINTINFOW* restore_point_info,
+                                       STATEMGRSTATUS* state_mgr_status) {
+  state_mgr_status->llSequenceNumber = kFakeSeqNumber;
+  state_mgr_status->nStatus = 0;
+  g_set_called = true;
+  return true;
+}
+
+BOOL WINAPI FakeRemoveRestorePointFn(DWORD sequence_number) {
+  EXPECT_EQ(kFakeSeqNumber, sequence_number);
+  g_remove_called = true;
+  return true;
+}
+
+BOOL WINAPI
+FakeSetRestorePointInfoWFailFn(RESTOREPOINTINFOW* restore_point_info,
+                               STATEMGRSTATUS* state_mgr_status) {
+  state_mgr_status->llSequenceNumber = kFakeSeqNumber;
+  state_mgr_status->nStatus = 0;
+  g_set_called = true;
+  return false;
+}
+
+BOOL WINAPI FakeRemoveRestorePointFailFn(DWORD sequence_number) {
+  EXPECT_EQ(kFakeSeqNumber, sequence_number);
+  g_remove_called = true;
+  return false;
+}
+
+}  // namespace
+
+class TestSystemRestorePointComponent : public SystemRestorePointComponent {
+ public:
+  TestSystemRestorePointComponent()
+      : SystemRestorePointComponent(TEST_PRODUCT_FULLNAME_STRING) {}
+
+  void OverrideSetRestorePointInfoWFn(
+      SystemRestorePointComponent::SetRestorePointInfoWFn func) {
+    set_restore_point_info_fn_ = func;
+  }
+  void OverrideRemoveRestorePointFn(
+      SystemRestorePointComponent::RemoveRestorePointFn func) {
+    remove_restore_point_info_fn_ = func;
+  }
+};
+
+class SystemRestorePointComponentTest : public testing::Test {
+ protected:
+  SystemRestorePointComponentTest() : auto_lock_(*SharedLock()) {}
+
+  void SetUp() override {
+    system_restore_point_component_.OverrideSetRestorePointInfoWFn(
+        &FakeSetRestorePointInfoWFn);
+    system_restore_point_component_.OverrideRemoveRestorePointFn(
+        &FakeRemoveRestorePointFn);
+
+    registry_override_.OverrideRegistry(HKEY_LOCAL_MACHINE);
+    g_set_called = false;
+    g_remove_called = false;
+  }
+
+  base::AutoLock auto_lock_;
+
+  TestSystemRestorePointComponent system_restore_point_component_;
+  registry_util::RegistryOverrideManager registry_override_;
+};
+
+TEST_F(SystemRestorePointComponentTest, CheckRestoreCallsSuccess) {
+  system_restore_point_component_.PreCleanup();
+  system_restore_point_component_.PostCleanup(RESULT_CODE_SUCCESS, nullptr);
+  EXPECT_TRUE(g_set_called);
+  EXPECT_FALSE(g_remove_called);
+}
+
+TEST_F(SystemRestorePointComponentTest, CheckRestoreCallsFailure) {
+  system_restore_point_component_.PreCleanup();
+  system_restore_point_component_.PostCleanup(RESULT_CODE_FAILED, nullptr);
+  EXPECT_TRUE(g_set_called);
+  EXPECT_TRUE(g_remove_called);
+}
+
+TEST_F(SystemRestorePointComponentTest, CheckRestoreCallsRestorePointFailure) {
+  system_restore_point_component_.OverrideSetRestorePointInfoWFn(
+      &FakeSetRestorePointInfoWFailFn);
+  system_restore_point_component_.PreCleanup();
+  system_restore_point_component_.PostCleanup(RESULT_CODE_SUCCESS, nullptr);
+  EXPECT_TRUE(g_set_called);
+  EXPECT_FALSE(g_remove_called);
+}
+
+TEST_F(SystemRestorePointComponentTest, CheckRestoreCommitRestorePointFailure) {
+  system_restore_point_component_.OverrideRemoveRestorePointFn(
+      &FakeRemoveRestorePointFailFn);
+  system_restore_point_component_.PreCleanup();
+  system_restore_point_component_.PostCleanup(RESULT_CODE_FAILED, nullptr);
+  EXPECT_TRUE(g_set_called);
+  EXPECT_TRUE(g_remove_called);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/os/rebooter_api.h b/chrome/chrome_cleaner/os/rebooter_api.h
index 5e51681..4fa8d97 100644
--- a/chrome/chrome_cleaner/os/rebooter_api.h
+++ b/chrome/chrome_cleaner/os/rebooter_api.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/command_line.h"
 #include "components/chrome_cleaner/public/constants/constants.h"
 
 namespace chrome_cleaner {
diff --git a/chrome/chrome_cleaner/test/BUILD.gn b/chrome/chrome_cleaner/test/BUILD.gn
index 98aad55..37fc2f3 100644
--- a/chrome/chrome_cleaner/test/BUILD.gn
+++ b/chrome/chrome_cleaner/test/BUILD.gn
@@ -33,6 +33,20 @@
   ]
 }
 
+source_set("test_component") {
+  testonly = true
+
+  sources = [
+    "test_component.cc",
+    "test_component.h",
+  ]
+
+  deps = [
+    "//chrome/chrome_cleaner/components:components",
+    "//chrome/chrome_cleaner/constants:uws_id",
+  ]
+}
+
 source_set("test_executables") {
   testonly = true
 
diff --git a/chrome/chrome_cleaner/test/test_component.cc b/chrome/chrome_cleaner/test/test_component.cc
new file mode 100644
index 0000000..a6a20f4
--- /dev/null
+++ b/chrome/chrome_cleaner/test/test_component.cc
@@ -0,0 +1,44 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/test/test_component.h"
+
+namespace chrome_cleaner {
+
+TestComponent::Calls::Calls() = default;
+TestComponent::Calls::~Calls() = default;
+
+TestComponent::~TestComponent() {
+  calls_->destroyed = true;
+}
+
+void TestComponent::PreScan() {
+  calls_->pre_scan = true;
+}
+
+void TestComponent::PostScan(const std::vector<UwSId>& found_pups) {
+  calls_->post_scan = true;
+  calls_->post_scan_found_pups = found_pups;
+}
+
+void TestComponent::PreCleanup() {
+  calls_->pre_cleanup = true;
+}
+
+void TestComponent::PostCleanup(ResultCode result_code, RebooterAPI* rebooter) {
+  calls_->result_code = result_code;
+  calls_->post_cleanup = true;
+}
+
+void TestComponent::PostValidation(ResultCode result_code) {
+  calls_->result_code = result_code;
+  calls_->post_validation = true;
+}
+
+void TestComponent::OnClose(ResultCode result_code) {
+  calls_->result_code = result_code;
+  calls_->on_close = true;
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/test/test_component.h b/chrome/chrome_cleaner/test/test_component.h
new file mode 100644
index 0000000..0a0eada
--- /dev/null
+++ b/chrome/chrome_cleaner/test/test_component.h
@@ -0,0 +1,48 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_CLEANER_TEST_TEST_COMPONENT_H_
+#define CHROME_CHROME_CLEANER_TEST_TEST_COMPONENT_H_
+
+#include <vector>
+
+#include "chrome/chrome_cleaner/components/component_api.h"
+
+namespace chrome_cleaner {
+
+class TestComponent : public ComponentAPI {
+ public:
+  struct Calls {
+    Calls();
+    ~Calls();
+
+    bool pre_scan = false;
+    bool post_scan = false;
+    bool pre_cleanup = false;
+    bool post_cleanup = false;
+    bool post_validation = false;
+    bool on_close = false;
+    bool destroyed = false;
+    std::vector<UwSId> post_scan_found_pups;
+    ResultCode result_code = RESULT_CODE_INVALID;
+  };
+
+  explicit TestComponent(Calls* calls) : calls_(calls) {}
+  ~TestComponent() override;
+
+  // ComponentAPI.
+  void PreScan() override;
+  void PostScan(const std::vector<UwSId>& found_pups) override;
+  void PreCleanup() override;
+  void PostCleanup(ResultCode result_code, RebooterAPI* rebooter) override;
+  void PostValidation(ResultCode result_code) override;
+  void OnClose(ResultCode result_code) override;
+
+ private:
+  Calls* calls_;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_TEST_TEST_COMPONENT_H_
diff --git a/chrome/common/apps/platform_apps/api/BUILD.gn b/chrome/common/apps/platform_apps/api/BUILD.gn
index 0938bb8..027709b3 100644
--- a/chrome/common/apps/platform_apps/api/BUILD.gn
+++ b/chrome/common/apps/platform_apps/api/BUILD.gn
@@ -32,7 +32,7 @@
 # Private Targets
 
 generated_json_strings("generated_api_json_strings") {
-  sources = chrome_apps_api_schema_files
+  sources = chrome_apps_api_schema_files + chrome_apps_uncompiled_schema_files
   bundle_name = "ChromeApps"
   root_namespace = apps_api_root_namespace
   deps = [
diff --git a/chrome/common/apps/platform_apps/api/_api_features.json b/chrome/common/apps/platform_apps/api/_api_features.json
index 19c51f9..5878b6e 100644
--- a/chrome/common/apps/platform_apps/api/_api_features.json
+++ b/chrome/common/apps/platform_apps/api/_api_features.json
@@ -14,5 +14,9 @@
   "easyUnlockPrivate": {
     "dependencies": ["permission:easyUnlockPrivate"],
     "contexts": ["blessed_extension"]
+  },
+  "musicManagerPrivate": {
+    "dependencies": ["permission:musicManagerPrivate"],
+    "contexts": ["blessed_extension"]
   }
 }
diff --git a/chrome/common/apps/platform_apps/api/_permission_features.json b/chrome/common/apps/platform_apps/api/_permission_features.json
index 2e5469f..1b54c437 100644
--- a/chrome/common/apps/platform_apps/api/_permission_features.json
+++ b/chrome/common/apps/platform_apps/api/_permission_features.json
@@ -16,5 +16,18 @@
     "extension_types": ["platform_app"],
     "location": "component",
     "platforms": ["chromeos"]
+  },
+  "musicManagerPrivate": {
+    "channel": "stable",
+    "extension_types": ["platform_app"],
+    "whitelist": [
+      "4B1D0E19C6C43C008C44A8278C8B5BFE15ABEB3C", // Music Manager
+      "B8F61FD1B25DE03706DBB8906A73261E4DBB992A", // Test
+      "F7FA7ABC1ECB89BA8EE6656847EFABBF43BB9BCA",
+      "4FE45FA56EF6A25FDE8C302C44045CA9CE8A605A",
+      "3D14248405B8A59043420AAC160077C99E7788A9",
+      "A6C87307BBE5886CC5F1393025000E2FE8060BF2",
+      "3407516021EA3669C0EC8E65E6B9837E5A521B9C"
+    ]
   }
 }
diff --git a/chrome/common/apps/platform_apps/api/api_sources.gni b/chrome/common/apps/platform_apps/api/api_sources.gni
index dd8dcff..dd1b8472 100644
--- a/chrome/common/apps/platform_apps/api/api_sources.gni
+++ b/chrome/common/apps/platform_apps/api/api_sources.gni
@@ -13,7 +13,11 @@
   chrome_apps_api_schema_files_ += [ "easy_unlock_private.idl" ]
 }
 
+chrome_apps_uncompiled_schema_files_ = [ "music_manager_private.idl" ]
+
 chrome_apps_api_schema_files =
     get_path_info(chrome_apps_api_schema_files_, "abspath")
+chrome_apps_uncompiled_schema_files =
+    get_path_info(chrome_apps_uncompiled_schema_files_, "abspath")
 
 apps_api_root_namespace = "chrome_apps::api::%(namespace)s"
diff --git a/chrome/common/extensions/api/music_manager_private.idl b/chrome/common/apps/platform_apps/api/music_manager_private.idl
similarity index 100%
rename from chrome/common/extensions/api/music_manager_private.idl
rename to chrome/common/apps/platform_apps/api/music_manager_private.idl
diff --git a/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc b/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc
index 9afa445f..493be62a 100644
--- a/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc
+++ b/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc
@@ -13,6 +13,8 @@
 constexpr extensions::APIPermissionInfo::InitInfo permissions_to_register[] = {
     {extensions::APIPermission::kBrowser, "browser"},
     {extensions::APIPermission::kEasyUnlockPrivate, "easyUnlockPrivate"},
+    {extensions::APIPermission::kMusicManagerPrivate, "musicManagerPrivate",
+     extensions::APIPermissionInfo::kFlagCannotBeOptional},
 };
 
 }  // namespace
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 4c2b3ec0..6095648 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -588,10 +588,6 @@
     "channel": "stable",
     "matches": ["<all_urls>"]
   },
-  "musicManagerPrivate": {
-    "dependencies": ["permission:musicManagerPrivate"],
-    "contexts": ["blessed_extension"]
-  },
   "networking.castPrivate": {
     "channel": "stable",
     "contexts": ["blessed_extension"],
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index a0b761e..010832c4 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -566,19 +566,6 @@
     "channel": "stable",
     "extension_types": ["platform_app"]
   }],
-  "musicManagerPrivate": {
-    "channel": "stable",
-    "extension_types": ["platform_app"],
-    "whitelist": [
-      "4B1D0E19C6C43C008C44A8278C8B5BFE15ABEB3C", // Music Manager
-      "B8F61FD1B25DE03706DBB8906A73261E4DBB992A", // Test
-      "F7FA7ABC1ECB89BA8EE6656847EFABBF43BB9BCA",
-      "4FE45FA56EF6A25FDE8C302C44045CA9CE8A605A",
-      "3D14248405B8A59043420AAC160077C99E7788A9",
-      "A6C87307BBE5886CC5F1393025000E2FE8060BF2",
-      "3407516021EA3669C0EC8E65E6B9837E5A521B9C"
-    ]
-  },
   "notifications": {
     // The chrome.notifications functionality listed in notifications.idl is
     // available only to extension/platform_app types. The implementation of
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni
index 7abf8a9b..97f8b43e 100644
--- a/chrome/common/extensions/api/api_sources.gni
+++ b/chrome/common/extensions/api/api_sources.gni
@@ -136,7 +136,6 @@
   "browsing_data.json",
   "extension.json",
   "idltest.idl",
-  "music_manager_private.idl",
   "top_sites.json",
 ]
 
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl
index e3ff3d8a..a7d8e6a 100644
--- a/chrome/common/extensions/api/autotest_private.idl
+++ b/chrome/common/extensions/api/autotest_private.idl
@@ -104,6 +104,8 @@
 
   callback IsAppShownCallback = void (boolean appShown);
 
+  callback TakeScreenshotCallback = void (DOMString base64Png);
+
   callback VoidCallback = void ();
 
   interface Functions {
@@ -208,6 +210,9 @@
     // |callback|: Called when the operation has completed.
     static void setCrostiniEnabled(boolean enabled, VoidCallback callback);
 
+    // Takes a screenshot and returns the data in base64 encoded PNG format.
+    static void takeScreenshot(TakeScreenshotCallback callback);
+
     // Makes a basic request to ML Service, triggering 1. ML Service
     // daemon startup, and 2. the initial D-Bus -> Mojo IPC bootstrap.
     // |callback|: Called when the operation has completed.
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index 0bf08a2..d9bbc2f 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -125,8 +125,6 @@
      APIPermissionInfo::kFlagCannotBeOptional},
     {APIPermission::kMediaRouterPrivate, "mediaRouterPrivate",
      APIPermissionInfo::kFlagCannotBeOptional},
-    {APIPermission::kMusicManagerPrivate, "musicManagerPrivate",
-     APIPermissionInfo::kFlagCannotBeOptional},
     {APIPermission::kNetworkingCastPrivate, "networking.castPrivate"},
     {APIPermission::kPreferencesPrivate, "preferencesPrivate",
      APIPermissionInfo::kFlagCannotBeOptional},
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index aba2ebe..826469f3c 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -829,19 +829,6 @@
 // system volume, and higher than 1.0 is louder.
 const char kTextToSpeechVolume[] = "settings.tts.speech_volume";
 
-// This is a timestamp to keep track of the screen start time when a unichrome
-// user starts using the device for the first time of the day. Used to calculate
-// the screen time limit and this will be refreshed daily.
-const char kFirstScreenStartTime[] = "screen_time.first_screen.start_time";
-
-// This is a timestamp to keep track of the screen start time for the current
-// active screen. The pref is used to restore the screen start time after
-// browser crashes and device reboots.
-const char kCurrentScreenStartTime[] = "screen_time.current_screen.start_time";
-
-// How much screen time in minutes has been used.
-const char kScreenTimeMinutesUsed[] = "screen_time.time_usage";
-
 // A dictionary preference holding the usage time limit definitions for a user.
 const char kUsageTimeLimit[] = "screen_time.limit";
 
@@ -873,6 +860,15 @@
 const char kNetBiosShareDiscoveryEnabled[] =
     "network_file_shares.netbios_discovery.enabled";
 
+// Amount of screen time that a child user has used in the current day.
+const char kChildScreenTimeMilliseconds[] = "child_screen_time";
+
+// Last time the kChildScreenTimeMilliseconds was saved.
+const char kLastChildScreenTimeSaved[] = "last_child_screen_time_saved";
+
+// Last time that the kChildScreenTime pref was reset.
+const char kLastChildScreenTimeReset[] = "last_child_screen_time_reset";
+
 #endif  // defined(OS_CHROMEOS)
 
 // A boolean pref set to true if a Home button to open the Home pages should be
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 6ba77e8..ad0e63f 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -270,9 +270,6 @@
 extern const char kTextToSpeechRate[];
 extern const char kTextToSpeechPitch[];
 extern const char kTextToSpeechVolume[];
-extern const char kFirstScreenStartTime[];
-extern const char kCurrentScreenStartTime[];
-extern const char kScreenTimeMinutesUsed[];
 extern const char kUsageTimeLimit[];
 extern const char kScreenTimeLastState[];
 extern const char kEnableSyncConsent[];
@@ -280,6 +277,9 @@
 extern const char kManagedSessionEnabled[];
 extern const char kTPMFirmwareUpdateCleanupDismissed[];
 extern const char kNetBiosShareDiscoveryEnabled[];
+extern const char kChildScreenTimeMilliseconds[];
+extern const char kLastChildScreenTimeSaved[];
+extern const char kLastChildScreenTimeReset[];
 #endif  // defined(OS_CHROMEOS)
 extern const char kShowHomeButton[];
 extern const char kSpeechRecognitionFilterProfanities[];
diff --git a/chrome/common/secure_origin_whitelist.cc b/chrome/common/secure_origin_whitelist.cc
index 3319df1..b70d6ce 100644
--- a/chrome/common/secure_origin_whitelist.cc
+++ b/chrome/common/secure_origin_whitelist.cc
@@ -126,7 +126,7 @@
 
     // Drop .unique() origins, as they are unequal to any other origins.
     url::Origin origin(url::Origin::Create(GURL(origin_str)));
-    if (!origin.unique())
+    if (!origin.opaque())
       origin_patterns.push_back(origin.Serialize());
   }
 
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 7a1395c..cfaf2746 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -316,6 +316,9 @@
 
 const char kTimeZoneSettingsLearnMoreURL[] =
     "https://support.google.com/chromebook?p=chromebook_timezone&hl=%s";
+
+const char kSmbSharesLearnMoreURL[] =
+    "https://support.google.com/chromebook?p=network_file_shares";
 #endif  // defined(OS_CHROMEOS)
 
 #if defined(OS_MACOSX)
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 7ddffa8e..5e3098f 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -273,6 +273,9 @@
 
 // The URL for the "Learn more" page for the time zone settings page.
 extern const char kTimeZoneSettingsLearnMoreURL[];
+
+// The URL for the "Learn more" page for the network file shares settings page.
+extern const char kSmbSharesLearnMoreURL[];
 #endif  // defined(OS_CHROMEOS)
 
 #if defined(OS_MACOSX)
diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc
index 3c538c9..6901a9d 100644
--- a/chrome/renderer/content_settings_observer.cc
+++ b/chrome/renderer/content_settings_observer.cc
@@ -65,7 +65,7 @@
   // TODO(alexmos): This is broken for --site-per-process, since top() can be a
   // WebRemoteFrame which does not have a document(), and the WebRemoteFrame's
   // URL is not replicated.  See https://crbug.com/628759.
-  if (top_origin.unique() && frame->Top()->IsWebLocalFrame())
+  if (top_origin.opaque() && frame->Top()->IsWebLocalFrame())
     return frame->Top()->ToWebLocalFrame()->GetDocument().Url();
   return top_origin.GetURL();
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 252ed9d..6e7bb4c 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1203,6 +1203,7 @@
       sources += [
         "../browser/accessibility/accessibility_extension_api_browsertest.cc",
         "../browser/apps/platform_apps/api/browser/browser_apitest.cc",
+        "../browser/apps/platform_apps/api/music_manager_private/music_manager_private_browsertest.cc",
         "../browser/apps/platform_apps/app_browsertest_util.cc",
         "../browser/apps/platform_apps/app_browsertest_util.h",
         "../browser/extensions/active_tab_apitest.cc",
@@ -1265,7 +1266,6 @@
         "../browser/extensions/api/messaging/native_messaging_apitest.cc",
         "../browser/extensions/api/metrics_private/metrics_apitest.cc",
         "../browser/extensions/api/module/module_apitest.cc",
-        "../browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc",
         "../browser/extensions/api/networking_config_chromeos_apitest_chromeos.cc",
         "../browser/extensions/api/omnibox/omnibox_api_browsertest.cc",
         "../browser/extensions/api/page_capture/page_capture_apitest.cc",
@@ -3996,7 +3996,6 @@
     sources += [
       "../browser/printing/print_job_unittest.cc",
       "../browser/printing/print_preview_dialog_controller_unittest.cc",
-      "../browser/printing/print_preview_message_handler_unittest.cc",
       "../browser/printing/print_preview_test.cc",
       "../browser/printing/print_preview_test.h",
       "../browser/printing/print_test_utils.cc",
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index b32a606e..2ffa1ca 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -155,41 +155,6 @@
 // Default profile name
 const char kTestingProfile[] = "testing_profile";
 
-class TestExtensionURLRequestContext : public net::URLRequestContext {
- public:
-  TestExtensionURLRequestContext() {
-    content::CookieStoreConfig cookie_config;
-    cookie_config.cookieable_schemes.push_back(extensions::kExtensionScheme);
-    cookie_store_ =
-        content::CreateCookieStore(cookie_config, nullptr /* netlog */);
-    set_cookie_store(cookie_store_.get());
-  }
-
-  std::unique_ptr<net::CookieStore> cookie_store_;
-
-  ~TestExtensionURLRequestContext() override { AssertNoURLRequests(); }
-};
-
-class TestExtensionURLRequestContextGetter
-    : public net::URLRequestContextGetter {
- public:
-  net::URLRequestContext* GetURLRequestContext() override {
-    if (!context_.get())
-      context_.reset(new TestExtensionURLRequestContext());
-    return context_.get();
-  }
-  scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
-      const override {
-    return base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO});
-  }
-
- protected:
-  ~TestExtensionURLRequestContextGetter() override {}
-
- private:
-  std::unique_ptr<net::URLRequestContext> context_;
-};
-
 std::unique_ptr<KeyedService> BuildHistoryService(
     content::BrowserContext* context) {
   return std::make_unique<history::HistoryService>(
@@ -852,10 +817,23 @@
   return GetDefaultStoragePartition(this)->GetURLRequestContext();
 }
 
-net::URLRequestContextGetter* TestingProfile::GetRequestContextForExtensions() {
-  if (!extensions_request_context_.get())
-    extensions_request_context_ = new TestExtensionURLRequestContextGetter();
-  return extensions_request_context_.get();
+base::OnceCallback<net::CookieStore*()>
+TestingProfile::GetExtensionsCookieStoreGetter() {
+  return base::BindOnce(
+      [](std::unique_ptr<net::CookieStore,
+                         content::BrowserThread::DeleteOnIOThread>*
+             cookie_store) {
+        if (!*cookie_store) {
+          content::CookieStoreConfig cookie_config;
+          cookie_config.cookieable_schemes.push_back(
+              extensions::kExtensionScheme);
+          cookie_store->reset(
+              content::CreateCookieStore(cookie_config, nullptr /* netlog */)
+                  .release());
+        }
+        return cookie_store->get();
+      },
+      &extensions_cookie_store_);
 }
 
 scoped_refptr<network::SharedURLLoaderFactory>
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index 7c56cc1..1e27ef2 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -18,6 +18,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/domain_reliability/clear_mode.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "content/public/browser/browser_thread.h"
 #include "extensions/buildflags/buildflags.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/network_service.mojom.h"
@@ -323,7 +324,8 @@
   ChromeZoomLevelPrefs* GetZoomLevelPrefs() override;
 #endif  // !defined(OS_ANDROID)
   net::URLRequestContextGetter* GetRequestContext() override;
-  net::URLRequestContextGetter* GetRequestContextForExtensions() override;
+  base::OnceCallback<net::CookieStore*()> GetExtensionsCookieStoreGetter()
+      override;
   scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
 
   void set_last_session_exited_cleanly(bool value) {
@@ -401,9 +403,8 @@
   // maps to this profile.
   void CreateProfilePolicyConnector();
 
-  // Internally, this is a TestURLRequestContextGetter that creates a dummy
-  // request context. Currently, only the CookieMonster is hooked up.
-  scoped_refptr<net::URLRequestContextGetter> extensions_request_context_;
+  std::unique_ptr<net::CookieStore, content::BrowserThread::DeleteOnIOThread>
+      extensions_cookie_store_;
 
   // Holds a dummy network context request to avoid triggering connection error
   // handler.
diff --git a/chrome/test/chromedriver/element_commands.cc b/chrome/test/chromedriver/element_commands.cc
index 65bdc998..39e420ad 100644
--- a/chrome/test/chromedriver/element_commands.cc
+++ b/chrome/test/chromedriver/element_commands.cc
@@ -289,6 +289,21 @@
                            const std::string& element_id,
                            const base::DictionaryValue& params,
                            std::unique_ptr<base::Value>* value) {
+  // Scrolling to element is done by webdriver::atoms::CLEAR
+  bool is_displayed = false;
+  base::TimeTicks start_time = base::TimeTicks::Now();
+  while (true) {
+    Status status = IsElementDisplayed(
+      session, web_view, element_id, true, &is_displayed);
+    if (status.IsError())
+      return status;
+    if (is_displayed)
+      break;
+    if (base::TimeTicks::Now() - start_time >= session->implicit_wait) {
+      return Status(kElementNotVisible);
+    }
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
+  }
   base::ListValue args;
   args.Append(CreateElement(element_id));
   std::unique_ptr<base::Value> result;
diff --git a/chrome/test/data/extensions/api_test/autotest_private/test.js b/chrome/test/data/extensions/api_test/autotest_private/test.js
index e14b825..7e3e2e92e 100644
--- a/chrome/test/data/extensions/api_test/autotest_private/test.js
+++ b/chrome/test/data/extensions/api_test/autotest_private/test.js
@@ -193,6 +193,15 @@
     chrome.autotestPrivate.runCrostiniUninstaller(chrome.test.callbackFail(
         'Crostini is not available for the current user'));
   },
+  function takeScreenshot() {
+    chrome.autotestPrivate.takeScreenshot(
+      function(base64Png) {
+        chrome.test.assertTrue(base64Png.length > 0);
+        chrome.test.assertNoLastError();
+        chrome.test.succeed();
+      }
+    )
+  },
   function getPrinterList() {
     chrome.autotestPrivate.getPrinterList(function(){
       chrome.test.succeed();
diff --git a/chromecast/common/extensions_api/accessibility_private.json b/chromecast/common/extensions_api/accessibility_private.json
index 9ad01ec..0bee8ca 100644
--- a/chromecast/common/extensions_api/accessibility_private.json
+++ b/chromecast/common/extensions_api/accessibility_private.json
@@ -35,7 +35,7 @@
       {
         "id": "Gesture",
         "type": "string",
-        "enum": [ "click", "swipeLeft1", "swipeUp1", "swipeRight1", "swipeDown1", "swipeLeft2", "swipeUp2", "swipeRight2", "swipeDown2", "swipeLeft3", "swipeUp3", "swipeRight3", "swipeDown3", "swipeLeft4", "swipeUp4", "swipeRight4", "swipeDown4" ],
+        "enum": [ "click", "swipeLeft1", "swipeUp1", "swipeRight1", "swipeDown1", "swipeLeft2", "swipeUp2", "swipeRight2", "swipeDown2", "swipeLeft3", "swipeUp3", "swipeRight3", "swipeDown3", "swipeLeft4", "swipeUp4", "swipeRight4", "swipeDown4", "tap2", "tap3", "tap4" ],
         "description": "Accessibility gestures fired by the touch exploration controller."
       },
       {
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index a5144da..1f4a57a 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -782,6 +782,14 @@
     ]
   }
 
+  tast_test("chrome_login_tast_tests") {
+    tast_tests = [
+      "ui.ChromeLogin",
+      "ui.ChromeCrashLoggedIn",
+      "ui.ChromeCrashNotLoggedIn",
+    ]
+  }
+
   group("cros_chrome_deploy") {
     # The following run-time dependencies are needed to deploy chrome to a
     # ChromeOS device. See the link for the full list:
diff --git a/chromeos/login/auth/cryptohome_authenticator.cc b/chromeos/login/auth/cryptohome_authenticator.cc
index c745fff..0c365aa1 100644
--- a/chromeos/login/auth/cryptohome_authenticator.cc
+++ b/chromeos/login/auth/cryptohome_authenticator.cc
@@ -76,6 +76,67 @@
                             CryptohomeMigrationToGaiaId::ENTRIES_COUNT);
 }
 
+// Returns a human-readable string describing |state|.
+const char* AuthStateToString(CryptohomeAuthenticator::AuthState state) {
+  switch (state) {
+    case CryptohomeAuthenticator::CONTINUE:
+      return "CONTINUE";
+    case CryptohomeAuthenticator::NO_MOUNT:
+      return "NO_MOUNT";
+    case CryptohomeAuthenticator::FAILED_MOUNT:
+      return "FAILED_MOUNT";
+    case CryptohomeAuthenticator::FAILED_REMOVE:
+      return "FAILED_REMOVE";
+    case CryptohomeAuthenticator::FAILED_TMPFS:
+      return "FAILED_TMPFS";
+    case CryptohomeAuthenticator::FAILED_TPM:
+      return "FAILED_TPM";
+    case CryptohomeAuthenticator::CREATE_NEW:
+      return "CREATE_NEW";
+    case CryptohomeAuthenticator::RECOVER_MOUNT:
+      return "RECOVER_MONUT";
+    case CryptohomeAuthenticator::POSSIBLE_PW_CHANGE:
+      return "POSSIBLE_PW_CHANGE";
+    case CryptohomeAuthenticator::NEED_NEW_PW:
+      return "NEED_NEW_PW";
+    case CryptohomeAuthenticator::NEED_OLD_PW:
+      return "NEED_OLD_PW";
+    case CryptohomeAuthenticator::HAVE_NEW_PW:
+      return "HAVE_NEW_PW";
+    case CryptohomeAuthenticator::OFFLINE_LOGIN:
+      return "OFFLINE_LOGIN";
+    case CryptohomeAuthenticator::ONLINE_LOGIN:
+      return "ONLINE_LOGIN";
+    case CryptohomeAuthenticator::UNLOCK:
+      return "UNLOCK";
+    case CryptohomeAuthenticator::ONLINE_FAILED:
+      return "ONLINE_FAILED";
+    case CryptohomeAuthenticator::GUEST_LOGIN:
+      return "GUEST_LOGIN";
+    case CryptohomeAuthenticator::PUBLIC_ACCOUNT_LOGIN:
+      return "PUBLIC_ACCOUNT_LOGIN";
+    case CryptohomeAuthenticator::SUPERVISED_USER_LOGIN:
+      return "SUPERVISED_USER_LOGIN";
+    case CryptohomeAuthenticator::LOGIN_FAILED:
+      return "LOGIN_FAILED";
+    case CryptohomeAuthenticator::OWNER_REQUIRED:
+      return "OWNER_REQUIRED";
+    case CryptohomeAuthenticator::FAILED_USERNAME_HASH:
+      return "FAILED_USERNAME_HASH";
+    case CryptohomeAuthenticator::KIOSK_ACCOUNT_LOGIN:
+      return "KIOSK_ACCOUNT_LOGIN";
+    case CryptohomeAuthenticator::REMOVED_DATA_AFTER_FAILURE:
+      return "REMOVED_DATA_AFTER_FAILURE";
+    case CryptohomeAuthenticator::FAILED_OLD_ENCRYPTION:
+      return "FAILED_OLD_ENCRYPTION";
+    case CryptohomeAuthenticator::FAILED_PREVIOUS_MIGRATION_INCOMPLETE:
+      return "FAILED_PREVIOUS_MIGRATION_INCOMPLETE";
+    case CryptohomeAuthenticator::OFFLINE_NO_MOUNT:
+      return "OFFLINE_NO_MOUNT";
+  }
+  return "UNKNOWN";
+}
+
 // Hashes |key| with |system_salt| if it its type is KEY_TYPE_PASSWORD_PLAIN.
 // Returns the keys unmodified otherwise.
 std::unique_ptr<Key> TransformKeyIfNeeded(const Key& key,
@@ -808,7 +869,8 @@
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   bool create_if_nonexistent = false;
   CryptohomeAuthenticator::AuthState state = ResolveState();
-  VLOG(1) << "Resolved state to: " << state;
+  VLOG(1) << "Resolved state to " << state << " (" << AuthStateToString(state)
+          << ")";
   switch (state) {
     case CONTINUE:
     case POSSIBLE_PW_CHANGE:
diff --git a/components/arc/arc_prefs.cc b/components/arc/arc_prefs.cc
index db86fb7..f13fdbc 100644
--- a/components/arc/arc_prefs.cc
+++ b/components/arc/arc_prefs.cc
@@ -93,17 +93,21 @@
 // control settings.
 const char kVoiceInteractionActivityControlAccepted[] =
     "settings.voice_interaction.activity_control.accepted";
-// A preference that indicates the user has enabled voice interaction services.
-const char kVoiceInteractionEnabled[] = "settings.voice_interaction.enabled";
 // A preference that indicates the user has allowed voice interaction services
 // to access the "context" (text and graphic content that is currently on
 // screen).
 const char kVoiceInteractionContextEnabled[] =
     "settings.voice_interaction.context.enabled";
+// A preference that indicates the user has enabled voice interaction services.
+const char kVoiceInteractionEnabled[] = "settings.voice_interaction.enabled";
 // A preference that indicates the user has allowed voice interaction services
 // to use hotword listening.
 const char kVoiceInteractionHotwordEnabled[] =
     "settings.voice_interaction.hotword.enabled";
+// A preference that indicates whether microphone should be open when the voice
+// interaction launches.
+const char kVoiceInteractionLaunchWithMicOpen[] =
+    "settings.voice_interaction.launch_with_mic_open";
 // A preference that indicates the user has allowed voice interaction services
 // to send notification.
 const char kVoiceInteractionNotificationEnabled[] =
@@ -152,6 +156,7 @@
   registry->RegisterBooleanPref(kVoiceInteractionEnabled, false);
   registry->RegisterBooleanPref(kVoiceInteractionHotwordEnabled, false);
   registry->RegisterBooleanPref(kVoiceInteractionNotificationEnabled, true);
+  registry->RegisterBooleanPref(kVoiceInteractionLaunchWithMicOpen, false);
 }
 
 }  // namespace prefs
diff --git a/components/arc/arc_prefs.h b/components/arc/arc_prefs.h
index 209098c..2a900ca 100644
--- a/components/arc/arc_prefs.h
+++ b/components/arc/arc_prefs.h
@@ -41,9 +41,10 @@
 
 // TODO(b/110211045): Move Assistant related prefs to ash.
 ARC_EXPORT extern const char kVoiceInteractionActivityControlAccepted[];
-ARC_EXPORT extern const char kVoiceInteractionEnabled[];
 ARC_EXPORT extern const char kVoiceInteractionContextEnabled[];
+ARC_EXPORT extern const char kVoiceInteractionEnabled[];
 ARC_EXPORT extern const char kVoiceInteractionHotwordEnabled[];
+ARC_EXPORT extern const char kVoiceInteractionLaunchWithMicOpen[];
 ARC_EXPORT extern const char kVoiceInteractionNotificationEnabled[];
 
 void RegisterProfilePrefs(PrefRegistrySimple* registry);
diff --git a/components/browser_sync/sync_auth_manager.cc b/components/browser_sync/sync_auth_manager.cc
index b559018..8f6edaf 100644
--- a/components/browser_sync/sync_auth_manager.cc
+++ b/components/browser_sync/sync_auth_manager.cc
@@ -113,8 +113,17 @@
   return sync_account_;
 }
 
-const syncer::SyncTokenStatus& SyncAuthManager::GetSyncTokenStatus() const {
-  return token_status_;
+syncer::SyncTokenStatus SyncAuthManager::GetSyncTokenStatus() const {
+  DCHECK(partial_token_status_.next_token_request_time.is_null());
+
+  syncer::SyncTokenStatus token_status = partial_token_status_;
+  if (request_access_token_retry_timer_.IsRunning()) {
+    base::TimeDelta delta =
+        request_access_token_retry_timer_.desired_run_time() -
+        base::TimeTicks::Now();
+    token_status.next_token_request_time = base::Time::Now() + delta;
+  }
+  return token_status;
 }
 
 syncer::SyncCredentials SyncAuthManager::GetCredentials() const {
@@ -132,8 +141,8 @@
 }
 
 void SyncAuthManager::ConnectionStatusChanged(syncer::ConnectionStatus status) {
-  token_status_.connection_status_update_time = base::Time::Now();
-  token_status_.connection_status = status;
+  partial_token_status_.connection_status_update_time = base::Time::Now();
+  partial_token_status_.connection_status = status;
 
   switch (status) {
     case syncer::CONNECTION_AUTH_ERROR:
@@ -160,14 +169,11 @@
         // this point.
         DCHECK(access_token_.empty());
         DCHECK(!request_access_token_retry_timer_.IsRunning());
-        DCHECK(token_status_.next_token_request_time.is_null());
       } else if (request_access_token_retry_timer_.IsRunning()) {
         // The timer to perform a request later is already running; nothing
         // further needs to be done at this point.
         DCHECK(access_token_.empty());
-        DCHECK(!token_status_.next_token_request_time.is_null());
       } else if (request_access_token_backoff_.failure_count() == 0) {
-        DCHECK(token_status_.next_token_request_time.is_null());
         // First time request without delay. Currently invalid token is used
         // to initialize sync engine and we'll always end up here. We don't
         // want to delay initialization.
@@ -189,7 +195,6 @@
       // thus hammers token server. To be safe, only reset backoff delay when
       // no scheduled request.
       if (!request_access_token_retry_timer_.IsRunning()) {
-        DCHECK(token_status_.next_token_request_time.is_null());
         request_access_token_backoff_.Reset();
       }
       last_auth_error_ = GoogleServiceAuthError::AuthErrorNone();
@@ -224,7 +229,6 @@
 void SyncAuthManager::ClearAccessTokenAndRequest() {
   access_token_.clear();
   request_access_token_retry_timer_.Stop();
-  token_status_.next_token_request_time = base::Time();
   ongoing_access_token_fetch_.reset();
   weak_ptr_factory_.InvalidateWeakPtrs();
 }
@@ -233,12 +237,9 @@
   DCHECK(access_token_.empty());
   DCHECK(!ongoing_access_token_fetch_);
   DCHECK(!request_access_token_retry_timer_.IsRunning());
-  DCHECK(token_status_.next_token_request_time.is_null());
 
-  base::TimeDelta delay = request_access_token_backoff_.GetTimeUntilRelease();
-  token_status_.next_token_request_time = base::Time::Now() + delay;
   request_access_token_retry_timer_.Start(
-      FROM_HERE, delay,
+      FROM_HERE, request_access_token_backoff_.GetTimeUntilRelease(),
       base::BindRepeating(&SyncAuthManager::RequestAccessToken,
                           weak_ptr_factory_.GetWeakPtr()));
 }
@@ -412,12 +413,6 @@
 }
 
 void SyncAuthManager::RequestAccessToken() {
-  // First reset the next request time: Either we were called back by the retry
-  // timer, in which case this is now obsolete, or we'll cancel the timer below.
-  // Note that if we were called back by the retry timer, then it's already
-  // considered not running, so we reset this time unconditionally.
-  token_status_.next_token_request_time = base::Time();
-
   // Only one active request at a time.
   if (ongoing_access_token_fetch_) {
     DCHECK(access_token_.empty());
@@ -439,8 +434,8 @@
   InvalidateAccessToken();
 
   // Finally, kick off a new access token fetch.
-  token_status_.token_request_time = base::Time::Now();
-  token_status_.token_receive_time = base::Time();
+  partial_token_status_.token_request_time = base::Time::Now();
+  partial_token_status_.token_receive_time = base::Time();
   ongoing_access_token_fetch_ =
       identity_manager_->CreateAccessTokenFetcherForAccount(
           sync_account_.account_info.account_id, kSyncOAuthConsumerName,
@@ -458,14 +453,14 @@
   DCHECK(!request_access_token_retry_timer_.IsRunning());
 
   access_token_ = access_token_info.token;
-  token_status_.last_get_token_error = error;
+  partial_token_status_.last_get_token_error = error;
 
   DCHECK_EQ(access_token_.empty(),
             error.state() != GoogleServiceAuthError::NONE);
 
   switch (error.state()) {
     case GoogleServiceAuthError::NONE:
-      token_status_.token_receive_time = base::Time::Now();
+      partial_token_status_.token_receive_time = base::Time::Now();
       sync_prefs_->SetSyncAuthError(false);
       last_auth_error_ = GoogleServiceAuthError::AuthErrorNone();
       break;
diff --git a/components/browser_sync/sync_auth_manager.h b/components/browser_sync/sync_auth_manager.h
index 745919ad..4cc43ec 100644
--- a/components/browser_sync/sync_auth_manager.h
+++ b/components/browser_sync/sync_auth_manager.h
@@ -85,7 +85,7 @@
 
   // Returns the state of the access token and token request, for display in
   // internals UI.
-  const syncer::SyncTokenStatus& GetSyncTokenStatus() const;
+  syncer::SyncTokenStatus GetSyncTokenStatus() const;
 
   // Called by ProfileSyncService when the status of the connection to the Sync
   // server changed. Updates auth error state accordingly.
@@ -136,7 +136,7 @@
 
   // Immediately starts an access token request, unless one is already ongoing.
   // If another request is scheduled for later, it is canceled. Any access token
-  // we currently have is dropped and removed from IdentityManager's cache.
+  // we currently have is invalidated.
   void RequestAccessToken();
 
   void AccessTokenFetched(GoogleServiceAuthError error,
@@ -179,7 +179,9 @@
   net::BackoffEntry request_access_token_backoff_;
 
   // Info about the state of our access token, for display in the internals UI.
-  syncer::SyncTokenStatus token_status_;
+  // "Partial" because this instance is not fully populated - in particular,
+  // |next_token_request_time| gets computed on demand.
+  syncer::SyncTokenStatus partial_token_status_;
 
   base::WeakPtrFactory<SyncAuthManager> weak_ptr_factory_;
 
diff --git a/components/cdm/browser/media_drm_storage_impl.cc b/components/cdm/browser/media_drm_storage_impl.cc
index 480e3e1..5a1b2219 100644
--- a/components/cdm/browser/media_drm_storage_impl.cc
+++ b/components/cdm/browser/media_drm_storage_impl.cc
@@ -397,7 +397,7 @@
   DVLOG(1) << __func__ << ": origin = " << origin();
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(pref_service_);
-  DCHECK(!origin().unique());
+  DCHECK(!origin().opaque());
 }
 
 MediaDrmStorageImpl::~MediaDrmStorageImpl() {
diff --git a/components/error_page/common/localized_error.cc b/components/error_page/common/localized_error.cc
index 59801251..f7b6cd2 100644
--- a/components/error_page/common/localized_error.cc
+++ b/components/error_page/common/localized_error.cc
@@ -664,7 +664,7 @@
     DCHECK(suggestions_summary_list->empty());
     DCHECK(!(suggestions & ~SUGGEST_NAVIGATE_TO_ORIGIN));
     url::Origin failed_origin = url::Origin::Create(failed_url);
-    if (failed_origin.unique())
+    if (failed_origin.opaque())
       return;
 
     auto suggestion = std::make_unique<base::DictionaryValue>();
diff --git a/components/leveldb_proto/leveldb_database.cc b/components/leveldb_proto/leveldb_database.cc
index 7157518c..29b8f60 100644
--- a/components/leveldb_proto/leveldb_database.cc
+++ b/components/leveldb_proto/leveldb_database.cc
@@ -4,6 +4,7 @@
 
 #include "components/leveldb_proto/leveldb_database.h"
 
+#include <map>
 #include <string>
 #include <vector>
 
@@ -178,6 +179,34 @@
                              std::vector<std::string>* entries,
                              const leveldb::ReadOptions& options,
                              const std::string& target_prefix) {
+  std::map<std::string, std::string> keys_entries;
+  bool result = LoadKeysAndEntriesWithFilter(filter, &keys_entries, options,
+                                             target_prefix);
+  if (!result)
+    return false;
+
+  for (const auto& pair : keys_entries)
+    entries->push_back(pair.second);
+  return true;
+}
+
+bool LevelDB::LoadKeysAndEntries(
+    std::map<std::string, std::string>* keys_entries) {
+  return LoadKeysAndEntriesWithFilter(KeyFilter(), keys_entries);
+}
+
+bool LevelDB::LoadKeysAndEntriesWithFilter(
+    const KeyFilter& filter,
+    std::map<std::string, std::string>* keys_entries) {
+  return LoadKeysAndEntriesWithFilter(filter, keys_entries,
+                                      leveldb::ReadOptions(), std::string());
+}
+
+bool LevelDB::LoadKeysAndEntriesWithFilter(
+    const KeyFilter& filter,
+    std::map<std::string, std::string>* keys_entries,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix) {
   DFAKE_SCOPED_LOCK(thread_checker_);
   if (!db_)
     return false;
@@ -187,30 +216,30 @@
   for (db_iterator->Seek(target);
        db_iterator->Valid() && db_iterator->key().starts_with(target);
        db_iterator->Next()) {
-    if (!filter.is_null()) {
-      leveldb::Slice key_slice = db_iterator->key();
-      if (!filter.Run(std::string(key_slice.data(), key_slice.size())))
-        continue;
+    leveldb::Slice key_slice = db_iterator->key();
+    std::string key_slice_str(key_slice.data(), key_slice.size());
+    if (!filter.is_null() && !filter.Run(key_slice_str)) {
+      continue;
     }
+
     leveldb::Slice value_slice = db_iterator->value();
-    std::string entry(value_slice.data(), value_slice.size());
-    entries->push_back(entry);
+    keys_entries->insert(std::make_pair(
+        key_slice_str, std::string(value_slice.data(), value_slice.size())));
   }
   return true;
 }
 
 bool LevelDB::LoadKeys(std::vector<std::string>* keys) {
-  DFAKE_SCOPED_LOCK(thread_checker_);
-  if (!db_)
-    return false;
-
   leveldb::ReadOptions options;
   options.fill_cache = false;
-  std::unique_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
-  for (db_iterator->SeekToFirst(); db_iterator->Valid(); db_iterator->Next()) {
-    leveldb::Slice key_slice = db_iterator->key();
-    keys->push_back(std::string(key_slice.data(), key_slice.size()));
-  }
+  std::map<std::string, std::string> keys_entries;
+  bool result = LoadKeysAndEntriesWithFilter(KeyFilter(), &keys_entries,
+                                             options, std::string());
+  if (!result)
+    return false;
+
+  for (const auto& pair : keys_entries)
+    keys->push_back(pair.first);
   return true;
 }
 
diff --git a/components/leveldb_proto/leveldb_database.h b/components/leveldb_proto/leveldb_database.h
index 229afdb..2444e38 100644
--- a/components/leveldb_proto/leveldb_database.h
+++ b/components/leveldb_proto/leveldb_database.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_LEVELDB_PROTO_LEVELDB_DATABASE_H_
 #define COMPONENTS_LEVELDB_PROTO_LEVELDB_DATABASE_H_
 
+#include <map>
 #include <memory>
 #include <string>
 #include <vector>
@@ -55,6 +56,7 @@
                     const std::vector<std::string>& keys_to_remove);
   virtual bool UpdateWithRemoveFilter(const base::StringPairs& entries_to_save,
                                       const KeyFilter& delete_key_filter);
+
   virtual bool Load(std::vector<std::string>* entries);
   virtual bool LoadWithFilter(const KeyFilter& filter,
                               std::vector<std::string>* entries);
@@ -62,6 +64,18 @@
                               std::vector<std::string>* entries,
                               const leveldb::ReadOptions& options,
                               const std::string& target_prefix);
+
+  virtual bool LoadKeysAndEntries(
+      std::map<std::string, std::string>* keys_entries);
+  virtual bool LoadKeysAndEntriesWithFilter(
+      const KeyFilter& filter,
+      std::map<std::string, std::string>* keys_entries);
+  virtual bool LoadKeysAndEntriesWithFilter(
+      const KeyFilter& filter,
+      std::map<std::string, std::string>* keys_entries,
+      const leveldb::ReadOptions& options,
+      const std::string& target_prefix);
+
   virtual bool LoadKeys(std::vector<std::string>* keys);
   virtual bool Get(const std::string& key, bool* found, std::string* entry);
   // Close (if currently open) and then destroy (i.e. delete) the database
diff --git a/components/leveldb_proto/proto_database.h b/components/leveldb_proto/proto_database.h
index 1d0e543..b62bd4f 100644
--- a/components/leveldb_proto/proto_database.h
+++ b/components/leveldb_proto/proto_database.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_H_
 #define COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_H_
 
+#include <map>
 #include <memory>
 #include <string>
 #include <utility>
@@ -32,6 +33,9 @@
   using LoadKeysCallback =
       base::OnceCallback<void(bool success,
                               std::unique_ptr<std::vector<std::string>>)>;
+  using LoadKeysAndEntriesCallback =
+      base::OnceCallback<void(bool success,
+                              std::unique_ptr<std::map<std::string, T>>)>;
   using GetCallback =
       base::OnceCallback<void(bool success, std::unique_ptr<T>)>;
   using DestroyCallback = base::OnceCallback<void(bool success)>;
@@ -79,6 +83,17 @@
                                      const std::string& target_prefix,
                                      LoadCallback callback) = 0;
 
+  virtual void LoadKeysAndEntries(
+      typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) = 0;
+  virtual void LoadKeysAndEntriesWithFilter(
+      const LevelDB::KeyFilter& filter,
+      typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) = 0;
+  virtual void LoadKeysAndEntriesWithFilter(
+      const LevelDB::KeyFilter& filter,
+      const leveldb::ReadOptions& options,
+      const std::string& target_prefix,
+      typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) = 0;
+
   // Asynchronously loads all keys from the database and invokes |callback| with
   // those keys when complete.
   virtual void LoadKeys(LoadKeysCallback callback) = 0;
diff --git a/components/leveldb_proto/proto_database_impl.h b/components/leveldb_proto/proto_database_impl.h
index f7bc921..b7a2202 100644
--- a/components/leveldb_proto/proto_database_impl.h
+++ b/components/leveldb_proto/proto_database_impl.h
@@ -64,6 +64,16 @@
       const leveldb::ReadOptions& options,
       const std::string& target_prefix,
       typename ProtoDatabase<T>::LoadCallback callback) override;
+  void LoadKeysAndEntries(
+      typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) override;
+  void LoadKeysAndEntriesWithFilter(
+      const LevelDB::KeyFilter& filter,
+      typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) override;
+  void LoadKeysAndEntriesWithFilter(
+      const LevelDB::KeyFilter& filter,
+      const leveldb::ReadOptions& options,
+      const std::string& target_prefix,
+      typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) override;
   void LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) override;
   void GetEntry(const std::string& key,
                 typename ProtoDatabase<T>::GetCallback callback) override;
@@ -110,6 +120,14 @@
 }
 
 template <typename T>
+void RunLoadKeysAndEntriesCallback(
+    typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback,
+    bool* success,
+    std::unique_ptr<std::map<std::string, T>> keys_entries) {
+  std::move(callback).Run(*success, std::move(keys_entries));
+}
+
+template <typename T>
 void RunLoadKeysCallback(typename ProtoDatabase<T>::LoadKeysCallback callback,
                          std::unique_ptr<bool> success,
                          std::unique_ptr<std::vector<std::string>> keys) {
@@ -184,30 +202,46 @@
 }
 
 template <typename T>
+void LoadKeysAndEntriesFromTaskRunner(LevelDB* database,
+                                      const LevelDB::KeyFilter& filter,
+                                      const leveldb::ReadOptions& options,
+                                      const std::string& target_prefix,
+                                      std::map<std::string, T>* keys_entries,
+                                      bool* success) {
+  DCHECK(success);
+  DCHECK(keys_entries);
+
+  keys_entries->clear();
+
+  std::map<std::string, std::string> loaded_entries;
+  *success = database->LoadKeysAndEntriesWithFilter(filter, &loaded_entries,
+                                                    options, target_prefix);
+
+  for (const auto& pair : loaded_entries) {
+    T entry;
+    if (!entry.ParseFromString(pair.second)) {
+      DLOG(WARNING) << "Unable to parse leveldb_proto entry";
+      // TODO(cjhopman): Decide what to do about un-parseable entries.
+    }
+
+    keys_entries->insert(std::make_pair(pair.first, entry));
+  }
+}
+
+template <typename T>
 void LoadEntriesFromTaskRunner(LevelDB* database,
                                const LevelDB::KeyFilter& filter,
                                const leveldb::ReadOptions& options,
                                const std::string& target_prefix,
                                std::vector<T>* entries,
                                bool* success) {
-  DCHECK(success);
-  DCHECK(entries);
-
   entries->clear();
 
-  std::vector<std::string> loaded_entries;
-  *success =
-      database->LoadWithFilter(filter, &loaded_entries, options, target_prefix);
-
-  for (const auto& serialized_entry : loaded_entries) {
-    T entry;
-    if (!entry.ParseFromString(serialized_entry)) {
-      DLOG(WARNING) << "Unable to parse leveldb_proto entry";
-      // TODO(cjhopman): Decide what to do about un-parseable entries.
-    }
-
-    entries->push_back(entry);
-  }
+  std::map<std::string, T> keys_entries;
+  LoadKeysAndEntriesFromTaskRunner<T>(database, filter, options, target_prefix,
+                                      &keys_entries, success);
+  for (const auto& pair : keys_entries)
+    entries->push_back(pair.second);
 }
 
 inline void LoadKeysFromTaskRunner(LevelDB* database,
@@ -360,7 +394,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   bool* success = new bool(false);
 
-  std::unique_ptr<std::vector<T>> entries(new std::vector<T>());
+  auto entries = std::make_unique<std::vector<T>>();
   // Get this pointer before entries is std::move()'d so we can use it below.
   std::vector<T>* entries_ptr = entries.get();
 
@@ -373,6 +407,42 @@
 }
 
 template <typename T>
+void ProtoDatabaseImpl<T>::LoadKeysAndEntries(
+    typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWithFilter(LevelDB::KeyFilter(), std::move(callback));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadKeysAndEntriesWithFilter(
+    const LevelDB::KeyFilter& key_filter,
+    typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWithFilter(key_filter, leveldb::ReadOptions(),
+                               std::string(), std::move(callback));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadKeysAndEntriesWithFilter(
+    const LevelDB::KeyFilter& key_filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  bool* success = new bool(false);
+
+  auto keys_entries = std::make_unique<std::map<std::string, T>>();
+  // Get this pointer before entries is std::move()'d so we can use it below.
+  std::map<std::string, T>* keys_entries_ptr = keys_entries.get();
+
+  task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(LoadKeysAndEntriesFromTaskRunner<T>,
+                     base::Unretained(db_.get()), key_filter, options,
+                     target_prefix, keys_entries_ptr, success),
+      base::BindOnce(RunLoadKeysAndEntriesCallback<T>, std::move(callback),
+                     base::Owned(success), std::move(keys_entries)));
+}
+
+template <typename T>
 void ProtoDatabaseImpl<T>::LoadKeys(
     typename ProtoDatabase<T>::LoadKeysCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/components/leveldb_proto/proto_database_impl_unittest.cc b/components/leveldb_proto/proto_database_impl_unittest.cc
index 3da34f1..5ecf6a7d 100644
--- a/components/leveldb_proto/proto_database_impl_unittest.cc
+++ b/components/leveldb_proto/proto_database_impl_unittest.cc
@@ -62,6 +62,14 @@
                     std::vector<std::string>*,
                     const leveldb::ReadOptions&,
                     const std::string&));
+  MOCK_METHOD1(LoadKeysAndEntries, bool(std::map<std::string, std::string>*));
+  MOCK_METHOD2(LoadKeysAndEntriesWithFilter,
+               bool(const KeyFilter&, std::map<std::string, std::string>*));
+  MOCK_METHOD4(LoadKeysAndEntriesWithFilter,
+               bool(const KeyFilter&,
+                    std::map<std::string, std::string>*,
+                    const leveldb::ReadOptions&,
+                    const std::string&));
   MOCK_METHOD3(Get, bool(const std::string&, bool*, std::string*));
   MOCK_METHOD0(Destroy, bool());
 
@@ -78,6 +86,13 @@
     LoadCallback1(success, entries.get());
   }
   MOCK_METHOD2(LoadCallback1, void(bool, std::vector<TestProto>*));
+  void LoadKeysAndEntriesCallback(
+      bool success,
+      std::unique_ptr<std::map<std::string, TestProto>> keys_entries) {
+    LoadKeysAndEntriesCallback1(success, keys_entries.get());
+  }
+  MOCK_METHOD2(LoadKeysAndEntriesCallback1,
+               void(bool, std::map<std::string, TestProto>*));
   void GetCallback(bool success, std::unique_ptr<TestProto> entry) {
     GetCallback1(success, entry.get());
   }
@@ -265,11 +280,27 @@
   return true;
 }
 
+ACTION_P(AppendLoadKeysAndEntries, model) {
+  std::map<std::string, std::string>* output = arg1;
+  for (const auto& pair : model)
+    output->insert(std::make_pair(pair.first, pair.second.SerializeAsString()));
+
+  return true;
+}
+
 ACTION_P(VerifyLoadEntries, expected) {
   std::vector<TestProto>* actual = arg1;
   ExpectEntryPointersEquals(expected, *actual);
 }
 
+ACTION_P(VerifyLoadKeysAndEntries, expected) {
+  std::map<std::string, TestProto>* actual_map = arg1;
+  std::vector<TestProto> actual;
+  for (const auto& pair : *actual_map)
+    actual.push_back(pair.second);
+  ExpectEntryPointersEquals(expected, actual);
+}
+
 // Test that ProtoDatabaseImpl calls Load on the underlying database and that
 // the caller's LoadCallback is called with the correct success value. Also
 // confirms that on success, the expected entries are passed to the caller's
@@ -287,8 +318,8 @@
                         base::BindOnce(&MockDatabaseCaller::InitCallback,
                                        base::Unretained(&caller)));
 
-  EXPECT_CALL(*mock_db, LoadWithFilter(_, _, _, _))
-      .WillOnce(AppendLoadEntries(model));
+  EXPECT_CALL(*mock_db, LoadKeysAndEntriesWithFilter(_, _, _, _))
+      .WillOnce(AppendLoadKeysAndEntries(model));
   EXPECT_CALL(caller, LoadCallback1(true, _))
       .WillOnce(VerifyLoadEntries(testing::ByRef(model)));
   db_->LoadEntries(base::BindOnce(&MockDatabaseCaller::LoadCallback,
@@ -309,7 +340,8 @@
                         base::BindOnce(&MockDatabaseCaller::InitCallback,
                                        base::Unretained(&caller)));
 
-  EXPECT_CALL(*mock_db, LoadWithFilter(_, _, _, _)).WillOnce(Return(false));
+  EXPECT_CALL(*mock_db, LoadKeysAndEntriesWithFilter(_, _, _, _))
+      .WillOnce(Return(false));
   EXPECT_CALL(caller, LoadCallback1(false, _));
   db_->LoadEntries(base::BindOnce(&MockDatabaseCaller::LoadCallback,
                                   base::Unretained(&caller)));
@@ -738,6 +770,35 @@
   EXPECT_EQ(entry.SerializeAsString(), model["0"].SerializeAsString());
 }
 
+TEST_F(ProtoDatabaseImplLevelDBTest, TestDBLoadKeysAndEntries) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  EntryMap model = GetSmallModel();
+
+  KeyValueVector save_entries;
+  std::map<std::string, std::string> load_keys_entries;
+  KeyVector remove_keys;
+
+  for (const auto& pair : model) {
+    save_entries.push_back(
+        std::make_pair(pair.second.id(), pair.second.SerializeAsString()));
+  }
+
+  std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
+  EXPECT_TRUE(db->Init(temp_dir.GetPath(), CreateSimpleOptions()));
+  EXPECT_TRUE(db->Save(save_entries, remove_keys));
+
+  EXPECT_TRUE(db->LoadKeysAndEntries(&load_keys_entries));
+
+  EXPECT_EQ(load_keys_entries.size(), model.size());
+  for (const auto& pair : load_keys_entries) {
+    TestProto entry;
+    ASSERT_TRUE(entry.ParseFromString(pair.second));
+    EXPECT_EQ(entry.SerializeAsString(), model[pair.first].SerializeAsString());
+  }
+}
+
 TEST_F(ProtoDatabaseImplLevelDBTest, TestDBInitFail) {
   ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
diff --git a/components/leveldb_proto/proto_database_perftest.cc b/components/leveldb_proto/proto_database_perftest.cc
index dacd07e0..45e5825b 100644
--- a/components/leveldb_proto/proto_database_perftest.cc
+++ b/components/leveldb_proto/proto_database_perftest.cc
@@ -48,8 +48,6 @@
 
 namespace {
 
-static const std::string kSingleDBName = "singledb";
-
 using KeyEntryVector = ProtoDatabase<TestProto>::KeyEntryVector;
 using KeyEntryVectorMap =
     std::map<std::string, std::unique_ptr<KeyEntryVector>>;
@@ -68,6 +66,20 @@
   int num_runs = 0;
 };
 
+static const std::string kSingleDBName = "singledb";
+
+static const std::vector<TestParams> kFewEntriesDistributionTestParams = {
+    {20, 10, 1, false}, {10, 10, 1, false},  {10, 10, 1, false},
+    {25, 10, 1, false}, {40, 10, 1, false},  {50, 10, 1, false},
+    {80, 10, 1, false}, {100, 10, 1, false}, {100, 10, 1, false},
+};
+
+static const std::vector<TestParams> kManyEntriesDistributionTestParams = {
+    {200, 10, 1, false}, {100, 10, 1, false},  {100, 10, 1, false},
+    {250, 10, 1, false}, {400, 10, 1, false},  {500, 10, 1, false},
+    {800, 10, 1, false}, {1000, 10, 1, false}, {1000, 10, 1, false},
+};
+
 class TestDatabase {
  public:
   TestDatabase(const std::string& name,
@@ -530,267 +542,322 @@
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 };
 
-// Timed out on Win.  http://crbug.com/879922
-#if defined(OS_WIN)
-#define MAYBE_InsertMultipleDBsAlternating_Individual \
-  DISABLED_InsertMultipleDBsAlternating_Individual
-#else
-#define MAYBE_InsertMultipleDBsAlternating_Individual \
-  InsertMultipleDBsAlternating_Individual
-#endif
-
-TEST_F(ProtoDBPerfTest, MAYBE_InsertMultipleDBsAlternating_Individual) {
+TEST_F(ProtoDBPerfTest, InsertMultipleDBsAlternating_Individual_100b) {
   // num_entries, data_size, batch_size, single_db.
-  std::vector<TestParams> params = {
-      {500, 100, 1, false}, {500, 1000, 1, false},
-  };
-  RunAlternatingInsertTests(params, "InsertMultipleDBsAlternating_Individual",
-                            10);
+  TestParams params = {200, 100, 1, false};
+  RunAlternatingInsertTests({params}, "InsertMultipleDBsAlternating_Individual",
+                            5);
 }
 
-// Timed out on Win.  http://crbug.com/879922
-#if defined(OS_WIN)
-#define MAYBE_InsertSingleDBAlternating_Individual \
-  DISABLED_InsertSingleDBAlternating_Individual
-#else
-#define MAYBE_InsertSingleDBAlternating_Individual \
-  InsertSingleDBAlternating_Individual
-#endif
-
-TEST_F(ProtoDBPerfTest, MAYBE_InsertSingleDBAlternating_Individual) {
+TEST_F(ProtoDBPerfTest, InsertMultipleDBsAlternating_Individual_1000b) {
   // num_entries, data_size, batch_size, single_db.
-  std::vector<TestParams> params = {
-      {500, 100, 1, true}, {500, 1000, 1, true},
-  };
-  RunAlternatingInsertTests(params, "InsertSingleDBAlternating_Individual", 10);
+  TestParams params = {200, 1000, 1, false};
+  RunAlternatingInsertTests({params}, "InsertMultipleDBsAlternating_Individual",
+                            5);
 }
 
-TEST_F(ProtoDBPerfTest, InsertMultipleDBsAlternating_LargeBatch) {
+TEST_F(ProtoDBPerfTest, InsertSingleDBAlternating_Individual_100b) {
   // num_entries, data_size, batch_size, single_db.
-  std::vector<TestParams> params = {
-      {500, 100, 500, false}, {500, 1000, 500, false},
-  };
-  RunAlternatingInsertTests(params, "InsertMultipleDBsAlternating_LargeBatch",
-                            10);
+  TestParams params = {200, 100, 1, true};
+  RunAlternatingInsertTests({params}, "InsertSingleDBAlternating_Individual",
+                            5);
 }
 
-TEST_F(ProtoDBPerfTest, InsertSingleDBAlternating_LargeBatch) {
+TEST_F(ProtoDBPerfTest, InsertSingleDBAlternating_Individual_1000b) {
   // num_entries, data_size, batch_size, single_db.
-  std::vector<TestParams> params = {
-      {500, 100, 500, true}, {500, 1000, 500, true},
-  };
-  RunAlternatingInsertTests(params, "InsertSingleDBAlternating_LargeBatch", 10);
+  TestParams params = {200, 1000, 1, true};
+  RunAlternatingInsertTests({params}, "InsertSingleDBAlternating_Individual",
+                            5);
 }
 
-TEST_F(ProtoDBPerfTest, DistributionTestSmall_FewEntries) {
-  std::vector<TestParams> params = {
-      {20, 10, 1, false}, {10, 10, 1, false},  {10, 10, 1, false},
-      {25, 10, 1, false}, {40, 10, 1, false},  {50, 10, 1, false},
-      {80, 10, 1, false}, {100, 10, 1, false}, {100, 10, 1, false},
-  };
-  RunDistributionTestAndCleanup("DistributionTestSmall_FewEntries", "Multi",
-                                params, false);
+TEST_F(ProtoDBPerfTest, InsertMultipleDBsAlternating_LargeBatch_100b) {
+  // num_entries, data_size, batch_size, single_db.
+  TestParams params = {200, 100, 200, false};
+  RunAlternatingInsertTests({params}, "InsertMultipleDBsAlternating_LargeBatch",
+                            5);
+}
+
+TEST_F(ProtoDBPerfTest, InsertMultipleDBsAlternating_LargeBatch_1000b) {
+  // num_entries, data_size, batch_size, single_db.
+  TestParams params = {200, 1000, 200, false};
+  RunAlternatingInsertTests({params}, "InsertMultipleDBsAlternating_LargeBatch",
+                            5);
+}
+
+TEST_F(ProtoDBPerfTest, InsertSingleDBAlternating_LargeBatch_100b) {
+  // num_entries, data_size, batch_size, single_db.
+  TestParams params = {200, 100, 200, true};
+  RunAlternatingInsertTests({params}, "InsertSingleDBAlternating_LargeBatch",
+                            5);
+}
+
+TEST_F(ProtoDBPerfTest, InsertSingleDBAlternating_LargeBatch_1000b) {
+  // num_entries, data_size, batch_size, single_db.
+  TestParams params = {200, 1000, 200, true};
+  RunAlternatingInsertTests({params}, "InsertSingleDBAlternating_LargeBatch",
+                            5);
+}
+
+TEST_F(ProtoDBPerfTest, DistributionTestSmall_FewEntries_Single) {
   RunDistributionTestAndCleanup("DistributionTestSmall_FewEntries", "Single",
-                                params, true);
+                                kFewEntriesDistributionTestParams, true);
 }
 
-// Timed out on Win.  http://crbug.com/879922
-#if defined(OS_WIN)
-#define MAYBE_DistributionTestSmall_ManyEntries \
-  DISABLED_DistributionTestSmall_ManyEntries
-#else
-#define MAYBE_DistributionTestSmall_ManyEntries \
-  DistributionTestSmall_ManyEntries
-#endif
+TEST_F(ProtoDBPerfTest, DistributionTestSmall_FewEntries_Multi) {
+  RunDistributionTestAndCleanup("DistributionTestSmall_FewEntries", "Multi",
+                                kFewEntriesDistributionTestParams, false);
+}
 
-TEST_F(ProtoDBPerfTest, MAYBE_DistributionTestSmall_ManyEntries) {
-  std::vector<TestParams> params = {
-      {200, 10, 1, false}, {100, 10, 1, false},  {100, 10, 1, false},
-      {250, 10, 1, false}, {400, 10, 1, false},  {500, 10, 1, false},
-      {800, 10, 1, false}, {1000, 10, 1, false}, {1000, 10, 1, false},
-  };
-  RunDistributionTestAndCleanup("DistributionTestSmall_ManyEntries", "Multi",
-                                params, false);
+TEST_F(ProtoDBPerfTest, DistributionTestSmall_ManyEntries_Single) {
   RunDistributionTestAndCleanup("DistributionTestSmall_ManyEntries", "Single",
-                                params, true);
+                                kManyEntriesDistributionTestParams, true);
 }
 
-TEST_F(ProtoDBPerfTest, DistributionTestSmall_ManyEntries_Batch) {
-  std::vector<TestParams> params = {
-      {200, 10, 200, false}, {100, 10, 100, false},   {100, 10, 100, false},
-      {250, 10, 250, false}, {400, 10, 400, false},   {500, 10, 500, false},
-      {800, 10, 800, false}, {1000, 10, 1000, false}, {1000, 10, 1000, false},
-  };
-  RunDistributionTestAndCleanup("DistributionTestSmall_ManyEntries_Batch",
-                                "Multi", params, false);
-  RunDistributionTestAndCleanup("DistributionTestSmall_ManyEntries_Batch",
-                                "Single", params, true);
+TEST_F(ProtoDBPerfTest, DistributionTestSmall_ManyEntries_Multi) {
+  RunDistributionTestAndCleanup("DistributionTestSmall_ManyEntries", "Multi",
+                                kManyEntriesDistributionTestParams, false);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesSingle) {
+TEST_F(ProtoDBPerfTest, DistributionTestSmall_ManyEntries_Batch_Single) {
+  RunDistributionTestAndCleanup("DistributionTestSmall_ManyEntries_Batch",
+                                "Single", kManyEntriesDistributionTestParams,
+                                true);
+}
+
+TEST_F(ProtoDBPerfTest, DistributionTestSmall_ManyEntries_Batch_Multi) {
+  RunDistributionTestAndCleanup("DistributionTestSmall_ManyEntries_Batch",
+                                "Multi", kManyEntriesDistributionTestParams,
+                                false);
+}
+
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(10, 3000, 10, {}, "LoadEntriesSingle",
                                      &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(10, 30000, 10, {}, "LoadEntriesSingle",
                                      &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(10, 30000, 100, {}, "LoadEntriesSingle",
                                      &num_entries);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix) {
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix_Small) {
   // Load only the entries that start with a particular prefix.
   unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       10, 3000, 10, {1}, "LoadEntriesSingle_OnePrefix", &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix_Medium) {
+  // Load only the entries that start with a particular prefix.
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       10, 30000, 10, {1}, "LoadEntriesSingle_OnePrefix", &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix_Large) {
+  // Load only the entries that start with a particular prefix.
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       10, 30000, 100, {1}, "LoadEntriesSingle_OnePrefix", &num_entries);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesMulti) {
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 3000, 10, {}, "LoadEntriesMulti",
                                     &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 30000, 10, {}, "LoadEntriesMulti",
                                     &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 30000, 100, {}, "LoadEntriesMulti",
                                     &num_entries);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix) {
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 3000, 10, {1},
                                     "LoadEntriesMulti_OnePrefix", &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 30000, 10, {1},
                                     "LoadEntriesMulti_OnePrefix", &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 30000, 100, {1},
                                     "LoadEntriesMulti_OnePrefix", &num_entries);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesSingle_SkipReadCache) {
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_SkipReadCache_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(10, 3000, 10, {},
                                      "LoadEntriesSingle_SkipReadCache",
                                      &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_SkipReadCache_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(10, 30000, 10, {},
                                      "LoadEntriesSingle_SkipReadCache",
                                      &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_SkipReadCache_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(10, 30000, 100, {},
                                      "LoadEntriesSingle_SkipReadCache",
                                      &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix_SkipReadCache) {
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix_SkipReadCache_Small) {
   // Load only the entries that start with a particular prefix.
   unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       10, 3000, 10, {1}, "LoadEntriesSingle_OnePrefix_SkipReadCache",
       &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix_SkipReadCache_Medium) {
+  // Load only the entries that start with a particular prefix.
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       10, 30000, 10, {1}, "LoadEntriesSingle_OnePrefix_SkipReadCache",
       &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix_SkipReadCache_Large) {
+  // Load only the entries that start with a particular prefix.
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       10, 30000, 100, {1}, "LoadEntriesSingle_OnePrefix_SkipReadCache",
       &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesMulti_SkipReadCache) {
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_SkipReadCache_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 3000, 10, {},
                                     "LoadEntriesMulti_SkipReadCache",
                                     &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_SkipReadCache_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 30000, 10, {},
                                     "LoadEntriesMulti_SkipReadCache",
                                     &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_SkipReadCache_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 30000, 100, {},
                                     "LoadEntriesMulti_SkipReadCache",
                                     &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix_SkipReadCache) {
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix_SkipReadCache_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 3000, 10, {1},
                                     "LoadEntriesMulti_OnePrefix_SkipReadCache",
                                     &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix_SkipReadCache_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 30000, 10, {1},
                                     "LoadEntriesMulti_OnePrefix_SkipReadCache",
                                     &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix_SkipReadCache_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(10, 30000, 100, {1},
                                     "LoadEntriesMulti_OnePrefix_SkipReadCache",
                                     &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix_DifferingNumDBs) {
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix_DifferingNumDBs_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       10, 3000, 10, {1}, "LoadEntriesSingle_OnePrefix_DifferingNumDBs",
       &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix_DifferingNumDBs_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       25, 3000, 10, {1}, "LoadEntriesSingle_OnePrefix_DifferingNumDBs",
       &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_OnePrefix_DifferingNumDBs_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       100, 3000, 10, {1}, "LoadEntriesSingle_OnePrefix_DifferingNumDBs",
       &num_entries);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix_DifferingNumDBs) {
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix_DifferingNumDBs_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       10, 3000, 10, {1}, "LoadEntriesMulti_OnePrefix_DifferingNumDBs",
       &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix_DifferingNumDBs_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       25, 3000, 10, {1}, "LoadEntriesMulti_OnePrefix_DifferingNumDBs",
       &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_OnePrefix_DifferingNumDBs_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       100, 3000, 10, {1}, "LoadEntriesMulti_OnePrefix_DifferingNumDBs",
       &num_entries);
@@ -798,20 +865,28 @@
 }
 
 TEST_F(ProtoDBPerfTest,
-       LoadEntriesSingle_OnePrefix_DifferingNumDBs_SkipReadCache) {
+       LoadEntriesSingle_OnePrefix_DifferingNumDBs_SkipReadCache_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       10, 3000, 10, {1},
       "LoadEntriesSingle_OnePrefix_DifferingNumDBs_SkipReadCache", &num_entries,
       false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest,
+       LoadEntriesSingle_OnePrefix_DifferingNumDBs_SkipReadCache_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       25, 3000, 10, {1},
       "LoadEntriesSingle_OnePrefix_DifferingNumDBs_SkipReadCache", &num_entries,
       false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest,
+       LoadEntriesSingle_OnePrefix_DifferingNumDBs_SkipReadCache_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       100, 3000, 10, {1},
       "LoadEntriesSingle_OnePrefix_DifferingNumDBs_SkipReadCache", &num_entries,
@@ -820,20 +895,28 @@
 }
 
 TEST_F(ProtoDBPerfTest,
-       LoadEntriesMulti_OnePrefix_DifferingNumDBs_SkipReadCache) {
+       LoadEntriesMulti_OnePrefix_DifferingNumDBs_SkipReadCache_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       10, 3000, 10, {1},
       "LoadEntriesMulti_OnePrefix_DifferingNumDBs_SkipReadCache", &num_entries,
       false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest,
+       LoadEntriesMulti_OnePrefix_DifferingNumDBs_SkipReadCache_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       25, 3000, 10, {1},
       "LoadEntriesMulti_OnePrefix_DifferingNumDBs_SkipReadCache", &num_entries,
       false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest,
+       LoadEntriesMulti_OnePrefix_DifferingNumDBs_SkipReadCache_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       100, 3000, 10, {1},
       "LoadEntriesMulti_OnePrefix_DifferingNumDBs_SkipReadCache", &num_entries,
@@ -841,66 +924,91 @@
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesSingle_DifferingNumDBs) {
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_DifferingNumDBs_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       10, 3000, 10, {}, "LoadEntriesSingle_DifferingNumDBs", &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_DifferingNumDBs_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       25, 3000, 10, {}, "LoadEntriesSingle_DifferingNumDBs", &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_DifferingNumDBs_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       100, 3000, 10, {}, "LoadEntriesSingle_DifferingNumDBs", &num_entries);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesMulti_DifferingNumDBs) {
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_DifferingNumDBs_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       10, 3000, 10, {}, "LoadEntriesMulti_DifferingNumDBs", &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_DifferingNumDBs_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       25, 3000, 10, {}, "LoadEntriesMulti_DifferingNumDBs", &num_entries);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_DifferingNumDBs_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       100, 3000, 10, {}, "LoadEntriesMulti_DifferingNumDBs", &num_entries);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesSingle_DifferingNumDBs_SkipReadCache) {
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_DifferingNumDBs_SkipReadCache_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       10, 3000, 10, {}, "LoadEntriesSingle_DifferingNumDBs_SkipReadCache",
       &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest,
+       LoadEntriesSingle_DifferingNumDBs_SkipReadCache_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       25, 3000, 10, {}, "LoadEntriesSingle_DifferingNumDBs_SkipReadCache",
       &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesSingle_DifferingNumDBs_SkipReadCache_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesSingleTestAndCleanup(
       100, 3000, 10, {}, "LoadEntriesSingle_DifferingNumDBs_SkipReadCache",
       &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
 }
 
-TEST_F(ProtoDBPerfTest, LoadEntriesMulti_DifferingNumDBs_SkipReadCache) {
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_DifferingNumDBs_SkipReadCache_Small) {
   unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       10, 3000, 10, {}, "LoadEntriesMulti_DifferingNumDBs_SkipReadCache",
       &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_DifferingNumDBs_SkipReadCache_Medium) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       25, 3000, 10, {}, "LoadEntriesMulti_DifferingNumDBs_SkipReadCache",
       &num_entries, false /* fill_read_cache */);
   ASSERT_NE(num_entries, 0U);
+}
 
+TEST_F(ProtoDBPerfTest, LoadEntriesMulti_DifferingNumDBs_SkipReadCache_Large) {
+  unsigned int num_entries = 0;
   RunLoadEntriesMultiTestAndCleanup(
       100, 3000, 10, {}, "LoadEntriesMulti_DifferingNumDBs_SkipReadCache",
       &num_entries, false /* fill_read_cache */);
diff --git a/components/leveldb_proto/testing/fake_db.h b/components/leveldb_proto/testing/fake_db.h
index bfce3cd..56ed635 100644
--- a/components/leveldb_proto/testing/fake_db.h
+++ b/components/leveldb_proto/testing/fake_db.h
@@ -53,6 +53,16 @@
       const leveldb::ReadOptions& options,
       const std::string& target_prefix,
       typename ProtoDatabase<T>::LoadCallback callback) override;
+  void LoadKeysAndEntries(
+      typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) override;
+  void LoadKeysAndEntriesWithFilter(
+      const LevelDB::KeyFilter& filter,
+      typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) override;
+  void LoadKeysAndEntriesWithFilter(
+      const LevelDB::KeyFilter& filter,
+      const leveldb::ReadOptions& options,
+      const std::string& target_prefix,
+      typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) override;
   void LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) override;
   void GetEntry(const std::string& key,
                 typename ProtoDatabase<T>::GetCallback callback) override;
@@ -78,6 +88,10 @@
   static void RunLoadCallback(typename ProtoDatabase<T>::LoadCallback callback,
                               std::unique_ptr<typename std::vector<T>> entries,
                               bool success);
+  static void RunLoadKeysAndEntriesCallback(
+      typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback,
+      std::unique_ptr<typename std::map<std::string, T>> entries,
+      bool success);
 
   static void RunLoadKeysCallback(
       typename ProtoDatabase<T>::LoadKeysCallback callback,
@@ -180,6 +194,38 @@
 }
 
 template <typename T>
+void FakeDB<T>::LoadKeysAndEntries(
+    typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWithFilter(LevelDB::KeyFilter(), std::move(callback));
+}
+
+template <typename T>
+void FakeDB<T>::LoadKeysAndEntriesWithFilter(
+    const LevelDB::KeyFilter& key_filter,
+    typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWithFilter(key_filter, leveldb::ReadOptions(),
+                               std::string(), std::move(callback));
+}
+
+template <typename T>
+void FakeDB<T>::LoadKeysAndEntriesWithFilter(
+    const LevelDB::KeyFilter& key_filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) {
+  auto keys_entries = std::make_unique<std::map<std::string, T>>();
+  for (const auto& pair : *db_) {
+    if (key_filter.is_null() || key_filter.Run(pair.first)) {
+      if (pair.first.compare(0, target_prefix.length(), target_prefix) == 0)
+        keys_entries->insert(pair);
+    }
+  }
+
+  load_callback_ = base::BindOnce(RunLoadKeysAndEntriesCallback,
+                                  std::move(callback), std::move(keys_entries));
+}
+
+template <typename T>
 void FakeDB<T>::LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) {
   std::unique_ptr<std::vector<std::string>> keys(
       new std::vector<std::string>());
@@ -254,6 +300,15 @@
 
 // static
 template <typename T>
+void FakeDB<T>::RunLoadKeysAndEntriesCallback(
+    typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback,
+    std::unique_ptr<typename std::map<std::string, T>> keys_entries,
+    bool success) {
+  std::move(callback).Run(success, std::move(keys_entries));
+}
+
+// static
+template <typename T>
 void FakeDB<T>::RunLoadKeysCallback(
     typename ProtoDatabase<T>::LoadKeysCallback callback,
     std::unique_ptr<std::vector<std::string>> keys,
diff --git a/components/os_crypt/os_crypt_features_mac.cc b/components/os_crypt/os_crypt_features_mac.cc
index cdbc7b7..6e9351a 100644
--- a/components/os_crypt/os_crypt_features_mac.cc
+++ b/components/os_crypt/os_crypt_features_mac.cc
@@ -11,7 +11,7 @@
 // unavailable, but there is a preference set that the key was created in the
 // past.
 const base::Feature kPreventEncryptionKeyOverwrites = {
-    "PreventEncryptionKeyOverwrites", base::FEATURE_DISABLED_BY_DEFAULT};
+    "PreventEncryptionKeyOverwrites", base::FEATURE_ENABLED_BY_DEFAULT};
 
 }  // namespace features
 }  // namespace os_crypt
diff --git a/components/password_manager/core/browser/credential_manager_impl.cc b/components/password_manager/core/browser/credential_manager_impl.cc
index 16baac0..f1e53b7 100644
--- a/components/password_manager/core/browser/credential_manager_impl.cc
+++ b/components/password_manager/core/browser/credential_manager_impl.cc
@@ -177,7 +177,7 @@
   CredentialInfo info;
   if (form) {
     password_manager::CredentialType type_to_return =
-        form->federation_origin.unique()
+        form->federation_origin.opaque()
             ? CredentialType::CREDENTIAL_TYPE_PASSWORD
             : CredentialType::CREDENTIAL_TYPE_FEDERATED;
     info = CredentialInfo(*form, type_to_return);
@@ -227,7 +227,7 @@
     return;
   }
 
-  if (!form.federation_origin.unique()) {
+  if (!form.federation_origin.opaque()) {
     // If this is a federated credential, check it against the federated matches
     // produced by the PasswordFormManager. If a match is found, update it and
     // return.
diff --git a/components/password_manager/core/browser/credential_manager_impl_unittest.cc b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
index 4de1873..539121a 100644
--- a/components/password_manager/core/browser/credential_manager_impl_unittest.cc
+++ b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
@@ -386,7 +386,7 @@
   EXPECT_EQ(form_.password_value, new_form.password_value);
   EXPECT_EQ(form_.origin, new_form.origin);
   EXPECT_EQ(form_.signon_realm, new_form.signon_realm);
-  EXPECT_TRUE(new_form.federation_origin.unique());
+  EXPECT_TRUE(new_form.federation_origin.opaque());
   EXPECT_EQ(form_.icon_url, new_form.icon_url);
   EXPECT_FALSE(form_.skip_zero_click);
   EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, new_form.scheme);
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index 72030d4..ea4f5da 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -72,7 +72,7 @@
            std::unique_ptr<autofill::PasswordForm>>
       credentials;
   for (auto& form : *forms) {
-    if (!form->federation_origin.unique()) {
+    if (!form->federation_origin.opaque()) {
       federated_forms.push_back(std::move(form));
     } else {
       auto key = std::make_pair(
@@ -168,8 +168,8 @@
   for (auto& form : results) {
     // Ensure that the form we're looking at matches the password and
     // federation filters provided.
-    if (!((form->federation_origin.unique() && include_passwords_) ||
-          (!form->federation_origin.unique() &&
+    if (!((form->federation_origin.opaque() && include_passwords_) ||
+          (!form->federation_origin.opaque() &&
            federations_.count(form->federation_origin.Serialize())))) {
       continue;
     }
@@ -205,7 +205,7 @@
       !password_bubble_experiment::ShouldShowAutoSignInPromptFirstRunExperience(
           delegate_->client()->GetPrefs())) {
     CredentialInfo info(*local_results[0],
-                        local_results[0]->federation_origin.unique()
+                        local_results[0]->federation_origin.opaque()
                             ? CredentialType::CREDENTIAL_TYPE_PASSWORD
                             : CredentialType::CREDENTIAL_TYPE_FEDERATED);
     delegate_->client()->NotifyUserAutoSignin(std::move(local_results),
diff --git a/components/password_manager/core/browser/form_fetcher_impl.cc b/components/password_manager/core/browser/form_fetcher_impl.cc
index d1f5515..f095ecf 100644
--- a/components/password_manager/core/browser/form_fetcher_impl.cc
+++ b/components/password_manager/core/browser/form_fetcher_impl.cc
@@ -35,7 +35,7 @@
   const auto first_federated = std::partition(
       store_results->begin(), store_results->end(),
       [](const std::unique_ptr<PasswordForm>& form) {
-        return form->federation_origin.unique();  // False means federated.
+        return form->federation_origin.opaque();  // False means federated.
       });
 
   // Move out federated matches.
diff --git a/components/password_manager/core/browser/http_credentials_cleaner.cc b/components/password_manager/core/browser/http_credentials_cleaner.cc
index 0119b85..73fd3e16 100644
--- a/components/password_manager/core/browser/http_credentials_cleaner.cc
+++ b/components/password_manager/core/browser/http_credentials_cleaner.cc
@@ -5,7 +5,10 @@
 #include "components/password_manager/core/browser/http_credentials_cleaner.h"
 
 #include "base/metrics/histogram_functions.h"
+#include "components/password_manager/core/browser/http_password_store_migrator.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_service.h"
 #include "url/gurl.h"
 
 namespace password_manager {
@@ -13,13 +16,20 @@
 HttpCredentialCleaner::HttpCredentialCleaner(
     scoped_refptr<PasswordStore> store,
     base::RepeatingCallback<network::mojom::NetworkContext*()>
-        network_context_getter)
+        network_context_getter,
+    PrefService* prefs)
     : store_(std::move(store)),
-      network_context_getter_(network_context_getter) {
-}
+      network_context_getter_(network_context_getter),
+      prefs_(prefs) {}
 
 HttpCredentialCleaner::~HttpCredentialCleaner() = default;
 
+bool HttpCredentialCleaner::ShouldRunCleanUp(PrefService* prefs) {
+  auto last = base::Time::FromDoubleT(prefs->GetDouble(
+      password_manager::prefs::kLastTimeObsoleteHttpCredentialsRemoved));
+  return ((base::Time::Now() - last).InDays() >= kCleanUpDelayInDays);
+}
+
 void HttpCredentialCleaner::StartCleaning(Observer* observer) {
   DCHECK(observer);
   DCHECK(!observer_);
@@ -40,10 +50,11 @@
              password_manager_util::GetSignonRealmWithProtocolExcluded(*form)),
          form->scheme, form->username_value});
     if (form->origin.SchemeIs(url::kHttpScheme)) {
+      const GURL origin = form->origin;
       PostHSTSQueryForHostAndNetworkContext(
-          form->origin, network_context_getter_.Run(),
+          origin, network_context_getter_.Run(),
           base::Bind(&HttpCredentialCleaner::OnHSTSQueryResult,
-                     base::Unretained(this), form_key, form->password_value));
+                     base::Unretained(this), base::Passed(&form), form_key));
       ++total_http_credentials_;
     } else {  // HTTPS
       https_credentials_map_[form_key].insert(form->password_value);
@@ -54,11 +65,10 @@
   ReportMetrics();
 }
 
-// |key| and |password_value| was created from the same form.
 void HttpCredentialCleaner::OnHSTSQueryResult(
+    std::unique_ptr<autofill::PasswordForm> form,
     FormKey key,
-    base::string16 password_value,
-    password_manager::HSTSResult hsts_result) {
+    HSTSResult hsts_result) {
   ++processed_results_;
   base::ScopedClosureRunner report(base::BindOnce(
       &HttpCredentialCleaner::ReportMetrics, base::Unretained(this)));
@@ -72,13 +82,23 @@
   if (user_it == https_credentials_map_.end()) {
     // Credentials are not migrated yet.
     ++https_credential_not_found_[is_hsts];
+    if (is_hsts) {
+      // Migrate credentials to HTTPS, by moving them.
+      store_->AddLogin(
+          HttpPasswordStoreMigrator::MigrateHttpFormToHttps(*form));
+      store_->RemoveLogin(*form);
+    }
     return;
   }
 
-  if (base::ContainsKey(user_it->second, password_value)) {
+  if (base::ContainsKey(user_it->second, form->password_value)) {
     // The password store contains the same credentials (signon_realm, scheme,
-    // username and password) on HTTP version of the form.
+    // username and password) on HTTPS version of the form.
     ++same_password_[is_hsts];
+    if (is_hsts) {
+      // This HTTP credential is no more used.
+      store_->RemoveLogin(*form);
+    }
   } else {
     ++different_password_[is_hsts];
   }
@@ -109,6 +129,8 @@
         https_credential_not_found_[is_hsts_enabled]);
   }
 
+  prefs_->SetDouble(prefs::kLastTimeObsoleteHttpCredentialsRemoved,
+                    base::Time::Now().ToDoubleT());
   observer_->CleaningCompleted();
 }
 
diff --git a/components/password_manager/core/browser/http_credentials_cleaner.h b/components/password_manager/core/browser/http_credentials_cleaner.h
index ec01e306..bd1bd97 100644
--- a/components/password_manager/core/browser/http_credentials_cleaner.h
+++ b/components/password_manager/core/browser/http_credentials_cleaner.h
@@ -25,26 +25,46 @@
 }  // namespace mojom
 }  // namespace network
 
+class PrefService;
+
 namespace password_manager {
 
 class PasswordStore;
 
-// This class is responsible for reporting metrics about HTTP to HTTPS
-// migration.
+// This class is responsible for removing obsolete HTTP credentials that can
+// safely be deleted and reporting metrics about HTTP to HTTPS migration. This
+// class will delete HTTP credentials with HSTS enabled for that site and for
+// which an equivalent (i.e. same signon_realm excluding protocol,
+// PasswordForm::scheme (i.e. HTML, BASIC, etc.), username and password) HTTPS
+// credential exists in the password store. Also it replace HTTP credentials for
+// which no HTTPS credential with same signon_realm excluding protocol,
+// PasswordForm::scheme and username exists and site has
+// HSTS enabled, by an HTTPS version of that form.
 class HttpCredentialCleaner : public PasswordStoreConsumer,
                               public CredentialsCleaner {
  public:
+  // The cleaning will be made for credentials from |store|.
   // |network_context_getter| should return nullptr if it can't get the network
   // context because whatever owns it is dead.
+  // A preference from |prefs| is used to set the last time (in seconds) when
+  // the cleaning was performed.
   HttpCredentialCleaner(
       scoped_refptr<PasswordStore> store,
       base::RepeatingCallback<network::mojom::NetworkContext*()>
-          network_context_getter);
+          network_context_getter,
+      PrefService* prefs);
   ~HttpCredentialCleaner() override;
 
+  // Indicate whether there are at least |kCleanUpDelayInDays| days passed in
+  // order to run the clean-up.
+  static bool ShouldRunCleanUp(PrefService* prefs);
+
   // CredentialsCleaner:
   void StartCleaning(Observer* observer) override;
 
+  // The time that should pass in order to do the clean-up again.
+  static constexpr int kCleanUpDelayInDays = 90;
+
  private:
   // This type define a subset of PasswordForm where first argument is the
   // signon-realm excluding the protocol, the second argument is
@@ -57,20 +77,30 @@
   void OnGetPasswordStoreResults(
       std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
 
-  void OnHSTSQueryResult(FormKey key,
-                         base::string16 password_value,
+  // This function will inform us using |hsts_result| parameter if the |form|'s
+  // host has HSTS enabled. |key| is |form|'s encoding which is used for
+  // matching |form| with an HTTPS credential with the same FormKey.
+  // Inside the function the metric counters are updated and, if needed, the
+  // |form| is removed or migrated to HTTPS.
+  void OnHSTSQueryResult(std::unique_ptr<autofill::PasswordForm> form,
+                         FormKey key,
                          HSTSResult hsts_result);
 
   // After metrics are reported, this function will inform the |observer_| about
   // completion.
   void ReportMetrics();
 
+  // Clean-up is performed on |store_|.
   scoped_refptr<PasswordStore> store_;
 
   // Needed to create HSTS request.
   base::RepeatingCallback<network::mojom::NetworkContext*()>
       network_context_getter_;
 
+  // |prefs_| is not an owning pointer. It is used to record he last time (in
+  // seconds) when the cleaning was performed.
+  PrefService* prefs_;
+
   // Map from (signon-realm excluding the protocol, Password::Scheme, username)
   // tuples of HTTPS forms to a list of passwords for that pair.
   std::map<FormKey, base::flat_set<base::string16>> https_credentials_map_;
diff --git a/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc b/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
index 1720124..e256ed28 100644
--- a/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
+++ b/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
@@ -10,6 +10,8 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_task_environment.h"
+#include "base/time/time.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/browser/test_password_store.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -181,6 +183,12 @@
   scoped_task_environment.RunUntilIdle();
 
   base::HistogramTester histogram_tester;
+  const TestPasswordStore::PasswordMap passwords_before_cleaning =
+      store_->stored_passwords();
+
+  TestingPrefServiceSimple prefs;
+  prefs.registry()->RegisterDoublePref(
+      prefs::kLastTimeObsoleteHttpCredentialsRemoved, 0.0);
 
   MockCredentialsCleanerObserver observer;
   HttpCredentialCleaner cleaner(
@@ -193,7 +201,8 @@
         // StoragePartition::GetNetworkContext will return a mojo pipe
         // even in the in-process case.
         return network_context_pipe.get();
-      }));
+      }),
+      &prefs);
   EXPECT_CALL(observer, CleaningCompleted);
   cleaner.StartCleaning(&observer);
   scoped_task_environment.RunUntilIdle();
@@ -222,6 +231,22 @@
     histogram_tester.ExpectUniqueSample(histogram.histogram_name, sample, 1);
   }
 
+  const TestPasswordStore::PasswordMap current_store =
+      store_->stored_passwords();
+  if (test.is_hsts_enabled &&
+      test.expected != HttpCredentialType::kConflicting) {
+    // HTTP credentials have to be removed.
+    EXPECT_TRUE(current_store.find(http_form.signon_realm)->second.empty());
+
+    // For no matching case https credentials were added and for an equivalent
+    // case they already existed.
+    EXPECT_TRUE(base::ContainsKey(current_store, "https://example.org/"));
+  } else {
+    // Hsts not enabled or credentials are have different passwords, so
+    // nothing should change in the password store.
+    EXPECT_EQ(current_store, passwords_before_cleaning);
+  }
+
   store_->ShutdownOnUIThread();
   scoped_task_environment.RunUntilIdle();
 }
@@ -230,4 +255,75 @@
                         HttpCredentialCleanerTest,
                         ::testing::ValuesIn(kCases));
 
+TEST(HttpCredentialCleaner, StartCleanUpTest) {
+  for (bool should_start_clean_up : {false, true}) {
+    SCOPED_TRACE(testing::Message()
+                 << "should_start_clean_up=" << should_start_clean_up);
+
+    base::test::ScopedTaskEnvironment scoped_task_environment;
+    auto password_store = base::MakeRefCounted<TestPasswordStore>();
+    ASSERT_TRUE(password_store->Init(syncer::SyncableService::StartSyncFlare(),
+                                     nullptr));
+
+    double last_time =
+        (base::Time::Now() - base::TimeDelta::FromMinutes(10)).ToDoubleT();
+    if (should_start_clean_up) {
+      // Simulate that the clean-up was performed
+      // (HttpCredentialCleaner::kCleanUpDelayInDays + 1) days ago.
+      // We have to simulate this because the cleaning of obsolete HTTP
+      // credentials is done with low frequency (with a delay of
+      // |HttpCredentialCleaner::kCleanUpDelayInDays| days between two
+      // clean-ups)
+      last_time = (base::Time::Now() -
+                   base::TimeDelta::FromDays(
+                       HttpCredentialCleaner::kCleanUpDelayInDays + 1))
+                      .ToDoubleT();
+    }
+
+    TestingPrefServiceSimple prefs;
+    prefs.registry()->RegisterDoublePref(
+        prefs::kLastTimeObsoleteHttpCredentialsRemoved, last_time);
+
+    EXPECT_EQ(should_start_clean_up,
+              HttpCredentialCleaner::ShouldRunCleanUp(&prefs));
+
+    if (!should_start_clean_up) {
+      password_store->ShutdownOnUIThread();
+      scoped_task_environment.RunUntilIdle();
+      continue;
+    }
+
+    auto request_context =
+        base::MakeRefCounted<net::TestURLRequestContextGetter>(
+            base::ThreadTaskRunnerHandle::Get());
+    network::mojom::NetworkContextPtr network_context_pipe;
+    auto network_context = std::make_unique<network::NetworkContext>(
+        nullptr, mojo::MakeRequest(&network_context_pipe),
+        request_context->GetURLRequestContext());
+
+    MockCredentialsCleanerObserver observer;
+    HttpCredentialCleaner cleaner(
+        password_store,
+        base::BindLambdaForTesting([&]() -> network::mojom::NetworkContext* {
+          // This needs to be network_context_pipe.get() and
+          // not network_context.get() to make HSTS queries asynchronous, which
+          // is what the progress tracking logic in HttpMetricsMigrationReporter
+          // assumes.  This also matches reality, since
+          // StoragePartition::GetNetworkContext will return a mojo pipe
+          // even in the in-process case.
+          return network_context_pipe.get();
+        }),
+        &prefs);
+    EXPECT_CALL(observer, CleaningCompleted);
+    cleaner.StartCleaning(&observer);
+    scoped_task_environment.RunUntilIdle();
+
+    EXPECT_NE(prefs.GetDouble(prefs::kLastTimeObsoleteHttpCredentialsRemoved),
+              last_time);
+
+    password_store->ShutdownOnUIThread();
+    scoped_task_environment.RunUntilIdle();
+  }
+}
+
 }  // namespace password_manager
\ No newline at end of file
diff --git a/components/password_manager/core/browser/http_password_store_migrator.cc b/components/password_manager/core/browser/http_password_store_migrator.cc
index 73ccdf5c..5882823 100644
--- a/components/password_manager/core/browser/http_password_store_migrator.cc
+++ b/components/password_manager/core/browser/http_password_store_migrator.cc
@@ -4,10 +4,14 @@
 
 #include "components/password_manager/core/browser/http_password_store_migrator.h"
 
+#include <string>
+#include <utility>
+
 #include "base/memory/weak_ptr.h"
 #include "base/stl_util.h"
 #include "components/password_manager/core/browser/password_manager_client.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "url/gurl.h"
 #include "url/url_constants.h"
@@ -51,6 +55,29 @@
 
 HttpPasswordStoreMigrator::~HttpPasswordStoreMigrator() = default;
 
+autofill::PasswordForm HttpPasswordStoreMigrator::MigrateHttpFormToHttps(
+    const autofill::PasswordForm& http_form) {
+  DCHECK(http_form.origin.SchemeIs(url::kHttpScheme));
+
+  autofill::PasswordForm https_form = http_form;
+  GURL::Replacements rep;
+  rep.SetSchemeStr(url::kHttpsScheme);
+  https_form.origin = http_form.origin.ReplaceComponents(rep);
+  https_form.signon_realm =
+      std::string(url::kHttpsScheme) +
+      std::string(url::kStandardSchemeSeparator) +
+      std::string(
+          password_manager_util::GetSignonRealmWithProtocolExcluded(http_form));
+  // If |action| is not HTTPS then it's most likely obsolete. Otherwise, it
+  // may still be valid.
+  if (!http_form.action.SchemeIs(url::kHttpsScheme))
+    https_form.action = https_form.origin;
+  https_form.form_data = autofill::FormData();
+  https_form.generation_upload_status = autofill::PasswordForm::NO_SIGNAL_SENT;
+  https_form.skip_zero_click = false;
+  return https_form;
+}
+
 void HttpPasswordStoreMigrator::OnGetPasswordStoreResults(
     std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -84,19 +111,8 @@
   // Add the new credentials to the password store. The HTTP forms are
   // removed iff |mode_| == MigrationMode::MOVE.
   for (const auto& form : results_) {
-    autofill::PasswordForm new_form = *form;
-
-    GURL::Replacements rep;
-    rep.SetSchemeStr(url::kHttpsScheme);
-    new_form.origin = form->origin.ReplaceComponents(rep);
-    new_form.signon_realm = new_form.origin.GetOrigin().spec();
-    // If |action| is not HTTPS then it's most likely obsolete. Otherwise, it
-    // may still be valid.
-    if (!form->action.SchemeIs(url::kHttpsScheme))
-      new_form.action = new_form.origin;
-    new_form.form_data = autofill::FormData();
-    new_form.generation_upload_status = autofill::PasswordForm::NO_SIGNAL_SENT;
-    new_form.skip_zero_click = false;
+    autofill::PasswordForm new_form =
+        HttpPasswordStoreMigrator::MigrateHttpFormToHttps(*form);
     client_->GetPasswordStore()->AddLogin(new_form);
 
     if (mode_ == MigrationMode::MOVE)
diff --git a/components/password_manager/core/browser/http_password_store_migrator.h b/components/password_manager/core/browser/http_password_store_migrator.h
index 55c6865..91bf4dc 100644
--- a/components/password_manager/core/browser/http_password_store_migrator.h
+++ b/components/password_manager/core/browser/http_password_store_migrator.h
@@ -50,6 +50,10 @@
                             Consumer* consumer);
   ~HttpPasswordStoreMigrator() override;
 
+  // Creates HTTPS version of |http_form|.
+  static autofill::PasswordForm MigrateHttpFormToHttps(
+      const autofill::PasswordForm& http_form);
+
   // PasswordStoreConsumer:
   void OnGetPasswordStoreResults(
       std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
diff --git a/components/password_manager/core/browser/http_password_store_migrator_unittest.cc b/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
index f2dd806..8cc337ad 100644
--- a/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
+++ b/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
@@ -242,4 +242,37 @@
   TestMigratorDeletionByConsumer(false);
 }
 
+TEST(HttpPasswordStoreMigrator, MigrateHttpFormToHttpsTestSignonRealm) {
+  const GURL kOrigins[] = {GURL("http://example.org/"),
+                           GURL("http://example.org/path/")};
+
+  for (bool origin_has_paths : {true, false}) {
+    PasswordForm http_html_form;
+    http_html_form.origin = kOrigins[origin_has_paths];
+    http_html_form.signon_realm = "http://example.org/";
+    http_html_form.scheme = PasswordForm::Scheme::SCHEME_HTML;
+
+    PasswordForm non_html_empty_realm_form;
+    non_html_empty_realm_form.origin = kOrigins[origin_has_paths];
+    non_html_empty_realm_form.signon_realm = "http://example.org/";
+    non_html_empty_realm_form.scheme = PasswordForm::Scheme::SCHEME_BASIC;
+
+    PasswordForm non_html_form;
+    non_html_form.origin = kOrigins[origin_has_paths];
+    non_html_form.signon_realm = "http://example.org/realm";
+    non_html_form.scheme = PasswordForm::Scheme::SCHEME_BASIC;
+
+    EXPECT_EQ(HttpPasswordStoreMigrator::MigrateHttpFormToHttps(http_html_form)
+                  .signon_realm,
+              "https://example.org/");
+    EXPECT_EQ(HttpPasswordStoreMigrator::MigrateHttpFormToHttps(
+                  non_html_empty_realm_form)
+                  .signon_realm,
+              "https://example.org/");
+    EXPECT_EQ(HttpPasswordStoreMigrator::MigrateHttpFormToHttps(non_html_form)
+                  .signon_realm,
+              "https://example.org/realm");
+  }
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index 060e093b..693f619 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -154,7 +154,7 @@
   s->BindString(COLUMN_ICON_URL, form.icon_url.spec());
   // An empty Origin serializes as "null" which would be strange to store here.
   s->BindString(COLUMN_FEDERATION_URL,
-                form.federation_origin.unique()
+                form.federation_origin.opaque()
                     ? std::string()
                     : form.federation_origin.Serialize());
   s->BindInt(COLUMN_SKIP_ZERO_CLICK, form.skip_zero_click);
@@ -953,7 +953,7 @@
   s.BindString16(next_param++, form.display_name);
   s.BindString(next_param++, form.icon_url.spec());
   // An empty Origin serializes as "null" which would be strange to store here.
-  s.BindString(next_param++, form.federation_origin.unique()
+  s.BindString(next_param++, form.federation_origin.opaque()
                                  ? std::string()
                                  : form.federation_origin.Serialize());
   s.BindInt(next_param++, form.skip_zero_click);
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc
index debc221..4a9d1398 100644
--- a/components/password_manager/core/browser/login_database_unittest.cc
+++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -2111,6 +2111,12 @@
 }
 
 TEST_F(LoginDatabaseUndecryptableLoginsTest, DeleteUndecryptableLoginsTest) {
+  // Disable feature for deleting corrupted passwords, so GetAutofillableLogins
+  // doesn't remove any passwords.
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(
+      features::kDeleteCorruptedPasswords);
+
   auto form1 = AddDummyLogin("foo1", GURL("https://foo1.com/"), false);
   auto form2 = AddDummyLogin("foo2", GURL("https://foo2.com/"), true);
   auto form3 = AddDummyLogin("foo3", GURL("https://foo3.com/"), false);
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc
index a1db4f6..ea1479e 100644
--- a/components/password_manager/core/browser/new_password_form_manager.cc
+++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -695,7 +695,7 @@
 
 const PasswordForm* NewPasswordFormManager::FindBestSavedMatch(
     const PasswordForm* submitted_form) const {
-  if (!submitted_form->federation_origin.unique())
+  if (!submitted_form->federation_origin.opaque())
     return nullptr;
 
   // Return form with matching |username_value|.
@@ -762,7 +762,7 @@
 
 void NewPasswordFormManager::ProcessUpdate() {
   DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
-  DCHECK(preferred_match_ || !pending_credentials_.federation_origin.unique());
+  DCHECK(preferred_match_ || !pending_credentials_.federation_origin.opaque());
   // If we're doing an Update, we either autofilled correctly and need to
   // update the stats, or the user typed in a new password for autofilled
   // username, or the user selected one of the non-preferred matches,
@@ -793,7 +793,7 @@
 std::vector<PasswordForm>
 NewPasswordFormManager::FindOtherCredentialsToUpdate() {
   std::vector<autofill::PasswordForm> credentials_to_update;
-  if (!pending_credentials_.federation_origin.unique())
+  if (!pending_credentials_.federation_origin.opaque())
     return credentials_to_update;
 
   auto updated_password_it =
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 3a82997..a1568f7 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -589,7 +589,7 @@
 
 void PasswordFormManager::ProcessUpdate() {
   DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
-  DCHECK(preferred_match_ || !pending_credentials_.federation_origin.unique());
+  DCHECK(preferred_match_ || !pending_credentials_.federation_origin.opaque());
   // If we're doing an Update, we either autofilled correctly and need to
   // update the stats, or the user typed in a new password for autofilled
   // username, or the user selected one of the non-preferred matches,
@@ -792,7 +792,7 @@
 
 const PasswordForm* PasswordFormManager::FindBestSavedMatch(
     const PasswordForm* submitted_form) const {
-  if (!submitted_form->federation_origin.unique())
+  if (!submitted_form->federation_origin.opaque())
     return nullptr;
 
   // Return form with matching |username_value|.
@@ -1035,7 +1035,7 @@
 
 std::vector<PasswordForm> PasswordFormManager::FindOtherCredentialsToUpdate() {
   std::vector<autofill::PasswordForm> credentials_to_update;
-  if (!pending_credentials_.federation_origin.unique())
+  if (!pending_credentials_.federation_origin.opaque())
     return credentials_to_update;
 
   auto updated_password_it =
diff --git a/components/password_manager/core/browser/password_list_sorter.cc b/components/password_manager/core/browser/password_list_sorter.cc
index a1c029a..223cb0e 100644
--- a/components/password_manager/core/browser/password_list_sorter.cc
+++ b/components/password_manager/core/browser/password_list_sorter.cc
@@ -65,7 +65,7 @@
            kSortKeyPartsSeparator + base::UTF16ToUTF8(form.password_value);
 
     key += kSortKeyPartsSeparator;
-    if (!form.federation_origin.unique())
+    if (!form.federation_origin.opaque())
       key += form.federation_origin.host();
     else
       key += kSortKeyNoFederationSymbol;
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 5f9cdd29..6ee3211 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -347,6 +347,8 @@
                                 false);
   registry->RegisterBooleanPref(prefs::kCredentialsWithWrongSignonRealmRemoved,
                                 false);
+  registry->RegisterDoublePref(prefs::kLastTimeObsoleteHttpCredentialsRemoved,
+                               0.0);
 
 #if defined(OS_MACOSX)
   registry->RegisterIntegerPref(
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.h b/components/password_manager/core/browser/password_manager_metrics_util.h
index abf7c44..99341ff 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -181,13 +181,6 @@
   REAUTH_COUNT
 };
 
-// Metrics: PasswordManager.IE7LookupResult
-enum IE7LookupResultStatus {
-  IE7_RESULTS_ABSENT = 0,
-  IE7_RESULTS_PRESENT = 1,
-  IE7_RESULTS_COUNT
-};
-
 // Specifies the type of PasswordFormManagers and derived classes to distinguish
 // the context in which a PasswordFormManager is being created and used.
 enum class CredentialSourceType {
diff --git a/components/password_manager/core/browser/password_manager_util.cc b/components/password_manager/core/browser/password_manager_util.cc
index 49314ba..4d2e1b3 100644
--- a/components/password_manager/core/browser/password_manager_util.cc
+++ b/components/password_manager/core/browser/password_manager_util.cc
@@ -10,6 +10,7 @@
 
 #include "base/metrics/histogram_functions.h"
 #include "base/stl_util.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/popup_item_ids.h"
@@ -120,7 +121,7 @@
   base::EraseIf(*android_credentials,
                 [](const std::unique_ptr<PasswordForm>& form) {
                   return form->scheme == PasswordForm::SCHEME_USERNAME_ONLY &&
-                         form->federation_origin.unique();
+                         form->federation_origin.opaque();
                 });
 
   // Set "skip_zero_click" on federated credentials.
@@ -186,6 +187,8 @@
       autofill::password_generation::PASSWORD_GENERATION_CONTEXT_MENU_PRESSED);
 }
 
+// TODO(http://crbug.com/890318): Add unitests to check cleaners are correctly
+// created.
 void RemoveUselessCredentials(
     scoped_refptr<password_manager::PasswordStore> store,
     PrefService* prefs,
@@ -229,10 +232,11 @@
 
 #if !defined(OS_IOS)
   // Can be null for some unittests.
-  if (!network_context_getter.is_null()) {
+  if (!network_context_getter.is_null() &&
+      password_manager::HttpCredentialCleaner::ShouldRunCleanUp(prefs)) {
     cleaning_tasks_runner->AddCleaningTask(
         std::make_unique<password_manager::HttpCredentialCleaner>(
-            store, network_context_getter));
+            store, network_context_getter, prefs));
   }
 #endif  // !defined(OS_IOS)
 
diff --git a/components/password_manager/core/browser/password_manager_util.h b/components/password_manager/core/browser/password_manager_util.h
index e6b75d65..3e64fe7 100644
--- a/components/password_manager/core/browser/password_manager_util.h
+++ b/components/password_manager/core/browser/password_manager_util.h
@@ -100,10 +100,10 @@
 // hence blacklisted duplicates need to be removed.
 // (2) Removing or fixing of HTTPS credentials with wrong signon_realm. See
 // https://crbug.com/881731 for details.
-// (3) Report metrics about HTTP to HTTPS migration process. This feature
-// is not available on iOS platform because the HSTS query is not supported.
-// |network_context_getter| is always null for iOS and it can also be null for
-// some unittests.
+// (3) Report metrics about HTTP to HTTPS migration process and remove obsolete
+// HTTP credentials. This feature is not available on iOS platform because the
+// HSTS query is not supported. |network_context_getter| is always null for iOS
+// and it can also be null for some unittests.
 void RemoveUselessCredentials(
     scoped_refptr<password_manager::PasswordStore> store,
     PrefService* prefs,
diff --git a/components/password_manager/core/browser/password_syncable_service.cc b/components/password_manager/core/browser/password_syncable_service.cc
index 11d37104..02fc3ce 100644
--- a/components/password_manager/core/browser/password_syncable_service.cc
+++ b/components/password_manager/core/browser/password_syncable_service.cc
@@ -464,7 +464,7 @@
   CopyStringField(display_name);
   password_specifics->set_avatar_url(password_form.icon_url.spec());
   password_specifics->set_federation_url(
-      password_form.federation_origin.unique()
+      password_form.federation_origin.opaque()
           ? std::string()
           : password_form.federation_origin.Serialize());
 #undef CopyStringField
diff --git a/components/password_manager/core/browser/password_syncable_service_unittest.cc b/components/password_manager/core/browser/password_syncable_service_unittest.cc
index 61467bf8..417eec1 100644
--- a/components/password_manager/core/browser/password_syncable_service_unittest.cc
+++ b/components/password_manager/core/browser/password_syncable_service_unittest.cc
@@ -495,11 +495,8 @@
   syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
                           "Failed to get passwords from store.",
                           syncer::PASSWORDS);
-  EXPECT_CALL(*password_store(), DeleteUndecryptableLogins())
-      .WillOnce(Return(DatabaseCleanupResult::kSuccess));
   EXPECT_CALL(*password_store(), FillAutofillableLogins(_))
-      .Times(2)
-      .WillRepeatedly(Return(false));
+      .WillOnce(Return(false));
   EXPECT_CALL(*error_factory, CreateAndUploadError(_, _))
       .WillOnce(Return(error));
   // ActOnPasswordStoreChanges() below shouldn't generate any changes for Sync.
@@ -539,11 +536,15 @@
   EXPECT_TRUE(result.error().IsSet());
 }
 
-// Enable feature for deleting undecryptable logins.
+// Test that passwords are recovered for Sync users using the older feature
+// (kRecoverPasswordsForSyncUsers) when feature for recovering passwords for
+// Sync users is enabled, while feature for deleting corrupted passwords for
+// all users is disabled.
 TEST_F(PasswordSyncableServiceTest, RecoverPasswordsForSyncUsersEnabled) {
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      features::kRecoverPasswordsForSyncUsers);
+  scoped_feature_list.InitWithFeatures(
+      {features::kRecoverPasswordsForSyncUsers},
+      {features::kDeleteCorruptedPasswords});
 
   EXPECT_CALL(*processor_, ProcessSyncChanges(_, IsEmpty()));
   EXPECT_CALL(*password_store(), FillAutofillableLogins(_))
@@ -560,8 +561,10 @@
   EXPECT_FALSE(result.error().IsSet());
 }
 
-// Test that corrupted logins are not removed when merging data if features
-// for recovering passwords for both Sync and non-Sync users are enabled.
+// Test that passwords are not recovered using the older feature
+// (kRecoverPasswordForSyncUsers) when merging data if both features for
+// recovering passwords for Sync users and deleting passwords for all users
+// are enabled.
 TEST_F(PasswordSyncableServiceTest, PasswordRecoveryForAllUsersEnabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures({features::kRecoverPasswordsForSyncUsers,
@@ -588,8 +591,9 @@
 // Database cleanup fails because encryption is unavailable.
 TEST_F(PasswordSyncableServiceTest, FailedDeleteUndecryptableLogins) {
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      features::kRecoverPasswordsForSyncUsers);
+  scoped_feature_list.InitWithFeatures(
+      {features::kRecoverPasswordsForSyncUsers},
+      {features::kDeleteCorruptedPasswords});
   auto error_factory = std::make_unique<syncer::SyncErrorFactoryMock>();
   syncer::SyncError error(
       FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
@@ -644,7 +648,7 @@
 // string.
 TEST_F(PasswordSyncableServiceTest, SerializeEmptyFederation) {
   autofill::PasswordForm form;
-  EXPECT_TRUE(form.federation_origin.unique());
+  EXPECT_TRUE(form.federation_origin.opaque());
   syncer::SyncData data = SyncDataFromPassword(form);
   const sync_pb::PasswordSpecificsData& specifics = GetPasswordSpecifics(data);
   EXPECT_TRUE(specifics.has_federation_url());
@@ -652,7 +656,7 @@
 
   // Deserialize back.
   form = PasswordFromSpecifics(specifics);
-  EXPECT_TRUE(form.federation_origin.unique());
+  EXPECT_TRUE(form.federation_origin.opaque());
 
   // Make sure that the Origins uploaded incorrectly are still deserialized
   // correctly.
@@ -660,7 +664,7 @@
   sync_pb::PasswordSpecificsData specifics1;
   specifics1.set_federation_url("null");
   form = PasswordFromSpecifics(specifics1);
-  EXPECT_TRUE(form.federation_origin.unique());
+  EXPECT_TRUE(form.federation_origin.opaque());
 }
 
 // Serialize empty PasswordForm and make sure the Sync representation is
diff --git a/components/password_manager/core/browser/psl_matching_helper.cc b/components/password_manager/core/browser/psl_matching_helper.cc
index 6cbb305..d660f23 100644
--- a/components/password_manager/core/browser/psl_matching_helper.cc
+++ b/components/password_manager/core/browser/psl_matching_helper.cc
@@ -66,7 +66,7 @@
 
   const bool allow_psl_match = ShouldPSLDomainMatchingApply(
       GetRegistryControlledDomain(GURL(form_digest.signon_realm)));
-  const bool allow_federated_match = !form.federation_origin.unique();
+  const bool allow_federated_match = !form.federation_origin.opaque();
 
   if (allow_psl_match &&
       IsPublicSuffixDomainMatch(form.signon_realm, form_digest.signon_realm))
diff --git a/components/password_manager/core/common/credential_manager_types_unittest.cc b/components/password_manager/core/common/credential_manager_types_unittest.cc
index 7d25d7b..54dc23d 100644
--- a/components/password_manager/core/common/credential_manager_types_unittest.cc
+++ b/components/password_manager/core/common/credential_manager_types_unittest.cc
@@ -81,7 +81,7 @@
 
   // Local credentials have empty federation_origins, non-empty passwords, and
   // a signon realm that matches the origin.
-  EXPECT_TRUE(form->federation_origin.unique());
+  EXPECT_TRUE(form->federation_origin.opaque());
   EXPECT_EQ(info.password, form->password_value);
   EXPECT_EQ(origin_.spec(), form->signon_realm);
 }
@@ -95,7 +95,7 @@
   EXPECT_EQ(base::string16(), form->display_name);
   EXPECT_EQ(origin_, form->origin);
   EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, form->scheme);
-  EXPECT_TRUE(form->federation_origin.unique());
+  EXPECT_TRUE(form->federation_origin.opaque());
   EXPECT_EQ(base::string16(), form->password_value);
   EXPECT_EQ(origin_.spec(), form->signon_realm);
 }
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index 14af7d2..dc449da 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -19,10 +19,10 @@
 const base::Feature kAutofillHome = {"AutofillHome",
                                      base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Recovers lost passwords on Mac by deleting ones that cannot be decrypted
+// Recovers lost passwords on Mac by deleting the ones that cannot be decrypted
 // with the present encryption key from the Keychain.
 const base::Feature kDeleteCorruptedPasswords = {
-    "DeleteCorruptedPasswords", base::FEATURE_DISABLED_BY_DEFAULT};
+    "DeleteCorruptedPasswords", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Use HTML based username detector.
 const base::Feature kHtmlBasedUsernameDetector = {
@@ -58,7 +58,7 @@
 // Deletes entries from local database on Mac which cannot be decrypted when
 // merging data with Sync.
 const base::Feature kRecoverPasswordsForSyncUsers = {
-    "RecoverPasswordsForSyncUsers", base::FEATURE_ENABLED_BY_DEFAULT};
+    "RecoverPasswordsForSyncUsers", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Enables the experiment for the password manager to only fill on account
 // selection, rather than autofilling on page load, with highlighting of fields.
diff --git a/components/password_manager/core/common/password_manager_pref_names.cc b/components/password_manager/core/common/password_manager_pref_names.cc
index 9a99340b..10ec887 100644
--- a/components/password_manager/core/common/password_manager_pref_names.cc
+++ b/components/password_manager/core/common/password_manager_pref_names.cc
@@ -47,6 +47,9 @@
 const char kCredentialsWithWrongSignonRealmRemoved[] =
     "profile.credentials_with_wrong_signon_realm_removed";
 
+const char kLastTimeObsoleteHttpCredentialsRemoved[] =
+    "profile.last_time_obsolete_http_credentials_removed";
+
 const char kPasswordHashDataList[] = "profile.password_hash_data_list";
 
 }  // namespace prefs
diff --git a/components/password_manager/core/common/password_manager_pref_names.h b/components/password_manager/core/common/password_manager_pref_names.h
index a978d6e7..cd493d4 100644
--- a/components/password_manager/core/common/password_manager_pref_names.h
+++ b/components/password_manager/core/common/password_manager_pref_names.h
@@ -76,6 +76,10 @@
 // Whether Chrome deleted credentials that had wrong signon_realm.
 extern const char kCredentialsWithWrongSignonRealmRemoved[];
 
+// Indicates the time (in seconds) when last cleaning of obsolete HTTP
+// credentials was performed.
+extern const char kLastTimeObsoleteHttpCredentialsRemoved[];
+
 // List that contains captured password hashes.
 extern const char kPasswordHashDataList[];
 
diff --git a/components/policy/core/common/cloud/cloud_policy_client.cc b/components/policy/core/common/cloud/cloud_policy_client.cc
index dcfc28b..cfd2697 100644
--- a/components/policy/core/common/cloud/cloud_policy_client.cc
+++ b/components/policy/core/common/cloud/cloud_policy_client.cc
@@ -150,9 +150,6 @@
 
 CloudPolicyClient::Observer::~Observer() {}
 
-void CloudPolicyClient::Observer::OnRobotAuthCodesFetched(
-    CloudPolicyClient* client) {}
-
 CloudPolicyClient::CloudPolicyClient(
     const std::string& machine_id,
     const std::string& machine_model,
@@ -461,7 +458,8 @@
   request_jobs_.back()->Start(job_callback);
 }
 
-void CloudPolicyClient::FetchRobotAuthCodes(std::unique_ptr<DMAuth> auth) {
+void CloudPolicyClient::FetchRobotAuthCodes(std::unique_ptr<DMAuth> auth,
+                                            RobotAuthCodeCallback callback) {
   CHECK(is_registered());
   DCHECK(auth->has_dm_token());
 
@@ -479,9 +477,9 @@
   request->add_auth_scope(GaiaConstants::kAnyApiOAuth2Scope);
   request->set_device_type(em::DeviceServiceApiAccessRequest::CHROME_OS);
 
-  policy_fetch_request_job_->Start(
-      base::Bind(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted,
-                 weak_ptr_factory_.GetWeakPtr()));
+  policy_fetch_request_job_->Start(base::AdaptCallbackForRepeating(
+      base::BindOnce(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
 }
 
 void CloudPolicyClient::Unregister() {
@@ -870,6 +868,7 @@
 }
 
 void CloudPolicyClient::OnFetchRobotAuthCodesCompleted(
+    RobotAuthCodeCallback callback,
     DeviceManagementStatus status,
     int net_error,
     const em::DeviceManagementResponse& response) {
@@ -878,16 +877,14 @@
     LOG(WARNING) << "Invalid service api access response.";
     status = DM_STATUS_RESPONSE_DECODING_ERROR;
   }
-
   status_ = status;
   if (status == DM_STATUS_SUCCESS) {
-    robot_api_auth_code_ = response.service_api_access_response().auth_code();
     DVLOG(1) << "Device robot account auth code fetch complete - code = "
-             << robot_api_auth_code_;
-
-    NotifyRobotAuthCodesFetched();
+             << response.service_api_access_response().auth_code();
+    std::move(callback).Run(status,
+                            response.service_api_access_response().auth_code());
   } else {
-    NotifyClientError();
+    std::move(callback).Run(status, std::string());
   }
 }
 
@@ -1142,11 +1139,6 @@
     observer.OnRegistrationStateChanged(this);
 }
 
-void CloudPolicyClient::NotifyRobotAuthCodesFetched() {
-  for (auto& observer : observers_)
-    observer.OnRobotAuthCodesFetched(this);
-}
-
 void CloudPolicyClient::NotifyClientError() {
   for (auto& observer : observers_)
     observer.OnClientError(this);
diff --git a/components/policy/core/common/cloud/cloud_policy_client.h b/components/policy/core/common/cloud/cloud_policy_client.h
index 0954062..e205e8a01 100644
--- a/components/policy/core/common/cloud/cloud_policy_client.h
+++ b/components/policy/core/common/cloud/cloud_policy_client.h
@@ -71,6 +71,11 @@
       DeviceManagementStatus,
       const std::vector<enterprise_management::RemoteCommand>&)>;
 
+  // A callback for fetching device robot OAuth2 authorization tokens.
+  // Only occurs during enrollment, after the device is registered.
+  using RobotAuthCodeCallback =
+      base::OnceCallback<void(DeviceManagementStatus, const std::string&)>;
+
   // A callback which fetches device dm_token based on user affiliation.
   // Should be called once per registration.
   using DeviceDMTokenCallback = base::RepeatingCallback<std::string(
@@ -89,11 +94,6 @@
     // successful completion of registration and unregistration requests.
     virtual void OnRegistrationStateChanged(CloudPolicyClient* client) = 0;
 
-    // Called when a request for device robot OAuth2 authorization tokens
-    // returns successfully. Only occurs during enrollment. Optional
-    // (default implementation is a noop).
-    virtual void OnRobotAuthCodesFetched(CloudPolicyClient* client);
-
     // Indicates there's been an error in a previously-issued request.
     virtual void OnClientError(CloudPolicyClient* client) = 0;
   };
@@ -183,7 +183,9 @@
   // Requests OAuth2 auth codes for the device robot account. The client being
   // registered is a prerequisite to this operation and this call will CHECK if
   // the client is not in registered state.
-  virtual void FetchRobotAuthCodes(std::unique_ptr<DMAuth> auth);
+  // The |callback| will be called when the operation completes.
+  virtual void FetchRobotAuthCodes(std::unique_ptr<DMAuth> auth,
+                                   RobotAuthCodeCallback callback);
 
   // Sends an unregistration request to the server.
   virtual void Unregister();
@@ -349,10 +351,6 @@
     return status_;
   }
 
-  const std::string& robot_api_auth_code() const {
-    return robot_api_auth_code_;
-  }
-
   // Returns the invalidation version that was used for the last FetchPolicy.
   // Observers can call this method from their OnPolicyFetched method to
   // determine which at which invalidation version the policy was fetched.
@@ -403,6 +401,7 @@
 
   // Callback for robot account api authorization requests.
   void OnFetchRobotAuthCodesCompleted(
+      RobotAuthCodeCallback callback,
       DeviceManagementStatus status,
       int net_error,
       const enterprise_management::DeviceManagementResponse& response);
@@ -475,7 +474,6 @@
   // Observer notification helpers.
   void NotifyPolicyFetched();
   void NotifyRegistrationStateChanged();
-  void NotifyRobotAuthCodesFetched();
   void NotifyClientError();
 
   // Data necessary for constructing policy requests.
@@ -492,7 +490,6 @@
   base::Time last_policy_timestamp_;
   int public_key_version_ = -1;
   bool public_key_version_valid_ = false;
-  std::string robot_api_auth_code_;
   // Device DMToken for affiliated user policy requests.
   // Retrieved from |device_dm_token_callback_| on registration.
   std::string device_dm_token_;
diff --git a/components/policy/core/common/cloud/cloud_policy_validator.cc b/components/policy/core/common/cloud/cloud_policy_validator.cc
index 485c526..84cb9ef 100644
--- a/components/policy/core/common/cloud/cloud_policy_validator.cc
+++ b/components/policy/core/common/cloud/cloud_policy_validator.cc
@@ -64,6 +64,45 @@
 
 }  // namespace
 
+// static
+const char* CloudPolicyValidatorBase::StatusToString(Status status) {
+  switch (status) {
+    case VALIDATION_OK:
+      return "OK";
+    case VALIDATION_BAD_INITIAL_SIGNATURE:
+      return "BAD_INITIAL_SIGNATURE";
+    case VALIDATION_BAD_SIGNATURE:
+      return "BAD_SIGNATURE";
+    case VALIDATION_ERROR_CODE_PRESENT:
+      return "ERROR_CODE_PRESENT";
+    case VALIDATION_PAYLOAD_PARSE_ERROR:
+      return "PAYLOAD_PARSE_ERROR";
+    case VALIDATION_WRONG_POLICY_TYPE:
+      return "WRONG_POLICY_TYPE";
+    case VALIDATION_WRONG_SETTINGS_ENTITY_ID:
+      return "WRONG_SETTINGS_ENTITY_ID";
+    case VALIDATION_BAD_TIMESTAMP:
+      return "BAD_TIMESTAMP";
+    case VALIDATION_BAD_DM_TOKEN:
+      return "BAD_DM_TOKEN";
+    case VALIDATION_BAD_DEVICE_ID:
+      return "BAD_DEVICE_ID";
+    case VALIDATION_BAD_USER:
+      return "BAD_USER";
+    case VALIDATION_POLICY_PARSE_ERROR:
+      return "POLICY_PARSE_ERROR";
+    case VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE:
+      return "BAD_KEY_VERIFICATION_SIGNATURE";
+    case VALIDATION_VALUE_WARNING:
+      return "VALUE_WARNING";
+    case VALIDATION_VALUE_ERROR:
+      return "VALUE_ERROR";
+    case VALIDATION_STATUS_SIZE:
+      return "UNKNOWN";
+  }
+  return "UNKNOWN";
+}
+
 CloudPolicyValidatorBase::ValidationResult::ValidationResult() = default;
 CloudPolicyValidatorBase::ValidationResult::~ValidationResult() = default;
 
diff --git a/components/policy/core/common/cloud/cloud_policy_validator.h b/components/policy/core/common/cloud/cloud_policy_validator.h
index 75c167f6..5c4a231d 100644
--- a/components/policy/core/common/cloud/cloud_policy_validator.h
+++ b/components/policy/core/common/cloud/cloud_policy_validator.h
@@ -138,6 +138,9 @@
     ~ValidationResult();
   };
 
+  // Returns a human-readable representation of |status|.
+  static const char* StatusToString(Status status);
+
   virtual ~CloudPolicyValidatorBase();
 
   // Validation status which can be read after completion has been signaled.
diff --git a/components/policy/core/common/cloud/mock_cloud_policy_client.h b/components/policy/core/common/cloud/mock_cloud_policy_client.h
index 463ea18d..50bc3f0 100644
--- a/components/policy/core/common/cloud/mock_cloud_policy_client.h
+++ b/components/policy/core/common/cloud/mock_cloud_policy_client.h
@@ -105,7 +105,6 @@
 
   MOCK_METHOD1(OnPolicyFetched, void(CloudPolicyClient*));
   MOCK_METHOD1(OnRegistrationStateChanged, void(CloudPolicyClient*));
-  MOCK_METHOD1(OnRobotAuthCodesFetched, void(CloudPolicyClient*));
   MOCK_METHOD1(OnClientError, void(CloudPolicyClient*));
 
  private:
diff --git a/components/signin/core/browser/account_reconcilor.cc b/components/signin/core/browser/account_reconcilor.cc
index ff07af8..cfeddd1 100644
--- a/components/signin/core/browser/account_reconcilor.cc
+++ b/components/signin/core/browser/account_reconcilor.cc
@@ -422,8 +422,9 @@
     OnSetAccountsInCookieCompleted(GoogleServiceAuthError::AuthErrorNone());
   }
   // TODO(valeriyas): Log operation here.
+  // TODO (valeriyas): Write correct first gaia account to cache for desktop.
   if (!is_reconcile_started_)
-    delegate_->OnReconcileFinished(gaia_accounts[0].id, reconcile_is_noop_);
+    delegate_->OnReconcileFinished(primary_account, reconcile_is_noop_);
   first_execution_ = false;
   ScheduleStartReconcileIfChromeAccountsChanged();
 }
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.cc b/components/signin/core/browser/gaia_cookie_manager_service.cc
index afc33597..134b601d 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -1005,6 +1005,9 @@
 
 void GaiaCookieManagerService::OnSetAccountsFinished(
     const GoogleServiceAuthError& error) {
+  // Set ListAccounts result to stale manually because on iOS
+  // GaiaCookieManagerService is not notified about changes in cookie storage.
+  list_accounts_stale_ = true;
   access_tokens_.clear();
   token_requests_.clear();
   cookies_to_set_.clear();
diff --git a/components/subresource_filter/content/browser/async_document_subresource_filter.cc b/components/subresource_filter/content/browser/async_document_subresource_filter.cc
index 212d823..86ff5b64 100644
--- a/components/subresource_filter/content/browser/async_document_subresource_filter.cc
+++ b/components/subresource_filter/content/browser/async_document_subresource_filter.cc
@@ -32,12 +32,12 @@
       "SubresourceFilter.DocumentLoad.Activation.CPUDuration");
 
   auto page_wall_duration_timer = ScopedTimers::StartIf(
-      parent_document_origin.unique(), [](base::TimeDelta delta) {
+      parent_document_origin.opaque(), [](base::TimeDelta delta) {
         UMA_HISTOGRAM_MICRO_TIMES(
             "SubresourceFilter.PageLoad.Activation.WallDuration", delta);
       });
   auto page_cpu_duration_timer = ScopedThreadTimers::StartIf(
-      parent_document_origin.unique(), [](base::TimeDelta delta) {
+      parent_document_origin.opaque(), [](base::TimeDelta delta) {
         UMA_HISTOGRAM_MICRO_TIMES(
             "SubresourceFilter.PageLoad.Activation.CPUDuration", delta);
       });
diff --git a/components/subresource_filter/core/common/first_party_origin.cc b/components/subresource_filter/core/common/first_party_origin.cc
index 46a218f..9a1580ab 100644
--- a/components/subresource_filter/core/common/first_party_origin.cc
+++ b/components/subresource_filter/core/common/first_party_origin.cc
@@ -22,7 +22,7 @@
     : document_origin_(std::move(document_origin)) {}
 
 bool FirstPartyOrigin::IsThirdParty(const GURL& url) const {
-  if (document_origin_.unique())
+  if (document_origin_.opaque())
     return true;
   base::StringPiece host_piece = url.host_piece();
   if (!last_checked_host_.empty() && host_piece == last_checked_host_)
@@ -35,7 +35,7 @@
 
 bool FirstPartyOrigin::IsThirdParty(const GURL& url,
                                     const url::Origin& first_party_origin) {
-  return first_party_origin.unique() ||
+  return first_party_origin.opaque() ||
          IsThirdPartyImpl(url, first_party_origin);
 }
 
diff --git a/components/ui_devtools/devtools_server.cc b/components/ui_devtools/devtools_server.cc
index 6827164..f7808b0 100644
--- a/components/ui_devtools/devtools_server.cc
+++ b/components/ui_devtools/devtools_server.cc
@@ -104,7 +104,8 @@
        i++) {
     pairs.push_back(std::pair<std::string, std::string>(
         devtools_server_->clients_[i]->name(),
-        base::StringPrintf("%s0.0.0.0:%d/%" PRIuS, kChromeDeveloperToolsPrefix,
+        base::StringPrintf("%s127.0.0.1:%d/%" PRIuS,
+                           kChromeDeveloperToolsPrefix,
                            devtools_server_->port(), i)));
   }
   return pairs;
diff --git a/components/url_pattern_index/url_pattern_index.cc b/components/url_pattern_index/url_pattern_index.cc
index 75e1dca..7ec8caf 100644
--- a/components/url_pattern_index/url_pattern_index.cc
+++ b/components/url_pattern_index/url_pattern_index.cc
@@ -502,7 +502,7 @@
   }
   // Otherwise look for each subdomain of the |origin| using binary search.
 
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   base::StringPiece canonicalized_host(origin.host());
   if (canonicalized_host.empty())
     return 0;
@@ -559,7 +559,7 @@
     return false;
 
   // Unique |origin| matches lists of exception domains only.
-  if (origin.unique())
+  if (origin.opaque())
     return is_generic;
 
   size_t longest_matching_included_domain_length = 1;
diff --git a/components/url_pattern_index/url_rule_test_support.cc b/components/url_pattern_index/url_rule_test_support.cc
index dd3a0a3..77701e5 100644
--- a/components/url_pattern_index/url_rule_test_support.cc
+++ b/components/url_pattern_index/url_rule_test_support.cc
@@ -46,7 +46,7 @@
 }
 
 bool IsThirdParty(const GURL& url, const url::Origin& first_party_origin) {
-  return first_party_origin.unique() ||
+  return first_party_origin.opaque() ||
          !net::registry_controlled_domains::SameDomainOrHost(
              url, first_party_origin,
              net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
diff --git a/components/web_modal/web_contents_modal_dialog_manager.cc b/components/web_modal/web_contents_modal_dialog_manager.cc
index 4669249e..2874a931 100644
--- a/components/web_modal/web_contents_modal_dialog_manager.cc
+++ b/components/web_modal/web_contents_modal_dialog_manager.cc
@@ -61,11 +61,10 @@
 }
 
 void WebContentsModalDialogManager::WillClose(gfx::NativeWindow dialog) {
-  WebContentsModalDialogList::iterator dlg =
-      std::find_if(child_dialogs_.begin(), child_dialogs_.end(),
-                   [dialog](const DialogState& child_dialog) {
-                     return child_dialog.dialog == dialog;
-                   });
+  auto dlg = std::find_if(child_dialogs_.begin(), child_dialogs_.end(),
+                          [dialog](const DialogState& child_dialog) {
+                            return child_dialog.dialog == dialog;
+                          });
 
   // The Views tab contents modal dialog calls WillClose twice.  Ignore the
   // second invocation.
@@ -106,10 +105,6 @@
 // then set the block state. Advantage: could restrict some of the
 // WCMDM delegate methods, then, and pass them behind the scenes.
 void WebContentsModalDialogManager::BlockWebContentsInteraction(bool blocked) {
-  if (blocked == web_contents_is_blocked_)
-    return;
-  web_contents_is_blocked_ = blocked;
-
   WebContents* contents = web_contents();
   if (!contents) {
     // The WebContents has already disconnected.
@@ -128,7 +123,6 @@
   while (!child_dialogs_.empty()) {
     child_dialogs_.front().manager->Close();
   }
-  BlockWebContentsInteraction(false);
 
   closing_all_dialogs_ = false;
 }
diff --git a/components/web_modal/web_contents_modal_dialog_manager.h b/components/web_modal/web_contents_modal_dialog_manager.h
index 844003c..ca0bcbe 100644
--- a/components/web_modal/web_contents_modal_dialog_manager.h
+++ b/components/web_modal/web_contents_modal_dialog_manager.h
@@ -82,8 +82,6 @@
     std::unique_ptr<SingleWebContentsDialogManager> manager;
   };
 
-  using WebContentsModalDialogList = base::circular_deque<DialogState>;
-
   // Blocks/unblocks interaction with renderer process.
   void BlockWebContentsInteraction(bool blocked);
 
@@ -101,7 +99,7 @@
   WebContentsModalDialogManagerDelegate* delegate_;
 
   // All active dialogs.
-  WebContentsModalDialogList child_dialogs_;
+  base::circular_deque<DialogState> child_dialogs_;
 
   // Whether the WebContents' visibility is content::Visibility::HIDDEN.
   bool web_contents_is_hidden_;
@@ -109,9 +107,6 @@
   // True while closing the dialogs on WebContents close.
   bool closing_all_dialogs_;
 
-  // True if the WebContents is blocked.
-  bool web_contents_is_blocked_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManager);
 };
 
diff --git a/content/browser/appcache/appcache_host.cc b/content/browser/appcache/appcache_host.cc
index f82d1f76..bbc891b 100644
--- a/content/browser/appcache/appcache_host.cc
+++ b/content/browser/appcache/appcache_host.cc
@@ -83,7 +83,7 @@
   if (group_being_updated_.get())
     group_being_updated_->RemoveUpdateObserver(this);
   storage()->CancelDelegateCallbacks(this);
-  if (service()->quota_manager_proxy() && !origin_in_use_.unique())
+  if (service()->quota_manager_proxy() && !origin_in_use_.opaque())
     service()->quota_manager_proxy()->NotifyOriginNoLongerInUse(origin_in_use_);
 }
 
@@ -113,7 +113,7 @@
   }
 
   origin_in_use_ = url::Origin::Create(document_url);
-  if (service()->quota_manager_proxy() && !origin_in_use_.unique())
+  if (service()->quota_manager_proxy() && !origin_in_use_.opaque())
     service()->quota_manager_proxy()->NotifyOriginInUse(origin_in_use_);
 
   if (main_resource_blocked_)
diff --git a/content/browser/background_fetch/background_fetch_cross_origin_filter.cc b/content/browser/background_fetch/background_fetch_cross_origin_filter.cc
index 120b53c..50d79fe 100644
--- a/content/browser/background_fetch/background_fetch_cross_origin_filter.cc
+++ b/content/browser/background_fetch/background_fetch_cross_origin_filter.cc
@@ -37,7 +37,7 @@
 
   for (const std::string& origin_string : origin_vector) {
     url::Origin origin = url::Origin::Create(GURL(origin_string));
-    if (origin.unique())
+    if (origin.opaque())
       return false;
 
     candidate_origins.insert(origin);
diff --git a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
index b84fd49..fc33a75 100644
--- a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
@@ -111,7 +111,7 @@
     // Fill |request_info| with a failed result.
     request_info->SetResult(std::make_unique<BackgroundFetchResult>(
         std::move(response), base::Time::Now(),
-        BackgroundFetchResult::FailureReason::UNKNOWN));
+        BackgroundFetchResult::FailureReason::FETCH_ERROR));
     return;
   }
 
diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc
index 7b06a6d5..aed7bec 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "content/browser/background_fetch/background_fetch_job_controller.h"
+#include "content/public/common/origin_util.h"
 #include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
 
 #include <utility>
@@ -74,6 +75,15 @@
   return completed_downloads_ < total_downloads_;
 }
 
+bool BackgroundFetchJobController::IsMixedContent(
+    const BackgroundFetchRequestInfo& request) {
+  // Empty request is valid, it shouldn't fail the mixed content check.
+  if (request.fetch_request().url.is_empty())
+    return false;
+
+  return !IsOriginSecure(request.fetch_request().url);
+}
+
 void BackgroundFetchJobController::StartRequest(
     scoped_refptr<BackgroundFetchRequestInfo> request,
     RequestFinishedCallback request_finished_callback) {
@@ -85,6 +95,15 @@
   active_request_downloaded_bytes_ = 0;
   active_request_finished_callback_ = std::move(request_finished_callback);
 
+  if (IsMixedContent(*request.get())) {
+    request->SetEmptyResultWithFailureReason(
+        BackgroundFetchResult::FailureReason::FETCH_ERROR);
+
+    ++completed_downloads_;
+    std::move(active_request_finished_callback_).Run(request);
+    return;
+  }
+
   delegate_proxy_->StartRequest(registration_id().unique_id(),
                                 registration_id().origin(), request);
 }
diff --git a/content/browser/background_fetch/background_fetch_job_controller.h b/content/browser/background_fetch/background_fetch_job_controller.h
index ada556c..254d69c 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.h
+++ b/content/browser/background_fetch/background_fetch_job_controller.h
@@ -116,6 +116,13 @@
       blink::mojom::BackgroundFetchFailureReason reason_to_abort) override;
 
  private:
+  // Performs mixed content checks on the |request| for Background Fetch.
+  // Background Fetch depends on Service Workers, which are restricted for use
+  // on secure origins. We can therefore assume that the registration's origin
+  // is secure. This test ensures that the origin for the url of every
+  // request is also secure.
+  bool IsMixedContent(const BackgroundFetchRequestInfo& request);
+
   // Options for the represented background fetch registration.
   BackgroundFetchOptions options_;
 
diff --git a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
index 8d2003d..1807219 100644
--- a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
@@ -78,6 +78,20 @@
     pending_requests_counts_[registration_id]--;
   }
 
+  // To be called when a request for |registration_id| has finished.
+  // Moves |request_info| to |out_request_info|.
+  void GetRequestInfoOnRequestFinished(
+      const BackgroundFetchRegistrationId& registration_id,
+      scoped_refptr<content::BackgroundFetchRequestInfo>* out_request_info,
+      scoped_refptr<content::BackgroundFetchRequestInfo> request_info) {
+    DCHECK(pending_requests_counts_.count(registration_id));
+    DCHECK(out_request_info);
+
+    EXPECT_GE(pending_requests_counts_[registration_id], 1);
+    pending_requests_counts_[registration_id]--;
+    *out_request_info = request_info;
+  }
+
   // Creates a new Background Fetch registration, whose id will be stored in the
   // |*registration_id|, and registers it with the DataManager for the included
   // |request_data|. If |auto_complete_requests| is true, the request will
@@ -238,6 +252,32 @@
             GetCompletionStatus(registration_id));
 }
 
+TEST_F(BackgroundFetchJobControllerTest, SingleRequestJobWithInsecureOrigin) {
+  BackgroundFetchRegistrationId registration_id;
+
+  auto requests = CreateRegistrationForRequests(
+      &registration_id, {{GURL("http://example.com/funny_cat.png"), "GET"}},
+      true /* auto_complete_requests */);
+
+  EXPECT_EQ(JobCompletionStatus::kRunning,
+            GetCompletionStatus(registration_id));
+
+  std::unique_ptr<BackgroundFetchJobController> controller =
+      CreateJobController(registration_id, requests.size());
+
+  controller->StartRequest(
+      requests[0],
+      base::BindOnce(
+          &BackgroundFetchJobControllerTest::GetRequestInfoOnRequestFinished,
+          base::Unretained(this), registration_id, &requests[0]));
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(JobCompletionStatus::kCompleted,
+            GetCompletionStatus(registration_id));
+  EXPECT_FALSE(requests[0]->IsResultSuccess());
+}
+
 TEST_F(BackgroundFetchJobControllerTest, MultipleRequestJob) {
   BackgroundFetchRegistrationId registration_id;
 
@@ -285,6 +325,46 @@
             GetCompletionStatus(registration_id));
 }
 
+TEST_F(BackgroundFetchJobControllerTest, MultipleRequestsJobWithMixedContent) {
+  BackgroundFetchRegistrationId registration_id;
+
+  auto requests = CreateRegistrationForRequests(
+      &registration_id,
+      {{GURL("http://example.com/funny_cat.png"), "GET"},
+       {GURL("https://example.com/scary_cat.png"), "GET"}},
+      true /* auto_complete_requests */);
+
+  EXPECT_EQ(JobCompletionStatus::kRunning,
+            GetCompletionStatus(registration_id));
+
+  std::unique_ptr<BackgroundFetchJobController> controller =
+      CreateJobController(registration_id, requests.size());
+
+  controller->StartRequest(
+      requests[0],
+      base::BindOnce(
+          &BackgroundFetchJobControllerTest::GetRequestInfoOnRequestFinished,
+          base::Unretained(this), registration_id, &requests[0]));
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(JobCompletionStatus::kRunning,
+            GetCompletionStatus(registration_id));
+  EXPECT_FALSE(requests[0]->IsResultSuccess());
+
+  controller->StartRequest(
+      requests[1],
+      base::BindOnce(
+          &BackgroundFetchJobControllerTest::GetRequestInfoOnRequestFinished,
+          base::Unretained(this), registration_id, &requests[1]));
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(JobCompletionStatus::kCompleted,
+            GetCompletionStatus(registration_id));
+  EXPECT_TRUE(requests[1]->IsResultSuccess());
+}
+
 TEST_F(BackgroundFetchJobControllerTest, Abort) {
   BackgroundFetchRegistrationId registration_id;
 
diff --git a/content/browser/background_fetch/background_fetch_request_info.cc b/content/browser/background_fetch/background_fetch_request_info.cc
index c2326fb0..d2103e65 100644
--- a/content/browser/background_fetch/background_fetch_request_info.cc
+++ b/content/browser/background_fetch/background_fetch_request_info.cc
@@ -51,6 +51,14 @@
   PopulateWithResponse(std::move(result_->response));
 }
 
+void BackgroundFetchRequestInfo::SetEmptyResultWithFailureReason(
+    BackgroundFetchResult::FailureReason failure_reason) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  result_ = std::make_unique<BackgroundFetchResult>(
+      nullptr /* response */, base::Time::Now(), failure_reason);
+}
+
 void BackgroundFetchRequestInfo::PopulateWithResponse(
     std::unique_ptr<BackgroundFetchResponse> response) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
diff --git a/content/browser/background_fetch/background_fetch_request_info.h b/content/browser/background_fetch/background_fetch_request_info.h
index 17cff434..3b359aa 100644
--- a/content/browser/background_fetch/background_fetch_request_info.h
+++ b/content/browser/background_fetch/background_fetch_request_info.h
@@ -20,6 +20,7 @@
 #include "content/browser/background_fetch/background_fetch_constants.h"
 #include "content/common/content_export.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/background_fetch_response.h"
 #include "url/gurl.h"
 
 namespace storage {
@@ -50,6 +51,11 @@
 
   void SetResult(std::unique_ptr<BackgroundFetchResult> result);
 
+  // Creates an empty result, with no response, and assigns |failure_reason|
+  // as its failure_reason.
+  void SetEmptyResultWithFailureReason(
+      BackgroundFetchResult::FailureReason failure_reason);
+
   // Returns the index of this request within a Background Fetch registration.
   int request_index() const { return request_index_; }
 
diff --git a/content/browser/background_fetch/mock_background_fetch_delegate.cc b/content/browser/background_fetch/mock_background_fetch_delegate.cc
index 75e026c..5a165cf 100644
--- a/content/browser/background_fetch/mock_background_fetch_delegate.cc
+++ b/content/browser/background_fetch/mock_background_fetch_delegate.cc
@@ -147,7 +147,7 @@
         std::vector<GURL>({url}), test_response->headers);
     auto result = std::make_unique<BackgroundFetchResult>(
         std::move(response), base::Time::Now(),
-        BackgroundFetchResult::FailureReason::UNKNOWN);
+        BackgroundFetchResult::FailureReason::FETCH_ERROR);
     PostAbortCheckingTask(
         job_unique_id,
         base::BindOnce(&BackgroundFetchDelegate::Client::OnDownloadComplete,
diff --git a/content/browser/bluetooth/bluetooth_allowed_devices_map.cc b/content/browser/bluetooth/bluetooth_allowed_devices_map.cc
index 4b4ce9a..1c275f34 100644
--- a/content/browser/bluetooth/bluetooth_allowed_devices_map.cc
+++ b/content/browser/bluetooth/bluetooth_allowed_devices_map.cc
@@ -19,7 +19,7 @@
     const url::Origin& origin) {
   // "Unique" Origins generate the same key in maps, therefore are not
   // supported.
-  CHECK(!origin.unique());
+  CHECK(!origin.opaque());
   auto iter = origin_to_allowed_devices_map_.find(origin);
   if (iter == origin_to_allowed_devices_map_.end()) {
     iter = origin_to_allowed_devices_map_.insert(
diff --git a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
index bea7677..b561ce3 100644
--- a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
+++ b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
@@ -344,9 +344,9 @@
                           REQUEST_DEVICE_FROM_CROSS_ORIGIN_IFRAME);
     return;
   }
-  // The above also excludes unique origins, which are not even same-origin with
+  // The above also excludes opaque origins, which are not even same-origin with
   // themselves.
-  DCHECK(!requesting_origin.unique());
+  DCHECK(!requesting_origin.opaque());
 
   if (!adapter_->IsPresent()) {
     DVLOG(1) << "Bluetooth Adapter not present. Can't serve requestDevice.";
diff --git a/content/browser/browsing_data/browsing_data_filter_builder_impl.cc b/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
index e569410d..b06695a 100644
--- a/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
+++ b/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
@@ -100,7 +100,7 @@
   // This means that std::set::find() will use the same semantics for
   // origin comparison as Origin::IsSameOriginWith(). Furthermore, this
   // means that two filters are equal iff they are equal element-wise.
-  DCHECK(!origin.unique()) << "Invalid origin passed into OriginFilter.";
+  DCHECK(!origin.opaque()) << "Invalid origin passed into OriginFilter.";
 
   // TODO(msramek): All urls with file scheme currently map to the same
   // origin. This is currently not a problem, but if it becomes one,
diff --git a/content/browser/browsing_data/clear_site_data_handler.cc b/content/browser/browsing_data/clear_site_data_handler.cc
index fc99ea9..902c6b6 100644
--- a/content/browser/browsing_data/clear_site_data_handler.cc
+++ b/content/browser/browsing_data/clear_site_data_handler.cc
@@ -290,7 +290,7 @@
   }
 
   url::Origin origin = url::Origin::Create(url_);
-  if (origin.unique()) {
+  if (origin.opaque()) {
     delegate_->AddMessage(url_, "Not supported for unique origins.",
                           CONSOLE_MESSAGE_LEVEL_ERROR);
     return false;
diff --git a/content/browser/browsing_data/clear_site_data_throttle.cc b/content/browser/browsing_data/clear_site_data_throttle.cc
index d8b32084..d1a6df3 100644
--- a/content/browser/browsing_data/clear_site_data_throttle.cc
+++ b/content/browser/browsing_data/clear_site_data_throttle.cc
@@ -369,7 +369,7 @@
   }
 
   url::Origin origin = url::Origin::Create(GetCurrentURL());
-  if (origin.unique()) {
+  if (origin.opaque()) {
     delegate_->AddMessage(GetCurrentURL(), "Not supported for unique origins.",
                           CONSOLE_MESSAGE_LEVEL_ERROR);
     return false;
diff --git a/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc b/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc
index d4a80f9..68e6527 100644
--- a/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc
+++ b/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc
@@ -174,18 +174,19 @@
       }
       case CacheState::DELETE_CODE: {
         next_cache_state_ = CacheState::DONE;
-        // Embedders can disable code caches.
         if (generated_code_cache_context_) {
-          GeneratedCodeCache* code_cache =
-              generated_code_cache_context_->generated_code_cache();
-          if (code_cache) {
-            auto callback = base::BindRepeating(
-                &StoragePartitionHttpCacheDataRemover::DoClearCache,
-                base::Unretained(this));
-            // TODO(crbug.com/866419): Currently we just clear the entire cache.
-            // Change it to conditionally clear the entries based on the
-            // filters.
-            rv = code_cache->ClearCache(callback);
+          // TODO(crbug.com/866419): Currently we just clear entire caches.
+          // Change it to conditionally clear entries based on the filters.
+          auto callback = base::BindRepeating(
+              &StoragePartitionHttpCacheDataRemover::DoClearCache,
+              base::Unretained(this));
+          if (generated_code_cache_context_->generated_js_code_cache()) {
+            rv = generated_code_cache_context_->generated_js_code_cache()
+                     ->ClearCache(callback);
+          }
+          if (generated_code_cache_context_->generated_wasm_code_cache()) {
+            rv = generated_code_cache_context_->generated_wasm_code_cache()
+                     ->ClearCache(callback);
           }
         }
         break;
diff --git a/content/browser/cache_storage/cache_storage.cc b/content/browser/cache_storage/cache_storage.cc
index c724523..6ac6747 100644
--- a/content/browser/cache_storage/cache_storage.cc
+++ b/content/browser/cache_storage/cache_storage.cc
@@ -133,7 +133,7 @@
         cache_storage_(cache_storage),
         origin_(origin),
         owner_(owner) {
-    DCHECK(!origin_.unique());
+    DCHECK(!origin_.opaque());
   }
 
   virtual ~CacheLoader() {}
diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc
index 6ad59b6..030b08a 100644
--- a/content/browser/cache_storage/cache_storage_cache.cc
+++ b/content/browser/cache_storage/cache_storage_cache.cc
@@ -929,7 +929,7 @@
       cache_observer_(nullptr),
       memory_only_(path.empty()),
       weak_ptr_factory_(this) {
-  DCHECK(!origin_.unique());
+  DCHECK(!origin_.opaque());
   DCHECK(quota_manager_proxy_.get());
   DCHECK(cache_padding_key_.get());
 
diff --git a/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
index 035fbe0..9394792 100644
--- a/content/browser/cache_storage/cache_storage_dispatcher_host.cc
+++ b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -41,7 +41,7 @@
 
 // TODO(lucmult): Check this before binding.
 bool OriginCanAccessCacheStorage(const url::Origin& origin) {
-  return !origin.unique() && IsOriginSecure(origin.GetURL());
+  return !origin.opaque() && IsOriginSecure(origin.GetURL());
 }
 
 void StopPreservingCache(CacheStorageCacheHandle cache_handle) {}
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index 09ebf9c..f444e2d 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -120,13 +120,13 @@
 
   // Grant permission to request and commit URLs with the specified origin.
   void GrantCommitOrigin(const url::Origin& origin) {
-    if (origin.unique())
+    if (origin.opaque())
       return;
     origin_map_[origin] = CommitRequestPolicy::kCommitAndRequest;
   }
 
   void GrantRequestOrigin(const url::Origin& origin) {
-    if (origin.unique())
+    if (origin.opaque())
       return;
     // Anything already in |origin_map_| must have at least request permission
     // already. In that case, the emplace() below will be a no-op.
@@ -510,7 +510,7 @@
   // TODO(dcheng): In the future, URLs with opaque origins would ideally carry
   // around an origin with them, so we wouldn't need to grant commit access to
   // the entire scheme.
-  if (!origin.unique())
+  if (!origin.opaque())
     GrantCommitOrigin(child_id, origin);
 
   // The scheme has already been whitelisted for every child process, so no need
@@ -524,7 +524,7 @@
   if (state == security_state_.end())
     return;
 
-  if (origin.unique()) {
+  if (origin.opaque()) {
     // If it's impossible to grant commit rights to just the origin (among other
     // things, URLs with non-standard schemes will be treated as opaque
     // origins), then grant access to commit all URLs of that scheme.
@@ -742,7 +742,7 @@
       return false;
 
     url::Origin origin = url::Origin::Create(url);
-    return origin.unique() || CanRequestURL(child_id, GURL(origin.Serialize()));
+    return origin.opaque() || CanRequestURL(child_id, GURL(origin.Serialize()));
   }
 
   if (IsWebSafeScheme(scheme))
@@ -814,7 +814,7 @@
       return false;
 
     url::Origin origin = url::Origin::Create(url);
-    return origin.unique() ||
+    return origin.opaque() ||
            CanCommitURL(child_id, GURL(origin.Serialize()), check_origin_locks);
   }
 
diff --git a/content/browser/child_process_security_policy_unittest.cc b/content/browser/child_process_security_policy_unittest.cc
index f584b132..d571d8e9 100644
--- a/content/browser/child_process_security_policy_unittest.cc
+++ b/content/browser/child_process_security_policy_unittest.cc
@@ -498,8 +498,8 @@
   const GURL url("httpxml://awesome");
   const GURL url2("httpxml://also-awesome");
 
-  ASSERT_TRUE(url::Origin::Create(url).unique());
-  ASSERT_TRUE(url::Origin::Create(url2).unique());
+  ASSERT_TRUE(url::Origin::Create(url).opaque());
+  ASSERT_TRUE(url::Origin::Create(url2).opaque());
   RegisterTestScheme("httpxml");
 
   p->Add(kRendererID);
diff --git a/content/browser/code_cache/generated_code_cache.cc b/content/browser/code_cache/generated_code_cache.cc
index c81475e4..b7094c1c 100644
--- a/content/browser/code_cache/generated_code_cache.cc
+++ b/content/browser/code_cache/generated_code_cache.cc
@@ -25,7 +25,7 @@
   // Don't cache the code corresponding to unique origins. The same-origin
   // checks should always fail for unique origins but the serialized value of
   // unique origins does not ensure this.
-  if (requesting_origin.unique())
+  if (requesting_origin.opaque())
     return false;
 
   // If the resource url or requesting url is invalid don't cache the code.
@@ -40,7 +40,7 @@
 // serialized url and origin with a separator in between.
 std::string GetCacheKey(const GURL& resource_url,
                         const url::Origin& requesting_origin) {
-  DCHECK(!requesting_origin.unique());
+  DCHECK(!requesting_origin.opaque());
   DCHECK(resource_url.is_valid());
   // Add a prefix _ so it can't be parsed as a valid URL.
   std::string key = "_key";
diff --git a/content/browser/code_cache/generated_code_cache_context.cc b/content/browser/code_cache/generated_code_cache_context.cc
index 97cc2a4..03f426f 100644
--- a/content/browser/code_cache/generated_code_cache_context.cc
+++ b/content/browser/code_cache/generated_code_cache_context.cc
@@ -26,12 +26,19 @@
 
 void GeneratedCodeCacheContext::InitializeOnIO(const base::FilePath& path,
                                                int max_bytes) {
-  generated_code_cache_.reset(new GeneratedCodeCache(path, max_bytes));
+  generated_js_code_cache_.reset(new GeneratedCodeCache(path, max_bytes));
+  generated_wasm_code_cache_.reset(new GeneratedCodeCache(path, max_bytes));
 }
 
-GeneratedCodeCache* GeneratedCodeCacheContext::generated_code_cache() const {
+GeneratedCodeCache* GeneratedCodeCacheContext::generated_js_code_cache() const {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  return generated_code_cache_.get();
+  return generated_js_code_cache_.get();
+}
+
+GeneratedCodeCache* GeneratedCodeCacheContext::generated_wasm_code_cache()
+    const {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  return generated_wasm_code_cache_.get();
 }
 
 GeneratedCodeCacheContext::~GeneratedCodeCacheContext() = default;
diff --git a/content/browser/code_cache/generated_code_cache_context.h b/content/browser/code_cache/generated_code_cache_context.h
index 4a42beb..7e26e326 100644
--- a/content/browser/code_cache/generated_code_cache_context.h
+++ b/content/browser/code_cache/generated_code_cache_context.h
@@ -30,8 +30,9 @@
   // being setup.
   void Initialize(const base::FilePath& path, int max_bytes);
 
-  // Call on the IO thread to get the code cache instance.
-  GeneratedCodeCache* generated_code_cache() const;
+  // Call on the IO thread to get the code cache instances.
+  GeneratedCodeCache* generated_js_code_cache() const;
+  GeneratedCodeCache* generated_wasm_code_cache() const;
 
  private:
   friend class base::RefCountedThreadSafe<GeneratedCodeCacheContext>;
@@ -41,7 +42,9 @@
 
   // Created, used and deleted on the IO thread.
   std::unique_ptr<GeneratedCodeCache, BrowserThread::DeleteOnIOThread>
-      generated_code_cache_;
+      generated_js_code_cache_;
+  std::unique_ptr<GeneratedCodeCache, BrowserThread::DeleteOnIOThread>
+      generated_wasm_code_cache_;
 
   DISALLOW_COPY_AND_ASSIGN(GeneratedCodeCacheContext);
 };
diff --git a/content/browser/frame_host/frame_tree_browsertest.cc b/content/browser/frame_host/frame_tree_browsertest.cc
index 6a2c55f4..7159859c 100644
--- a/content/browser/frame_host/frame_tree_browsertest.cc
+++ b/content/browser/frame_host/frame_tree_browsertest.cc
@@ -275,7 +275,7 @@
   // Navigating to a data URL should set a unique origin.  This is represented
   // as "null" per RFC 6454.
   EXPECT_EQ("null", root->current_origin().Serialize());
-  EXPECT_TRUE(contents->GetMainFrame()->GetLastCommittedOrigin().unique());
+  EXPECT_TRUE(contents->GetMainFrame()->GetLastCommittedOrigin().opaque());
   EXPECT_EQ("null", GetOriginFromRenderer(root));
 
   // Re-navigating to a normal URL should update the origin.
@@ -285,7 +285,7 @@
   EXPECT_EQ(
       main_url.GetOrigin().spec(),
       contents->GetMainFrame()->GetLastCommittedOrigin().Serialize() + '/');
-  EXPECT_FALSE(contents->GetMainFrame()->GetLastCommittedOrigin().unique());
+  EXPECT_FALSE(contents->GetMainFrame()->GetLastCommittedOrigin().opaque());
   EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
 }
 
@@ -334,7 +334,7 @@
     deleted_observer.WaitUntilDeleted();
   EXPECT_EQ(GURL(blob_url_string), target->current_url());
   EXPECT_EQ(url::kBlobScheme, target->current_url().scheme());
-  EXPECT_FALSE(target->current_origin().unique());
+  EXPECT_FALSE(target->current_origin().opaque());
   EXPECT_EQ("a.com", target->current_origin().host());
   EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
   EXPECT_EQ("This is blob content.",
@@ -379,7 +379,7 @@
   EXPECT_EQ(target->current_origin(), about_blank_origin);
   EXPECT_EQ(GURL(url::kAboutBlankURL), target->current_url());
   EXPECT_EQ(url::kAboutScheme, target->current_url().scheme());
-  EXPECT_FALSE(target->current_origin().unique());
+  EXPECT_FALSE(target->current_origin().opaque());
   EXPECT_EQ("b.com", target->current_origin().host());
   EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
 
@@ -427,7 +427,7 @@
   EXPECT_EQ(target->current_origin(), about_blank_origin);
   EXPECT_EQ(GURL(url::kAboutBlankURL), target->current_url());
   EXPECT_EQ(url::kAboutScheme, target->current_url().scheme());
-  EXPECT_FALSE(target->current_origin().unique());
+  EXPECT_FALSE(target->current_origin().opaque());
   EXPECT_EQ("a.com", target->current_origin().host());
   EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
 
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc
index 7d748ab..abda7b16 100644
--- a/content/browser/frame_host/navigator_impl_unittest.cc
+++ b/content/browser/frame_host/navigator_impl_unittest.cc
@@ -1301,7 +1301,7 @@
   blink::FeaturePolicy* subframe_feature_policy =
       subframe_rfh->feature_policy();
   ASSERT_TRUE(subframe_feature_policy);
-  ASSERT_FALSE(subframe_feature_policy->GetOriginForTest().unique());
+  ASSERT_FALSE(subframe_feature_policy->GetOriginForTest().opaque());
 }
 
 TEST_F(NavigatorTestWithBrowserSideNavigation, TwoNavigationsRacingCommit) {
diff --git a/content/browser/frame_host/origin_policy_throttle.cc b/content/browser/frame_host/origin_policy_throttle.cc
index 1ab06ea..724d4f8 100644
--- a/content/browser/frame_host/origin_policy_throttle.cc
+++ b/content/browser/frame_host/origin_policy_throttle.cc
@@ -118,7 +118,7 @@
 
   url::Origin origin = GetRequestOrigin();
   DCHECK(!origin.Serialize().empty());
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   KnownVersionMap& versions = GetKnownVersions();
   KnownVersionMap::iterator iter = versions.find(origin);
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index b676e3ea..d700994 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -424,6 +424,24 @@
   base::debug::SetCrashKeyString(site_url_key, site_url.spec());
 }
 
+url::Origin GetOriginForURLLoaderFactory(GURL target_url,
+                                         SiteInstanceImpl* site_instance) {
+  // Calculate the origin that will be used as a fallback for URLs such as
+  // about:blank and/or data:.  If full site isolation is enabled, then
+  // |site_instance|-based origin will be correct.  Otherwise, falling back to a
+  // unique/opaque origin should be safe.
+  //
+  // TODO(lukasza, nasko): https://crbug.com/888079: Do not fall back to
+  // |site_instance| - instead the browser process should already know at
+  // ready-to-commit time the origin to be committed.
+  url::Origin fallback_origin =
+      SiteIsolationPolicy::UseDedicatedProcessesForAllSites()
+          ? url::Origin::Create(site_instance->GetSiteURL())
+          : url::Origin();
+
+  return url::Origin::Resolve(target_url, fallback_origin);
+}
+
 }  // namespace
 
 class RenderFrameHostImpl::DroppedInterfaceRequestLogger
@@ -864,7 +882,7 @@
 bool RenderFrameHostImpl::CreateNetworkServiceDefaultFactory(
     network::mojom::URLLoaderFactoryRequest default_factory_request) {
   return CreateNetworkServiceDefaultFactoryInternal(
-      last_committed_url_, std::move(default_factory_request));
+      last_committed_origin_, std::move(default_factory_request));
 }
 
 gfx::NativeView RenderFrameHostImpl::GetNativeView() {
@@ -3642,7 +3660,7 @@
 
   // It is safe to commit into a unique origin, regardless of the URL, as it is
   // restricted from accessing other origins.
-  if (origin.unique())
+  if (origin.opaque())
     return true;
 
   // Standard URLs must match the reported origin.
@@ -4032,7 +4050,9 @@
       // appropriate NetworkContext.
       bool bypass_redirect_checks =
           CreateNetworkServiceDefaultFactoryAndObserve(
-              common_params.url, mojo::MakeRequest(&default_factory_info));
+              GetOriginForURLLoaderFactory(common_params.url,
+                                           GetSiteInstance()),
+              mojo::MakeRequest(&default_factory_info));
       subresource_loader_factories->set_bypass_redirect_checks(
           bypass_redirect_checks);
     }
@@ -4079,7 +4099,8 @@
       network::mojom::URLLoaderFactoryPtrInfo factory_proxy_info;
       auto factory_request = mojo::MakeRequest(&factory_proxy_info);
       GetContentClient()->browser()->WillCreateURLLoaderFactory(
-          browser_context, this, false /* is_navigation */, common_params.url,
+          browser_context, this, false /* is_navigation */,
+          GetOriginForURLLoaderFactory(common_params.url, GetSiteInstance()),
           &factory_request, nullptr /* bypass_redirect_checks */);
       // Keep DevTools proxy lasy, i.e. closest to the network.
       RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
@@ -4208,11 +4229,17 @@
   // completing an unload handler.
   ResetWaitingState();
 
+  // Error page will commit in an opaque origin.
+  //
+  // TODO(lukasza): https://crbug.com/888079: Use this origin when committing
+  // later on.
+  url::Origin origin = url::Origin();
+
   std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loader_factories;
   if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
     network::mojom::URLLoaderFactoryPtrInfo default_factory_info;
     bool bypass_redirect_checks = CreateNetworkServiceDefaultFactoryAndObserve(
-        common_params.url, mojo::MakeRequest(&default_factory_info));
+        origin, mojo::MakeRequest(&default_factory_info));
     subresource_loader_factories = std::make_unique<URLLoaderFactoryBundleInfo>(
         std::move(default_factory_info),
         URLLoaderFactoryBundleInfo::SchemeMap(), bypass_redirect_checks);
@@ -4753,7 +4780,7 @@
 
   network::mojom::URLLoaderFactoryPtrInfo default_factory_info;
   bool bypass_redirect_checks = CreateNetworkServiceDefaultFactoryAndObserve(
-      last_committed_url_, mojo::MakeRequest(&default_factory_info));
+      last_committed_origin_, mojo::MakeRequest(&default_factory_info));
 
   std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loader_factories =
       std::make_unique<URLLoaderFactoryBundleInfo>(
@@ -4774,10 +4801,10 @@
 }
 
 bool RenderFrameHostImpl::CreateNetworkServiceDefaultFactoryAndObserve(
-    const GURL& url,
+    const url::Origin& origin,
     network::mojom::URLLoaderFactoryRequest default_factory_request) {
   bool bypass_redirect_checks = CreateNetworkServiceDefaultFactoryInternal(
-      url, std::move(default_factory_request));
+      origin, std::move(default_factory_request));
 
   // Add connection error observer when Network Service is running
   // out-of-process.
@@ -4801,7 +4828,7 @@
 }
 
 bool RenderFrameHostImpl::CreateNetworkServiceDefaultFactoryInternal(
-    const GURL& url,
+    const url::Origin& origin,
     network::mojom::URLLoaderFactoryRequest default_factory_request) {
   network::mojom::URLLoaderFactoryParamsPtr params =
       network::mojom::URLLoaderFactoryParams::New();
@@ -4816,8 +4843,8 @@
 
   if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
     GetContentClient()->browser()->WillCreateURLLoaderFactory(
-        context, this, false /* is_navigation */, url, &default_factory_request,
-        &bypass_redirect_checks);
+        context, this, false /* is_navigation */, origin,
+        &default_factory_request, &bypass_redirect_checks);
   }
 
   // Keep DevTools proxy lasy, i.e. closest to the network.
@@ -5430,7 +5457,7 @@
 
       // Error pages must commit in a unique origin. Terminate the renderer
       // process if this is violated.
-      if (!validated_params->origin.unique()) {
+      if (!validated_params->origin.opaque()) {
         DEBUG_ALIAS_FOR_ORIGIN(origin_debug_alias, validated_params->origin);
         bad_message::ReceivedBadMessage(
             process, bad_message::RFH_ERROR_PROCESS_NON_UNIQUE_ORIGIN_COMMIT);
@@ -5448,7 +5475,7 @@
                                      net::ERR_BLOCKED_BY_CLIENT) {
       // Since this is known to be an error page commit, verify it happened in
       // a unique origin, terminating the renderer process otherwise.
-      if (!validated_params->origin.unique()) {
+      if (!validated_params->origin.opaque()) {
         DEBUG_ALIAS_FOR_ORIGIN(origin_debug_alias, validated_params->origin);
         bad_message::ReceivedBadMessage(
             process, bad_message::RFH_ERROR_PROCESS_NON_UNIQUE_ORIGIN_COMMIT);
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 3bd1639..1dc020f 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -1059,16 +1059,19 @@
   // |OnNetworkServiceConnectionError()| if the factory is out-of-process.  If
   // this returns true, any redirect safety checks should be bypassed in
   // downstream loaders.
-  // |url| is the URL that the RenderFrame is either committing (in the case of
-  // navigation) or has last committed (when handling network process crashes).
+  //
+  // |origin| is the origin that the RenderFrame is either committing (in the
+  // case of navigation) or has last committed (when handling network process
+  // crashes).
   bool CreateNetworkServiceDefaultFactoryAndObserve(
-      const GURL& url,
+      const url::Origin& origin,
       network::mojom::URLLoaderFactoryRequest default_factory_request);
 
-  // |url| is the URL that the RenderFrame is either committing (in the case of
-  // navigation) or has last committed (when handling network process crashes).
+  // |origin| is the origin that the RenderFrame is either committing (in the
+  // case of navigation) or has last committed (when handling network process
+  // crashes).
   bool CreateNetworkServiceDefaultFactoryInternal(
-      const GURL& url,
+      const url::Origin& origin,
       network::mojom::URLLoaderFactoryRequest default_factory_request);
 
   // Returns true if the ExecuteJavaScript() API can be used on this host.
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index e5c7a51..1281c89 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -1594,7 +1594,7 @@
   // It is possible that last_successful_url() was a nonstandard scheme (for
   // example, "about:blank"). If so, examine the replicated origin to determine
   // the site.
-  if (!candidate->GetLastCommittedOrigin().unique() &&
+  if (!candidate->GetLastCommittedOrigin().opaque() &&
       SiteInstanceImpl::IsSameWebSite(
           browser_context,
           GURL(candidate->GetLastCommittedOrigin().Serialize()), dest_url,
@@ -1609,7 +1609,7 @@
   // tests rely on that behavior.  To accomplish this, compare |dest_url|
   // against the site URL.
   if (candidate->last_successful_url().IsAboutBlank() &&
-      candidate->GetLastCommittedOrigin().unique() &&
+      candidate->GetLastCommittedOrigin().opaque() &&
       SiteInstanceImpl::IsSameWebSite(
           browser_context, candidate->GetSiteInstance()->original_url(),
           dest_url, should_compare_effective_urls)) {
@@ -2573,7 +2573,7 @@
   // If dest_url is a unique origin like about:blank, then the need for a swap
   // is determined by the source_instance or dest_instance.
   GURL resolved_url = dest_url;
-  if (url::Origin::Create(resolved_url).unique()) {
+  if (url::Origin::Create(resolved_url).opaque()) {
     if (source_instance) {
       resolved_url = source_instance->GetSiteURL();
     } else if (dest_instance) {
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index fd6639a..b657fa5 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -466,12 +466,11 @@
     const GURL& site_for_cookies,
     GetCookiesCallback callback,
     const net::CookieList& cookie_list) {
-  net::URLRequestContext* context = GetRequestContextForURL(url);
   // Check the policy for get cookies, and pass cookie_list to the
   // TabSpecificContentSetting for logging purpose.
-  if (context && GetContentClient()->browser()->AllowGetCookie(
-                     url, site_for_cookies, cookie_list, resource_context_,
-                     render_process_id_, render_frame_id)) {
+  if (GetContentClient()->browser()->AllowGetCookie(
+          url, site_for_cookies, cookie_list, resource_context_,
+          render_process_id_, render_frame_id)) {
     std::move(callback).Run(net::CanonicalCookie::BuildCookieLine(cookie_list));
   } else {
     std::move(callback).Run(std::string());
@@ -553,26 +552,32 @@
 
   if (!GetContentClient()->browser()->AllowSetCookie(
           url, site_for_cookies, *cookie, resource_context_, render_process_id_,
-          render_frame_id))
-    return;
-
-  net::URLRequestContext* context = GetRequestContextForURL(url);
-  // If the embedder overrides the URLRequestContext then always use it, even if
-  // the network service is enabled, instead of the CookieManager associated
-  // this process' StoragePartition.
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
-      context == request_context_->GetURLRequestContext()) {
-    (*GetCookieManager())
-        ->SetCanonicalCookie(*cookie, url.SchemeIsCryptographic(),
-                             !options.exclude_httponly(),
-                             net::CookieStore::SetCookiesCallback());
+          render_frame_id)) {
     return;
   }
 
-  // Pass a null callback since we don't care about when the 'set' completes.
-  context->cookie_store()->SetCanonicalCookieAsync(
-      std::move(cookie), url.SchemeIsCryptographic(),
-      !options.exclude_httponly(), net::CookieStore::SetCookiesCallback());
+  // If the embedder overrides the cookie store then always use it, even if
+  // the network service is enabled, instead of the CookieManager associated
+  // this process' StoragePartition.
+  net::CookieStore* cookie_store =
+      GetContentClient()->browser()->OverrideCookieStoreForURL(
+          url, resource_context_);
+  if (cookie_store ||
+      !base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    if (!cookie_store)
+      cookie_store = request_context_->GetURLRequestContext()->cookie_store();
+
+    // Pass a null callback since we don't care about when the 'set' completes.
+    cookie_store->SetCanonicalCookieAsync(
+        std::move(cookie), url.SchemeIsCryptographic(),
+        !options.exclude_httponly(), net::CookieStore::SetCookiesCallback());
+    return;
+  }
+
+  (*GetCookieManager())
+      ->SetCanonicalCookie(*cookie, url.SchemeIsCryptographic(),
+                           !options.exclude_httponly(),
+                           net::CookieStore::SetCookiesCallback());
 }
 
 void RenderFrameMessageFilter::GetCookies(int render_frame_id,
@@ -603,33 +608,35 @@
     options.set_same_site_cookie_mode(
         net::CookieOptions::SameSiteCookieMode::DO_NOT_INCLUDE);
   }
-
-  net::URLRequestContext* context = GetRequestContextForURL(url);
-  // If the embedder overrides the URLRequestContext then always use it, even if
+  // If the embedder overrides the cookie store then always use it, even if
   // the network service is enabled, instead of the CookieManager associated
   // this process' StoragePartition.
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
-      context == request_context_->GetURLRequestContext()) {
-    // TODO(jam): modify GetRequestContextForURL to work with network service.
-    // Merge this with code path below for non-network service.
-    (*GetCookieManager())
-        ->GetCookieList(
-            url, options,
-            base::BindOnce(&RenderFrameMessageFilter::CheckPolicyForCookies,
-                           this, render_frame_id, url, site_for_cookies,
-                           std::move(callback)));
+  net::CookieStore* cookie_store =
+      GetContentClient()->browser()->OverrideCookieStoreForURL(
+          url, resource_context_);
+  if (cookie_store ||
+      !base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    if (!cookie_store)
+      cookie_store = request_context_->GetURLRequestContext()->cookie_store();
+
+    // If we crash here, figure out what URL the renderer was requesting.
+    // http://crbug.com/99242
+    DEBUG_ALIAS_FOR_GURL(url_buf, url);
+
+    cookie_store->GetCookieListWithOptionsAsync(
+        url, options,
+        base::BindOnce(&RenderFrameMessageFilter::CheckPolicyForCookies, this,
+                       render_frame_id, url, site_for_cookies,
+                       std::move(callback)));
     return;
   }
 
-  // If we crash here, figure out what URL the renderer was requesting.
-  // http://crbug.com/99242
-  DEBUG_ALIAS_FOR_GURL(url_buf, url);
-
-  context->cookie_store()->GetCookieListWithOptionsAsync(
-      url, options,
-      base::BindOnce(&RenderFrameMessageFilter::CheckPolicyForCookies, this,
-                     render_frame_id, url, site_for_cookies,
-                     std::move(callback)));
+  (*GetCookieManager())
+      ->GetCookieList(
+          url, options,
+          base::BindOnce(&RenderFrameMessageFilter::CheckPolicyForCookies, this,
+                         render_frame_id, url, site_for_cookies,
+                         std::move(callback)));
 }
 
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -720,17 +727,4 @@
 
 #endif  // ENABLE_PLUGINS
 
-net::URLRequestContext* RenderFrameMessageFilter::GetRequestContextForURL(
-    const GURL& url) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  net::URLRequestContext* context =
-      GetContentClient()->browser()->OverrideRequestContextForURL(
-          url, resource_context_);
-  if (!context)
-    context = request_context_->GetURLRequestContext();
-
-  return context;
-}
-
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_message_filter.h b/content/browser/frame_host/render_frame_message_filter.h
index a661ac5..91a7d32 100644
--- a/content/browser/frame_host/render_frame_message_filter.h
+++ b/content/browser/frame_host/render_frame_message_filter.h
@@ -35,7 +35,6 @@
 }
 
 namespace net {
-class URLRequestContext;
 class URLRequestContextGetter;
 }
 
@@ -171,11 +170,6 @@
                                            bool is_throttled);
 #endif  // ENABLE_PLUGINS
 
-  // Returns the correct net::URLRequestContext depending on what type of url is
-  // given.
-  // Only call on the IO thread.
-  net::URLRequestContext* GetRequestContextForURL(const GURL& url);
-
 #if BUILDFLAG(ENABLE_PLUGINS)
   PluginServiceImpl* plugin_service_;
   base::FilePath profile_data_directory_;
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
index 0c919ba..2172021 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -31,7 +31,7 @@
 const char kInvalidOrigin[] = "Origin is invalid";
 
 bool IsValidOrigin(const url::Origin& origin) {
-  return !origin.unique();
+  return !origin.opaque();
 }
 
 blink::mojom::IDBStatus GetIndexedDBStatus(leveldb::Status status) {
diff --git a/content/browser/isolated_origin_util.cc b/content/browser/isolated_origin_util.cc
index fe25348..9086edb 100644
--- a/content/browser/isolated_origin_util.cc
+++ b/content/browser/isolated_origin_util.cc
@@ -31,7 +31,7 @@
 
 // static
 bool IsolatedOriginUtil::IsValidIsolatedOrigin(const url::Origin& origin) {
-  if (origin.unique())
+  if (origin.opaque())
     return false;
 
   // Isolated origins should have HTTP or HTTPS schemes.  Hosts in other
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index a5ea7dd9..90543ca5 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -1562,6 +1562,10 @@
         ->RegisterNonNetworkNavigationURLLoaderFactories(
             frame_tree_node_id, &non_network_url_loader_factories_);
 
+    // Navigation requests are not associated with any particular
+    // |network::ResourceRequest::request_initiator| origin - using an opaque
+    // origin instead.
+    url::Origin navigation_request_initiator = url::Origin();
     // The embedder may want to proxy all network-bound URLLoaderFactory
     // requests that it can. If it elects to do so, we'll pass its proxy
     // endpoints off to the URLLoaderRequestController where wthey will be
@@ -1570,8 +1574,8 @@
     auto factory_request = mojo::MakeRequest(&factory_info);
     bool use_proxy = GetContentClient()->browser()->WillCreateURLLoaderFactory(
         partition->browser_context(), frame_tree_node->current_frame_host(),
-        true /* is_navigation */, new_request->url, &factory_request,
-        &bypass_redirect_checks);
+        true /* is_navigation */, navigation_request_initiator,
+        &factory_request, &bypass_redirect_checks);
     if (RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
             frame_tree_node->current_frame_host(), true, false,
             &factory_request)) {
@@ -1698,12 +1702,18 @@
     DVLOG(1) << "Ignoring request with unknown scheme: " << url.spec();
     return;
   }
+
+  // Navigation requests are not associated with any particular
+  // |network::ResourceRequest::request_initiator| origin - using an opaque
+  // origin instead.
+  url::Origin navigation_request_initiator = url::Origin();
+
   FrameTreeNode* frame_tree_node =
       FrameTreeNode::GloballyFindByID(frame_tree_node_id);
   auto* frame = frame_tree_node->current_frame_host();
   GetContentClient()->browser()->WillCreateURLLoaderFactory(
       frame->GetSiteInstance()->GetBrowserContext(), frame,
-      true /* is_navigation */, url, &factory,
+      true /* is_navigation */, navigation_request_initiator, &factory,
       nullptr /* bypass_redirect_checks */);
   it->second->Clone(std::move(factory));
 }
diff --git a/content/browser/media/cdm_storage_impl.cc b/content/browser/media/cdm_storage_impl.cc
index dd19f2bd..fa67789 100644
--- a/content/browser/media/cdm_storage_impl.cc
+++ b/content/browser/media/cdm_storage_impl.cc
@@ -36,7 +36,7 @@
                             const std::string& cdm_file_system_id,
                             media::mojom::CdmStorageRequest request) {
   DVLOG(3) << __func__;
-  DCHECK(!render_frame_host->GetLastCommittedOrigin().unique())
+  DCHECK(!render_frame_host->GetLastCommittedOrigin().opaque())
       << "Invalid origin specified for CdmStorageImpl::Create";
 
   // Take a reference to the FileSystemContext.
diff --git a/content/browser/media/webaudio/OWNERS b/content/browser/media/webaudio/OWNERS
new file mode 100644
index 0000000..5f297b8b
--- /dev/null
+++ b/content/browser/media/webaudio/OWNERS
@@ -0,0 +1,4 @@
+hongchan@chromium.org
+rtoy@chromium.org
+
+# COMPONENT: Blink>WebAudio
\ No newline at end of file
diff --git a/content/browser/media/webaudio/audio_context_manager_impl.cc b/content/browser/media/webaudio/audio_context_manager_impl.cc
index 6660e4bd..889ccb0 100644
--- a/content/browser/media/webaudio/audio_context_manager_impl.cc
+++ b/content/browser/media/webaudio/audio_context_manager_impl.cc
@@ -15,14 +15,18 @@
 void AudioContextManagerImpl::Create(
     RenderFrameHost* render_frame_host,
     blink::mojom::AudioContextManagerRequest request) {
-  mojo::MakeStrongBinding(
-      std::make_unique<AudioContextManagerImpl>(render_frame_host),
-      std::move(request));
+  DCHECK(render_frame_host);
+
+  // The object is bound to the lifetime of |render_frame_host| and the mojo
+  // connection. See FrameServiceBase for details.
+  new AudioContextManagerImpl(render_frame_host, std::move(request));
 }
 
 AudioContextManagerImpl::AudioContextManagerImpl(
-    RenderFrameHost* render_frame_host)
-    : render_frame_host_impl_(
+    RenderFrameHost* render_frame_host,
+    blink::mojom::AudioContextManagerRequest request)
+    : FrameServiceBase(render_frame_host, std::move(request)),
+      render_frame_host_impl_(
           static_cast<RenderFrameHostImpl*>(render_frame_host)) {
   DCHECK(render_frame_host);
 }
diff --git a/content/browser/media/webaudio/audio_context_manager_impl.h b/content/browser/media/webaudio/audio_context_manager_impl.h
index cc03296f..06d1c6b4 100644
--- a/content/browser/media/webaudio/audio_context_manager_impl.h
+++ b/content/browser/media/webaudio/audio_context_manager_impl.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_MEDIA_WEBAUDIO_AUDIO_CONTEXT_MANAGER_IMPL_H_
 
 #include "content/common/content_export.h"
+#include "content/public/browser/frame_service_base.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "third_party/blink/public/mojom/webaudio/audio_context_manager.mojom.h"
 
@@ -17,10 +18,12 @@
 // Implements the mojo interface between WebAudio and the browser so that
 // WebAudio can report when audible sounds from an AudioContext starts and
 // stops.
-class CONTENT_EXPORT AudioContextManagerImpl
-    : public blink::mojom::AudioContextManager {
+class CONTENT_EXPORT AudioContextManagerImpl final
+    : public content::FrameServiceBase<blink::mojom::AudioContextManager> {
  public:
-  explicit AudioContextManagerImpl(RenderFrameHost* render_frame_host);
+  explicit AudioContextManagerImpl(
+      RenderFrameHost* render_frame_host,
+      blink::mojom::AudioContextManagerRequest request);
   ~AudioContextManagerImpl() override;
 
   static void Create(RenderFrameHost* render_frame_host,
diff --git a/content/browser/notifications/notification_id_generator.cc b/content/browser/notifications/notification_id_generator.cc
index 99fa0034..9ab34c9 100644
--- a/content/browser/notifications/notification_id_generator.cc
+++ b/content/browser/notifications/notification_id_generator.cc
@@ -64,7 +64,7 @@
 std::string NotificationIdGenerator::GenerateForNonPersistentNotification(
     const url::Origin& origin,
     const std::string& token) const {
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   DCHECK(!token.empty());
   return base::StringPrintf(
       "%c%c%s%c%s", kNonPersistentNotificationPrefix, kNotificationTagSeparator,
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
index 96cda1d..55d9db7e 100644
--- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
@@ -70,16 +70,6 @@
   return window_->GetBounds().size();
 }
 
-void PictureInPictureWindowControllerImpl::ClickCustomControl(
-    const std::string& control_id) {
-  DCHECK(window_);
-
-  media_player_id_->render_frame_host->Send(
-      new MediaPlayerDelegateMsg_ClickPictureInPictureControl(
-          media_player_id_->render_frame_host->GetRoutingID(),
-          media_player_id_->delegate_id, control_id));
-}
-
 void PictureInPictureWindowControllerImpl::SetPictureInPictureCustomControls(
     const std::vector<blink::PictureInPictureControlInfo>& controls) {
   DCHECK(window_);
@@ -186,6 +176,16 @@
   return true;
 }
 
+void PictureInPictureWindowControllerImpl::CustomControlPressed(
+    const std::string& control_id) {
+  DCHECK(window_);
+
+  media_player_id_->render_frame_host->Send(
+      new MediaPlayerDelegateMsg_ClickPictureInPictureControl(
+          media_player_id_->render_frame_host->GetRoutingID(),
+          media_player_id_->delegate_id, control_id));
+}
+
 void PictureInPictureWindowControllerImpl::SetAlwaysHidePlayPauseButton(
     bool is_visible) {
   if (!window_)
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
index 9677135..330fbec 100644
--- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
+++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
@@ -37,8 +37,6 @@
   CONTENT_EXPORT gfx::Size Show() override;
   CONTENT_EXPORT void Close(bool should_pause_video) override;
   CONTENT_EXPORT void OnWindowDestroyed() override;
-  CONTENT_EXPORT void ClickCustomControl(
-      const std::string& control_id) override;
   CONTENT_EXPORT void SetPictureInPictureCustomControls(
       const std::vector<blink::PictureInPictureControlInfo>& controls) override;
   CONTENT_EXPORT void EmbedSurface(const viz::SurfaceId& surface_id,
@@ -48,6 +46,8 @@
   CONTENT_EXPORT bool IsPlayerActive() override;
   CONTENT_EXPORT WebContents* GetInitiatorWebContents() override;
   CONTENT_EXPORT bool TogglePlayPause() override;
+  CONTENT_EXPORT void CustomControlPressed(
+      const std::string& control_id) override;
   CONTENT_EXPORT void UpdatePlaybackState(bool is_playing,
                                           bool reached_end_of_stream) override;
   CONTENT_EXPORT void SetAlwaysHidePlayPauseButton(bool is_visible) override;
diff --git a/content/browser/quota_dispatcher_host.cc b/content/browser/quota_dispatcher_host.cc
index c6f72bd8..dee8d4e 100644
--- a/content/browser/quota_dispatcher_host.cc
+++ b/content/browser/quota_dispatcher_host.cc
@@ -117,7 +117,7 @@
     return;
   }
 
-  if (origin.unique()) {
+  if (origin.opaque()) {
     mojo::ReportBadMessage("Unique origins may not request storage quota.");
     return;
   }
diff --git a/content/browser/renderer_host/code_cache_host_impl.cc b/content/browser/renderer_host/code_cache_host_impl.cc
index d9fa155..3bc520f 100644
--- a/content/browser/renderer_host/code_cache_host_impl.cc
+++ b/content/browser/renderer_host/code_cache_host_impl.cc
@@ -49,7 +49,7 @@
   // Don't cache the code corresponding to unique origins. The same-origin
   // checks should always fail for unique origins but the serialized value of
   // unique origins does not ensure this.
-  if (origin.unique())
+  if (origin.opaque())
     return base::nullopt;
 
   return origin;
@@ -85,6 +85,7 @@
 }
 
 void CodeCacheHostImpl::DidGenerateCacheableMetadata(
+    blink::mojom::CodeCacheType cache_type,
     const GURL& url,
     base::Time expected_response_time,
     const std::vector<uint8_t>& data) {
@@ -96,13 +97,20 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (!base::FeatureList::IsEnabled(features::kIsolatedCodeCache)) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(&CodeCacheHostImpl::DidGenerateCacheableMetadataOnUI,
-                       render_process_id_, url, expected_response_time, data));
+    // Only store Javascript (not WebAssembly) code in the single-keyed cache.
+    if (cache_type == blink::mojom::CodeCacheType::kJavascript) {
+      base::PostTaskWithTraits(
+          FROM_HERE, {BrowserThread::UI},
+          base::BindOnce(&CodeCacheHostImpl::DidGenerateCacheableMetadataOnUI,
+                         render_process_id_, url, expected_response_time,
+                         data));
+    } else {
+      mojo::ReportBadMessage("Single-keyed code cache is Javascript only.");
+      return;
+    }
   } else {
-    if (!generated_code_cache_context_ ||
-        !generated_code_cache_context_->generated_code_cache())
+    GeneratedCodeCache* code_cache = GetCodeCache(cache_type);
+    if (!code_cache)
       return;
 
     base::Optional<url::Origin> requesting_origin =
@@ -110,15 +118,16 @@
     if (!requesting_origin)
       return;
 
-    generated_code_cache_context_->generated_code_cache()->WriteData(
-        url, *requesting_origin, expected_response_time, data);
+    code_cache->WriteData(url, *requesting_origin, expected_response_time,
+                          data);
   }
 }
 
-void CodeCacheHostImpl::FetchCachedCode(const GURL& url,
+void CodeCacheHostImpl::FetchCachedCode(blink::mojom::CodeCacheType cache_type,
+                                        const GURL& url,
                                         FetchCachedCodeCallback callback) {
-  if (!generated_code_cache_context_ ||
-      !generated_code_cache_context_->generated_code_cache()) {
+  GeneratedCodeCache* code_cache = GetCodeCache(cache_type);
+  if (!code_cache) {
     std::move(callback).Run(base::Time(), std::vector<uint8_t>());
     return;
   }
@@ -133,13 +142,14 @@
   auto read_callback = base::BindRepeating(
       &CodeCacheHostImpl::OnReceiveCachedCode, weak_ptr_factory_.GetWeakPtr(),
       base::Passed(&callback));
-  generated_code_cache_context_->generated_code_cache()->FetchEntry(
-      url, *requesting_origin, read_callback);
+  code_cache->FetchEntry(url, *requesting_origin, read_callback);
 }
 
-void CodeCacheHostImpl::ClearCodeCacheEntry(const GURL& url) {
-  if (!generated_code_cache_context_ ||
-      !generated_code_cache_context_->generated_code_cache())
+void CodeCacheHostImpl::ClearCodeCacheEntry(
+    blink::mojom::CodeCacheType cache_type,
+    const GURL& url) {
+  GeneratedCodeCache* code_cache = GetCodeCache(cache_type);
+  if (!code_cache)
     return;
 
   base::Optional<url::Origin> requesting_origin =
@@ -147,8 +157,7 @@
   if (!requesting_origin)
     return;
 
-  generated_code_cache_context_->generated_code_cache()->DeleteEntry(
-      url, *requesting_origin);
+  code_cache->DeleteEntry(url, *requesting_origin);
 }
 
 void CodeCacheHostImpl::DidGenerateCacheableMetadataInCacheStorage(
@@ -170,6 +179,18 @@
                      expected_response_time, buf, data.size()));
 }
 
+GeneratedCodeCache* CodeCacheHostImpl::GetCodeCache(
+    blink::mojom::CodeCacheType cache_type) {
+  if (!generated_code_cache_context_)
+    return nullptr;
+
+  if (cache_type == blink::mojom::CodeCacheType::kJavascript)
+    return generated_code_cache_context_->generated_js_code_cache();
+
+  DCHECK_EQ(blink::mojom::CodeCacheType::kWebAssembly, cache_type);
+  return generated_code_cache_context_->generated_wasm_code_cache();
+}
+
 void CodeCacheHostImpl::OnReceiveCachedCode(FetchCachedCodeCallback callback,
                                             const base::Time& response_time,
                                             const std::vector<uint8_t>& data) {
diff --git a/content/browser/renderer_host/code_cache_host_impl.h b/content/browser/renderer_host/code_cache_host_impl.h
index 18e9b4ba..4e0844ada 100644
--- a/content/browser/renderer_host/code_cache_host_impl.h
+++ b/content/browser/renderer_host/code_cache_host_impl.h
@@ -30,6 +30,7 @@
 
 class CacheStorageContextImpl;
 class CacheStorageCacheHandle;
+class GeneratedCodeCache;
 class GeneratedCodeCacheContext;
 
 // The implementation of a CodeCacheHost, which stores and retrieves resource
@@ -53,11 +54,15 @@
 
  private:
   // blink::mojom::CodeCacheHost implementation.
-  void DidGenerateCacheableMetadata(const GURL& url,
+  void DidGenerateCacheableMetadata(blink::mojom::CodeCacheType cache_type,
+                                    const GURL& url,
                                     base::Time expected_response_time,
                                     const std::vector<uint8_t>& data) override;
-  void FetchCachedCode(const GURL& url, FetchCachedCodeCallback) override;
-  void ClearCodeCacheEntry(const GURL& url) override;
+  void FetchCachedCode(blink::mojom::CodeCacheType cache_type,
+                       const GURL& url,
+                       FetchCachedCodeCallback) override;
+  void ClearCodeCacheEntry(blink::mojom::CodeCacheType cache_type,
+                           const GURL& url) override;
   void DidGenerateCacheableMetadataInCacheStorage(
       const GURL& url,
       base::Time expected_response_time,
@@ -66,6 +71,7 @@
       const std::string& cache_storage_cache_name) override;
 
   // Helpers.
+  GeneratedCodeCache* GetCodeCache(blink::mojom::CodeCacheType cache_type);
   void OnReceiveCachedCode(FetchCachedCodeCallback callback,
                            const base::Time& response_time,
                            const std::vector<uint8_t>& data);
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h
index 60a7e28..5aa7c74 100644
--- a/content/browser/renderer_host/input/input_router_impl.h
+++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -110,9 +110,6 @@
   bool OnMessageReceived(const IPC::Message& message) override;
 
   void OnHasTouchEventHandlersForTest(bool has_handlers);
-  int num_of_active_touches_for_test() {
-    return touch_action_filter_.num_of_active_touches_for_test();
-  }
 
  private:
   friend class InputRouterImplTest;
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index d295be3..a2140d65 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -433,11 +433,11 @@
     input_router_->TouchEventHandled(
         TouchEventWithLatencyInfo(touch_event_), InputEventAckSource::BROWSER,
         ui::LatencyInfo(), state, overscroll, touch_action);
-    EXPECT_EQ(input_router_->num_of_active_touches_for_test(), 1);
+    EXPECT_EQ(input_router_->touch_action_filter_.num_of_active_touches_, 1);
     ReleaseTouchPoint(0);
     input_router_->OnTouchEventAck(TouchEventWithLatencyInfo(touch_event_),
                                    InputEventAckSource::BROWSER, state);
-    EXPECT_EQ(input_router_->num_of_active_touches_for_test(), 0);
+    EXPECT_EQ(input_router_->touch_action_filter_.num_of_active_touches_, 0);
   }
 
   void OnTouchEventAckWithAckState(InputEventAckState ack_state) {
diff --git a/content/browser/renderer_host/input/touch_action_filter.h b/content/browser/renderer_host/input/touch_action_filter.h
index 0d57857..0def2d9 100644
--- a/content/browser/renderer_host/input/touch_action_filter.h
+++ b/content/browser/renderer_host/input/touch_action_filter.h
@@ -68,12 +68,12 @@
 
   void IncreaseActiveTouches();
   void DecreaseActiveTouches();
-  int num_of_active_touches_for_test() { return num_of_active_touches_; }
 
   // Debugging only.
   void AppendToGestureSequenceForDebugging(const char* str);
 
  private:
+  friend class InputRouterImplTest;
   friend class MockRenderWidgetHost;
   friend class TouchActionFilterTest;
   friend class SitePerProcessBrowserTouchActionTest;
diff --git a/content/browser/renderer_host/web_database_host_impl.cc b/content/browser/renderer_host/web_database_host_impl.cc
index 955ad95..65af343 100644
--- a/content/browser/renderer_host/web_database_host_impl.cc
+++ b/content/browser/renderer_host/web_database_host_impl.cc
@@ -376,7 +376,7 @@
 }
 
 bool WebDatabaseHostImpl::ValidateOrigin(const url::Origin& origin) {
-  if (origin.unique()) {
+  if (origin.opaque()) {
     mojo::ReportBadMessage("Invalid origin.");
     return false;
   }
diff --git a/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc b/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc
index 3ba2c39c..f7baefc5 100644
--- a/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc
+++ b/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc
@@ -36,7 +36,7 @@
     std::move(callback).Run(false);
     return;
   }
-  if (origin_.unique()) {
+  if (origin_.opaque()) {
     std::move(callback).Run(false);
     return;
   }
diff --git a/content/browser/service_worker/service_worker_object_host.cc b/content/browser/service_worker/service_worker_object_host.cc
index cd4f6ea5..9989c75 100644
--- a/content/browser/service_worker/service_worker_object_host.cc
+++ b/content/browser/service_worker/service_worker_object_host.cc
@@ -88,7 +88,7 @@
   DCHECK(source_client_info && !source_client_info->client_uuid.empty());
   (*event)->source_info_for_client = std::move(source_client_info);
   // Hide the client url if the client has a unique origin.
-  if ((*event)->source_origin.unique())
+  if ((*event)->source_origin.opaque())
     (*event)->source_info_for_client->url = GURL();
 
   // Reset |registration->self_update_delay| iff postMessage is coming from a
@@ -130,7 +130,7 @@
 
   (*event)->source_info_for_service_worker = std::move(source_worker_info);
   // Hide the service worker url if the service worker has a unique origin.
-  if ((*event)->source_origin.unique())
+  if ((*event)->source_origin.opaque())
     (*event)->source_info_for_service_worker->url = GURL();
   return true;
 }
diff --git a/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.cc b/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.cc
index ba7feb6..3626969ae 100644
--- a/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.cc
+++ b/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.cc
@@ -26,7 +26,7 @@
 void SharedWorkerContentSettingsProxyImpl::AllowIndexedDB(
     const base::string16& name,
     AllowIndexedDBCallback callback) {
-  if (!origin_.unique()) {
+  if (!origin_.opaque()) {
     owner_->AllowIndexedDB(origin_.GetURL(), name, std::move(callback));
   } else {
     std::move(callback).Run(false);
@@ -35,7 +35,7 @@
 
 void SharedWorkerContentSettingsProxyImpl::RequestFileSystemAccessSync(
     RequestFileSystemAccessSyncCallback callback) {
-  if (!origin_.unique()) {
+  if (!origin_.opaque()) {
     owner_->AllowFileSystem(origin_.GetURL(), std::move(callback));
   } else {
     std::move(callback).Run(false);
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 1d1da537..f09529d 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -491,7 +491,7 @@
 
   // If there is no host but there is a scheme, return the scheme.
   // This is useful for cases like file URLs.
-  if (!origin.unique()) {
+  if (!origin.opaque()) {
     // Prefer to use the scheme of |origin| rather than |url|, to correctly
     // cover blob:file: and filesystem:file: URIs (see also
     // https://crbug.com/697111).
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index a4af347..c5e4d7d 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -8694,9 +8694,9 @@
   EXPECT_TRUE(root->child_at(0)
                   ->current_frame_host()
                   ->GetLastCommittedOrigin()
-                  .unique());
+                  .opaque());
   // And verify that the origin in the replication state is also opaque.
-  EXPECT_TRUE(root->child_at(0)->current_origin().unique());
+  EXPECT_TRUE(root->child_at(0)->current_origin().opaque());
 
   // Ask the sandboxed iframe to report the enabled state of the geolocation
   // feature. If the declared policy was correctly flagged as referring to the
@@ -8721,9 +8721,9 @@
   EXPECT_TRUE(root->child_at(0)
                   ->current_frame_host()
                   ->GetLastCommittedOrigin()
-                  .unique());
+                  .opaque());
   // And verify that the origin in the replication state is also opaque.
-  EXPECT_TRUE(root->child_at(0)->current_origin().unique());
+  EXPECT_TRUE(root->child_at(0)->current_origin().opaque());
 
   EXPECT_TRUE(ExecuteScriptAndExtractBool(
       root->child_at(0),
@@ -8755,9 +8755,9 @@
   EXPECT_TRUE(root->child_at(0)
                   ->current_frame_host()
                   ->GetLastCommittedOrigin()
-                  .unique());
+                  .opaque());
   // And verify that the origin in the replication state is also opaque.
-  EXPECT_TRUE(root->child_at(0)->current_origin().unique());
+  EXPECT_TRUE(root->child_at(0)->current_origin().opaque());
 
   // Verify that geolocation is enabled in the document.
   bool success = false;
@@ -8777,9 +8777,9 @@
   EXPECT_FALSE(root->child_at(0)
                    ->current_frame_host()
                    ->GetLastCommittedOrigin()
-                   .unique());
+                   .opaque());
   // Verify that the origin in the replication state is also no longer opaque.
-  EXPECT_FALSE(root->child_at(0)->current_origin().unique());
+  EXPECT_FALSE(root->child_at(0)->current_origin().opaque());
 
   // Verify that the new document does not have geolocation enabled.
   EXPECT_TRUE(ExecuteScriptAndExtractBool(
@@ -9004,7 +9004,7 @@
   const blink::ParsedFeaturePolicy initial_effective_policy =
       root->child_at(2)->effective_frame_policy().container_policy;
   EXPECT_EQ(1UL, initial_effective_policy[0].origins.size());
-  EXPECT_FALSE(initial_effective_policy[0].origins[0].unique());
+  EXPECT_FALSE(initial_effective_policy[0].origins[0].opaque());
 
   // Set the "sandbox" attribute; pending policy should update, and should now
   // be flagged as matching the opaque origin of the frame (without containing
@@ -9017,7 +9017,7 @@
   const blink::ParsedFeaturePolicy updated_pending_policy =
       root->child_at(2)->pending_frame_policy().container_policy;
   EXPECT_EQ(1UL, updated_effective_policy[0].origins.size());
-  EXPECT_FALSE(updated_effective_policy[0].origins[0].unique());
+  EXPECT_FALSE(updated_effective_policy[0].origins[0].opaque());
   EXPECT_TRUE(updated_pending_policy[0].matches_opaque_src);
   EXPECT_EQ(0UL, updated_pending_policy[0].origins.size());
 
diff --git a/content/browser/speech/speech_recognition_dispatcher_host.cc b/content/browser/speech/speech_recognition_dispatcher_host.cc
index 1f909be..e898a43 100644
--- a/content/browser/speech/speech_recognition_dispatcher_host.cc
+++ b/content/browser/speech/speech_recognition_dispatcher_host.cc
@@ -67,7 +67,7 @@
 
   // Check that the origin specified by the renderer process is one
   // that it is allowed to access.
-  if (!params->origin.unique() &&
+  if (!params->origin.opaque() &&
       !ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
           render_process_id_, params->origin.GetURL())) {
     LOG(ERROR) << "SRDH::OnStartRequest, disallowed origin: "
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 274dc206..ab06c5eb0 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -1344,7 +1344,7 @@
 
     if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
       GetContentClient()->browser()->WillCreateURLLoaderFactory(
-          browser_context(), nullptr, false /* is_navigation */, GURL(),
+          browser_context(), nullptr, false /* is_navigation */, url::Origin(),
           &request, nullptr /* bypass_redirect_checks */);
     }
     GetNetworkContext()->CreateURLLoaderFactory(std::move(request),
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index cfecba3..3f2be88 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -289,15 +289,15 @@
     entry_exists_ = false;
     GeneratedCodeCache::ReadDataCallback callback = base::BindRepeating(
         &RemoveCodeCacheTester::FetchEntryCallback, base::Unretained(this));
-    code_cache_context_->generated_code_cache()->FetchEntry(url, origin,
-                                                            callback);
+    code_cache_context_->generated_js_code_cache()->FetchEntry(url, origin,
+                                                               callback);
     await_completion_.BlockUntilNotified();
     return entry_exists_;
   }
 
   void AddEntry(GURL url, url::Origin origin, const std::string& data) {
     std::vector<uint8_t> data_vector(data.begin(), data.end());
-    code_cache_context_->generated_code_cache()->WriteData(
+    code_cache_context_->generated_js_code_cache()->WriteData(
         url, origin, base::Time::Now(), data_vector);
     base::RunLoop().RunUntilIdle();
   }
diff --git a/content/browser/webauth/authenticator_impl.cc b/content/browser/webauth/authenticator_impl.cc
index f91723a9..5170b50e 100644
--- a/content/browser/webauth/authenticator_impl.cc
+++ b/content/browser/webauth/authenticator_impl.cc
@@ -97,7 +97,7 @@
 // Reference https://url.spec.whatwg.org/#valid-domain-string and
 // https://html.spec.whatwg.org/multipage/origin.html#concept-origin-effective-domain.
 bool HasValidEffectiveDomain(url::Origin caller_origin) {
-  return !caller_origin.unique() &&
+  return !caller_origin.opaque() &&
          !url::HostIsIPAddress(caller_origin.host()) &&
          content::IsOriginSecure(caller_origin.GetURL()) &&
          // Additionally, the scheme is required to be HTTP(S). Other schemes
diff --git a/content/child/blink_platform_impl_unittest.cc b/content/child/blink_platform_impl_unittest.cc
index 0ac6dac..50e3c86 100644
--- a/content/child/blink_platform_impl_unittest.cc
+++ b/content/child/blink_platform_impl_unittest.cc
@@ -117,7 +117,7 @@
     EXPECT_TRUE(web_origin.IsUnique());
 
     url::Origin url_origin = web_origin;
-    EXPECT_TRUE(url_origin.unique());
+    EXPECT_TRUE(url_origin.opaque());
 
     web_origin = url::Origin::Create(GURL(""));
     EXPECT_TRUE(web_origin.IsUnique());
diff --git a/content/child/child_process.cc b/content/child/child_process.cc
index 7b55e6f2..4313421 100644
--- a/content/child/child_process.cc
+++ b/content/child/child_process.cc
@@ -21,7 +21,7 @@
 
 namespace {
 base::LazyInstance<base::ThreadLocalPointer<ChildProcess>>::DestructorAtExit
-    g_lazy_tls = LAZY_INSTANCE_INITIALIZER;
+    g_lazy_child_process_tls = LAZY_INSTANCE_INITIALIZER;
 }
 
 ChildProcess::ChildProcess(
@@ -32,8 +32,8 @@
       shutdown_event_(base::WaitableEvent::ResetPolicy::MANUAL,
                       base::WaitableEvent::InitialState::NOT_SIGNALED),
       io_thread_("Chrome_ChildIOThread") {
-  DCHECK(!g_lazy_tls.Pointer()->Get());
-  g_lazy_tls.Pointer()->Set(this);
+  DCHECK(!g_lazy_child_process_tls.Pointer()->Get());
+  g_lazy_child_process_tls.Pointer()->Set(this);
 
   // Initialize TaskScheduler if not already done. A TaskScheduler may already
   // exist when ChildProcess is instantiated in the browser process or in a
@@ -63,7 +63,7 @@
 }
 
 ChildProcess::~ChildProcess() {
-  DCHECK(g_lazy_tls.Pointer()->Get() == this);
+  DCHECK(g_lazy_child_process_tls.Pointer()->Get() == this);
 
   // Signal this event before destroying the child process.  That way all
   // background threads can cleanup.
@@ -82,7 +82,7 @@
     }
   }
 
-  g_lazy_tls.Pointer()->Set(nullptr);
+  g_lazy_child_process_tls.Pointer()->Set(nullptr);
   io_thread_.Stop();
 
   if (initialized_task_scheduler_) {
@@ -117,7 +117,7 @@
 }
 
 ChildProcess* ChildProcess::current() {
-  return g_lazy_tls.Pointer()->Get();
+  return g_lazy_child_process_tls.Pointer()->Get();
 }
 
 base::WaitableEvent* ChildProcess::GetShutDownEvent() {
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index 08c34e44..85a0d8f9 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -84,7 +84,7 @@
 const int kConnectionTimeoutS = 15;
 
 base::LazyInstance<base::ThreadLocalPointer<ChildThreadImpl>>::DestructorAtExit
-    g_lazy_tls = LAZY_INSTANCE_INITIALIZER;
+    g_lazy_child_thread_impl_tls = LAZY_INSTANCE_INITIALIZER;
 
 // This isn't needed on Windows because there the sandbox's job object
 // terminates child processes automatically. For unsandboxed processes (i.e.
@@ -402,7 +402,7 @@
 
 void ChildThreadImpl::Init(const Options& options) {
   TRACE_EVENT0("startup", "ChildThreadImpl::Init");
-  g_lazy_tls.Pointer()->Set(this);
+  g_lazy_child_thread_impl_tls.Pointer()->Set(this);
   on_channel_error_called_ = false;
   main_thread_runner_ = base::ThreadTaskRunnerHandle::Get();
 #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
@@ -605,7 +605,7 @@
   // automatically.  We used to watch the object handle on Windows to do this,
   // but it wasn't possible to do so on POSIX.
   channel_->ClearIPCTaskRunner();
-  g_lazy_tls.Pointer()->Set(nullptr);
+  g_lazy_child_thread_impl_tls.Pointer()->Set(nullptr);
 }
 
 void ChildThreadImpl::Shutdown() {}
@@ -771,7 +771,7 @@
 }
 
 ChildThreadImpl* ChildThreadImpl::current() {
-  return g_lazy_tls.Pointer()->Get();
+  return g_lazy_child_thread_impl_tls.Pointer()->Get();
 }
 
 #if defined(OS_ANDROID)
diff --git a/content/common/content_security_policy/csp_context.cc b/content/common/content_security_policy/csp_context.cc
index 94b0a96..5e52b72 100644
--- a/content/common/content_security_policy/csp_context.cc
+++ b/content/common/content_security_policy/csp_context.cc
@@ -80,7 +80,7 @@
 
   // When the origin is unique, no URL should match with 'self'. That's why
   // |self_source_| stays undefined here.
-  if (origin.unique())
+  if (origin.opaque())
     return;
 
   if (origin.scheme() == url::kFileScheme) {
diff --git a/content/common/origin_util.cc b/content/common/origin_util.cc
index 6cac476b..2b15f617 100644
--- a/content/common/origin_util.cc
+++ b/content/common/origin_util.cc
@@ -20,7 +20,7 @@
 // SecurityOrigin::create might return unique origins for URLs whose schemes are
 // included in SchemeRegistry::shouldTreatURLSchemeAsNoAccess.
 bool IsOriginUnique(const url::Origin& origin) {
-  return origin.unique() ||
+  return origin.opaque() ||
          base::ContainsValue(url::GetNoAccessSchemes(), origin.scheme());
 }
 
diff --git a/content/public/browser/background_fetch_response.h b/content/public/browser/background_fetch_response.h
index 0577d963..be3f6c9 100644
--- a/content/public/browser/background_fetch_response.h
+++ b/content/public/browser/background_fetch_response.h
@@ -52,8 +52,9 @@
     // Used when the download was cancelled by the user.
     CANCELLED,
 
-    // Used when the failure reason is unknown.
-    UNKNOWN,
+    // Catch-all error. Used when the failure reason is unknown or not exposed
+    // to the developer.
+    FETCH_ERROR,
   };
 
   // Constructor for failed downloads.
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 76796f9..9380603 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -382,8 +382,9 @@
     net::ClientCertIdentityList client_certs,
     std::unique_ptr<ClientCertificateDelegate> delegate) {}
 
-net::URLRequestContext* ContentBrowserClient::OverrideRequestContextForURL(
-    const GURL& url, ResourceContext* context) {
+net::CookieStore* ContentBrowserClient::OverrideCookieStoreForURL(
+    const GURL& url,
+    ResourceContext* context) {
   return nullptr;
 }
 
@@ -671,7 +672,7 @@
     BrowserContext* browser_context,
     RenderFrameHost* frame,
     bool is_navigation,
-    const GURL& url,
+    const url::Origin& request_initiator,
     network::mojom::URLLoaderFactoryRequest* factory_request,
     bool* bypass_redirect_checks) {
   return false;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 59cfc78..1342f7010 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -110,12 +110,12 @@
 class ClientCertIdentity;
 using ClientCertIdentityList = std::vector<std::unique_ptr<ClientCertIdentity>>;
 class ClientCertStore;
+class CookieStore;
 class HttpRequestHeaders;
 class NetLog;
 class SSLCertRequestInfo;
 class SSLInfo;
 class URLRequest;
-class URLRequestContext;
 }  // namespace net
 
 namespace network {
@@ -611,12 +611,11 @@
   // "1812:e, 00001800-0000-1000-8000-00805f9b34fb:w, ignored:1, alsoignored."
   virtual std::string GetWebBluetoothBlocklist();
 
-  // Allow the embedder to override the request context based on the URL for
-  // certain operations, like cookie access. Returns nullptr to indicate the
-  // regular request context should be used.
+  // Allow the embedder to override the cookie store for a particular URL.
+  // Returns nullptr to indicate the regular cookie store should be used.
   // This is called on the IO thread.
-  virtual net::URLRequestContext* OverrideRequestContextForURL(
-      const GURL& url, ResourceContext* context);
+  virtual net::CookieStore* OverrideCookieStoreForURL(const GURL& url,
+                                                      ResourceContext* context);
 
   // Allows the embedder to override the LocationProvider implementation.
   // Return nullptr to indicate the default one for the platform should be
@@ -1128,10 +1127,16 @@
   // BrowserContext.
   //
   // |is_navigation| is true when it's a request used for navigation.
-  // |url| is set when it's a request for navigations or for a renderer fetching
-  // subresources. It's not set in the 3rd case (browser-initiated
-  // non-navigation requests) because in that case the factory is cached and it
-  // can be used for multiple URLs.
+  //
+  // |request_initiator| indicates which origin will be the initiator of
+  // requests that will use the URLLoaderFactory (see also
+  // |network::ResourceRequest::requests|).  |request_initiator| is set when
+  // it's a request for a renderer fetching subresources. It's not set when
+  // creating a factory for navigation requests, because navigation requests are
+  // made on behalf of the browser, rather than on behalf of any particular
+  // origin. It's not set in the case of browser-initiated, non-navigation
+  // requests, because in that case the factory is cached and it can be used for
+  // multiple URLs.
   //
   // |*factory_request| is always valid upon entry and MUST be valid upon
   // return. The embedder may swap out the value of |*factory_request| for its
@@ -1152,7 +1157,7 @@
       BrowserContext* browser_context,
       RenderFrameHost* frame,
       bool is_navigation,
-      const GURL& url,
+      const url::Origin& request_initiator,
       network::mojom::URLLoaderFactoryRequest* factory_request,
       bool* bypass_redirect_checks);
 
diff --git a/content/public/browser/picture_in_picture_window_controller.h b/content/public/browser/picture_in_picture_window_controller.h
index 7eb691b..63afe6d8 100644
--- a/content/public/browser/picture_in_picture_window_controller.h
+++ b/content/public/browser/picture_in_picture_window_controller.h
@@ -51,7 +51,6 @@
   // window was requested to be closed and destroyed by the system.
   virtual void OnWindowDestroyed() = 0;
 
-  virtual void ClickCustomControl(const std::string& control_id) = 0;
   virtual void SetPictureInPictureCustomControls(
       const std::vector<blink::PictureInPictureControlInfo>&) = 0;
   virtual void EmbedSurface(const viz::SurfaceId& surface_id,
@@ -69,6 +68,9 @@
   // call.
   virtual bool TogglePlayPause() = 0;
 
+  // Called when the user interacts with a custom control.
+  virtual void CustomControlPressed(const std::string& control_id) = 0;
+
  protected:
   // Use PictureInPictureWindowController::GetOrCreateForWebContents() to
   // create an instance.
diff --git a/content/public/browser/site_isolation_policy.cc b/content/public/browser/site_isolation_policy.cc
index dfa4486..ccadc0cf 100644
--- a/content/public/browser/site_isolation_policy.cc
+++ b/content/public/browser/site_isolation_policy.cc
@@ -173,7 +173,7 @@
   origins.reserve(origin_strings.size());
   for (const base::StringPiece& origin_string : origin_strings) {
     url::Origin origin = url::Origin::Create(GURL(origin_string));
-    if (!origin.unique())
+    if (!origin.opaque())
       origins.push_back(origin);
   }
   return origins;
diff --git a/content/renderer/loader/code_cache_loader_impl.cc b/content/renderer/loader/code_cache_loader_impl.cc
index 0fbbeac..edc4e117 100644
--- a/content/renderer/loader/code_cache_loader_impl.cc
+++ b/content/renderer/loader/code_cache_loader_impl.cc
@@ -45,10 +45,11 @@
   // It is Ok to pass |fetch_code_cache_event| with base::Unretained. Since
   // this thread is stalled, the fetch_code_cache_event will be kept alive.
   task_runner->PostTask(
-      FROM_HERE,
-      base::BindOnce(&CodeCacheLoaderImpl::FetchFromCodeCacheImpl,
-                     weak_ptr_factory_.GetWeakPtr(), url, std::move(callback),
-                     base::Unretained(&fetch_code_cache_event)));
+      FROM_HERE, base::BindOnce(&CodeCacheLoaderImpl::FetchFromCodeCacheImpl,
+                                weak_ptr_factory_.GetWeakPtr(),
+                                blink::mojom::CodeCacheType::kJavascript, url,
+                                std::move(callback),
+                                base::Unretained(&fetch_code_cache_event)));
 
   // Wait for the fetch from code cache to finish.
   fetch_code_cache_event.Wait();
@@ -58,12 +59,15 @@
   *data_out = data_for_sync_load_;
 }
 
-void CodeCacheLoaderImpl::FetchFromCodeCache(const GURL& url,
-                                             FetchCodeCacheCallback callback) {
-  FetchFromCodeCacheImpl(url, std::move(callback), nullptr);
+void CodeCacheLoaderImpl::FetchFromCodeCache(
+    blink::mojom::CodeCacheType cache_type,
+    const GURL& url,
+    FetchCodeCacheCallback callback) {
+  FetchFromCodeCacheImpl(cache_type, url, std::move(callback), nullptr);
 }
 
 void CodeCacheLoaderImpl::FetchFromCodeCacheImpl(
+    blink::mojom::CodeCacheType cache_type,
     const GURL& gurl,
     FetchCodeCacheCallback callback,
     base::WaitableEvent* fetch_event) {
@@ -71,9 +75,10 @@
   // fetch_event, because the thread is stalled and it will keep the fetch_event
   // alive.
   blink::Platform::Current()->FetchCachedCode(
-      gurl, base::BindOnce(&CodeCacheLoaderImpl::OnReceiveCachedCode,
-                           weak_ptr_factory_.GetWeakPtr(), std::move(callback),
-                           fetch_event));
+      cache_type, gurl,
+      base::BindOnce(&CodeCacheLoaderImpl::OnReceiveCachedCode,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+                     fetch_event));
 }
 
 void CodeCacheLoaderImpl::OnReceiveCachedCode(
diff --git a/content/renderer/loader/code_cache_loader_impl.h b/content/renderer/loader/code_cache_loader_impl.h
index 99c9d15..fc4084b6 100644
--- a/content/renderer/loader/code_cache_loader_impl.h
+++ b/content/renderer/loader/code_cache_loader_impl.h
@@ -22,16 +22,18 @@
 
   // Fetches code cache corresponding to |url| and returns response in
   // |response_time_out| and |data_out|.  |response_time_out| and |data_out|
-  // cannot be nullptrs.
+  // cannot be nullptrs. This only fetches from the Javascript cache.
   void FetchFromCodeCacheSynchronously(const GURL& url,
                                        base::Time* response_time_out,
                                        std::vector<uint8_t>* data_out) override;
 
-  void FetchFromCodeCache(const GURL& url,
+  void FetchFromCodeCache(blink::mojom::CodeCacheType cache_type,
+                          const GURL& url,
                           FetchCodeCacheCallback callback) override;
 
  private:
-  void FetchFromCodeCacheImpl(const GURL& url,
+  void FetchFromCodeCacheImpl(blink::mojom::CodeCacheType cache_type,
+                              const GURL& url,
                               FetchCodeCacheCallback callback,
                               base::WaitableEvent* event);
 
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 917eea9..fcafcc9 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -5661,7 +5661,7 @@
   // Standard URLs must match the reported origin, when it is not unique.
   // This check is very similar to RenderFrameHostImpl::CanCommitOrigin, but
   // adapted to the renderer process side.
-  if (!params->origin.unique() && params->url.IsStandard() &&
+  if (!params->origin.opaque() && params->url.IsStandard() &&
       render_view_->GetWebkitPreferences().web_security_enabled) {
     // Exclude file: URLs when settings allow them access any origin.
     if (params->origin.scheme() != url::kFileScheme ||
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 807e75b..7358f5e 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -451,26 +451,37 @@
   return render_thread->GetUserAgent();
 }
 
-void RendererBlinkPlatformImpl::CacheMetadata(const blink::WebURL& url,
-                                              base::Time response_time,
-                                              const char* data,
-                                              size_t size) {
-  // Let the browser know we generated cacheable metadata for this resource. The
-  // browser may cache it and return it on subsequent responses to speed
-  // the processing of this resource.
-  std::vector<uint8_t> copy(data, data + size);
-  GetCodeCacheHost().DidGenerateCacheableMetadata(url, response_time, copy);
+void RendererBlinkPlatformImpl::CacheMetadata(
+    blink::mojom::CodeCacheType cache_type,
+    const blink::WebURL& url,
+    base::Time response_time,
+    const char* data,
+    size_t size) {
+  // Only cache WebAssembly if we have isolated code caches.
+  // TODO(bbudge) Remove this check when isolated code caches are on by default.
+  if (cache_type == blink::mojom::CodeCacheType::kJavascript ||
+      base::FeatureList::IsEnabled(features::kIsolatedCodeCache)) {
+    // Let the browser know we generated cacheable metadata for this resource.
+    // The browser may cache it and return it on subsequent responses to speed
+    // the processing of this resource.
+    std::vector<uint8_t> copy(data, data + size);
+    GetCodeCacheHost().DidGenerateCacheableMetadata(cache_type, url,
+                                                    response_time, copy);
+  }
 }
 
 void RendererBlinkPlatformImpl::FetchCachedCode(
+    blink::mojom::CodeCacheType cache_type,
     const GURL& url,
     base::OnceCallback<void(base::Time, const std::vector<uint8_t>&)>
         callback) {
-  GetCodeCacheHost().FetchCachedCode(url, std::move(callback));
+  GetCodeCacheHost().FetchCachedCode(cache_type, url, std::move(callback));
 }
 
-void RendererBlinkPlatformImpl::ClearCodeCacheEntry(const GURL& url) {
-  GetCodeCacheHost().ClearCodeCacheEntry(url);
+void RendererBlinkPlatformImpl::ClearCodeCacheEntry(
+    blink::mojom::CodeCacheType cache_type,
+    const GURL& url) {
+  GetCodeCacheHost().ClearCodeCacheEntry(cache_type, url);
 }
 
 void RendererBlinkPlatformImpl::CacheMetadataInCacheStorage(
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index b74b59a..81e542c 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -83,15 +83,18 @@
   bool IsLinkVisited(unsigned long long linkHash) override;
   blink::WebPrescientNetworking* PrescientNetworking() override;
   blink::WebString UserAgent() override;
-  void CacheMetadata(const blink::WebURL&,
+  void CacheMetadata(blink::mojom::CodeCacheType cache_type,
+                     const blink::WebURL&,
                      base::Time,
                      const char*,
                      size_t) override;
   void FetchCachedCode(
+      blink::mojom::CodeCacheType cache_type,
       const GURL&,
       base::OnceCallback<void(base::Time, const std::vector<uint8_t>&)>)
       override;
-  void ClearCodeCacheEntry(const GURL&) override;
+  void ClearCodeCacheEntry(blink::mojom::CodeCacheType cache_type,
+                           const GURL&) override;
   void CacheMetadataInCacheStorage(
       const blink::WebURL&,
       base::Time,
diff --git a/content/shell/browser/layout_test/layout_test_background_fetch_delegate.cc b/content/shell/browser/layout_test/layout_test_background_fetch_delegate.cc
index d7e7c85..3846d18 100644
--- a/content/shell/browser/layout_test/layout_test_background_fetch_delegate.cc
+++ b/content/shell/browser/layout_test/layout_test_background_fetch_delegate.cc
@@ -103,7 +103,8 @@
             content::BackgroundFetchResult::FailureReason::TIMEDOUT;
         break;
       case download::Client::FailureReason::UNKNOWN:
-        failure_reason = content::BackgroundFetchResult::FailureReason::UNKNOWN;
+        failure_reason =
+            content::BackgroundFetchResult::FailureReason::FETCH_ERROR;
         break;
       case download::Client::FailureReason::ABORTED:
       case download::Client::FailureReason::CANCELLED:
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_chooser_factory.cc b/content/shell/browser/layout_test/layout_test_bluetooth_chooser_factory.cc
index dba3161d..b58c7a8 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_chooser_factory.cc
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_chooser_factory.cc
@@ -100,7 +100,7 @@
     RenderFrameHost* frame,
     const BluetoothChooser::EventHandler& event_handler) {
   const url::Origin origin = frame->GetLastCommittedOrigin();
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   std::string event = "chooser-opened(";
   event += origin.Serialize();
   event += ")";
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 4f4d95d..ce998bc 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -172,7 +172,7 @@
 
   url::Origin origin = url::Origin::Create(effective_site_url);
 
-  if (!origin.unique()) {
+  if (!origin.opaque()) {
     // Schemes like blob or filesystem, which have an embedded origin, should
     // already have been canonicalized to the origin site.
     CHECK_EQ(origin.scheme(), effective_site_url.scheme())
diff --git a/device/bluetooth/bluez/bluetooth_socket_bluez.cc b/device/bluetooth/bluez/bluetooth_socket_bluez.cc
index 3f97c631..75fe8b1d 100644
--- a/device/bluetooth/bluez/bluetooth_socket_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_socket_bluez.cc
@@ -21,7 +21,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/task_runner_util.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "dbus/bus.h"
 #include "dbus/object_path.h"
@@ -450,7 +450,7 @@
     const bluez::BluetoothProfileServiceProvider::Delegate::Options& options,
     const ConfirmationCallback& callback) {
   DCHECK(socket_thread()->task_runner()->RunsTasksInCurrentSequence());
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   if (!fd.is_valid()) {
     LOG(WARNING) << uuid_.canonical_value() << " :" << fd.get()
diff --git a/extensions/browser/api/declarative_net_request/ruleset_manager.cc b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
index 70881f3..f650956 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_manager.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
@@ -96,7 +96,7 @@
 // Returns whether the request to |url| is third party to its |document_origin|.
 // TODO(crbug.com/696822): Look into caching this.
 bool IsThirdPartyRequest(const GURL& url, const url::Origin& document_origin) {
-  if (document_origin.unique())
+  if (document_origin.opaque())
     return true;
 
   return !net::registry_controlled_domains::SameDomainOrHost(
diff --git a/extensions/browser/api/web_request/web_request_event_details.cc b/extensions/browser/api/web_request/web_request_event_details.cc
index 54984b47..da0c7b7 100644
--- a/extensions/browser/api/web_request/web_request_event_details.cc
+++ b/extensions/browser/api/web_request/web_request_event_details.cc
@@ -165,7 +165,7 @@
   if (extension_info_map && initiator_) {
     int tab_id = -1;
     dict_.GetInteger(keys::kTabIdKey, &tab_id);
-    if (initiator_->unique() ||
+    if (initiator_->opaque() ||
         WebRequestPermissions::CanExtensionAccessInitiator(
             extension_info_map, extension_id, initiator_, tab_id,
             crosses_incognito)) {
diff --git a/extensions/browser/api/web_request/web_request_permissions.cc b/extensions/browser/api/web_request/web_request_permissions.cc
index dfff113..f33db4d 100644
--- a/extensions/browser/api/web_request/web_request_permissions.cc
+++ b/extensions/browser/api/web_request/web_request_permissions.cc
@@ -156,7 +156,7 @@
       PermissionsData::PageAccess request_access =
           GetHostAccessForURL(*extension, url, tab_id);
       PermissionsData::PageAccess initiator_access =
-          initiator && !initiator->unique()
+          initiator && !initiator->opaque()
               ? GetHostAccessForURL(*extension, initiator->GetURL(), tab_id)
               : PermissionsData::PageAccess::kAllowed;
       access = GetMinimumAccessType(request_access, initiator_access);
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 2c9921648..2f194bc4 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1343,6 +1343,7 @@
   AUTOTESTPRIVATE_LAUNCHAPP = 1280,
   AUTOTESTPRIVATE_BOOTSTRAPMACHINELEARNINGSERVICE = 1281,
   AUTOTESTPRIVATE_RUNCROSTINIUNINSTALLER = 1282,
+  AUTOTESTPRIVATE_TAKESCREENSHOT = 1283,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/extension_web_contents_observer.cc b/extensions/browser/extension_web_contents_observer.cc
index 51759af..65c9e6a 100644
--- a/extensions/browser/extension_web_contents_observer.cc
+++ b/extensions/browser/extension_web_contents_observer.cc
@@ -304,11 +304,10 @@
     const url::Origin& origin(render_frame_host->GetLastCommittedOrigin());
     // Without site isolation, this check is needed to eliminate non-extension
     // schemes. With site isolation, this is still needed to exclude sandboxed
-    // extension frames with a unique origin.
+    // extension frames with an opaque origin.
     const GURL site_url(render_frame_host->GetSiteInstance()->GetSiteURL());
-    if (origin.unique() ||
-        site_url != content::SiteInstance::GetSiteForURL(browser_context,
-                                                         origin.GetURL()))
+    if (origin.opaque() || site_url != content::SiteInstance::GetSiteForURL(
+                                           browser_context, origin.GetURL()))
       return nullptr;
   }
 
diff --git a/extensions/shell/browser/shell_content_browser_client.cc b/extensions/shell/browser/shell_content_browser_client.cc
index 39df64b..4bf301e 100644
--- a/extensions/shell/browser/shell_content_browser_client.cc
+++ b/extensions/shell/browser/shell_content_browser_client.cc
@@ -288,7 +288,7 @@
     content::BrowserContext* browser_context,
     content::RenderFrameHost* frame,
     bool is_navigation,
-    const GURL& url,
+    const url::Origin& request_initiator,
     network::mojom::URLLoaderFactoryRequest* factory_request,
     bool* bypass_redirect_checks) {
   auto* web_request_api =
diff --git a/extensions/shell/browser/shell_content_browser_client.h b/extensions/shell/browser/shell_content_browser_client.h
index 7b419386..8a7b6205 100644
--- a/extensions/shell/browser/shell_content_browser_client.h
+++ b/extensions/shell/browser/shell_content_browser_client.h
@@ -77,7 +77,7 @@
       content::BrowserContext* browser_context,
       content::RenderFrameHost* frame_host,
       bool is_navigation,
-      const GURL& url,
+      const url::Origin& request_initiator,
       network::mojom::URLLoaderFactoryRequest* factory_request,
       bool* bypass_redirect_checks) override;
   bool HandleExternalProtocol(
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index 1ae2806..8f226bd 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -227,6 +227,11 @@
   fetch_pending_ = false;
 }
 
+bool GaiaAuthFetcher::IsMultiloginUrl(const GURL& url) {
+  return base::StartsWith(url.spec(), oauth_multilogin_gurl_.spec(),
+                          base::CompareCase::SENSITIVE);
+}
+
 void GaiaAuthFetcher::CreateAndStartGaiaFetcher(
     const std::string& body,
     const std::string& headers,
@@ -1116,8 +1121,7 @@
     OnUberAuthTokenFetch(data, net_error, response_code);
   } else if (url == oauth_login_gurl_) {
     OnOAuthLoginFetched(data, net_error, response_code);
-  } else if (base::StartsWith(url.spec(), oauth_multilogin_gurl_.spec(),
-                              base::CompareCase::SENSITIVE)) {
+  } else if (IsMultiloginUrl(url)) {
     OnOAuthMultiloginFetched(data, net_error, response_code);
   } else if (url == oauth2_revoke_gurl_) {
     OnOAuth2RevokeTokenFetched(data, net_error, response_code);
diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h
index 723ca2d..cb5662b 100644
--- a/google_apis/gaia/gaia_auth_fetcher.h
+++ b/google_apis/gaia/gaia_auth_fetcher.h
@@ -196,6 +196,13 @@
 
   void SetPendingFetch(bool pending_fetch);
 
+  // Needed to use XmlHTTPRequest for Multilogin requeston iOS even after
+  // iOS11 because WKWebView cannot read response body if content-disposition
+  // header is set.
+  // TODO(https://crbug.com/889471) Remove this once requests are done using
+  // NSUrlSession in iOS.
+  bool IsMultiloginUrl(const GURL& url);
+
  private:
   // The format of the POST body for IssueAuthToken.
   static const char kIssueAuthTokenFormat[];
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 2389884d..2734cfd 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -641,6 +641,13 @@
     }
 
     builders {
+      name: "Android FYI 32 dEQP Vk Release (Pixel XL)"
+      mixins: "android-gpu-fyi-ci"
+      # Increase timeout to allow tryjobs against small number of phones.
+      mixins: "gpu-slow-bot"
+    }
+
+    builders {
       name: "Android FYI 32 Vk Release (Nexus 5X)"
       mixins: "android-gpu-fyi-ci"
     }
@@ -653,6 +660,13 @@
     }
 
     builders {
+      name: "Android FYI 32 Vk Release (Pixel XL)"
+      mixins: "android-gpu-fyi-ci"
+      # Increase timeout to allow tryjobs against small number of phones.
+      mixins: "gpu-slow-bot"
+    }
+
+    builders {
       name: "Android FYI 64 dEQP Vk Release (Nexus 5X)"
       mixins: "android-gpu-fyi-ci"
     }
@@ -665,6 +679,13 @@
     }
 
     builders {
+      name: "Android FYI 64 dEQP Vk Release (Pixel XL)"
+      mixins: "android-gpu-fyi-ci"
+      # Increase timeout to allow tryjobs against small number of phones.
+      mixins: "gpu-slow-bot"
+    }
+
+    builders {
       name: "Android FYI 64 Vk Release (Nexus 5X)"
       mixins: "android-gpu-fyi-ci"
     }
@@ -677,6 +698,13 @@
     }
 
     builders {
+      name: "Android FYI 64 Vk Release (Pixel XL)"
+      mixins: "android-gpu-fyi-ci"
+      # Increase timeout to allow tryjobs against small number of phones.
+      mixins: "gpu-slow-bot"
+    }
+
+    builders {
       name: "Android FYI dEQP Release (Nexus 5X)"
       mixins: "android-gpu-fyi-ci"
     }
@@ -2854,6 +2882,22 @@
       name: "gpu-manual-try-android-p-pixel-2-64-deqp"
     }
     builders {
+      mixins: "android-gpu-manual-try"
+      name: "gpu-manual-try-android-p-pixel-xl-32"
+    }
+    builders {
+      mixins: "android-gpu-manual-try"
+      name: "gpu-manual-try-android-p-pixel-xl-32-deqp"
+    }
+    builders {
+      mixins: "android-gpu-manual-try"
+      name: "gpu-manual-try-android-p-pixel-xl-64"
+    }
+    builders {
+      mixins: "android-gpu-manual-try"
+      name: "gpu-manual-try-android-p-pixel-xl-64-deqp"
+    }
+    builders {
       mixins: "android-try"
       name: "try-nougat-phone-tester"
     }
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 749eb4b..68f1c16 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -3633,6 +3633,16 @@
     short_name: "N5X"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Android FYI 32 Vk Release (Pixel XL)"
+    category: "Android|vk|P32"
+    short_name: "PXL"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/Android FYI 64 Vk Release (Pixel XL)"
+    category: "Android|vk|P64"
+    short_name: "PXL"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/Android FYI 32 Vk Release (Pixel 2)"
     category: "Android|vk|P32"
     short_name: "P2"
@@ -3658,6 +3668,16 @@
     short_name: "N5X"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Android FYI 32 dEQP Vk Release (Pixel XL)"
+    category: "Android|dqp|vk|P32"
+    short_name: "PXL"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/Android FYI 64 dEQP Vk Release (Pixel XL)"
+    category: "Android|dqp|vk|P64"
+    short_name: "PXL"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/Android FYI 32 dEQP Vk Release (Pixel 2)"
     category: "Android|dqp|vk|P32"
     short_name: "P2"
@@ -4270,6 +4290,18 @@
     name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-64-deqp"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-32"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-32-deqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-64"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-64-deqp"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/try-nougat-phone-tester"
   }
   builder_view_only: true
@@ -4828,6 +4860,18 @@
     name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-64-deqp"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-32"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-32-deqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-64"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-64-deqp"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/gpu_manual_try_win7_nvidia_rel"
   }
   builders {
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index 20e29458..651cbab9 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -75,12 +75,16 @@
   triggers: "Android Cronet Builder"
   triggers: "Android FYI 32 Vk Release (Nexus 5X)"
   triggers: "Android FYI 32 Vk Release (Pixel 2)"
+  triggers: "Android FYI 32 Vk Release (Pixel XL)"
   triggers: "Android FYI 32 dEQP Vk Release (Nexus 5X)"
   triggers: "Android FYI 32 dEQP Vk Release (Pixel 2)"
+  triggers: "Android FYI 32 dEQP Vk Release (Pixel XL)"
   triggers: "Android FYI 64 Vk Release (Nexus 5X)"
   triggers: "Android FYI 64 Vk Release (Pixel 2)"
+  triggers: "Android FYI 64 Vk Release (Pixel XL)"
   triggers: "Android FYI 64 dEQP Vk Release (Nexus 5X)"
   triggers: "Android FYI 64 dEQP Vk Release (Pixel 2)"
+  triggers: "Android FYI 64 dEQP Vk Release (Pixel XL)"
   triggers: "Android FYI Release (NVIDIA Shield TV)"
   triggers: "Android FYI Release (Nexus 5)"
   triggers: "Android FYI Release (Nexus 5X)"
@@ -415,6 +419,16 @@
 }
 
 job {
+  id: "Android FYI 32 dEQP Vk Release (Pixel XL)"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Android FYI 32 dEQP Vk Release (Pixel XL)"
+  }
+}
+
+job {
   id: "Android FYI 32 Vk Release (Nexus 5X)"
   acl_sets: "default"
   buildbucket: {
@@ -435,6 +449,16 @@
 }
 
 job {
+  id: "Android FYI 32 Vk Release (Pixel XL)"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Android FYI 32 Vk Release (Pixel XL)"
+  }
+}
+
+job {
   id: "Android FYI 64 dEQP Vk Release (Nexus 5X)"
   acl_sets: "default"
   buildbucket: {
@@ -455,6 +479,16 @@
 }
 
 job {
+  id: "Android FYI 64 dEQP Vk Release (Pixel XL)"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Android FYI 64 dEQP Vk Release (Pixel XL)"
+  }
+}
+
+job {
   id: "Android FYI 64 Vk Release (Nexus 5X)"
   acl_sets: "default"
   buildbucket: {
@@ -475,6 +509,16 @@
 }
 
 job {
+  id: "Android FYI 64 Vk Release (Pixel XL)"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Android FYI 64 Vk Release (Pixel XL)"
+  }
+}
+
+job {
   id: "Android FYI dEQP Release (Nexus 5X)"
   acl_sets: "default"
   buildbucket: {
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd
index 920aec2..8ad7b9e 100644
--- a/ios/chrome/app/strings/ios_chromium_strings.grd
+++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -237,9 +237,6 @@
       <message name="IDS_IOS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY" desc="The text of the identity section for iOS.">
         Chromium verified that <ph name="ISSUER">$1<ex>VeriSign</ex></ph> issued this website's certificate.
       </message>
-      <message name="IDS_IOS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT" desc="Info bar message to save a password. [Length: 60em]">
-        Do you want Chromium to save your password for this site?
-      </message>
       <message name="IDS_IOS_PRODUCT_NAME" desc="The Chrome application name">
         Chromium
       </message>
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd
index 82cc54d..7480ff25 100644
--- a/ios/chrome/app/strings/ios_google_chrome_strings.grd
+++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -237,9 +237,6 @@
       <message name="IDS_IOS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY" desc="The text of the identity section for iOS.">
         Chrome verified that <ph name="ISSUER">$1<ex>VeriSign</ex></ph> issued this website's certificate.
       </message>
-      <message name="IDS_IOS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT" desc="Info bar message to save a password. [Length: 60em]">
-        Do you want Chrome to save your password for this site?
-      </message>
       <message name="IDS_IOS_PRODUCT_NAME" desc="The Chrome application name">
         Google Chrome
       </message>
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 2f0c71b..ae3211e 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1064,20 +1064,20 @@
       <message name="IDS_IOS_PASSWORD_MANAGER_SAVE_BUTTON" desc="Save button text for password manager [Length: 10em]">
         Save
       </message>
-      <message name="IDS_IOS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT_SMART_LOCK_BRANDING" desc="Info bar message to save a password, referring to the Google Smart Lock brand. [Length: 70em]">
-        Do you want Google Smart Lock to save your password for this site?
-      </message>
-      <message name="IDS_IOS_PASSWORD_MANAGER_SMART_LOCK_FOR_PASSWORDS" desc="The more descriptive brand name of the password manager when the user is signed in. Used in various UI elements, can be in link format.">
-        Google Smart Lock for Passwords
+      <message name="IDS_IOS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT" desc="Info bar message to save a password. [Length: 60em]">
+        Save password?
       </message>
       <message name="IDS_IOS_PASSWORD_MANAGER_UPDATE_BUTTON" desc="Label for the 'update' button in the Update Password infobar. This infobar asks if the user wishes to update the saved password for a site to a new password the user has just entered; the button applies the suggested update. [Length: 10em]">
         Update
       </message>
       <message name="IDS_IOS_PASSWORD_MANAGER_UPDATE_PASSWORD" desc="Infobar message to update a password without associated credential [Length: 70em].">
-        Do you want <ph name="PASSWORD_MANAGER_BRAND">$1<ex>Google Chrome</ex></ph> to update your password for this site?
+        Update password?
       </message>
-      <message name="IDS_IOS_PASSWORD_MANAGER_UPDATE_PASSWORD_FOR_ACCOUNT" desc="Infobar message to update a password for named account, referring to PASSWORD_MANAGER_BRAND as the  [Length:70em]">
-        Do you want <ph name="PASSWORD_MANAGER_BRAND">$1<ex>Google Chrome</ex></ph> to update your password for <ph name="USERNAME">$2<ex>don.john.lemon@example.com</ex></ph> for this site?
+      <message name="IDS_IOS_PASSWORD_MANAGER_UPDATE_PASSWORD_FOR_ACCOUNT" desc="Infobar message to update a password for named account. [Length:70em]">
+        Update password for <ph name="USERNAME">$1<ex>don.john.lemon@example.com</ex></ph>?
+      </message>
+      <message name="IDS_SAVE_PASSWORD_FOOTER" desc="The footer text of the infobar that offers user to save/update a password to Chrome.">
+        Passwords are saved in your Google Account so you can use them on any device.
       </message>
       <message name="IDS_IOS_PHOTO_LIBRARY_USAGE_DESCRIPTION" desc="Specifies the reason for accessing the user's photo library while the app is in use [Length: unlimited] [iOS only].">
         This lets you save and upload photos.
@@ -1187,9 +1187,6 @@
       <message name="IDS_IOS_READING_LIST_EMPTY_MESSAGE" desc="Message to explain to the user how to add entries to the reading list" meaning="[Length: unlimited]">
         Your reading list is available offline. To add a page to your reading list, tap  <ph name="SHARE_OPENING_ICON">SHARE_OPENING_ICON<ex>(menu icon)</ex></ph>  then <ph name="READ_LATER_TEXT">READ_LATER_TEXT<ex>Read Later</ex></ph>.
       </message>
-      <message name="IDS_IOS_READING_LIST_EMPTY_MESSAGE_LEGACY" desc="Message to explain to the user how to add entries to the reading list" meaning="[Length: unlimited]">
-        Your reading list is available offline. To add a page to your reading list, tap <ph name="SHARE_OPENING_ICON">SHARE_OPENING_ICON<ex>Menu > Share > Read Later</ex></ph>.
-      </message>
       <message name="IDS_IOS_READING_LIST_JUST_NOW" desc="String indicating that an event (adding item, distillation) happened less than one minute ago. [Length: 25em]">
         Just now
       </message>
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
index 8d2be47..935242b8 100644
--- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
@@ -100,7 +100,8 @@
 bool AppLauncherTabHelper::IsAppUrl(const GURL& url) {
   return !(web::UrlHasWebScheme(url) ||
            web::GetWebClient()->IsAppSpecificURL(url) ||
-           url.SchemeIs(url::kFileScheme) || url.SchemeIs(url::kAboutScheme));
+           url.SchemeIs(url::kFileScheme) || url.SchemeIs(url::kAboutScheme) ||
+           url.SchemeIs(url::kBlobScheme));
 }
 
 bool AppLauncherTabHelper::RequestToLaunchApp(const GURL& url,
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
index 6d3404da..1650258 100644
--- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
@@ -277,6 +277,9 @@
   EXPECT_TRUE(TestShouldAllowRequest(@"data://test",
                                      /*target_frame_is_main=*/false,
                                      /*has_user_gesture=*/true));
+  EXPECT_TRUE(TestShouldAllowRequest(@"blob://test",
+                                     /*target_frame_is_main=*/false,
+                                     /*has_user_gesture=*/true));
   EXPECT_EQ(0U, delegate_.countOfAppsLaunched);
 }
 
diff --git a/ios/chrome/browser/experimental_flags.h b/ios/chrome/browser/experimental_flags.h
index f8565e8..cd9a6ec 100644
--- a/ios/chrome/browser/experimental_flags.h
+++ b/ios/chrome/browser/experimental_flags.h
@@ -58,10 +58,6 @@
 // TODO (crbug.com/884719): Remove all use of this flag.
 bool IsBookmarksUIRebootEnabled();
 
-// Whether the Reading List UI Reboot is enabled.
-// TODO (crbug.com/884720): Remove all use of this flag.
-bool IsReadingListUIRebootEnabled();
-
 // Whether the application group sandbox must be cleared before starting.
 // Calling this method will reset the flag to false, so the sandbox is cleared
 // only once.
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm
index f9200d9..42b1c0e 100644
--- a/ios/chrome/browser/experimental_flags.mm
+++ b/ios/chrome/browser/experimental_flags.mm
@@ -130,8 +130,4 @@
   return true;
 }
 
-bool IsReadingListUIRebootEnabled() {
-  return true;
-}
-
 }  // namespace experimental_flags
diff --git a/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm b/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
index 7ea9178a..d13e3d3 100644
--- a/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
+++ b/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
@@ -302,15 +302,9 @@
   }
 
   [chrome_test_util::BrowserCommandDispatcherForMainBVC() showReadingList];
-  if (experimental_flags::IsReadingListUIRebootEnabled()) {
-    [[EarlGrey
-        selectElementWithMatcher:grey_accessibilityID(
-                                     kTableViewNavigationDismissButtonId)]
-        performAction:grey_tap()];
-  } else {
-    [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Done")]
-        performAction:grey_tap()];
-  }
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kTableViewNavigationDismissButtonId)]
+      performAction:grey_tap()];
 
   [ChromeEarlGreyUI openToolsMenu];
 
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.h b/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.h
index 2a72bd2..3931787 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.h
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.h
@@ -27,16 +27,14 @@
 
  protected:
   IOSChromePasswordManagerInfoBarDelegate(
-      bool is_smart_lock_branding_enabled,
+      bool is_sync_user,
       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_manager);
 
   password_manager::PasswordFormManagerForUI* form_to_save() const {
     return form_to_save_.get();
   }
 
-  bool is_smart_lock_branding_enabled() const {
-    return is_smart_lock_branding_enabled_;
-  }
+  bool is_sync_user() const { return is_sync_user_; }
 
   void set_infobar_response(
       password_manager::metrics_util::UIDismissalReason response) {
@@ -53,9 +51,7 @@
 
  private:
   // ConfirmInfoBarDelegate implementation.
-  base::string16 GetLinkText() const override;
   int GetIconId() const override;
-  bool LinkClicked(WindowOpenDisposition disposition) override;
 
   // The password_manager::PasswordFormManager managing the form we're asking
   // the user about, and should save as per their decision.
@@ -64,8 +60,8 @@
   // Used to track the results we get from the info bar.
   password_manager::metrics_util::UIDismissalReason infobar_response_;
 
-  // Whether to show the password manager branded as Smart Lock.
-  const bool is_smart_lock_branding_enabled_;
+  // Whether to show the additional footer.
+  const bool is_sync_user_;
 
   // Dispatcher for calling Application commands.
   __weak id<ApplicationCommands> dispatcher_ = nil;
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.mm b/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.mm
index 379236c..2c39a57 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.mm
@@ -8,15 +8,7 @@
 
 #include "base/strings/string16.h"
 #include "components/password_manager/core/browser/password_form_manager_for_ui.h"
-#include "components/password_manager/core/browser/password_manager_constants.h"
-#include "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/ui/commands/application_commands.h"
-#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
-#include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
-#include "ios/web/public/referrer.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -27,31 +19,13 @@
 
 IOSChromePasswordManagerInfoBarDelegate::
     IOSChromePasswordManagerInfoBarDelegate(
-        bool is_smart_lock_branding_enabled,
+        bool is_sync_user,
         std::unique_ptr<password_manager::PasswordFormManagerForUI>
             form_to_save)
     : form_to_save_(std::move(form_to_save)),
       infobar_response_(password_manager::metrics_util::NO_DIRECT_INTERACTION),
-      is_smart_lock_branding_enabled_(is_smart_lock_branding_enabled) {}
-
-base::string16 IOSChromePasswordManagerInfoBarDelegate::GetLinkText() const {
-  return is_smart_lock_branding_enabled_
-             ? l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SMART_LOCK)
-             : base::string16();
-};
+      is_sync_user_(is_sync_user) {}
 
 int IOSChromePasswordManagerInfoBarDelegate::GetIconId() const {
   return IDR_IOS_INFOBAR_SAVE_PASSWORD;
 };
-
-bool IOSChromePasswordManagerInfoBarDelegate::LinkClicked(
-    WindowOpenDisposition disposition) {
-  OpenNewTabCommand* command = [[OpenNewTabCommand alloc]
-       initWithURL:GURL(password_manager::kPasswordManagerHelpCenterSmartLock)
-          referrer:web::Referrer()
-       inIncognito:NO
-      inBackground:NO
-          appendTo:kCurrentTab];
-  [dispatcher_ openURLInNewTab:command];
-  return true;
-};
diff --git a/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.h b/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.h
index 796ed42f..dd41983 100644
--- a/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.h
+++ b/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.h
@@ -28,10 +28,9 @@
     : public IOSChromePasswordManagerInfoBarDelegate {
  public:
   // Creates the infobar for |form_to_save| and adds it to |infobar_manager|.
-  // |is_smart_lock_enabled| controls the branding string. |dispatcher| is not
-  // retained.
+  // |is_sync_user| controls the footer string. |dispatcher| is not retained.
   static void Create(
-      bool is_smart_lock_branding_enabled,
+      bool is_sync_user,
       infobars::InfoBarManager* infobar_manager,
       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_to_save,
       id<ApplicationCommands> dispatcher);
@@ -42,7 +41,7 @@
 
  private:
   IOSChromeSavePasswordInfoBarDelegate(
-      bool is_smart_lock_branding_enabled,
+      bool is_sync_user,
       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_to_save);
 
   // ConfirmInfoBarDelegate implementation.
diff --git a/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm b/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm
index f659a52..af5e4f0 100644
--- a/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm
@@ -25,13 +25,13 @@
 
 // static
 void IOSChromeSavePasswordInfoBarDelegate::Create(
-    bool is_smart_lock_branding_enabled,
+    bool is_sync_user,
     infobars::InfoBarManager* infobar_manager,
     std::unique_ptr<PasswordFormManagerForUI> form_to_save,
     id<ApplicationCommands> dispatcher) {
   DCHECK(infobar_manager);
   auto delegate = base::WrapUnique(new IOSChromeSavePasswordInfoBarDelegate(
-      is_smart_lock_branding_enabled, std::move(form_to_save)));
+      is_sync_user, std::move(form_to_save)));
   delegate->set_dispatcher(dispatcher);
   infobar_manager->AddInfoBar(
       infobar_manager->CreateConfirmInfoBar(std::move(delegate)));
@@ -44,9 +44,9 @@
 }
 
 IOSChromeSavePasswordInfoBarDelegate::IOSChromeSavePasswordInfoBarDelegate(
-    bool is_smart_lock_branding_enabled,
+    bool is_sync_user,
     std::unique_ptr<PasswordFormManagerForUI> form_manager)
-    : IOSChromePasswordManagerInfoBarDelegate(is_smart_lock_branding_enabled,
+    : IOSChromePasswordManagerInfoBarDelegate(is_sync_user,
                                               std::move(form_manager)) {
   form_to_save()->GetMetricsRecorder()->RecordPasswordBubbleShown(
       form_to_save()->GetCredentialSource(),
@@ -59,10 +59,6 @@
 }
 
 base::string16 IOSChromeSavePasswordInfoBarDelegate::GetMessageText() const {
-  if (is_smart_lock_branding_enabled()) {
-    return l10n_util::GetStringUTF16(
-        IDS_IOS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT_SMART_LOCK_BRANDING);
-  }
   return l10n_util::GetStringUTF16(
       IDS_IOS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT);
 }
diff --git a/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.h b/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.h
index 9400fc3c..0ecc20b 100644
--- a/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.h
+++ b/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.h
@@ -26,11 +26,11 @@
     : public IOSChromePasswordManagerInfoBarDelegate {
  public:
   // Creates the infobar for |form_to_save| and adds it to |infobar_manager|.
-  // |is_smart_lock_enabled| controls the branding string. |baseViewController|
-  // is the base view controller from which to present UI, and is not retained.
+  // |is_sync_user| controls the footer text. |baseViewController| is the base
+  // view controller from which to present UI, and is not retained.
   // |dispatcher| is not retained.
   static void Create(
-      bool is_smart_lock_branding_enabled,
+      bool is_sync_user,
       infobars::InfoBarManager* infobar_manager,
       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_to_save,
       UIViewController* baseViewController,
@@ -55,13 +55,9 @@
 
  private:
   IOSChromeUpdatePasswordInfoBarDelegate(
-      bool is_smart_lock_branding_enabled,
+      bool is_sync_user,
       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_to_save);
 
-  // Returns the string with the branded title of the password manager (e.g.
-  // "Google Smart Lock for Passwords").
-  base::string16 GetBranding() const;
-
   // ConfirmInfoBarDelegate implementation.
   infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
   base::string16 GetMessageText() const override;
diff --git a/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm b/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm
index 9894811..65ece545 100644
--- a/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm
@@ -29,14 +29,14 @@
 
 // static
 void IOSChromeUpdatePasswordInfoBarDelegate::Create(
-    bool is_smart_lock_branding_enabled,
+    bool is_sync_user,
     infobars::InfoBarManager* infobar_manager,
     std::unique_ptr<PasswordFormManagerForUI> form_manager,
     UIViewController* baseViewController,
     id<ApplicationCommands> dispatcher) {
   DCHECK(infobar_manager);
   auto delegate = base::WrapUnique(new IOSChromeUpdatePasswordInfoBarDelegate(
-      is_smart_lock_branding_enabled, std::move(form_manager)));
+      is_sync_user, std::move(form_manager)));
   delegate->set_dispatcher(dispatcher);
   UpdatePasswordInfoBarController* controller =
       [[UpdatePasswordInfoBarController alloc]
@@ -55,9 +55,9 @@
 }
 
 IOSChromeUpdatePasswordInfoBarDelegate::IOSChromeUpdatePasswordInfoBarDelegate(
-    bool is_smart_lock_branding_enabled,
+    bool is_sync_user,
     std::unique_ptr<PasswordFormManagerForUI> form_manager)
-    : IOSChromePasswordManagerInfoBarDelegate(is_smart_lock_branding_enabled,
+    : IOSChromePasswordManagerInfoBarDelegate(is_sync_user,
                                               std::move(form_manager)) {
   selected_account_ = form_to_save()->GetPreferredMatch()->username_value;
   form_to_save()->GetMetricsRecorder()->RecordPasswordBubbleShown(
@@ -80,13 +80,6 @@
   return usernames;
 }
 
-base::string16 IOSChromeUpdatePasswordInfoBarDelegate::GetBranding() const {
-  return l10n_util::GetStringUTF16(
-      is_smart_lock_branding_enabled()
-          ? IDS_IOS_PASSWORD_MANAGER_SMART_LOCK_FOR_PASSWORDS
-          : IDS_IOS_SHORT_PRODUCT_NAME);
-}
-
 infobars::InfoBarDelegate::InfoBarIdentifier
 IOSChromeUpdatePasswordInfoBarDelegate::GetIdentifier() const {
   return UPDATE_PASSWORD_INFOBAR_DELEGATE_MOBILE;
@@ -96,9 +89,9 @@
   return selected_account_.length() > 0
              ? l10n_util::GetStringFUTF16(
                    IDS_IOS_PASSWORD_MANAGER_UPDATE_PASSWORD_FOR_ACCOUNT,
-                   GetBranding(), selected_account_)
-             : l10n_util::GetStringFUTF16(
-                   IDS_IOS_PASSWORD_MANAGER_UPDATE_PASSWORD, GetBranding());
+                   selected_account_)
+             : l10n_util::GetStringUTF16(
+                   IDS_IOS_PASSWORD_MANAGER_UPDATE_PASSWORD);
 }
 
 int IOSChromeUpdatePasswordInfoBarDelegate::GetButtons() const {
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm
index 457d024..e2beaad 100644
--- a/ios/chrome/browser/passwords/password_controller.mm
+++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -621,12 +621,11 @@
   if (!_webState)
     return;
 
-  bool isSmartLockBrandingEnabled = false;
+  bool isSyncUser = false;
   if (self.browserState) {
     syncer::SyncService* sync_service =
         ProfileSyncServiceFactory::GetForBrowserState(self.browserState);
-    isSmartLockBrandingEnabled =
-        password_bubble_experiment::IsSmartLockUser(sync_service);
+    isSyncUser = password_bubble_experiment::IsSmartLockUser(sync_service);
   }
   infobars::InfoBarManager* infoBarManager =
       InfoBarManagerImpl::FromWebState(_webState);
@@ -634,14 +633,13 @@
   switch (type) {
     case PasswordInfoBarType::SAVE:
       IOSChromeSavePasswordInfoBarDelegate::Create(
-          isSmartLockBrandingEnabled, infoBarManager, std::move(form),
-          self.dispatcher);
+          isSyncUser, infoBarManager, std::move(form), self.dispatcher);
       break;
 
     case PasswordInfoBarType::UPDATE:
       IOSChromeUpdatePasswordInfoBarDelegate::Create(
-          isSmartLockBrandingEnabled, infoBarManager, std::move(form),
-          self.baseViewController, self.dispatcher);
+          isSyncUser, infoBarManager, std::move(form), self.baseViewController,
+          self.dispatcher);
       break;
   }
 }
diff --git a/ios/chrome/browser/passwords/update_password_infobar_controller.mm b/ios/chrome/browser/passwords/update_password_infobar_controller.mm
index 8eec95d..a2d40161 100644
--- a/ios/chrome/browser/passwords/update_password_infobar_controller.mm
+++ b/ios/chrome/browser/passwords/update_password_infobar_controller.mm
@@ -75,9 +75,7 @@
 }
 
 - (void)infobarLinkDidPress:(NSUInteger)tag {
-  [super infobarLinkDidPress:tag];
-  if (tag != kAccountTag)
-    return;
+  DCHECK_EQ(kAccountTag, tag);
 
   DCHECK(self.baseViewController);
   self.selectorCoordinator = [[SelectorCoordinator alloc]
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm b/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm
index d701444..1a081c4 100644
--- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm
+++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm
@@ -113,16 +113,16 @@
 
 // Simulates a POST request on |web_view| using a XMLHttpRequest in
 // JavaScript.
-// This is needed because WKWebView ignores the HTTPBody in a POST request.
-// See
+// This is needed because WKWebView ignores the HTTPBody in a POST request
+// before iOS11 and because WKWebView cannot read response body if
+// content-disposition header is set. See
 // https://bugs.webkit.org/show_bug.cgi?id=145410
-// TODO(crbug.com/740987): Remove this function workaround once iOS 10 is
-// dropped.
+// TODO(crbug.com/889471) Remove this once requests are done using
+// NSUrlSession in iOS.
 void DoPostRequest(WKWebView* web_view,
                    const std::string& body,
                    const std::string& headers,
                    const GURL& url) {
-  DCHECK(!base::ios::IsRunningOnIOS11OrLater());
   NSMutableString* header_data = [NSMutableString string];
   net::HttpRequestHeaders request_headers;
   request_headers.AddHeadersFromString(headers);
@@ -200,15 +200,21 @@
 #pragma mark - GaiaAuthFetcherIOSBridge::Request
 
 GaiaAuthFetcherIOSBridge::Request::Request()
-    : pending(false), url(), headers(), body() {}
+    : pending(false),
+      url(),
+      headers(),
+      body(),
+      shouldUseXmlHTTPRequest(false) {}
 
 GaiaAuthFetcherIOSBridge::Request::Request(const GURL& request_url,
                                            const std::string& request_headers,
-                                           const std::string& request_body)
+                                           const std::string& request_body,
+                                           bool shouldUseXmlHTTPRequest)
     : pending(true),
       url(request_url),
       headers(request_headers),
-      body(request_body) {}
+      body(request_body),
+      shouldUseXmlHTTPRequest(shouldUseXmlHTTPRequest) {}
 
 #pragma mark - GaiaAuthFetcherIOSBridge
 
@@ -226,8 +232,9 @@
 
 void GaiaAuthFetcherIOSBridge::Fetch(const GURL& url,
                                      const std::string& headers,
-                                     const std::string& body) {
-  request_ = Request(url, headers, body);
+                                     const std::string& body,
+                                     bool shouldUseXmlHTTPRequest) {
+  request_ = Request(url, headers, body, shouldUseXmlHTTPRequest);
   FetchPendingRequest();
 }
 
@@ -265,7 +272,7 @@
 void GaiaAuthFetcherIOSBridge::FetchPendingRequest() {
   if (!request_.pending)
     return;
-  if (!request_.body.empty() && !base::ios::IsRunningOnIOS11OrLater()) {
+  if (!request_.body.empty() && request_.shouldUseXmlHTTPRequest) {
     DoPostRequest(GetWKWebView(), request_.body, request_.headers,
                   request_.url);
   } else {
@@ -355,7 +362,9 @@
   // a network request with cookies sent and saved is by making it through a
   // WKWebView.
   SetPendingFetch(true);
-  bridge_->Fetch(gaia_gurl, headers, body);
+  bool shouldUseXmlHTTPRequest =
+      IsMultiloginUrl(gaia_gurl) || !base::ios::IsRunningOnIOS11OrLater();
+  bridge_->Fetch(gaia_gurl, headers, body, shouldUseXmlHTTPRequest);
 }
 
 void GaiaAuthFetcherIOS::CancelRequest() {
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_private.h b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_private.h
index 766549c..40e8459e 100644
--- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_private.h
+++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_private.h
@@ -36,7 +36,8 @@
   //   will be a POST request.
   void Fetch(const GURL& url,
              const std::string& headers,
-             const std::string& body);
+             const std::string& body,
+             bool shouldUseXmlHTTPRequest);
 
   // Cancels the current fetch.
   void Cancel();
@@ -61,7 +62,8 @@
     Request();
     Request(const GURL& url,
             const std::string& headers,
-            const std::string& body);
+            const std::string& body,
+            bool shouldUseXmlHTTPRequest);
     // Whether the request is pending (i.e. awaiting to be processed or
     // currently being processed).
     bool pending;
@@ -71,6 +73,9 @@
     std::string headers;
     // HTTP body to add to the request.
     std::string body;
+    // Whether XmlHTTPRequest should be injected in JS instead of using
+    // WKWebView directly.
+    bool shouldUseXmlHTTPRequest;
   };
 
   // Fetches the pending request if it exists.
diff --git a/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
index 1e239dd..1c81248b 100644
--- a/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
+++ b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
@@ -213,16 +213,16 @@
     AuthenticationFlowPerformer* strongSelf = weakSelf;
     if (!strongSelf)
       return;
+    [strongSelf alertControllerDidDisappear:weakAlert];
     [[strongSelf delegate]
         didChooseClearDataPolicy:SHOULD_CLEAR_DATA_CLEAR_DATA];
-    [strongSelf alertControllerDidDisappear:weakAlert];
   };
   ProceduralBlock cancelBlock = ^{
     AuthenticationFlowPerformer* strongSelf = weakSelf;
     if (!strongSelf)
       return;
-    [[strongSelf delegate] didChooseCancel];
     [strongSelf alertControllerDidDisappear:weakAlert];
+    [[strongSelf delegate] didChooseCancel];
   };
 
   [_alertCoordinator addItemWithTitle:cancelLabel
@@ -337,15 +337,15 @@
     AuthenticationFlowPerformer* strongSelf = weakSelf;
     if (!strongSelf)
       return;
-    [[strongSelf delegate] didAcceptManagedConfirmation];
     [strongSelf alertControllerDidDisappear:weakAlert];
+    [[strongSelf delegate] didAcceptManagedConfirmation];
   };
   ProceduralBlock cancelBlock = ^{
     AuthenticationFlowPerformer* strongSelf = weakSelf;
     if (!strongSelf)
       return;
-    [[strongSelf delegate] didCancelManagedConfirmation];
     [strongSelf alertControllerDidDisappear:weakAlert];
+    [[strongSelf delegate] didCancelManagedConfirmation];
   };
 
   [_alertCoordinator addItemWithTitle:cancelLabel
@@ -368,9 +368,9 @@
   __weak AuthenticationFlowPerformer* weakSelf = self;
   __weak AlertCoordinator* weakAlert = _alertCoordinator;
   ProceduralBlock dismissAction = ^{
+    [weakSelf alertControllerDidDisappear:weakAlert];
     if (callback)
       callback();
-    [weakSelf alertControllerDidDisappear:weakAlert];
   };
 
   NSString* okButtonLabel = l10n_util::GetNSString(IDS_OK);
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 0331322..5b6001b1 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -178,7 +178,6 @@
 #import "ios/chrome/browser/ui/print/print_controller.h"
 #import "ios/chrome/browser/ui/qr_scanner/qr_scanner_legacy_coordinator.h"
 #import "ios/chrome/browser/ui/qr_scanner/requirements/qr_scanner_presenting.h"
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator.h"
 #import "ios/chrome/browser/ui/reading_list/offline_page_native_content.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_coordinator.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_menu_notifier.h"
@@ -4511,17 +4510,10 @@
 }
 
 - (void)showReadingList {
-  _readingListCoordinator =
-      experimental_flags::IsReadingListUIRebootEnabled()
-          ? [[ReadingListCoordinator alloc]
-                initWithBaseViewController:self
-                              browserState:self.browserState
-                                    loader:self]
-          : [[LegacyReadingListCoordinator alloc]
-                initWithBaseViewController:self
-                              browserState:self.browserState
-                                    loader:self];
-
+  _readingListCoordinator = [[ReadingListCoordinator alloc]
+      initWithBaseViewController:self
+                    browserState:self.browserState
+                          loader:self];
   [_readingListCoordinator start];
 }
 
diff --git a/ios/chrome/browser/ui/reading_list/BUILD.gn b/ios/chrome/browser/ui/reading_list/BUILD.gn
index 743e610..f56c4d5 100644
--- a/ios/chrome/browser/ui/reading_list/BUILD.gn
+++ b/ios/chrome/browser/ui/reading_list/BUILD.gn
@@ -4,12 +4,8 @@
 
 source_set("reading_list") {
   sources = [
-    "legacy_reading_list_coordinator.h",
-    "legacy_reading_list_coordinator.mm",
     "offline_page_native_content.h",
     "offline_page_native_content.mm",
-    "reading_list_collection_view_item.h",
-    "reading_list_collection_view_item.mm",
     "reading_list_coordinator.h",
     "reading_list_coordinator.mm",
     "reading_list_list_item.h",
@@ -33,6 +29,7 @@
   ]
   deps = [
     ":reading_list_ui",
+    "resources:distillation_fail_new",
     "//base",
     "//components/favicon/core",
     "//components/feature_engagement",
@@ -80,18 +77,8 @@
     "empty_reading_list_background_view.mm",
     "empty_reading_list_message_util.h",
     "empty_reading_list_message_util.mm",
-    "legacy_reading_list_toolbar.h",
-    "legacy_reading_list_toolbar.mm",
-    "legacy_reading_list_toolbar_button.h",
-    "legacy_reading_list_toolbar_button.mm",
-    "legacy_reading_list_view_controller.h",
-    "legacy_reading_list_view_controller.mm",
     "number_badge_view.h",
     "number_badge_view.mm",
-    "reading_list_collection_view_cell.h",
-    "reading_list_collection_view_cell.mm",
-    "reading_list_collection_view_controller.h",
-    "reading_list_collection_view_controller.mm",
     "reading_list_data_sink.h",
     "reading_list_data_source.h",
     "reading_list_list_item_accessibility_delegate.h",
@@ -110,13 +97,9 @@
     "text_badge_view.mm",
   ]
   deps = [
-    "resources:distillation_fail",
-    "resources:distillation_success",
     "resources:reading_list_empty_state",
     "resources:reading_list_empty_state_new",
-    "resources:reading_list_share_icon",
     "resources:reading_list_side_swipe",
-    "resources:reading_list_toolbar_icon",
     "resources:reading_list_tools_icon",
     "//base",
     "//base:i18n",
@@ -126,8 +109,6 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/ui",
     "//ios/chrome/browser/ui/alert_coordinator",
-    "//ios/chrome/browser/ui/collection_view/cells",
-    "//ios/chrome/browser/ui/colors",
     "//ios/chrome/browser/ui/keyboard",
     "//ios/chrome/browser/ui/list_model",
     "//ios/chrome/browser/ui/material_components",
@@ -137,15 +118,10 @@
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/common",
     "//ios/chrome/common/favicon",
-    "//ios/third_party/material_components_ios",
-    "//ios/third_party/material_roboto_font_loader_ios",
     "//ui/base",
     "//ui/strings:ui_strings_grit",
     "//url",
   ]
-  public_deps = [
-    "//ios/chrome/browser/ui/collection_view",
-  ]
   libs = [ "UIKit.framework" ]
 }
 
@@ -153,9 +129,7 @@
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
-    "legacy_reading_list_coordinator_unittest.mm",
     "offline_page_native_content_unittest.mm",
-    "reading_list_collection_view_controller_unittest.mm",
     "reading_list_list_item_factory_unittest.mm",
     "reading_list_mediator_unittest.mm",
     "text_badge_view_unittest.mm",
diff --git a/ios/chrome/browser/ui/reading_list/empty_reading_list_message_util.mm b/ios/chrome/browser/ui/reading_list/empty_reading_list_message_util.mm
index f562b4d6..51319f1 100644
--- a/ios/chrome/browser/ui/reading_list/empty_reading_list_message_util.mm
+++ b/ios/chrome/browser/ui/reading_list/empty_reading_list_message_util.mm
@@ -9,8 +9,6 @@
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -21,44 +19,17 @@
 
 // Images name.
 NSString* const kToolsIcon = @"reading_list_tools_icon";
-NSString* const kToolsIconLegacy = @"reading_list_toolbar_icon";
-NSString* const kShareIconLegacy = @"reading_list_share_icon";
 
 // Tag in string.
 NSString* const kOpenShareMarker = @"SHARE_OPENING_ICON";
 NSString* const kReadLaterTextMarker = @"READ_LATER_TEXT";
 
 // Background view constants.
-const CGFloat kFontSize = 16;
 const CGFloat kLineHeight = 24;
 
-// Enum type describing the icons used by the attributed empty table message.
-enum class IconType { TOOLS, SHARE };
-// Returns the UIImage corresponding with |icon_type|.
-UIImage* GetIconWithType(IconType icon_type) {
-  if (experimental_flags::IsReadingListUIRebootEnabled()) {
-    switch (icon_type) {
-      case IconType::TOOLS:
-        return [UIImage imageNamed:kToolsIcon];
-      case IconType::SHARE:
-        NOTREACHED() << "The share icon is not used in the UI refresh.";
-        return nil;
-    }
-  } else {
-    switch (icon_type) {
-      case IconType::TOOLS:
-        return [UIImage imageNamed:kToolsIconLegacy];
-      case IconType::SHARE:
-        return [UIImage imageNamed:kShareIconLegacy];
-    }
-  }
-}
-
 // Returns the font to use for the message text.
 UIFont* GetMessageFont() {
-  return experimental_flags::IsReadingListUIRebootEnabled()
-             ? [UIFont preferredFontForTextStyle:UIFontTextStyleBody]
-             : [[MDCTypography fontLoader] regularFontOfSize:kFontSize];
+  return [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
 }
 
 // Returns the attributes to use for the message text.
@@ -66,10 +37,7 @@
   NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
   UIFont* font = GetMessageFont();
   attributes[NSFontAttributeName] = font;
-  attributes[NSForegroundColorAttributeName] =
-      experimental_flags::IsReadingListUIRebootEnabled()
-          ? [UIColor grayColor]
-          : [[MDCPalette greyPalette] tint700];
+  attributes[NSForegroundColorAttributeName] = [UIColor grayColor];
   NSMutableParagraphStyle* paragraph_style =
       [[NSMutableParagraphStyle alloc] init];
   paragraph_style.lineBreakMode = NSLineBreakByWordWrapping;
@@ -87,9 +55,7 @@
 NSMutableDictionary* GetInstructionAttributes() {
   NSMutableDictionary* attributes = GetMessageAttributes();
   attributes[NSFontAttributeName] =
-      experimental_flags::IsReadingListUIRebootEnabled()
-          ? [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]
-          : [[MDCTypography fontLoader] boldFontOfSize:kFontSize];
+      [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
   return attributes;
 }
 
@@ -97,18 +63,15 @@
 // correct styling.
 NSAttributedString* GetReadLaterString() {
   NSString* read_later_text =
-      l10n_util::GetNSString(experimental_flags::IsReadingListUIRebootEnabled()
-                                 ? IDS_IOS_SHARE_MENU_READING_LIST_ACTION
-                                 : IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST);
+      l10n_util::GetNSString(IDS_IOS_SHARE_MENU_READING_LIST_ACTION);
   return [[NSAttributedString alloc] initWithString:read_later_text
                                          attributes:GetInstructionAttributes()];
 }
 
-// Appends the icon with |icon_type| to |text|.  Spacer text that is added by
-// this function is formatted with |attributes|.
-void AppendIcon(IconType icon_type,
-                NSMutableAttributedString* text,
-                NSDictionary* attributes) {
+// Appends the tools icon to |text|.  Spacer text that is added by this function
+// is formatted with |attributes|.
+void AppendToolsIcon(NSMutableAttributedString* text,
+                     NSDictionary* attributes) {
   // Add a zero width space to set the attributes for the image.
   NSAttributedString* spacer =
       [[NSAttributedString alloc] initWithString:@"\u200B"
@@ -117,7 +80,7 @@
 
   // The icon bounds must be offset to be vertically centered with the message
   // text.
-  UIImage* icon = GetIconWithType(icon_type);
+  UIImage* icon = [UIImage imageNamed:kToolsIcon];
   CGRect icon_bounds = CGRectZero;
   icon_bounds.size = icon.size;
   icon_bounds.origin.y = (GetMessageFont().xHeight - icon.size.height) / 2.0;
@@ -132,42 +95,13 @@
   [text appendAttributedString:attachment_string];
 }
 
-// Appends a carat string and some spacing to |text|.
-void AppendCarat(NSMutableAttributedString* text, NSDictionary* attributes) {
-  // Use a carat facing the appropriate direction for the language.
-  NSString* carat = [NSString
-      stringWithFormat:@" %@ ", UseRTLLayout() ? @"\u25C2" : @"\u25B8"];
-  [text appendAttributedString:[[NSAttributedString alloc]
-                                   initWithString:carat
-                                       attributes:attributes]];
-}
-
 // Returns the string to use to describe the buttons needed to access the "Read
 // Later" option.
 NSAttributedString* GetInstructionIconString() {
   NSDictionary* attributes = GetInstructionAttributes();
   NSMutableAttributedString* icon_string =
       [[NSMutableAttributedString alloc] init];
-  if (experimental_flags::IsReadingListUIRebootEnabled()) {
-    // In the UI reboot, only the single tools icon is used.
-    AppendIcon(IconType::TOOLS, icon_string, attributes);
-  } else {
-    if (IsCompactWidth() || !IsIPadIdiom()) {
-      // TODO(crbug.com/698726): When the share icon is displayed in the toolbar
-      // for landscape iPhone 6+, remove !IsIPadIdiom().
-      // If the device has a compact display the share menu is accessed from the
-      // toolbar menu. If it is expanded, the share menu is directly accessible.
-      AppendIcon(IconType::TOOLS, icon_string, attributes);
-      AppendCarat(icon_string, attributes);
-    }
-    AppendIcon(IconType::SHARE, icon_string, attributes);
-    AppendCarat(icon_string, attributes);
-    // Append an additional space at the end of the legacy icon string to
-    // improve the kerning between the carat and the "Read Later" text.
-    [icon_string appendAttributedString:[[NSAttributedString alloc]
-                                            initWithString:@" "
-                                                attributes:attributes]];
-  }
+  AppendToolsIcon(icon_string, attributes);
   return icon_string;
 }
 
@@ -177,29 +111,12 @@
   NSMutableAttributedString* icon_string =
       [[NSMutableAttributedString alloc] initWithString:@":"
                                              attributes:attributes];
-  if (experimental_flags::IsReadingListUIRebootEnabled()) {
-    NSString* tools_text = [NSString
-        stringWithFormat:@"%@, ",
-                         l10n_util::GetNSString(IDS_IOS_TOOLBAR_SETTINGS)];
-    [icon_string appendAttributedString:[[NSAttributedString alloc]
-                                            initWithString:tools_text
-                                                attributes:attributes]];
-  } else {
-    if ((IsCompactWidth() || !IsIPadIdiom())) {
-      NSString* tools_text = [NSString
-          stringWithFormat:@"%@, ",
-                           l10n_util::GetNSString(IDS_IOS_TOOLBAR_SETTINGS)];
-      [icon_string appendAttributedString:[[NSAttributedString alloc]
-                                              initWithString:tools_text
-                                                  attributes:attributes]];
-    }
-    NSString* share_text = [NSString
-        stringWithFormat:@"%@, ",
-                         l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_SHARE)];
-    [icon_string appendAttributedString:[[NSAttributedString alloc]
-                                            initWithString:share_text
-                                                attributes:attributes]];
-  }
+  NSString* tools_text = [NSString
+      stringWithFormat:@"%@, ",
+                       l10n_util::GetNSString(IDS_IOS_TOOLBAR_SETTINGS)];
+  [icon_string appendAttributedString:[[NSAttributedString alloc]
+                                          initWithString:tools_text
+                                              attributes:attributes]];
   return icon_string;
 }
 
@@ -207,10 +124,8 @@
 // icon images are added to the text; otherwise accessible text versions of the
 // instructions are used.
 NSAttributedString* GetReadingListEmptyMessage(bool use_icons) {
-  bool reboot_enabled = experimental_flags::IsReadingListUIRebootEnabled();
-  NSString* raw_text = l10n_util::GetNSString(
-      reboot_enabled ? IDS_IOS_READING_LIST_EMPTY_MESSAGE
-                     : IDS_IOS_READING_LIST_EMPTY_MESSAGE_LEGACY);
+  NSString* raw_text =
+      l10n_util::GetNSString(IDS_IOS_READING_LIST_EMPTY_MESSAGE);
   NSMutableAttributedString* message =
       [[NSMutableAttributedString alloc] initWithString:raw_text
                                              attributes:GetMessageAttributes()];
@@ -218,33 +133,19 @@
       use_icons ? GetInstructionIconString()
                 : GetAccessibleInstructionIconString();
   NSAttributedString* read_later_string = GetReadLaterString();
-  if (reboot_enabled) {
-    // When the reboot is enabled, two replacements must be made in the text:
-    // - kOpenShareMarker should be replaced with |instruction_icon_string|
-    // - kReadLaterTextMarker should be replaced with |read_later_text|
-    NSRange icon_range = [message.string rangeOfString:kOpenShareMarker];
-    DCHECK(icon_range.location != NSNotFound);
-    [message replaceCharactersInRange:icon_range
-                 withAttributedString:instruction_icon_string];
+  // Two replacements must be made in the text:
+  // - kOpenShareMarker should be replaced with |instruction_icon_string|
+  // - kReadLaterTextMarker should be replaced with |read_later_text|
+  NSRange icon_range = [message.string rangeOfString:kOpenShareMarker];
+  DCHECK(icon_range.location != NSNotFound);
+  [message replaceCharactersInRange:icon_range
+               withAttributedString:instruction_icon_string];
 
-    NSRange read_later_range =
-        [message.string rangeOfString:kReadLaterTextMarker];
-    DCHECK(read_later_range.location != NSNotFound);
-    [message replaceCharactersInRange:read_later_range
-                 withAttributedString:read_later_string];
-  } else {
-    // In the legacy implementation, kOpenShareMarker is replaced with the
-    // entire instruction string (i.e. "(tools icon) > (share icon) > Read
-    // Later".
-    NSMutableAttributedString* instruction_string =
-        [[NSMutableAttributedString alloc] init];
-    [instruction_string appendAttributedString:instruction_icon_string];
-    [instruction_string appendAttributedString:read_later_string];
-    NSRange replacement_range = [message.string rangeOfString:kOpenShareMarker];
-    DCHECK(replacement_range.location != NSNotFound);
-    [message replaceCharactersInRange:replacement_range
-                 withAttributedString:instruction_string];
-  }
+  NSRange read_later_range =
+      [message.string rangeOfString:kReadLaterTextMarker];
+  DCHECK(read_later_range.location != NSNotFound);
+  [message replaceCharactersInRange:read_later_range
+               withAttributedString:read_later_string];
   return message;
 }
 }  // namespace
diff --git a/ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator.h b/ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator.h
deleted file mode 100644
index 2474f677..0000000
--- a/ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator.h
+++ /dev/null
@@ -1,40 +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 IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_COORDINATOR_H_
-#define IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_COORDINATOR_H_
-
-#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_view_controller_delegate.h"
-
-namespace ios {
-class ChromeBrowserState;
-}
-
-@class ReadingListMediator;
-@protocol UrlLoader;
-
-// Coordinator for Reading List, displaying the Reading List when starting.
-@interface LegacyReadingListCoordinator
-    : ChromeCoordinator<ReadingListListViewControllerDelegate>
-
-// Mediator used by this coordinator. Reset when |-start| is called.
-@property(nonatomic, strong, nullable) ReadingListMediator* mediator;
-
-- (nullable instancetype)
-initWithBaseViewController:(nullable UIViewController*)viewController
-              browserState:(nonnull ios::ChromeBrowserState*)browserState
-                    loader:(nullable id<UrlLoader>)loader
-    NS_DESIGNATED_INITIALIZER;
-
-- (nullable instancetype)initWithBaseViewController:
-    (nullable UIViewController*)viewController NS_UNAVAILABLE;
-- (nullable instancetype)
-initWithBaseViewController:(nullable UIViewController*)viewController
-              browserState:(nullable ios::ChromeBrowserState*)browserState
-    NS_UNAVAILABLE;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator.mm b/ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator.mm
deleted file mode 100644
index 6a45e0e2..0000000
--- a/ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator.mm
+++ /dev/null
@@ -1,330 +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.
-
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator.h"
-
-#import "base/mac/foundation_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "base/metrics/user_metrics_action.h"
-#import "base/strings/sys_string_conversions.h"
-#include "components/feature_engagement/public/event_constants.h"
-#include "components/feature_engagement/public/tracker.h"
-#include "components/reading_list/core/reading_list_model.h"
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
-#include "ios/chrome/browser/feature_engagement/tracker_factory.h"
-#import "ios/chrome/browser/metrics/new_tab_page_uma.h"
-#include "ios/chrome/browser/reading_list/offline_url_utils.h"
-#include "ios/chrome/browser/reading_list/reading_list_download_service.h"
-#include "ios/chrome/browser/reading_list/reading_list_download_service_factory.h"
-#include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
-#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
-#import "ios/chrome/browser/ui/reading_list/context_menu/reading_list_context_menu_commands.h"
-#import "ios/chrome/browser/ui/reading_list/context_menu/reading_list_context_menu_coordinator.h"
-#import "ios/chrome/browser/ui/reading_list/context_menu/reading_list_context_menu_params.h"
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.h"
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_view_controller.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_mediator.h"
-#import "ios/chrome/browser/ui/url_loader.h"
-#import "ios/chrome/browser/ui/util/pasteboard_util.h"
-#include "ios/chrome/grit/ios_strings.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/referrer.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/strings/grit/ui_strings.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface LegacyReadingListCoordinator ()<ReadingListContextMenuCommands>
-
-@property(nonatomic, assign) ios::ChromeBrowserState* browserState;
-// Used to load the Reading List pages.
-@property(nonatomic, weak) id<UrlLoader> URLLoader;
-// The container view containing both the collection view and the toolbar.
-@property(nonatomic, strong)
-    LegacyReadingListViewController* containerViewController;
-// The collection view controller that displays the reading list items (owned by
-// |containerViewController|).
-@property(nonatomic, weak)
-    ReadingListCollectionViewController* collectionViewController;
-// The context menu displayed for long-presses on reading list items.
-@property(nonatomic, strong)
-    ReadingListContextMenuCoordinator* contextMenuCoordinator;
-
-@end
-
-@implementation LegacyReadingListCoordinator
-
-@synthesize containerViewController = _containerViewController;
-@synthesize collectionViewController = _collectionViewController;
-@synthesize contextMenuCoordinator = _contextMenuCoordinator;
-@synthesize URLLoader = _URLLoader;
-@synthesize browserState = _browserState;
-@synthesize mediator = _mediator;
-
-- (instancetype)initWithBaseViewController:(UIViewController*)viewController
-                              browserState:
-                                  (ios::ChromeBrowserState*)browserState
-                                    loader:(id<UrlLoader>)loader {
-  self = [super initWithBaseViewController:viewController
-                              browserState:browserState];
-  if (self) {
-    _browserState = browserState;
-    _URLLoader = loader;
-  }
-  return self;
-}
-
-#pragma mark - ChromeCoordinator
-
-- (void)start {
-  if (!self.containerViewController) {
-    ReadingListModel* model =
-        ReadingListModelFactory::GetInstance()->GetForBrowserState(
-            self.browserState);
-    favicon::LargeIconService* largeIconService =
-        IOSChromeLargeIconServiceFactory::GetForBrowserState(self.browserState);
-
-    ReadingListListItemFactory* itemFactory =
-        [ReadingListListItemFactory collectionViewItemFactory];
-
-    self.mediator = [[ReadingListMediator alloc] initWithModel:model
-                                              largeIconService:largeIconService
-                                               listItemFactory:itemFactory];
-    LegacyReadingListToolbar* toolbar = [[LegacyReadingListToolbar alloc] init];
-    ReadingListCollectionViewController* collectionViewController =
-        [[ReadingListCollectionViewController alloc]
-            initWithDataSource:self.mediator
-
-                       toolbar:toolbar];
-    collectionViewController.delegate = self;
-    itemFactory.accessibilityDelegate = collectionViewController;
-    self.collectionViewController = collectionViewController;
-
-    self.containerViewController = [[LegacyReadingListViewController alloc]
-        initWithCollectionViewController:collectionViewController
-                                 toolbar:toolbar];
-    self.containerViewController.delegate = self;
-  }
-
-  [self.baseViewController presentViewController:self.containerViewController
-                                        animated:YES
-                                      completion:nil];
-
-  // Send the "Viewed Reading List" event to the feature_engagement::Tracker
-  // when the user opens their reading list.
-  feature_engagement::TrackerFactory::GetForBrowserState(self.browserState)
-      ->NotifyEvent(feature_engagement::events::kViewedReadingList);
-}
-
-- (void)stop {
-  [self.containerViewController.presentingViewController
-      dismissViewControllerAnimated:YES
-                         completion:nil];
-
-  self.containerViewController = nil;
-}
-
-#pragma mark - ReadingListListViewControllerDelegate
-
-- (void)dismissReadingListListViewController:(UIViewController*)viewController {
-  DCHECK_EQ(viewController, self.collectionViewController);
-  [self.collectionViewController willBeDismissed];
-  [self stop];
-}
-
-- (void)readingListListViewController:(UIViewController*)viewController
-            displayContextMenuForItem:(ListItem<ReadingListListItem>*)item
-                              atPoint:(CGPoint)menuLocation {
-  DCHECK_EQ(viewController, self.collectionViewController);
-  if (!self.containerViewController) {
-    return;
-  }
-
-  ListItem<ReadingListListItem>* readingListItem =
-      base::mac::ObjCCastStrict<ReadingListCollectionViewItem>(item);
-
-  const ReadingListEntry* entry = [self.mediator entryFromItem:readingListItem];
-
-  if (!entry) {
-    [self.collectionViewController reloadData];
-    return;
-  }
-  const GURL entryURL = entry->URL();
-
-  GURL offlineURL;
-  if (entry->DistilledState() == ReadingListEntry::PROCESSED) {
-    offlineURL = reading_list::OfflineURLForPath(
-        entry->DistilledPath(), entryURL, entry->DistilledURL());
-  }
-
-  ReadingListContextMenuParams* params =
-      [[ReadingListContextMenuParams alloc] init];
-  params.title = readingListItem.title;
-  params.message = base::SysUTF8ToNSString(readingListItem.entryURL.host());
-  params.rect = CGRectMake(menuLocation.x, menuLocation.y, 0, 0);
-  params.view = self.collectionViewController.collectionView;
-  params.entryURL = entryURL;
-  params.offlineURL = offlineURL;
-
-  self.contextMenuCoordinator = [[ReadingListContextMenuCoordinator alloc]
-      initWithBaseViewController:self.containerViewController
-                          params:params];
-  self.contextMenuCoordinator.commandHandler = self;
-  [self.contextMenuCoordinator start];
-}
-
-- (void)readingListListViewController:(UIViewController*)viewController
-                             openItem:(ListItem<ReadingListListItem>*)item {
-  const ReadingListEntry* entry = [self.mediator entryFromItem:item];
-  if (!entry) {
-    [self.collectionViewController reloadData];
-    return;
-  }
-  [self loadEntryURL:entry->URL()
-      withOfflineURL:GURL::EmptyGURL()
-            inNewTab:NO
-           incognito:NO];
-}
-
-- (void)readingListListViewController:(UIViewController*)viewController
-                     openItemInNewTab:(ListItem<ReadingListListItem>*)item
-                            incognito:(BOOL)incognito {
-  const ReadingListEntry* entry = [self.mediator entryFromItem:item];
-  if (!entry) {
-    [self.collectionViewController reloadData];
-    return;
-  }
-  [self loadEntryURL:entry->URL()
-      withOfflineURL:GURL::EmptyGURL()
-            inNewTab:YES
-           incognito:incognito];
-}
-
-- (void)readingListListViewController:(UIViewController*)viewController
-              openItemOfflineInNewTab:(id<ReadingListListItem>)item {
-  const ReadingListEntry* entry = [self.mediator entryFromItem:item];
-  if (!entry)
-    return;
-
-  if (entry->DistilledState() == ReadingListEntry::PROCESSED) {
-    const GURL entryURL = entry->URL();
-    GURL offlineURL = reading_list::OfflineURLForPath(
-        entry->DistilledPath(), entryURL, entry->DistilledURL());
-    [self loadEntryURL:entry->URL()
-        withOfflineURL:offlineURL
-              inNewTab:YES
-             incognito:NO];
-  }
-}
-
-#pragma mark - ReadingListContextMenuCommands
-
-- (void)openURLInNewTabForContextMenuWithParams:
-    (ReadingListContextMenuParams*)params {
-  [self loadEntryURL:params.entryURL
-      withOfflineURL:GURL::EmptyGURL()
-            inNewTab:YES
-           incognito:NO];
-  [self cleanUpContextMenu];
-}
-
-- (void)openURLInNewIncognitoTabForContextMenuWithParams:
-    (ReadingListContextMenuParams*)params {
-  [self loadEntryURL:params.entryURL
-      withOfflineURL:GURL::EmptyGURL()
-            inNewTab:YES
-           incognito:YES];
-  [self cleanUpContextMenu];
-}
-
-- (void)copyURLForContextMenuWithParams:(ReadingListContextMenuParams*)params {
-  StoreURLInPasteboard(params.entryURL);
-  [self cleanUpContextMenu];
-}
-
-- (void)openOfflineURLInNewTabForContextMenuWithParams:
-    (ReadingListContextMenuParams*)params {
-  [self loadEntryURL:params.entryURL
-      withOfflineURL:params.offlineURL
-            inNewTab:YES
-           incognito:NO];
-  [self cleanUpContextMenu];
-}
-
-- (void)cancelReadingListContextMenuWithParams:
-    (ReadingListContextMenuParams*)params {
-  [self cleanUpContextMenu];
-}
-
-#pragma mark - Context Menu Helpers
-
-// Stops the context menu coordinator and resets the property.
-- (void)cleanUpContextMenu {
-  [self.contextMenuCoordinator stop];
-  self.contextMenuCoordinator = nil;
-}
-
-#pragma mark - Private
-
-// Loads reading list URLs.  If |offlineURL| is valid, the item will be loaded
-// offline; otherwise |entryURL| is loaded.  |newTab| and |incognito| can be
-// used to optionally open the URL in a new tab or in incognito.  The
-// coordinator is also stopped after the load is requested.
-- (void)loadEntryURL:(const GURL&)entryURL
-      withOfflineURL:(const GURL&)offlineURL
-            inNewTab:(BOOL)newTab
-           incognito:(BOOL)incognito {
-  DCHECK(entryURL.is_valid());
-  base::RecordAction(base::UserMetricsAction("MobileReadingListOpen"));
-  new_tab_page_uma::RecordAction(
-      self.browserState, new_tab_page_uma::ACTION_OPENED_READING_LIST_ENTRY);
-
-  // Load the offline URL if available.
-  GURL loadURL = entryURL;
-  if (offlineURL.is_valid()) {
-    loadURL = offlineURL;
-    // Offline URLs should always be opened in new tabs.
-    newTab = YES;
-    // Record the offline load and update the model.
-    UMA_HISTOGRAM_BOOLEAN("ReadingList.OfflineVersionDisplayed", true);
-    const GURL updateURL = entryURL;
-    [self.mediator markEntryRead:updateURL];
-  }
-
-  // Prepare the collection for dismissal.
-  [self.collectionViewController willBeDismissed];
-
-  if (newTab) {
-    // Use a referrer with a specific URL to signal that this entry should not
-    // be taken into account for the Most Visited tiles.
-    web::Referrer referrer = web::Referrer(GURL(kReadingListReferrerURL),
-                                           web::ReferrerPolicyDefault);
-    OpenNewTabCommand* command =
-        [[OpenNewTabCommand alloc] initWithURL:loadURL
-                                      referrer:referrer
-                                   inIncognito:incognito
-                                  inBackground:NO
-                                      appendTo:kLastTab];
-    [self.URLLoader webPageOrderedOpen:command];
-  } else {
-    web::NavigationManager::WebLoadParams params(loadURL);
-    params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
-    params.referrer = web::Referrer(GURL(kReadingListReferrerURL),
-                                    web::ReferrerPolicyDefault);
-    [self.URLLoader loadURLWithParams:params];
-  }
-
-  [self stop];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator_unittest.mm b/ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator_unittest.mm
deleted file mode 100644
index ef33eec3..0000000
--- a/ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator_unittest.mm
+++ /dev/null
@@ -1,202 +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.
-
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_coordinator.h"
-
-#include <memory>
-
-#include "base/time/default_clock.h"
-#include "components/favicon/core/large_icon_service.h"
-#include "components/favicon/core/test/mock_favicon_service.h"
-#include "components/feature_engagement/public/event_constants.h"
-#include "components/feature_engagement/public/feature_constants.h"
-#include "components/feature_engagement/public/tracker.h"
-#include "components/feature_engagement/test/mock_tracker.h"
-#include "components/reading_list/core/reading_list_entry.h"
-#include "components/reading_list/core/reading_list_model_impl.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#include "ios/chrome/browser/feature_engagement/tracker_factory.h"
-#include "ios/chrome/browser/reading_list/offline_url_utils.h"
-#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_mediator.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_utils.h"
-#import "ios/chrome/browser/ui/url_loader.h"
-#import "ios/chrome/test/fakes/fake_url_loader.h"
-#include "ios/web/public/referrer.h"
-#import "ios/web/public/test/web_test_with_web_state.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-#import "third_party/ocmock/gtest_support.h"
-#include "ui/base/page_transition_types.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-using favicon::PostReply;
-using testing::_;
-
-#pragma mark - LegacyReadingListCoordinatorTest
-
-class LegacyReadingListCoordinatorTest : public web::WebTestWithWebState {
- public:
-  LegacyReadingListCoordinatorTest() {
-    url_loader_ = [[FakeURLLoader alloc] init];
-
-    TestChromeBrowserState::Builder builder;
-    builder.AddTestingFactory(
-        feature_engagement::TrackerFactory::GetInstance(),
-        base::BindRepeating(&LegacyReadingListCoordinatorTest::
-                                BuildFeatureEngagementMockTracker));
-    browser_state_ = builder.Build();
-
-    reading_list_model_.reset(new ReadingListModelImpl(
-        nullptr, nullptr, base::DefaultClock::GetInstance()));
-    large_icon_service_.reset(new favicon::LargeIconService(
-        &mock_favicon_service_, /*image_fetcher=*/nullptr));
-    mediator_ = [[ReadingListMediator alloc]
-           initWithModel:reading_list_model_.get()
-        largeIconService:large_icon_service_.get()
-         listItemFactory:[ReadingListListItemFactory
-                             collectionViewItemFactory]];
-    coordinator_ = [[LegacyReadingListCoordinator alloc]
-        initWithBaseViewController:nil
-                      browserState:browser_state_.get()
-                            loader:url_loader_];
-    coordinator_.mediator = mediator_;
-
-    EXPECT_CALL(mock_favicon_service_,
-                GetLargestRawFaviconForPageURL(_, _, _, _, _))
-        .WillRepeatedly(PostReply<5>(favicon_base::FaviconRawBitmapResult()));
-  }
-
-  ~LegacyReadingListCoordinatorTest() override {}
-
-  LegacyReadingListCoordinator* GetCoordinator() { return coordinator_; }
-
-  ReadingListModel* GetReadingListModel() { return reading_list_model_.get(); }
-  FakeURLLoader* GetLoader() { return url_loader_; }
-
-  ios::ChromeBrowserState* GetBrowserState() { return browser_state_.get(); }
-
-  ReadingListCollectionViewController*
-  GetAReadingListCollectionViewController() {
-    return [[ReadingListCollectionViewController alloc]
-        initWithDataSource:mediator_
-                   toolbar:nil];
-  }
-
-  static std::unique_ptr<KeyedService> BuildFeatureEngagementMockTracker(
-      web::BrowserState*) {
-    return std::make_unique<feature_engagement::test::MockTracker>();
-  }
-
- private:
-  LegacyReadingListCoordinator* coordinator_;
-  ReadingListMediator* mediator_;
-  std::unique_ptr<ReadingListModelImpl> reading_list_model_;
-  FakeURLLoader* url_loader_;
-  testing::StrictMock<favicon::MockFaviconService> mock_favicon_service_;
-  std::unique_ptr<favicon::LargeIconService> large_icon_service_;
-  std::unique_ptr<TestChromeBrowserState> browser_state_;
-};
-
-// Tests that the implementation of LegacyReadingListCoordinator
-// openItemAtIndexPath opens the entry.
-TEST_F(LegacyReadingListCoordinatorTest, OpenItem) {
-  // Setup.
-  GURL url("https://chromium.org");
-  std::string title("Chromium");
-  ReadingListModel* model = GetReadingListModel();
-  model->AddEntry(url, title, reading_list::ADDED_VIA_CURRENT_APP);
-
-  ReadingListCollectionViewItem* item =
-      [[ReadingListCollectionViewItem alloc] initWithType:0];
-  item.entryURL = url;
-  item.distillationState = ReadingListUIDistillationStatusSuccess;
-
-  // Action.
-  [GetCoordinator()
-      readingListListViewController:GetAReadingListCollectionViewController()
-                           openItem:item];
-
-  // Tests.
-  FakeURLLoader* loader = GetLoader();
-  EXPECT_EQ(url, loader.url);
-  EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_AUTO_BOOKMARK,
-                                           loader.transition));
-  EXPECT_EQ(NO, loader.rendererInitiated);
-}
-
-TEST_F(LegacyReadingListCoordinatorTest, OpenItemOffline) {
-  // Setup.
-  GURL url("https://chromium.org");
-  std::string title("Chromium");
-  ReadingListModel* model = GetReadingListModel();
-  model->AddEntry(url, title, reading_list::ADDED_VIA_CURRENT_APP);
-  base::FilePath distilled_path("test");
-  GURL distilled_url("https://distilled.com");
-  model->SetEntryDistilledInfo(url, distilled_path, distilled_url, 123,
-                               base::Time::FromTimeT(10));
-
-  ReadingListCollectionViewItem* item =
-      [[ReadingListCollectionViewItem alloc] init];
-  item.entryURL = url;
-  item.distillationState = ReadingListUIDistillationStatusSuccess;
-  GURL offlineURL =
-      reading_list::OfflineURLForPath(distilled_path, url, distilled_url);
-  ASSERT_FALSE(model->GetEntryByURL(url)->IsRead());
-
-  // Action.
-  [GetCoordinator()
-      readingListListViewController:GetAReadingListCollectionViewController()
-            openItemOfflineInNewTab:item];
-
-  // Tests.
-  FakeURLLoader* loader = GetLoader();
-  EXPECT_EQ(offlineURL, loader.url);
-  EXPECT_FALSE(loader.inIncognito);
-  EXPECT_TRUE(model->GetEntryByURL(url)->IsRead());
-}
-
-TEST_F(LegacyReadingListCoordinatorTest, OpenItemInNewTab) {
-  // Setup.
-  GURL url("https://chromium.org");
-  std::string title("Chromium");
-  ReadingListModel* model = GetReadingListModel();
-  model->AddEntry(url, title, reading_list::ADDED_VIA_CURRENT_APP);
-
-  ReadingListCollectionViewItem* item =
-      [[ReadingListCollectionViewItem alloc] init];
-  item.entryURL = url;
-  item.distillationState = ReadingListUIDistillationStatusSuccess;
-
-  // Action.
-  [GetCoordinator()
-      readingListListViewController:GetAReadingListCollectionViewController()
-                   openItemInNewTab:item
-                          incognito:YES];
-
-  // Tests.
-  FakeURLLoader* loader = GetLoader();
-  EXPECT_EQ(url, loader.url);
-  EXPECT_TRUE(loader.inIncognito);
-}
-
-TEST_F(LegacyReadingListCoordinatorTest, SendViewedReadingListEventInStart) {
-  // Setup.
-  feature_engagement::test::MockTracker* tracker =
-      static_cast<feature_engagement::test::MockTracker*>(
-          feature_engagement::TrackerFactory::GetForBrowserState(
-              GetBrowserState()));
-
-  // Actions and Tests.
-  EXPECT_CALL((*tracker),
-              NotifyEvent(feature_engagement::events::kViewedReadingList));
-  [GetCoordinator() start];
-}
diff --git a/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.h b/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.h
deleted file mode 100644
index be47c61b..0000000
--- a/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.h
+++ /dev/null
@@ -1,60 +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 IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_TOOLBAR_H_
-#define IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_TOOLBAR_H_
-
-#import <UIKit/UIKit.h>
-
-@class ActionSheetCoordinator;
-@class LegacyReadingListToolbar;
-
-typedef NS_ENUM(NSInteger, LegacyReadingListToolbarState) {
-  NoneSelected,
-  OnlyReadSelected,
-  OnlyUnreadSelected,
-  MixedItemsSelected
-};
-
-typedef NS_ENUM(NSInteger, LegacyReadingListToolbarHeight) {
-  NormalHeight,
-  ExpandedHeight
-};
-
-@protocol LegacyReadingListToolbarActions<NSObject>
-
-// Callback for the toolbar mark button.
-- (void)markPressed;
-// Callback for the toolbar delete button.
-- (void)deletePressed;
-// Enters editing mode. Updates the toolbar.
-- (void)enterEditingModePressed;
-// Exits editing mode. Updates the toolbar.
-- (void)exitEditingModePressed;
-
-@end
-
-// View at the bottom of the reading list panel that presents options to edit
-// the entries. When editing, the interface changes, allowing the user to delete
-// them and mark them read/unread.
-@interface LegacyReadingListToolbar : UIView
-
-// The toolbar state. The text of the buttons change to reflect the state.
-@property(nonatomic, assign) LegacyReadingListToolbarState state;
-
-// Informs the toolbar whether there are read items. The "Delete All Read"
-// button will be enabled accordingly.
-- (void)setHasReadItem:(BOOL)hasRead;
-// Sets the editing mode for the toolbar, showing/hiding buttons accordingly.
-- (void)setEditing:(BOOL)editing;
-// Returns an empty ActionSheetCoordiantor anchored to the mark button with no
-// message and no title.
-- (ActionSheetCoordinator*)actionSheetForMarkWithBaseViewController:
-    (UIViewController*)viewController;
-// Updates the height of the toolbar.
-- (void)updateHeight;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_TOOLBAR_H_
diff --git a/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.mm b/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.mm
deleted file mode 100644
index 608b147..0000000
--- a/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.mm
+++ /dev/null
@@ -1,293 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.h"
-
-#import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar_button.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_toolbar_button_identifiers.h"
-#import "ios/chrome/common/ui_util/constraints_ui_util.h"
-#include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-const CGFloat kToolbarNormalHeight = 48.0f;
-// Height of the toolbar when button labels has word-wrap up to 2 lines.
-const CGFloat kToolbarTwoLinesHeight = 58.0f;
-// Height of the toolbar when button labels has word-wrap up to 3 lines.
-const CGFloat kToolbarThreeLinesHeight = 68.0f;
-// Shadow opacity.
-const CGFloat kShadowOpacity = 0.12f;
-// Shadow radius.
-const CGFloat kShadowRadius = 12.0f;
-// Horizontal margin for the stack view content.
-const CGFloat kHorizontalMargin = 16.0f;
-// Vertical margin for the stack view content.
-const CGFloat kVerticalMargin = 8.0f;
-// Horizontal spacing between the buttons of the stack view.  This is used for
-// calculating the maximum width of buttons but NOT used directly to set
-// stackView.spacing.
-const CGFloat kHorizontalSpacing = 8.0f;
-
-}  // namespace
-
-@interface LegacyReadingListToolbar ()
-
-// Button that displays "Edit".
-@property(nonatomic, strong) LegacyReadingListToolbarButton* editButton;
-// Button that displays "Delete".
-@property(nonatomic, strong) LegacyReadingListToolbarButton* deleteButton;
-// Button that displays "Delete All Read".
-@property(nonatomic, strong) LegacyReadingListToolbarButton* deleteAllButton;
-// Button that displays "Cancel".
-@property(nonatomic, strong) LegacyReadingListToolbarButton* cancelButton;
-// Button that displays the mark options.
-@property(nonatomic, strong) LegacyReadingListToolbarButton* markButton;
-// Stack view for arranging the buttons.
-@property(nonatomic, strong) UIStackView* stackView;
-// Height constraint for the stack view containing the buttons.
-@property(nonatomic, strong) NSLayoutConstraint* heightConstraint;
-
-// Set the mark button label to |text|.
-- (void)setMarkButtonText:(NSString*)text;
-// Updates the button labels to match an empty selection.
-- (void)updateButtonsForEmptySelection;
-// Updates the button labels to match a selection containing only read items.
-- (void)updateButtonsForOnlyReadSelection;
-// Updates the button labels to match a selection containing only unread items.
-- (void)updateButtonsForOnlyUnreadSelection;
-// Updates the button labels to match a selection containing unread and read
-// items.
-- (void)updateButtonsForOnlyMixedSelection;
-
-@end
-
-@implementation LegacyReadingListToolbar
-
-@synthesize editButton = _editButton;
-@synthesize deleteButton = _deleteButton;
-@synthesize deleteAllButton = _deleteAllButton;
-@synthesize cancelButton = _cancelButton;
-@synthesize markButton = _markButton;
-@synthesize stackView = _stackView;
-@synthesize state = _state;
-@synthesize heightConstraint = _heightConstraint;
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    _deleteButton = [[LegacyReadingListToolbarButton alloc]
-        initWithText:l10n_util::GetNSString(IDS_IOS_READING_LIST_DELETE_BUTTON)
-         destructive:YES
-            position:Leading
-          identifier:kReadingListToolbarDeleteButtonID];
-
-    _deleteAllButton = [[LegacyReadingListToolbarButton alloc]
-        initWithText:l10n_util::GetNSString(
-                         IDS_IOS_READING_LIST_DELETE_ALL_READ_BUTTON)
-         destructive:YES
-            position:Leading
-          identifier:kReadingListToolbarDeleteAllReadButtonID];
-
-    _markButton = [[LegacyReadingListToolbarButton alloc]
-        initWithText:l10n_util::GetNSString(
-                         IDS_IOS_READING_LIST_MARK_ALL_BUTTON)
-         destructive:NO
-            position:Centered
-          identifier:kReadingListToolbarMarkButtonID];
-
-    _cancelButton = [[LegacyReadingListToolbarButton alloc]
-        initWithText:l10n_util::GetNSString(IDS_IOS_READING_LIST_CANCEL_BUTTON)
-         destructive:NO
-            position:Trailing
-          identifier:kReadingListToolbarCancelButtonID];
-
-    _editButton = [[LegacyReadingListToolbarButton alloc]
-        initWithText:l10n_util::GetNSString(IDS_IOS_READING_LIST_EDIT_BUTTON)
-         destructive:NO
-            position:Trailing
-          identifier:kReadingListToolbarEditButtonID];
-
-    [_editButton addTarget:nil
-                    action:@selector(enterEditingModePressed)
-          forControlEvents:UIControlEventTouchUpInside];
-
-    [_deleteButton addTarget:nil
-                      action:@selector(deletePressed)
-            forControlEvents:UIControlEventTouchUpInside];
-
-    [_deleteAllButton addTarget:nil
-                         action:@selector(deletePressed)
-               forControlEvents:UIControlEventTouchUpInside];
-
-    [_markButton addTarget:nil
-                    action:@selector(markPressed)
-          forControlEvents:UIControlEventTouchUpInside];
-
-    [_cancelButton addTarget:nil
-                      action:@selector(exitEditingModePressed)
-            forControlEvents:UIControlEventTouchUpInside];
-
-    _stackView = [[UIStackView alloc] initWithArrangedSubviews:@[
-      _editButton, _deleteButton, _deleteAllButton, _markButton, _cancelButton
-    ]];
-    _stackView.axis = UILayoutConstraintAxisHorizontal;
-    _stackView.alignment = UIStackViewAlignmentFill;
-    _stackView.distribution = UIStackViewDistributionFillEqually;
-
-    [self addSubview:_stackView];
-    _stackView.translatesAutoresizingMaskIntoConstraints = NO;
-
-    PinToSafeArea(_stackView, self);
-    _heightConstraint = [_stackView.heightAnchor
-        constraintEqualToConstant:kToolbarNormalHeight];
-    _heightConstraint.active = YES;
-
-    _stackView.layoutMargins = UIEdgeInsetsMake(
-        kVerticalMargin, kHorizontalMargin, kVerticalMargin, kHorizontalMargin);
-    _stackView.layoutMarginsRelativeArrangement = YES;
-
-    self.backgroundColor = [UIColor whiteColor];
-    [[self layer] setShadowOpacity:kShadowOpacity];
-    [[self layer] setShadowRadius:kShadowRadius];
-    [self setEditing:NO];
-  }
-  return self;
-}
-
-#pragma mark Public Methods
-
-- (void)setEditing:(BOOL)editing {
-  self.editButton.hidden = editing;
-  self.deleteButton.hidden = YES;
-  self.deleteAllButton.hidden = !editing;
-  self.cancelButton.hidden = !editing;
-  self.markButton.hidden = !editing;
-
-  [self updateHeight];
-}
-
-- (void)setState:(LegacyReadingListToolbarState)state {
-  switch (state) {
-    case NoneSelected:
-      [self updateButtonsForEmptySelection];
-      break;
-    case OnlyReadSelected:
-      [self updateButtonsForOnlyReadSelection];
-      break;
-    case OnlyUnreadSelected:
-      [self updateButtonsForOnlyUnreadSelection];
-      break;
-    case MixedItemsSelected:
-      [self updateButtonsForOnlyMixedSelection];
-      break;
-  }
-  _state = state;
-
-  [self updateHeight];
-}
-
-- (void)setHasReadItem:(BOOL)hasRead {
-  [self.deleteAllButton setEnabled:hasRead];
-}
-
-- (ActionSheetCoordinator*)actionSheetForMarkWithBaseViewController:
-    (UIViewController*)viewController {
-  return [[ActionSheetCoordinator alloc]
-      initWithBaseViewController:viewController
-                           title:nil
-                         message:nil
-                            rect:self.markButton.bounds
-                            view:self.markButton];
-}
-
-#pragma mark Private Methods
-
-- (void)updateButtonsForEmptySelection {
-  self.deleteAllButton.hidden = NO;
-  self.deleteButton.hidden = YES;
-  [self setMarkButtonText:l10n_util::GetNSStringWithFixup(
-                              IDS_IOS_READING_LIST_MARK_ALL_BUTTON)];
-}
-
-- (void)updateButtonsForOnlyReadSelection {
-  self.deleteAllButton.hidden = YES;
-  self.deleteButton.hidden = NO;
-  [self setMarkButtonText:l10n_util::GetNSStringWithFixup(
-                              IDS_IOS_READING_LIST_MARK_UNREAD_BUTTON)];
-}
-
-- (void)updateButtonsForOnlyUnreadSelection {
-  self.deleteAllButton.hidden = YES;
-  self.deleteButton.hidden = NO;
-  [self setMarkButtonText:l10n_util::GetNSStringWithFixup(
-                              IDS_IOS_READING_LIST_MARK_READ_BUTTON)];
-}
-
-- (void)updateButtonsForOnlyMixedSelection {
-  self.deleteAllButton.hidden = YES;
-  self.deleteButton.hidden = NO;
-  [self setMarkButtonText:l10n_util::GetNSStringWithFixup(
-                              IDS_IOS_READING_LIST_MARK_BUTTON)];
-}
-
-- (void)setMarkButtonText:(NSString*)text {
-  [self.markButton setTitle:text];
-}
-
-- (void)updateHeight {
-  NSArray* buttons = @[
-    _editButton, _deleteButton, _deleteAllButton, _markButton, _cancelButton
-  ];
-
-  CGFloat availableWidth = self.frame.size.width - kHorizontalMargin * 2;
-  NSUInteger visibleCount = 0;
-
-  // Count the number of visible buttons and deduct the button spacings from
-  // availableWidth.
-  for (LegacyReadingListToolbarButton* button in buttons) {
-    if (!button.hidden) {
-      visibleCount++;
-      if (visibleCount > 1) {
-        availableWidth -= kHorizontalSpacing;
-      }
-    }
-  }
-
-  // Set the button width manually here instead of relying on UIStackView's auto
-  // width distribution which is unpredictable when rounding happens.
-  CGFloat maxButtonWidth = ceil(availableWidth / visibleCount);
-  for (LegacyReadingListToolbarButton* button in buttons) {
-    if (!button.hidden) {
-      [button setMaxWidth:maxButtonWidth];
-    }
-  }
-
-  CGFloat toolbarHeight = kToolbarNormalHeight;
-  CGFloat lineHeight =
-      ceil([LegacyReadingListToolbarButton textFont].lineHeight);
-  CGSize labelBounds = CGSizeMake(maxButtonWidth, CGFLOAT_MAX);
-  // Expand toolbar height in case word wrapping happens.
-  for (LegacyReadingListToolbarButton* button in buttons) {
-    if (!button.hidden) {
-      CGFloat labelHeight =
-          [[button titleLabel] sizeThatFits:labelBounds].height;
-      if (labelHeight > lineHeight * 2) {
-        toolbarHeight = kToolbarThreeLinesHeight;
-        break;
-      }
-      if (labelHeight > lineHeight) {
-        toolbarHeight = kToolbarTwoLinesHeight;
-      }
-    }
-  }
-  self.heightConstraint.constant = toolbarHeight;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar_button.h b/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar_button.h
deleted file mode 100644
index e8e5f62..0000000
--- a/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar_button.h
+++ /dev/null
@@ -1,44 +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 IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_TOOLBAR_BUTTON_H_
-#define IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_TOOLBAR_BUTTON_H_
-
-#import <UIKit/UIKit.h>
-
-typedef NS_ENUM(NSInteger, ButtonPositioning) { Leading, Centered, Trailing };
-
-// A button class for the buttons in LegacyReadingListToolbar's stackview.
-// Handles the layout alignment of the button and its titleLabel.
-@interface LegacyReadingListToolbarButton : UIView
-
-// Initializer.
-- (instancetype)initWithText:(NSString*)labelText
-                 destructive:(BOOL)isDestructive
-                    position:(ButtonPositioning)position
-                  identifier:(NSString*)identifier;
-
-// Associates a target object and action method with the UIButton.
-- (void)addTarget:(id)target
-              action:(SEL)action
-    forControlEvents:(UIControlEvents)controlEvents;
-
-// Sets the title text of the UIButton.
-- (void)setTitle:(NSString*)title;
-
-// Enables or disables the UIButton.
-- (void)setEnabled:(BOOL)enabled;
-
-// Gets the titleLabel of the UIButton.
-- (UILabel*)titleLabel;
-
-// Sets the maximum width contraint of LegacyReadingListToolbarButton.
-- (void)setMaxWidth:(CGFloat)maxWidth;
-
-// The font of the title text.
-+ (UIFont*)textFont;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_TOOLBAR_BUTTON_H_
diff --git a/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar_button.mm b/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar_button.mm
deleted file mode 100644
index c522cd6..0000000
--- a/ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar_button.mm
+++ /dev/null
@@ -1,176 +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.
-
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar_button.h"
-
-#include "base/logging.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#include "ios/chrome/browser/ui/rtl_geometry.h"
-#import "ios/chrome/common/ui_util/constraints_ui_util.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface LegacyReadingListToolbarButton ()
-
-// The actual UIButton object inside LegacyReadingListToolbarButton.
-@property(nonatomic, strong) UIButton* button;
-
-// Width constraint for the LegacyReadingListToolbarButton.
-@property(nonatomic, strong) NSLayoutConstraint* widthConstraint;
-
-@end
-
-@implementation LegacyReadingListToolbarButton
-
-@synthesize button = _button;
-@synthesize widthConstraint = _widthConstraint;
-
-#pragma mark - Public
-
-- (instancetype)initWithText:(NSString*)labelText
-                 destructive:(BOOL)isDestructive
-                    position:(ButtonPositioning)position
-                  identifier:(NSString*)identifier {
-  self = [super init];
-  if (!self) {
-    return self;
-  }
-
-  _button = [self buttonWithText:labelText
-                     destructive:isDestructive
-                        position:position];
-  _button.translatesAutoresizingMaskIntoConstraints = NO;
-  _button.accessibilityIdentifier = identifier;
-  [self addSubview:_button];
-
-  NSDictionary* views = @{@"button" : _button};
-  NSArray* constraints = nil;
-
-  switch (position) {
-    case Leading: {
-      constraints = @[ @"V:|[button]|", @"H:|[button]" ];
-      ApplyVisualConstraints(constraints, views);
-      [_button.trailingAnchor
-          constraintLessThanOrEqualToAnchor:self.trailingAnchor]
-          .active = YES;
-      break;
-    }
-    case Centered: {
-      constraints = @[ @"V:|[button]|" ];
-      ApplyVisualConstraints(constraints, views);
-      [_button.centerXAnchor constraintEqualToAnchor:self.centerXAnchor]
-          .active = YES;
-      [_button.trailingAnchor
-          constraintLessThanOrEqualToAnchor:self.trailingAnchor]
-          .active = YES;
-      [_button.leadingAnchor
-          constraintGreaterThanOrEqualToAnchor:self.leadingAnchor]
-          .active = YES;
-      break;
-    }
-    case Trailing: {
-      constraints = @[ @"V:|[button]|", @"H:[button]|" ];
-      ApplyVisualConstraints(constraints, views);
-      [_button.leadingAnchor
-          constraintGreaterThanOrEqualToAnchor:self.leadingAnchor]
-          .active = YES;
-      break;
-    }
-  }
-  return self;
-}
-
-- (void)addTarget:(id)target
-              action:(SEL)action
-    forControlEvents:(UIControlEvents)controlEvents {
-  [self.button addTarget:target action:action forControlEvents:controlEvents];
-}
-
-- (void)setTitle:(NSString*)title {
-  [self.button setTitle:title forState:UIControlStateNormal];
-}
-
-- (void)setEnabled:(BOOL)enabled {
-  self.button.enabled = enabled;
-}
-
-- (UILabel*)titleLabel {
-  return self.button.titleLabel;
-}
-
-- (void)setMaxWidth:(CGFloat)maxWidth {
-  if (!self.widthConstraint) {
-    self.widthConstraint =
-        [self.button.widthAnchor constraintLessThanOrEqualToConstant:maxWidth];
-    self.widthConstraint.active = YES;
-  }
-  self.widthConstraint.constant = maxWidth;
-}
-
-#pragma mark - Private
-
-- (UIButton*)buttonWithText:(NSString*)title
-                destructive:(BOOL)isDestructive
-                   position:(ButtonPositioning)position {
-  UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
-  [button setTitle:title forState:UIControlStateNormal];
-  button.titleLabel.numberOfLines = 3;
-  button.titleLabel.adjustsFontSizeToFitWidth = YES;
-
-  button.backgroundColor = [UIColor whiteColor];
-  UIColor* textColor = isDestructive ? [[MDCPalette cr_redPalette] tint500]
-                                     : [[MDCPalette cr_bluePalette] tint500];
-  [button setTitleColor:textColor forState:UIControlStateNormal];
-  [button setTitleColor:[UIColor lightGrayColor]
-               forState:UIControlStateDisabled];
-  [button setTitleColor:[textColor colorWithAlphaComponent:0.3]
-               forState:UIControlStateHighlighted];
-  [[button titleLabel] setFont:[[self class] textFont]];
-
-  switch (position) {
-    case Leading: {
-      button.titleLabel.textAlignment = NSTextAlignmentNatural;
-      if (UseRTLLayout()) {
-        button.contentHorizontalAlignment =
-            UIControlContentHorizontalAlignmentRight;
-      } else {
-        button.contentHorizontalAlignment =
-            UIControlContentHorizontalAlignmentLeft;
-      }
-      break;
-    }
-    case Centered: {
-      button.titleLabel.textAlignment = NSTextAlignmentCenter;
-      button.contentHorizontalAlignment =
-          UIControlContentHorizontalAlignmentCenter;
-      break;
-    }
-    case Trailing: {
-      if (UseRTLLayout()) {
-        button.titleLabel.textAlignment = NSTextAlignmentLeft;
-        button.contentHorizontalAlignment =
-            UIControlContentHorizontalAlignmentLeft;
-      } else {
-        button.titleLabel.textAlignment = NSTextAlignmentRight;
-        button.contentHorizontalAlignment =
-            UIControlContentHorizontalAlignmentRight;
-      }
-      break;
-    }
-  }
-
-  return button;
-}
-
-#pragma mark - Static Properties
-
-// The font of the title text.
-+ (UIFont*)textFont {
-  return [MDCTypography subheadFont];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/reading_list/legacy_reading_list_view_controller.h b/ios/chrome/browser/ui/reading_list/legacy_reading_list_view_controller.h
deleted file mode 100644
index 752cf32..0000000
--- a/ios/chrome/browser/ui/reading_list/legacy_reading_list_view_controller.h
+++ /dev/null
@@ -1,32 +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 IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_VIEW_CONTROLLER_H_
-
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.h"
-
-@class ReadingListCollectionViewController;
-@protocol ReadingListListViewControllerDelegate;
-
-// Container for the ReadingList Collection View Controller and the toolbar. It
-// handles the interactions between the two.
-@interface LegacyReadingListViewController : UIViewController
-
-- (instancetype)
-initWithCollectionViewController:
-    (ReadingListCollectionViewController*)collectionViewController
-                         toolbar:(LegacyReadingListToolbar*)toolbar
-    NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)initWithNibName:(NSString*)nibNameOrNil
-                         bundle:(NSBundle*)nibBundleOrNil NS_UNAVAILABLE;
-- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
-- (instancetype)init NS_UNAVAILABLE;
-
-@property(nonatomic, weak) id<ReadingListListViewControllerDelegate> delegate;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_READING_LIST_LEGACY_READING_LIST_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/reading_list/legacy_reading_list_view_controller.mm b/ios/chrome/browser/ui/reading_list/legacy_reading_list_view_controller.mm
deleted file mode 100644
index acccdc0..0000000
--- a/ios/chrome/browser/ui/reading_list/legacy_reading_list_view_controller.mm
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_view_controller.h"
-
-#import <MobileCoreServices/MobileCoreServices.h>
-
-#import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_view_controller_audience.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_view_controller_delegate.h"
-#import "ios/chrome/common/ui_util/constraints_ui_util.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-typedef NS_ENUM(NSInteger, LayoutPriority) {
-  LayoutPriorityLow = 750,
-  LayoutPriorityHigh = 751
-};
-}
-
-@interface LegacyReadingListViewController ()<
-    LegacyReadingListToolbarActions,
-    ReadingListListViewControllerAudience>
-
-@property(nonatomic, strong, readonly)
-    ReadingListCollectionViewController* readingListCollectionViewController;
-@property(nonatomic, strong, readonly) LegacyReadingListToolbar* toolbar;
-
-@end
-
-@implementation LegacyReadingListViewController
-
-@synthesize delegate = _delegate;
-@synthesize readingListCollectionViewController =
-    _readingListCollectionViewController;
-@synthesize toolbar = _toolbar;
-
-- (instancetype)
-initWithCollectionViewController:
-    (ReadingListCollectionViewController*)collectionViewController
-                         toolbar:(LegacyReadingListToolbar*)toolbar {
-  self = [super initWithNibName:nil bundle:nil];
-  if (self) {
-    _toolbar = toolbar;
-    _readingListCollectionViewController = collectionViewController;
-    collectionViewController.audience = self;
-
-    // Configure modal presentation.
-    [self setModalPresentationStyle:UIModalPresentationFormSheet];
-    [self setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
-  }
-  return self;
-}
-
-- (void)viewDidLoad {
-  [self addChildViewController:self.readingListCollectionViewController];
-  [self.view addSubview:self.readingListCollectionViewController.view];
-  [self.readingListCollectionViewController didMoveToParentViewController:self];
-
-  [_toolbar setTranslatesAutoresizingMaskIntoConstraints:NO];
-  [self.readingListCollectionViewController.view
-      setTranslatesAutoresizingMaskIntoConstraints:NO];
-
-  NSDictionary* views =
-      @{@"collection" : self.readingListCollectionViewController.view};
-  NSArray* constraints = @[ @"V:|[collection]", @"H:|[collection]|" ];
-  ApplyVisualConstraints(constraints, views);
-
-  // This constraint has a low priority so it will only take effect when the
-  // toolbar isn't present, allowing the collection to take the whole page.
-  NSLayoutConstraint* constraint =
-      [self.readingListCollectionViewController.view.bottomAnchor
-          constraintEqualToAnchor:self.view.bottomAnchor];
-  constraint.priority = LayoutPriorityLow;
-  constraint.active = YES;
-}
-
-- (BOOL)prefersStatusBarHidden {
-  return NO;
-}
-
-#pragma mark UIAccessibilityAction
-
-- (BOOL)accessibilityPerformEscape {
-  [self.delegate dismissReadingListListViewController:
-                     self.readingListCollectionViewController];
-  return YES;
-}
-
-#pragma mark - LegacyReadingListToolbarActionTarget
-
-- (void)markPressed {
-  [self.readingListCollectionViewController markPressed];
-}
-
-- (void)deletePressed {
-  [self.readingListCollectionViewController deletePressed];
-}
-
-- (void)enterEditingModePressed {
-  // Ignore the button tap if view controller presenting.
-  if ([self presentedViewController]) {
-    return;
-  }
-  [self.readingListCollectionViewController enterEditingModePressed];
-}
-
-- (void)exitEditingModePressed {
-  [self.readingListCollectionViewController exitEditingModePressed];
-}
-
-#pragma mark - ReadingListListViewControllerAudience
-
-- (void)readingListHasItems:(BOOL)hasItems {
-  if (hasItems) {
-    // If there are items, add the toolbar.
-    [self.view addSubview:_toolbar];
-    NSDictionary* views = @{
-      @"toolbar" : _toolbar,
-      @"collection" : self.readingListCollectionViewController.view
-    };
-    NSArray* constraints = @[ @"V:[collection][toolbar]|", @"H:|[toolbar]|" ];
-    ApplyVisualConstraints(constraints, views);
-  } else {
-    // If there is no item, remove the toolbar. The constraints will make sure
-    // the collection takes the whole view.
-    [_toolbar removeFromSuperview];
-  }
-}
-
-#pragma mark - UIResponder
-
-- (BOOL)canBecomeFirstResponder {
-  return YES;
-}
-
-- (NSArray*)keyCommands {
-  __weak LegacyReadingListViewController* weakSelf = self;
-  return
-      @[ [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape
-                                modifierFlags:Cr_UIKeyModifierNone
-                                        title:nil
-                                       action:^{
-                                         [weakSelf accessibilityPerformEscape];
-                                       }] ];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_cell.h b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_cell.h
deleted file mode 100644
index 61526f1..0000000
--- a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_cell.h
+++ /dev/null
@@ -1,33 +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 IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_COLLECTION_VIEW_CELL_H_
-#define IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_COLLECTION_VIEW_CELL_H_
-
-#import "ios/chrome/browser/ui/reading_list/reading_list_ui_distillation_status.h"
-#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
-
-@class FaviconViewNew;
-
-// Cell for ReadingListCollectionViewItem.
-@interface ReadingListCell : MDCCollectionViewCell
-
-// Title label.
-@property(nonatomic, readonly, strong) UILabel* titleLabel;
-// Subtitle label.
-@property(nonatomic, readonly, strong) UILabel* subtitleLabel;
-// Timestamp of the distillation in microseconds since Jan 1st 1970.
-@property(nonatomic, readonly, strong) UILabel* distillationDateLabel;
-// Size of the distilled files.
-@property(nonatomic, readonly, strong) UILabel* distillationSizeLabel;
-// Whether to show |distillationDateLabel| and |distillationSizeLabel|.
-@property(nonatomic, assign) BOOL showDistillationInfo;
-// View for displaying the favicon for the reading list entry.
-@property(nonatomic, readonly, strong) FaviconViewNew* faviconView;
-// Status of the offline version. Updates the visual indicator when updated.
-@property(nonatomic, assign) ReadingListUIDistillationStatus distillationState;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_COLLECTION_VIEW_CELL_H_
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_cell.mm b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_cell.mm
deleted file mode 100644
index 5bb51e8..0000000
--- a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_cell.mm
+++ /dev/null
@@ -1,240 +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.
-
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_cell.h"
-
-#include "base/strings/sys_string_conversions.h"
-#include "base/time/time.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#import "ios/chrome/common/favicon/favicon_view.h"
-#import "ios/chrome/common/ui_util/constraints_ui_util.h"
-#include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/time_format.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-NSString* kSuccessImageString = @"distillation_success";
-NSString* kFailureImageString = @"distillation_fail";
-
-// Height of the cell.
-const CGFloat kCellHeight = 72;
-
-// Distillation indicator constants.
-const CGFloat kDistillationIndicatorSize = 18;
-
-// Margin for the elements displayed in the cell.
-const CGFloat kMargin = 16;
-
-// Transparency of the distillation size and date.
-const CGFloat kInfoTextTransparency = 0.38;
-}  // namespace
-
-@implementation ReadingListCell {
-  UIImageView* _downloadIndicator;
-  UILayoutGuide* _textGuide;
-
-  // View containing |_distillationSizeLabel| and |_distillationDateLabel|.
-  UIView* _infoView;
-}
-@synthesize faviconView = _faviconView;
-@synthesize titleLabel = _titleLabel;
-@synthesize subtitleLabel = _subtitleLabel;
-@synthesize distillationDateLabel = _distillationDateLabel;
-@synthesize distillationSizeLabel = _distillationSizeLabel;
-@synthesize showDistillationInfo = _showDistillationInfo;
-@synthesize distillationState = _distillationState;
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    id<MDCTypographyFontLoading> fontLoader = [MDCTypography fontLoader];
-    CGFloat faviconSize = kFaviconPreferredSize;
-    _titleLabel = [[UILabel alloc] init];
-    _titleLabel.font = [fontLoader mediumFontOfSize:16];
-    _titleLabel.textColor = [[MDCPalette greyPalette] tint900];
-    _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    _titleLabel.accessibilityIdentifier = @"Reading List Item title";
-
-    _subtitleLabel = [[UILabel alloc] init];
-    _subtitleLabel.font = [fontLoader mediumFontOfSize:14];
-    _subtitleLabel.textColor = [[MDCPalette greyPalette] tint500];
-    _subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    _subtitleLabel.accessibilityIdentifier = @"Reading List Item subtitle";
-
-    _distillationDateLabel = [[UILabel alloc] init];
-    _distillationDateLabel.font = [fontLoader mediumFontOfSize:12];
-    [_distillationDateLabel
-        setContentHuggingPriority:UILayoutPriorityDefaultHigh
-                          forAxis:UILayoutConstraintAxisHorizontal];
-    _distillationDateLabel.textColor =
-        [UIColor colorWithWhite:0 alpha:kInfoTextTransparency];
-    _distillationDateLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    _distillationDateLabel.accessibilityIdentifier =
-        @"Reading List Item distillation date";
-
-    _distillationSizeLabel = [[UILabel alloc] init];
-    _distillationSizeLabel.font = [fontLoader mediumFontOfSize:12];
-    [_distillationSizeLabel
-        setContentHuggingPriority:UILayoutPriorityDefaultHigh
-                          forAxis:UILayoutConstraintAxisHorizontal];
-    _distillationSizeLabel.textColor =
-        [UIColor colorWithWhite:0 alpha:kInfoTextTransparency];
-    _distillationSizeLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    _distillationSizeLabel.accessibilityIdentifier =
-        @"Reading List Item distillation size";
-
-    _faviconView = [[FaviconViewNew alloc] init];
-    CGFloat fontSize = floorf(faviconSize / 2);
-    [_faviconView setFont:[fontLoader regularFontOfSize:fontSize]];
-    _faviconView.translatesAutoresizingMaskIntoConstraints = NO;
-
-    _downloadIndicator = [[UIImageView alloc] init];
-    [_downloadIndicator setTranslatesAutoresizingMaskIntoConstraints:NO];
-    _downloadIndicator.accessibilityIdentifier =
-        @"Reading List Item download indicator";
-    [_faviconView addSubview:_downloadIndicator];
-
-    [self.contentView addSubview:_faviconView];
-    [self.contentView addSubview:_titleLabel];
-    [self.contentView addSubview:_subtitleLabel];
-
-    _infoView = [[UIView alloc] initWithFrame:CGRectZero];
-    [_infoView addSubview:_distillationDateLabel];
-    [_infoView addSubview:_distillationSizeLabel];
-    _infoView.translatesAutoresizingMaskIntoConstraints = NO;
-
-    _textGuide = [[UILayoutGuide alloc] init];
-    [self.contentView addLayoutGuide:_textGuide];
-
-    ApplyVisualConstraintsWithMetrics(
-        @[
-          @"H:|[date]-(>=margin)-[size]|",
-          @"V:[title][subtitle]",
-          @"H:|-(margin)-[favicon]-(margin)-[title]-(>=margin)-|",
-          @"H:[favicon]-(margin)-[subtitle]-(>=margin)-|",
-          @"V:|[date]|",
-          @"V:|[size]|",
-        ],
-        @{
-          @"favicon" : _faviconView,
-          @"title" : _titleLabel,
-          @"subtitle" : _subtitleLabel,
-          @"date" : _distillationDateLabel,
-          @"size" : _distillationSizeLabel,
-        },
-        @{
-          @"margin" : @(kMargin),
-        });
-
-    // Sets the bottom of the text. Lower the priority so we can add the details
-    // later.
-    NSLayoutConstraint* bottomTextConstraint = [_textGuide.bottomAnchor
-        constraintEqualToAnchor:_subtitleLabel.bottomAnchor];
-    bottomTextConstraint.priority = UILayoutPriorityDefaultHigh;
-    NSLayoutConstraint* topTextConstraint =
-        [_textGuide.topAnchor constraintEqualToAnchor:_titleLabel.topAnchor];
-
-    [NSLayoutConstraint activateConstraints:@[
-      // Height for the cell.
-      [self.contentView.heightAnchor constraintEqualToConstant:kCellHeight],
-
-      // Text constraints.
-      topTextConstraint,
-      bottomTextConstraint,
-
-      // Favicons are always the same size.
-      [_faviconView.widthAnchor constraintEqualToConstant:faviconSize],
-      [_faviconView.heightAnchor constraintEqualToConstant:faviconSize],
-
-      // Center the content (favicon and text) vertically.
-      [_faviconView.centerYAnchor
-          constraintEqualToAnchor:self.contentView.centerYAnchor],
-      [_textGuide.centerYAnchor
-          constraintEqualToAnchor:self.contentView.centerYAnchor],
-
-      // Place the download indicator in the bottom right corner of the favicon.
-      [[_downloadIndicator centerXAnchor]
-          constraintEqualToAnchor:_faviconView.trailingAnchor],
-      [[_downloadIndicator centerYAnchor]
-          constraintEqualToAnchor:_faviconView.bottomAnchor],
-      [[_downloadIndicator widthAnchor]
-          constraintEqualToConstant:kDistillationIndicatorSize],
-      [[_downloadIndicator heightAnchor]
-          constraintEqualToConstant:kDistillationIndicatorSize],
-    ]];
-
-    self.editingSelectorColor = [[MDCPalette cr_bluePalette] tint500];
-  }
-  return self;
-}
-
-- (void)setDistillationState:
-    (ReadingListUIDistillationStatus)distillationState {
-  if (_distillationState == distillationState)
-    return;
-
-  _distillationState = distillationState;
-  switch (distillationState) {
-    case ReadingListUIDistillationStatusFailure:
-      [_downloadIndicator setImage:[UIImage imageNamed:kFailureImageString]];
-      break;
-
-    case ReadingListUIDistillationStatusSuccess:
-      [_downloadIndicator setImage:[UIImage imageNamed:kSuccessImageString]];
-      break;
-
-    case ReadingListUIDistillationStatusPending:
-      [_downloadIndicator setImage:nil];
-      break;
-  }
-}
-
-- (void)setShowDistillationInfo:(BOOL)showDistillationInfo {
-  if (_showDistillationInfo == showDistillationInfo)
-    return;
-
-  _showDistillationInfo = showDistillationInfo;
-  if (!_showDistillationInfo) {
-    [_infoView removeFromSuperview];
-    return;
-  }
-  [self.contentView addSubview:_infoView];
-  ApplyVisualConstraintsWithMetrics(
-      @[
-        @"H:|-(margin)-[favicon]-(margin)-[detail]-(margin)-|",
-      ],
-      @{
-        @"favicon" : _faviconView,
-        @"detail" : _infoView,
-      },
-      @{
-        @"margin" : @(kMargin),
-      });
-  [NSLayoutConstraint activateConstraints:@[
-    [_infoView.topAnchor constraintEqualToAnchor:_subtitleLabel.bottomAnchor],
-    [_infoView.bottomAnchor constraintEqualToAnchor:_textGuide.bottomAnchor],
-  ]];
-}
-
-#pragma mark - UICollectionViewCell
-
-- (void)prepareForReuse {
-  self.titleLabel.text = nil;
-  self.subtitleLabel.text = nil;
-  self.distillationDateLabel.text = nil;
-  self.distillationSizeLabel.text = nil;
-  self.showDistillationInfo = NO;
-  self.distillationState = ReadingListUIDistillationStatusPending;
-  [self.faviconView configureWithAttributes:nil];
-  self.accessibilityCustomActions = nil;
-  [super prepareForReuse];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.h b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.h
deleted file mode 100644
index 22c6bedd..0000000
--- a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.h
+++ /dev/null
@@ -1,42 +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 IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_COLLECTION_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_COLLECTION_VIEW_CONTROLLER_H_
-
-#import "ios/chrome/browser/ui/collection_view/collection_view_controller.h"
-
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_item_accessibility_delegate.h"
-
-@protocol ReadingListDataSource;
-@protocol ReadingListListViewControllerAudience;
-@protocol ReadingListListViewControllerDelegate;
-
-@interface ReadingListCollectionViewController
-    : CollectionViewController<ReadingListListItemAccessibilityDelegate,
-                               LegacyReadingListToolbarActions>
-
-- (instancetype)initWithDataSource:(id<ReadingListDataSource>)dataSource
-                           toolbar:(LegacyReadingListToolbar*)toolbar
-    NS_DESIGNATED_INITIALIZER;
-- (instancetype)initWithLayout:(UICollectionViewLayout*)layout
-                         style:(CollectionViewControllerStyle)style
-    NS_UNAVAILABLE;
-
-@property(nonatomic, weak) id<ReadingListListViewControllerDelegate> delegate;
-@property(nonatomic, weak) id<ReadingListListViewControllerAudience> audience;
-@property(nonatomic, weak) id<ReadingListDataSource> dataSource;
-
-// Prepares this view controller to be dismissed.
-- (void)willBeDismissed;
-
-// Reloads all the data.
-- (void)reloadData;
-
-+ (NSString*)accessibilityIdentifier;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_COLLECTION_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.mm
deleted file mode 100644
index ff29e33..0000000
--- a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.mm
+++ /dev/null
@@ -1,967 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.h"
-
-#include "base/logging.h"
-#import "base/mac/foundation_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "base/metrics/user_metrics_action.h"
-#include "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
-#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
-#import "ios/chrome/browser/ui/list_model/list_item+Controller.h"
-#import "ios/chrome/browser/ui/material_components/chrome_app_bar_view_controller.h"
-#import "ios/chrome/browser/ui/reading_list/empty_reading_list_background_view.h"
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_data_sink.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_data_source.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_item_updater.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_view_controller_audience.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_view_controller_delegate.h"
-#include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// Types of ListItems used by the reading list UI.
-typedef NS_ENUM(NSInteger, ItemType) {
-  ItemTypeHeader = kItemTypeEnumZero,
-  ItemTypeItem,
-};
-// Identifiers for sections in the reading list.
-typedef NS_ENUM(NSInteger, SectionIdentifier) {
-  SectionIdentifierUnread = kSectionIdentifierEnumZero,
-  SectionIdentifierRead,
-};
-}  // namespace
-
-@interface ReadingListCollectionViewController ()<
-    ReadingListDataSink,
-    UIGestureRecognizerDelegate> {
-  // Toolbar with the actions.
-  LegacyReadingListToolbar* _toolbar;
-  // Action sheet presenting the subactions of the toolbar.
-  AlertCoordinator* _actionSheet;
-  UIView* _emptyCollectionBackground;
-
-  // Whether the data source has pending modifications.
-  BOOL _dataSourceHasBeenModified;
-}
-
-// Redefine the model to return ReadingListListItems
-@property(nonatomic, readonly)
-    CollectionViewModel<CollectionViewItem<ReadingListListItem>*>*
-        collectionViewModel;
-
-// Whether the data source modifications should be taken into account.
-@property(nonatomic, assign) BOOL shouldMonitorDataSource;
-
-// Casts |item| to a CollectionViewItem.
-- (CollectionViewItem<ReadingListListItem>*)collectionItemForReadingListItem:
-    (id<ReadingListListItem>)item;
-// Handles "Done" button touches.
-- (void)donePressed;
-// Loads all the items in all sections.
-- (void)loadItems;
-// Fills section |sectionIdentifier| with the items from |array|.
-- (void)loadItemsFromArray:(NSArray<id<ReadingListListItem>>*)array
-                 toSection:(SectionIdentifier)sectionIdentifier;
-// Reloads the data if a change occurred during editing
-- (void)applyPendingUpdates;
-// Returns whether there are elements in the section identified by
-// |sectionIdentifier|.
-- (BOOL)hasItemInSection:(SectionIdentifier)sectionIdentifier;
-// Adds an empty background if needed.
-- (void)collectionIsEmpty;
-// Handles a long press.
-- (void)handleLongPress:(UILongPressGestureRecognizer*)gestureRecognizer;
-// Updates the toolbar state according to the selected items.
-- (void)updateToolbarState;
-// Displays an action sheet to let the user choose to mark all the elements as
-// read or as unread. Used when nothing is selected.
-- (void)markAllItemsAs;
-// Displays an action sheet to let the user choose to mark all the selected
-// elements as read or as unread. Used if read and unread elements are selected.
-- (void)markMixedItemsAs;
-// Marks all items as read.
-- (void)markAllRead;
-// Marks all items as unread.
-- (void)markAllUnread;
-// Marks the items at |indexPaths| as read.
-- (void)markItemsReadAtIndexPath:(NSArray*)indexPaths;
-// Marks the items at |indexPaths| as unread.
-- (void)markItemsUnreadAtIndexPath:(NSArray*)indexPaths;
-// Deletes all the read items.
-- (void)deleteAllReadItems;
-// Deletes all the items at |indexPath|.
-- (void)deleteItemsAtIndexPaths:(NSArray*)indexPaths;
-// Initializes |_actionSheet| with |self| as base view controller, and the
-// toolbar's mark button as anchor point.
-- (void)initializeActionSheet;
-// Exits the editing mode and update the toolbar state with animation.
-- (void)exitEditingModeAnimated:(BOOL)animated;
-// Applies |updater| to the URL of every cell in the section |identifier|. The
-// updates are done in reverse order of the cells in the section to keep the
-// order. The monitoring of the data source updates are suspended during this
-// time.
-- (void)updateItemsInSectionIdentifier:(SectionIdentifier)identifier
-                      usingItemUpdater:(ReadingListListItemUpdater)updater;
-// Applies |updater| to the URL of every element in |indexPaths|. The updates
-// are done in reverse order |indexPaths| to keep the order. The monitoring of
-// the data source updates are suspended during this time.
-- (void)updateIndexPaths:(NSArray<NSIndexPath*>*)indexPaths
-        usingItemUpdater:(ReadingListListItemUpdater)updater;
-// Move all the items from |sourceSectionIdentifier| to
-// |destinationSectionIdentifier| and removes the empty section from the
-// collection.
-- (void)moveItemsFromSection:(SectionIdentifier)sourceSectionIdentifier
-                   toSection:(SectionIdentifier)destinationSectionIdentifier;
-// Move the currently selected elements to |sectionIdentifier| and removes the
-// empty sections.
-- (void)moveSelectedItems:(NSArray*)sortedIndexPaths
-                toSection:(SectionIdentifier)sectionIdentifier;
-// Makes sure |sectionIdentifier| exists with the correct header.
-// Returns the index of the new section in the collection view; NSIntegerMax if
-// no section has been created.
-- (NSInteger)initializeSection:(SectionIdentifier)sectionIdentifier;
-// Returns the header for the |sectionIdentifier|.
-- (CollectionViewTextItem*)headerForSection:
-    (SectionIdentifier)sectionIdentifier;
-// Removes the empty sections from the collection and the model.
-- (void)removeEmptySections;
-
-@end
-
-@implementation ReadingListCollectionViewController
-
-@synthesize audience = _audience;
-@synthesize delegate = _delegate;
-@synthesize dataSource = _dataSource;
-
-@dynamic collectionViewModel;
-@synthesize shouldMonitorDataSource = _shouldMonitorDataSource;
-
-+ (NSString*)accessibilityIdentifier {
-  return @"ReadingListCollectionView";
-}
-
-#pragma mark lifecycle
-
-- (instancetype)initWithDataSource:(id<ReadingListDataSource>)dataSource
-                           toolbar:(LegacyReadingListToolbar*)toolbar {
-  UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init];
-  self =
-      [super initWithLayout:layout style:CollectionViewControllerStyleAppBar];
-  if (self) {
-    _toolbar = toolbar;
-
-    _dataSource = dataSource;
-    _emptyCollectionBackground = [[EmptyReadingListBackgroundView alloc] init];
-
-    _shouldMonitorDataSource = YES;
-    _dataSourceHasBeenModified = NO;
-
-    _dataSource.dataSink = self;
-  }
-  return self;
-}
-
-#pragma mark - properties
-
-- (void)setToolbarState:(LegacyReadingListToolbarState)toolbarState {
-  [_toolbar setState:toolbarState];
-}
-
-- (void)setAudience:(id<ReadingListListViewControllerAudience>)audience {
-  _audience = audience;
-  if (self.dataSource.ready) {
-    [audience readingListHasItems:self.dataSource.hasElements];
-  }
-}
-
-#pragma mark - UIViewController
-
-- (void)viewDidLoad {
-  [super viewDidLoad];
-
-  self.title = l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_READING_LIST);
-  self.collectionView.accessibilityIdentifier =
-      [ReadingListCollectionViewController accessibilityIdentifier];
-  // Add "Done" button.
-  UIBarButtonItem* doneItem = [[UIBarButtonItem alloc]
-      initWithTitle:l10n_util::GetNSString(IDS_IOS_READING_LIST_DONE_BUTTON)
-              style:UIBarButtonItemStylePlain
-             target:self
-             action:@selector(donePressed)];
-  doneItem.accessibilityIdentifier = @"Done";
-  self.navigationItem.rightBarButtonItem = doneItem;
-
-  // Customize collection view settings.
-  self.styler.cellStyle = MDCCollectionViewCellStyleCard;
-  self.styler.separatorInset = UIEdgeInsetsMake(0, 16, 0, 16);
-
-  UILongPressGestureRecognizer* longPressRecognizer =
-      [[UILongPressGestureRecognizer alloc]
-          initWithTarget:self
-                  action:@selector(handleLongPress:)];
-  longPressRecognizer.delegate = self;
-  [self.collectionView addGestureRecognizer:longPressRecognizer];
-}
-
-- (void)viewDidLayoutSubviews {
-  [super viewDidLayoutSubviews];
-  [_toolbar updateHeight];
-}
-
-#pragma mark - UICollectionViewDelegate
-
-- (void)collectionView:(UICollectionView*)collectionView
-    didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
-  [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
-
-  if (self.editor.editing) {
-    [self updateToolbarState];
-  } else {
-    id<ReadingListListItem> item =
-        [self.collectionViewModel itemAtIndexPath:indexPath];
-    [self.delegate readingListListViewController:self openItem:item];
-  }
-}
-
-- (void)collectionView:(UICollectionView*)collectionView
-    didDeselectItemAtIndexPath:(NSIndexPath*)indexPath {
-  [super collectionView:collectionView didDeselectItemAtIndexPath:indexPath];
-  if (self.editor.editing) {
-    // When deselecting an item, if we are editing, we want to update the
-    // toolbar based on the selected items.
-    [self updateToolbarState];
-  }
-}
-
-#pragma mark - MDCCollectionViewController
-
-- (void)updateFooterInfoBarIfNecessary {
-  // No-op. This prevents the default infobar from showing.
-  // TODO(crbug.com/653547): Remove this once the MDC adds an option for
-  // preventing the infobar from showing.
-}
-
-#pragma mark - MDCCollectionViewStylingDelegate
-
-- (CGFloat)collectionView:(UICollectionView*)collectionView
-    cellHeightAtIndexPath:(NSIndexPath*)indexPath {
-  NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath];
-  if (type == ItemTypeItem)
-    return MDCCellDefaultTwoLineHeight;
-  else
-    return MDCCellDefaultOneLineHeight;
-}
-
-#pragma mark - MDCCollectionViewEditingDelegate
-
-- (BOOL)collectionViewAllowsEditing:(nonnull UICollectionView*)collectionView {
-  return YES;
-}
-
-#pragma mark - ReadingListDataSink
-
-- (void)dataSourceReady:(id<ReadingListDataSource>)dataSource {
-  [self loadModel];
-  if ([self isViewLoaded]) {
-    [self.collectionView reloadData];
-  }
-}
-
-- (void)dataSourceChanged {
-  // If we are editing and monitoring the model updates, set a flag to reload
-  // the data at the end of the editing.
-  if (self.editor.editing) {
-    _dataSourceHasBeenModified = YES;
-  } else {
-    [self reloadData];
-  }
-}
-
-- (NSArray<id<ReadingListListItem>>*)readItems {
-  return [self readingListItemsForSection:SectionIdentifierRead];
-}
-
-- (NSArray<id<ReadingListListItem>>*)unreadItems {
-  return [self readingListItemsForSection:SectionIdentifierUnread];
-}
-
-- (void)itemHasChangedAfterDelay:(id<ReadingListListItem>)item {
-  CollectionViewItem<ReadingListListItem>* collectionItem =
-      [self collectionItemForReadingListItem:item];
-  if ([self.collectionViewModel hasItem:collectionItem]) {
-    [self reconfigureCellsForItems:@[ collectionItem ]];
-  }
-}
-
-- (void)itemsHaveChanged:(NSArray<id<ReadingListListItem>>*)items {
-  [self reconfigureCellsForItems:items];
-}
-
-#pragma mark - ReadingListDataSink Helpers
-
-- (NSArray<id<ReadingListListItem>>*)readingListItemsForSection:
-    (SectionIdentifier)sectionID {
-  if (![self.collectionViewModel hasSectionForSectionIdentifier:sectionID]) {
-    return nil;
-  }
-  NSMutableArray<id<ReadingListListItem>>* items = [NSMutableArray array];
-  NSArray<CollectionViewItem*>* sectionItems =
-      [self.collectionViewModel itemsInSectionWithIdentifier:sectionID];
-  for (id<ReadingListListItem> item in sectionItems) {
-    [items addObject:item];
-  }
-  return items;
-}
-
-#pragma mark - Public methods
-
-- (void)reloadData {
-  [self loadModel];
-  if ([self isViewLoaded]) {
-    [self.collectionView reloadData];
-  }
-}
-
-- (void)willBeDismissed {
-  [self.dataSource dataSinkWillBeDismissed];
-  [_actionSheet stop];
-}
-
-#pragma mark - ReadingListListItemAccessibilityDelegate
-
-- (BOOL)isItemRead:(id<ReadingListListItem>)item {
-  return [self.dataSource isItemRead:item];
-}
-
-- (void)deleteItem:(id<ReadingListListItem>)item {
-  CollectionViewItem<ReadingListListItem>* collectionItem =
-      [self collectionItemForReadingListItem:item];
-  if ([self.collectionViewModel hasItem:collectionItem]) {
-    [self deleteItemsAtIndexPaths:@[ [self.collectionViewModel
-                                      indexPathForItem:collectionItem] ]];
-  }
-}
-
-- (void)openItemInNewTab:(id<ReadingListListItem>)item {
-  [self.delegate readingListListViewController:self
-                              openItemInNewTab:item
-                                     incognito:NO];
-}
-
-- (void)openItemInNewIncognitoTab:(id<ReadingListListItem>)item {
-  [self.delegate readingListListViewController:self
-                              openItemInNewTab:item
-                                     incognito:YES];
-}
-
-- (void)openItemOffline:(id<ReadingListListItem>)item {
-  [self.delegate readingListListViewController:self
-                       openItemOfflineInNewTab:item];
-}
-
-- (void)markItemRead:(id<ReadingListListItem>)item {
-  CollectionViewItem<ReadingListListItem>* collectionItem =
-      [self collectionItemForReadingListItem:item];
-  if ([self.collectionViewModel hasItem:collectionItem
-                inSectionWithIdentifier:SectionIdentifierUnread]) {
-    [self markItemsReadAtIndexPath:@[ [self.collectionViewModel
-                                       indexPathForItem:collectionItem] ]];
-  }
-}
-
-- (void)markItemUnread:(id<ReadingListListItem>)item {
-  CollectionViewItem<ReadingListListItem>* collectionItem =
-      [self collectionItemForReadingListItem:item];
-  if ([self.collectionViewModel hasItem:collectionItem
-                inSectionWithIdentifier:SectionIdentifierRead]) {
-    [self markItemsUnreadAtIndexPath:@[ [self.collectionViewModel
-                                         indexPathForItem:collectionItem] ]];
-  }
-}
-
-#pragma mark - UIGestureRecognizerDelegate
-
-- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
-       shouldReceiveTouch:(UITouch*)touch {
-  // Prevent the context menu to be displayed if the long press is done on the
-  // App Bar.
-  CGPoint location =
-      [touch locationInView:self.appBarViewController.navigationBar];
-  return !CGRectContainsPoint(self.appBarViewController.navigationBar.frame,
-                              location);
-}
-
-#pragma mark - Private methods
-
-- (void)donePressed {
-  if ([self.editor isEditing]) {
-    [self exitEditingModeAnimated:NO];
-  }
-  [self dismiss];
-}
-
-- (void)dismiss {
-  [self.delegate dismissReadingListListViewController:self];
-}
-
-- (void)loadModel {
-  [super loadModel];
-  _dataSourceHasBeenModified = NO;
-
-  if (!self.dataSource.hasElements) {
-    [self collectionIsEmpty];
-  } else {
-    self.collectionView.alwaysBounceVertical = YES;
-    [self loadItems];
-    self.collectionView.backgroundView = nil;
-    [self.audience readingListHasItems:YES];
-  }
-}
-
-- (void)loadItemsFromArray:(NSArray<id<ReadingListListItem>>*)items
-                 toSection:(SectionIdentifier)sectionIdentifier {
-  if (items.count == 0) {
-    return;
-  }
-  CollectionViewModel* model = self.collectionViewModel;
-  [model addSectionWithIdentifier:sectionIdentifier];
-  [model setHeader:[self headerForSection:sectionIdentifier]
-      forSectionWithIdentifier:sectionIdentifier];
-  for (CollectionViewItem<ReadingListListItem>* item in items) {
-    item.type = ItemTypeItem;
-    [self.dataSource fetchFaviconForItem:item];
-    [model addItem:item toSectionWithIdentifier:sectionIdentifier];
-  }
-}
-
-- (void)loadItems {
-  NSMutableArray<id<ReadingListListItem>>* readArray = [NSMutableArray array];
-  NSMutableArray<id<ReadingListListItem>>* unreadArray = [NSMutableArray array];
-  [self.dataSource fillReadItems:readArray unreadItems:unreadArray];
-  [self loadItemsFromArray:unreadArray toSection:SectionIdentifierUnread];
-  [self loadItemsFromArray:readArray toSection:SectionIdentifierRead];
-
-  BOOL hasRead = readArray.count > 0;
-  [_toolbar setHasReadItem:hasRead];
-}
-
-- (void)applyPendingUpdates {
-  if (_dataSourceHasBeenModified) {
-    [self reloadData];
-  }
-}
-
-- (BOOL)hasItemInSection:(SectionIdentifier)sectionIdentifier {
-  if (![self.collectionViewModel
-          hasSectionForSectionIdentifier:sectionIdentifier]) {
-    // No section.
-    return NO;
-  }
-
-  NSInteger section =
-      [self.collectionViewModel sectionForSectionIdentifier:sectionIdentifier];
-  NSInteger numberOfItems =
-      [self.collectionViewModel numberOfItemsInSection:section];
-
-  return numberOfItems > 0;
-}
-
-- (void)collectionIsEmpty {
-  if (self.collectionView.backgroundView) {
-    return;
-  }
-  // The collection is empty, add background.
-  self.collectionView.alwaysBounceVertical = NO;
-  self.collectionView.backgroundView = _emptyCollectionBackground;
-  [self.audience readingListHasItems:NO];
-}
-
-- (void)handleLongPress:(UILongPressGestureRecognizer*)gestureRecognizer {
-  if (self.editor.editing ||
-      gestureRecognizer.state != UIGestureRecognizerStateBegan) {
-    return;
-  }
-
-  CGPoint touchLocation =
-      [gestureRecognizer locationOfTouch:0 inView:self.collectionView];
-  NSIndexPath* touchedItemIndexPath =
-      [self.collectionView indexPathForItemAtPoint:touchLocation];
-  if (!touchedItemIndexPath ||
-      ![self.collectionViewModel hasItemAtIndexPath:touchedItemIndexPath]) {
-    // Make sure there is an item at this position.
-    return;
-  }
-
-  CollectionViewItem<ReadingListListItem>* item =
-      [self.collectionViewModel itemAtIndexPath:touchedItemIndexPath];
-  if (item.type != ItemTypeItem) {
-    // Do not trigger context menu on headers.
-    return;
-  }
-
-  [self.delegate readingListListViewController:self
-                     displayContextMenuForItem:item
-                                       atPoint:touchLocation];
-}
-
-#pragma mark - LegacyReadingListToolbarDelegate
-
-- (void)markPressed {
-  if (![self.editor isEditing]) {
-    return;
-  }
-  switch ([_toolbar state]) {
-    case NoneSelected:
-      [self markAllItemsAs];
-      break;
-    case OnlyUnreadSelected:
-      [self markItemsReadAtIndexPath:self.collectionView
-                                         .indexPathsForSelectedItems];
-      break;
-    case OnlyReadSelected:
-      [self markItemsUnreadAtIndexPath:self.collectionView
-                                           .indexPathsForSelectedItems];
-      break;
-    case MixedItemsSelected:
-      [self markMixedItemsAs];
-      break;
-  }
-}
-
-- (void)deletePressed {
-  if (![self.editor isEditing]) {
-    return;
-  }
-  if ([_toolbar state] == NoneSelected) {
-    [self deleteAllReadItems];
-  } else {
-    [self
-        deleteItemsAtIndexPaths:self.collectionView.indexPathsForSelectedItems];
-  }
-}
-- (void)enterEditingModePressed {
-  if ([self.editor isEditing]) {
-    return;
-  }
-  self.toolbarState = NoneSelected;
-  [self.editor setEditing:YES animated:YES];
-  [_toolbar setEditing:YES];
-}
-
-- (void)exitEditingModePressed {
-  if (![self.editor isEditing]) {
-    return;
-  }
-  [self exitEditingModeAnimated:YES];
-}
-
-#pragma mark - Private methods - Toolbar
-
-- (CollectionViewItem<ReadingListListItem>*)collectionItemForReadingListItem:
-    (id<ReadingListListItem>)item {
-  return base::mac::ObjCCastStrict<CollectionViewItem<ReadingListListItem>>(
-      item);
-}
-
-- (void)updateToolbarState {
-  BOOL readSelected = NO;
-  BOOL unreadSelected = NO;
-
-  if ([self.collectionView.indexPathsForSelectedItems count] == 0) {
-    // No entry selected.
-    self.toolbarState = NoneSelected;
-    return;
-  }
-
-  // Sections for section identifiers.
-  NSInteger sectionRead = NSNotFound;
-  NSInteger sectionUnread = NSNotFound;
-
-  if ([self hasItemInSection:SectionIdentifierRead]) {
-    sectionRead = [self.collectionViewModel
-        sectionForSectionIdentifier:SectionIdentifierRead];
-  }
-  if ([self hasItemInSection:SectionIdentifierUnread]) {
-    sectionUnread = [self.collectionViewModel
-        sectionForSectionIdentifier:SectionIdentifierUnread];
-  }
-
-  // Check selected sections.
-  for (NSIndexPath* index in self.collectionView.indexPathsForSelectedItems) {
-    if (index.section == sectionRead) {
-      readSelected = YES;
-    } else if (index.section == sectionUnread) {
-      unreadSelected = YES;
-    }
-  }
-
-  // Update toolbar state.
-  if (readSelected) {
-    if (unreadSelected) {
-      // Read and Unread selected.
-      self.toolbarState = MixedItemsSelected;
-    } else {
-      // Read selected.
-      self.toolbarState = OnlyReadSelected;
-    }
-  } else if (unreadSelected) {
-    // Unread selected.
-    self.toolbarState = OnlyUnreadSelected;
-  }
-}
-
-- (void)markAllItemsAs {
-  [self initializeActionSheet];
-  __weak ReadingListCollectionViewController* weakSelf = self;
-  [_actionSheet addItemWithTitle:l10n_util::GetNSStringWithFixup(
-                                     IDS_IOS_READING_LIST_MARK_ALL_READ_ACTION)
-                          action:^{
-                            [weakSelf markAllRead];
-                          }
-                           style:UIAlertActionStyleDefault];
-  [_actionSheet
-      addItemWithTitle:l10n_util::GetNSStringWithFixup(
-                           IDS_IOS_READING_LIST_MARK_ALL_UNREAD_ACTION)
-                action:^{
-                  [weakSelf markAllUnread];
-                }
-                 style:UIAlertActionStyleDefault];
-  [_actionSheet start];
-}
-
-- (void)markMixedItemsAs {
-  [self initializeActionSheet];
-  __weak ReadingListCollectionViewController* weakSelf = self;
-  [_actionSheet
-      addItemWithTitle:l10n_util::GetNSStringWithFixup(
-                           IDS_IOS_READING_LIST_MARK_READ_BUTTON)
-                action:^{
-                  [weakSelf
-                      markItemsReadAtIndexPath:weakSelf.collectionView
-                                                   .indexPathsForSelectedItems];
-                }
-                 style:UIAlertActionStyleDefault];
-  [_actionSheet
-      addItemWithTitle:l10n_util::GetNSStringWithFixup(
-                           IDS_IOS_READING_LIST_MARK_UNREAD_BUTTON)
-                action:^{
-                  [weakSelf
-                      markItemsUnreadAtIndexPath:
-                          weakSelf.collectionView.indexPathsForSelectedItems];
-                }
-                 style:UIAlertActionStyleDefault];
-  [_actionSheet start];
-}
-
-- (void)initializeActionSheet {
-  _actionSheet = [_toolbar actionSheetForMarkWithBaseViewController:self];
-
-  [_actionSheet addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)
-                          action:nil
-                           style:UIAlertActionStyleCancel];
-}
-
-- (void)markAllRead {
-  if (![self.editor isEditing]) {
-    return;
-  }
-  if (![self hasItemInSection:SectionIdentifierUnread]) {
-    [self exitEditingModeAnimated:YES];
-    return;
-  }
-
-  [self updateItemsInSectionIdentifier:SectionIdentifierUnread
-                      usingItemUpdater:^(id<ReadingListListItem> item) {
-                        [self.dataSource setReadStatus:YES forItem:item];
-                      }];
-
-  [self exitEditingModeAnimated:YES];
-  [self moveItemsFromSection:SectionIdentifierUnread
-                   toSection:SectionIdentifierRead];
-}
-
-- (void)markAllUnread {
-  if (![self hasItemInSection:SectionIdentifierRead]) {
-    [self exitEditingModeAnimated:YES];
-    return;
-  }
-
-  [self updateItemsInSectionIdentifier:SectionIdentifierRead
-                      usingItemUpdater:^(id<ReadingListListItem> item) {
-                        [self.dataSource setReadStatus:NO forItem:item];
-                      }];
-
-  [self exitEditingModeAnimated:YES];
-  [self moveItemsFromSection:SectionIdentifierRead
-                   toSection:SectionIdentifierUnread];
-}
-
-- (void)markItemsReadAtIndexPath:(NSArray*)indexPaths {
-  base::RecordAction(base::UserMetricsAction("MobileReadingListMarkRead"));
-  NSArray* sortedIndexPaths =
-      [indexPaths sortedArrayUsingSelector:@selector(compare:)];
-  [self updateIndexPaths:sortedIndexPaths
-        usingItemUpdater:^(id<ReadingListListItem> item) {
-          [self.dataSource setReadStatus:YES forItem:item];
-        }];
-
-  [self exitEditingModeAnimated:YES];
-  [self moveSelectedItems:sortedIndexPaths toSection:SectionIdentifierRead];
-}
-
-- (void)markItemsUnreadAtIndexPath:(NSArray*)indexPaths {
-  base::RecordAction(base::UserMetricsAction("MobileReadingListMarkUnread"));
-  NSArray* sortedIndexPaths =
-      [indexPaths sortedArrayUsingSelector:@selector(compare:)];
-  [self updateIndexPaths:sortedIndexPaths
-        usingItemUpdater:^(id<ReadingListListItem> item) {
-          [self.dataSource setReadStatus:NO forItem:item];
-        }];
-
-  [self exitEditingModeAnimated:YES];
-  [self moveSelectedItems:sortedIndexPaths toSection:SectionIdentifierUnread];
-}
-
-- (void)deleteAllReadItems {
-  base::RecordAction(base::UserMetricsAction("MobileReadingListDeleteRead"));
-  if (![self hasItemInSection:SectionIdentifierRead]) {
-    [self exitEditingModeAnimated:YES];
-    return;
-  }
-
-  [self updateItemsInSectionIdentifier:SectionIdentifierRead
-                      usingItemUpdater:^(id<ReadingListListItem> item) {
-                        [self.dataSource removeEntryFromItem:item];
-                      }];
-
-  [self exitEditingModeAnimated:YES];
-  [self.collectionView performBatchUpdates:^{
-    NSInteger readSection = [self.collectionViewModel
-        sectionForSectionIdentifier:SectionIdentifierRead];
-    [self.collectionView
-        deleteSections:[NSIndexSet indexSetWithIndex:readSection]];
-    [self.collectionViewModel
-        removeSectionWithIdentifier:SectionIdentifierRead];
-  }
-      completion:^(BOOL) {
-        // Reload data to take into account possible sync events.
-        [self applyPendingUpdates];
-      }];
-  // As we modified the section in the batch update block, remove the section in
-  // another block.
-  [self removeEmptySections];
-}
-
-- (void)deleteItemsAtIndexPaths:(NSArray*)indexPaths {
-  [self updateIndexPaths:indexPaths
-        usingItemUpdater:^(id<ReadingListListItem> item) {
-          [self.dataSource removeEntryFromItem:item];
-        }];
-
-  [self exitEditingModeAnimated:YES];
-
-  [self.collectionView performBatchUpdates:^{
-    [self collectionView:self.collectionView
-        willDeleteItemsAtIndexPaths:indexPaths];
-
-    [self.collectionView deleteItemsAtIndexPaths:indexPaths];
-  }
-      completion:^(BOOL) {
-        // Reload data to take into account possible sync events.
-        [self applyPendingUpdates];
-      }];
-  // As we modified the section in the batch update block, remove the section in
-  // another block.
-  [self removeEmptySections];
-}
-
-- (void)updateItemsInSectionIdentifier:(SectionIdentifier)identifier
-                      usingItemUpdater:(ReadingListListItemUpdater)updater {
-  [self.dataSource beginBatchUpdates];
-  NSArray* readItems =
-      [self.collectionViewModel itemsInSectionWithIdentifier:identifier];
-  // Read the objects in reverse order to keep the order (last modified first).
-  for (id item in [readItems reverseObjectEnumerator]) {
-    if (updater)
-      updater(item);
-  }
-  [self.dataSource endBatchUpdates];
-}
-
-- (void)updateIndexPaths:(NSArray<NSIndexPath*>*)indexPaths
-        usingItemUpdater:(ReadingListListItemUpdater)updater {
-  [self.dataSource beginBatchUpdates];
-  // Read the objects in reverse order to keep the order (last modified first).
-  for (NSIndexPath* index in [indexPaths reverseObjectEnumerator]) {
-    id<ReadingListListItem> item =
-        [self.collectionViewModel itemAtIndexPath:index];
-    if (updater)
-      updater(item);
-  }
-  [self.dataSource endBatchUpdates];
-}
-
-- (void)moveItemsFromSection:(SectionIdentifier)sourceSectionIdentifier
-                   toSection:(SectionIdentifier)destinationSectionIdentifier {
-  NSInteger sourceSection = [self.collectionViewModel
-      sectionForSectionIdentifier:sourceSectionIdentifier];
-  NSInteger numberOfSourceItems =
-      [self.collectionViewModel numberOfItemsInSection:sourceSection];
-
-  NSMutableArray* sortedIndexPaths = [NSMutableArray array];
-
-  for (int index = 0; index < numberOfSourceItems; index++) {
-    NSIndexPath* itemIndex =
-        [NSIndexPath indexPathForItem:index inSection:sourceSection];
-    [sortedIndexPaths addObject:itemIndex];
-  }
-
-  [self moveSelectedItems:sortedIndexPaths
-                toSection:destinationSectionIdentifier];
-}
-
-- (void)moveSelectedItems:(NSArray*)sortedIndexPaths
-                toSection:(SectionIdentifier)sectionIdentifier {
-  // Reconfigure cells, allowing the custom actions to be updated.
-  [self reconfigureCellsAtIndexPaths:sortedIndexPaths];
-
-  NSInteger sectionCreatedIndex = [self initializeSection:sectionIdentifier];
-
-  [self.collectionView performBatchUpdates:^{
-    NSInteger section = [self.collectionViewModel
-        sectionForSectionIdentifier:sectionIdentifier];
-
-    NSInteger newItemIndex = 0;
-    for (NSIndexPath* index in sortedIndexPaths) {
-      // The |sortedIndexPaths| is a copy of the index paths before the
-      // destination section has been added if necessary. The section part of
-      // the index potentially needs to be updated.
-      NSInteger updatedSection = index.section;
-      if (updatedSection >= sectionCreatedIndex)
-        updatedSection++;
-      if (updatedSection == section) {
-        // The item is already in the targeted section, there is no need to move
-        // it.
-        continue;
-      }
-
-      NSIndexPath* updatedIndex =
-          [NSIndexPath indexPathForItem:index.item inSection:updatedSection];
-      NSIndexPath* indexForModel =
-          [NSIndexPath indexPathForItem:index.item - newItemIndex
-                              inSection:updatedSection];
-
-      // Index of the item in the new section. The newItemIndex is the index of
-      // this item in the targeted section.
-      NSIndexPath* newIndexPath =
-          [NSIndexPath indexPathForItem:newItemIndex++ inSection:section];
-
-      [self collectionView:self.collectionView
-          willMoveItemAtIndexPath:indexForModel
-                      toIndexPath:newIndexPath];
-      [self.collectionView moveItemAtIndexPath:updatedIndex
-                                   toIndexPath:newIndexPath];
-    }
-  }
-      completion:^(BOOL) {
-        // Reload data to take into account possible sync events.
-        [self applyPendingUpdates];
-      }];
-  // As we modified the section in the batch update block, remove the section in
-  // another block.
-  [self removeEmptySections];
-}
-
-- (NSInteger)initializeSection:(SectionIdentifier)sectionIdentifier {
-  if (![self.collectionViewModel
-          hasSectionForSectionIdentifier:sectionIdentifier]) {
-    // The new section IndexPath will be 1 if it is the read section with
-    // items in the unread section, 0 otherwise.
-    BOOL hasNonEmptySectionAbove =
-        sectionIdentifier == SectionIdentifierRead &&
-        [self hasItemInSection:SectionIdentifierUnread];
-    NSInteger sectionIndex = hasNonEmptySectionAbove ? 1 : 0;
-
-    [self.collectionView performBatchUpdates:^{
-      [self.collectionViewModel insertSectionWithIdentifier:sectionIdentifier
-                                                    atIndex:sectionIndex];
-
-      [self.collectionViewModel
-                         setHeader:[self headerForSection:sectionIdentifier]
-          forSectionWithIdentifier:sectionIdentifier];
-
-      [self.collectionView
-          insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]];
-    }
-                                  completion:nil];
-
-    return sectionIndex;
-  }
-  return NSIntegerMax;
-}
-
-- (CollectionViewTextItem*)headerForSection:
-    (SectionIdentifier)sectionIdentifier {
-  CollectionViewTextItem* header =
-      [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader];
-
-  switch (sectionIdentifier) {
-    case SectionIdentifierRead:
-      header.text = l10n_util::GetNSString(IDS_IOS_READING_LIST_READ_HEADER);
-      break;
-    case SectionIdentifierUnread:
-      header.text = l10n_util::GetNSString(IDS_IOS_READING_LIST_UNREAD_HEADER);
-      break;
-  }
-  header.textColor = [[MDCPalette greyPalette] tint500];
-  return header;
-}
-
-- (void)removeEmptySections {
-  [self.collectionView performBatchUpdates:^{
-
-    SectionIdentifier a[] = {SectionIdentifierRead, SectionIdentifierUnread};
-    for (size_t i = 0; i < arraysize(a); i++) {
-      SectionIdentifier sectionIdentifier = a[i];
-
-      if ([self.collectionViewModel
-              hasSectionForSectionIdentifier:sectionIdentifier] &&
-          ![self hasItemInSection:sectionIdentifier]) {
-        NSInteger section = [self.collectionViewModel
-            sectionForSectionIdentifier:sectionIdentifier];
-
-        [self.collectionView
-            deleteSections:[NSIndexSet indexSetWithIndex:section]];
-        [self.collectionViewModel
-            removeSectionWithIdentifier:sectionIdentifier];
-      }
-    }
-  }
-                                completion:nil];
-  if (!self.dataSource.hasElements) {
-    [self collectionIsEmpty];
-  } else {
-    [_toolbar setHasReadItem:self.dataSource.hasReadElements];
-  }
-}
-
-- (void)exitEditingModeAnimated:(BOOL)animated {
-  [_actionSheet stop];
-  [self.editor setEditing:NO animated:animated];
-  [_toolbar setEditing:NO];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller_unittest.mm
deleted file mode 100644
index 508917e..0000000
--- a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller_unittest.mm
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.h"
-
-#include <memory>
-#include <unordered_set>
-
-#import "base/mac/foundation_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/time/default_clock.h"
-#include "components/favicon/core/large_icon_service.h"
-#include "components/favicon/core/test/mock_favicon_service.h"
-#include "components/reading_list/core/reading_list_model.h"
-#include "components/reading_list/core/reading_list_model_impl.h"
-#include "components/reading_list/core/reading_list_model_storage.h"
-#include "components/url_formatter/url_formatter.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#import "ios/chrome/browser/favicon/favicon_loader.h"
-#include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
-#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_item_custom_action_factory.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_view_controller_delegate.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_mediator.h"
-#include "ios/web/public/test/test_web_thread_bundle.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-#import "third_party/ocmock/gtest_support.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-using favicon::PostReply;
-using testing::_;
-
-#pragma mark - ReadingListCollectionViewControllerTest
-
-class ReadingListCollectionViewControllerTest : public PlatformTest {
- public:
-  ReadingListCollectionViewControllerTest() {}
-  ~ReadingListCollectionViewControllerTest() override {}
-
-  testing::StrictMock<favicon::MockFaviconService> mock_favicon_service_;
-  std::unique_ptr<ReadingListModelImpl> reading_list_model_;
-  ReadingListMediator* mediator_;
-  std::unique_ptr<favicon::LargeIconService> large_icon_service_;
-  std::unique_ptr<FaviconLoader> favicon_loader;
-
-  ReadingListCollectionViewController* reading_list_view_controller_;
-  id mock_delegate_;
-
-  void SetUp() override {
-    PlatformTest::SetUp();
-
-    EXPECT_CALL(mock_favicon_service_,
-                GetLargestRawFaviconForPageURL(_, _, _, _, _))
-        .WillRepeatedly(PostReply<5>(favicon_base::FaviconRawBitmapResult()));
-
-    reading_list_model_.reset(new ReadingListModelImpl(
-        nullptr, nullptr, base::DefaultClock::GetInstance()));
-    favicon_loader.reset(new FaviconLoader(new favicon::LargeIconService(
-        &mock_favicon_service_, /*image_fetcher=*/nullptr)));
-    mediator_ = [[ReadingListMediator alloc]
-          initWithModel:reading_list_model_.get()
-          faviconLoader:favicon_loader.get()
-        listItemFactory:[ReadingListListItemFactory collectionViewItemFactory]];
-    reading_list_view_controller_ = [[ReadingListCollectionViewController alloc]
-        initWithDataSource:mediator_
-                   toolbar:nil];
-
-    mock_delegate_ = [OCMockObject
-        niceMockForProtocol:@protocol(ReadingListListViewControllerDelegate)];
-    [reading_list_view_controller_ setDelegate:mock_delegate_];
-  }
-
- private:
-  web::TestWebThreadBundle thread_bundle_;
-  DISALLOW_COPY_AND_ASSIGN(ReadingListCollectionViewControllerTest);
-};
-
-// Tests that reading list items are displayed.
-TEST_F(ReadingListCollectionViewControllerTest, DisplaysItems) {
-  // Prefill some items.
-  reading_list_model_->AddEntry(GURL("https://chromium.org"), "news",
-                                reading_list::ADDED_VIA_CURRENT_APP);
-  reading_list_model_->AddEntry(GURL("https://mail.chromium.org"), "mail",
-                                reading_list::ADDED_VIA_CURRENT_APP);
-  reading_list_model_->AddEntry(GURL("https://foo.bar"), "Foo",
-                                reading_list::ADDED_VIA_CURRENT_APP);
-  reading_list_model_->SetReadStatus(GURL("https://foo.bar"), true);
-
-  // Load view.
-  [reading_list_view_controller_ view];
-
-  // There are two sections: Read and Unread.
-  DCHECK([reading_list_view_controller_.collectionView numberOfSections] == 2);
-  // There are two unread articles.
-  DCHECK([reading_list_view_controller_.collectionView
-             numberOfItemsInSection:0] == 2);
-  // There is one read article.
-  DCHECK([reading_list_view_controller_.collectionView
-             numberOfItemsInSection:1] == 1);
-}
-
-// Tests that the view controller is dismissed when Done button is pressed.
-TEST_F(ReadingListCollectionViewControllerTest, GetsDismissed) {
-  // Load view.
-  [reading_list_view_controller_ view];
-
-  [[mock_delegate_ expect]
-      dismissReadingListListViewController:reading_list_view_controller_];
-
-  // Simulate tap on "Done" button.
-  UIBarButtonItem* done =
-      reading_list_view_controller_.navigationItem.rightBarButtonItem;
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
-  // Since @selector stored in done.action is a method returning void, there is
-  // no potential for memory leak. It is OK to ignore this warning here.
-  [done.target performSelector:done.action];
-#pragma clang diagnostic pop
-
-  EXPECT_OCMOCK_VERIFY(mock_delegate_);
-}
-
-// Tests that when an item is selected, the article is opened with UrlLoader and
-// the view controller is dismissed.
-TEST_F(ReadingListCollectionViewControllerTest, OpensItems) {
-  NSIndexPath* indexPath = [NSIndexPath indexPathForItem:1 inSection:0];
-
-  GURL url("https://chromium.org");
-  GURL url2("https://chromium.org/2");
-  reading_list_model_->AddEntry(url, "chromium",
-                                reading_list::ADDED_VIA_CURRENT_APP);
-  reading_list_model_->AddEntry(url2, "chromium - 2",
-                                reading_list::ADDED_VIA_CURRENT_APP);
-
-  ReadingListCollectionViewItem* readingListItem =
-      base::mac::ObjCCastStrict<ReadingListCollectionViewItem>(
-          [[reading_list_view_controller_ collectionViewModel]
-              itemAtIndexPath:indexPath]);
-
-  [[mock_delegate_ expect]
-      readingListListViewController:reading_list_view_controller_
-                           openItem:readingListItem];
-
-  // Simulate touch on second cell.
-  [reading_list_view_controller_
-                collectionView:reading_list_view_controller_.collectionView
-      didSelectItemAtIndexPath:indexPath];
-
-  EXPECT_OCMOCK_VERIFY(mock_delegate_);
-}
-
-// Tests that the ReadingListCollectionView is creating
-// ReadingListCollectionViewItem with the correct informations.
-TEST_F(ReadingListCollectionViewControllerTest,
-       TestItemInitializationUndistilled) {
-  // Setup.
-  GURL url("https://chromium.org");
-  std::string title("Chromium");
-  reading_list_model_->AddEntry(url, title,
-                                reading_list::ADDED_VIA_CURRENT_APP);
-  // Load view.
-  [reading_list_view_controller_ view];
-  DCHECK([reading_list_view_controller_.collectionView
-             numberOfItemsInSection:0] == 1);
-  NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
-  ReadingListCollectionViewItem* readingListItem =
-      base::mac::ObjCCastStrict<ReadingListCollectionViewItem>(
-          [[reading_list_view_controller_ collectionViewModel]
-              itemAtIndexPath:indexPath]);
-  EXPECT_EQ(base::SysNSStringToUTF8([readingListItem title]), title);
-  EXPECT_EQ([readingListItem entryURL], url);
-  EXPECT_EQ([readingListItem faviconPageURL], url);
-  EXPECT_EQ([readingListItem distillationState],
-            ReadingListUIDistillationStatusPending);
-}
-
-// Tests that the ReadingListCollectionView is creating
-// ReadingListCollectionViewItem with the correct informations for distilled
-// items.
-TEST_F(ReadingListCollectionViewControllerTest,
-       TestItemInitializationDistilled) {
-  // Setup.
-  GURL url("https://chromium.org");
-  std::string title("Chromium");
-  GURL distilled_url("https://chromium.org/distilled");
-  base::FilePath distilled_path("/distilled/path");
-  reading_list_model_->AddEntry(url, title,
-                                reading_list::ADDED_VIA_CURRENT_APP);
-  int64_t size = 50;
-  reading_list_model_->SetEntryDistilledInfo(url, distilled_path, distilled_url,
-                                             size, base::Time::FromTimeT(100));
-  // Load view.
-  [reading_list_view_controller_ view];
-  DCHECK([reading_list_view_controller_.collectionView
-             numberOfItemsInSection:0] == 1);
-  NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
-  ReadingListCollectionViewItem* readingListItem =
-      base::mac::ObjCCastStrict<ReadingListCollectionViewItem>(
-          [[reading_list_view_controller_ collectionViewModel]
-              itemAtIndexPath:indexPath]);
-  EXPECT_EQ(base::SysNSStringToUTF8([readingListItem title]), title);
-  EXPECT_EQ([readingListItem entryURL], url);
-  EXPECT_EQ([readingListItem faviconPageURL], distilled_url);
-  EXPECT_EQ([readingListItem distillationState],
-            ReadingListUIDistillationStatusSuccess);
-}
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h
deleted file mode 100644
index d2933b7..0000000
--- a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h
+++ /dev/null
@@ -1,17 +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 IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_COLLECTION_VIEW_ITEM_H_
-#define IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_COLLECTION_VIEW_ITEM_H_
-
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
-
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_item.h"
-
-// Collection view item for representing a ReadingListEntry.
-@interface ReadingListCollectionViewItem
-    : CollectionViewItem<ReadingListListItem>
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_COLLECTION_VIEW_ITEM_H_
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.mm b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.mm
deleted file mode 100644
index 0f8a9949..0000000
--- a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.mm
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h"
-
-#include "base/strings/sys_string_conversions.h"
-#include "components/url_formatter/url_formatter.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_cell.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_item_custom_action_factory.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_list_item_util.h"
-#import "ios/chrome/browser/ui/util/pasteboard_util.h"
-#import "ios/chrome/common/favicon/favicon_view.h"
-#include "ios/chrome/grit/ios_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#import "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-#pragma mark - ReadingListCollectionViewItem
-
-@implementation ReadingListCollectionViewItem
-@synthesize title = _title;
-@synthesize entryURL = _entryURL;
-@synthesize faviconPageURL = _faviconPageURL;
-@synthesize distillationState = _distillationState;
-@synthesize distillationSizeText = _distillationSizeText;
-@synthesize distillationDateText = _distillationDateText;
-@synthesize customActionFactory = _customActionFactory;
-@synthesize attributes = _attributes;
-
-#pragma mark - ListItem
-
-- (Class)cellClass {
-  return [ReadingListCell class];
-}
-
-#pragma mark - CollectionViewTextItem
-
-- (void)configureCell:(ReadingListCell*)cell {
-  [super configureCell:cell];
-  [cell.faviconView configureWithAttributes:self.attributes];
-  cell.titleLabel.text = self.title;
-  NSString* subtitle = base::SysUTF16ToNSString(
-      url_formatter::FormatUrl(self.entryURL.GetOrigin()));
-  cell.subtitleLabel.text = subtitle;
-  cell.distillationSizeLabel.text = self.distillationSizeText;
-  cell.distillationDateLabel.text = self.distillationDateText;
-  cell.showDistillationInfo = self.distillationSizeText.length > 0 &&
-                              self.distillationDateText.length > 0;
-  cell.distillationState = _distillationState;
-  cell.isAccessibilityElement = YES;
-  cell.accessibilityLabel = GetReadingListCellAccessibilityLabel(
-      self.title, subtitle, self.distillationState);
-  cell.accessibilityCustomActions =
-      [self.customActionFactory customActionsForItem:self];
-}
-
-#pragma mark - NSObject
-
-- (NSString*)description {
-  return [NSString stringWithFormat:@"Reading List item \"%@\" for url %s",
-                                    self.title, self.entryURL.spec().c_str()];
-}
-
-- (BOOL)isEqual:(id)other {
-  return AreReadingListListItemsEqual(self, other);
-}
-
-@end
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm b/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
index 891b641..b9d17c3 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
@@ -107,7 +107,7 @@
       ReadingListModelFactory::GetInstance()->GetForBrowserState(
           self.browserState);
   ReadingListListItemFactory* itemFactory =
-      [ReadingListListItemFactory tableViewItemFactory];
+      [[ReadingListListItemFactory alloc] init];
   FaviconLoader* faviconLoader =
       IOSChromeFaviconLoaderFactory::GetForBrowserState(self.browserState);
   self.mediator = [[ReadingListMediator alloc] initWithModel:model
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
index 63bb324..8654318 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -18,16 +18,11 @@
 #import "ios/chrome/browser/ui/commands/reading_list_add_command.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
 #import "ios/chrome/browser/ui/reading_list/empty_reading_list_background_view.h"
-#import "ios/chrome/browser/ui/reading_list/legacy_reading_list_toolbar_button.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_cell.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_toolbar_button_identifiers.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_url_cell_favicon_badge_view.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h"
 #import "ios/chrome/browser/ui/table_view/table_view_empty_view.h"
-#include "ios/chrome/browser/ui/ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
@@ -116,33 +111,12 @@
   return model;
 }
 
-// The ancestor class of toolbar buttons.
-Class ToolbarButtonAncestorClass() {
-  return experimental_flags::IsReadingListUIRebootEnabled()
-             ? [UIToolbar class]
-             : [LegacyReadingListToolbarButton class];
-}
-
-// The class displaying the reading list cells.
-Class ReadingListCellClass() {
-  return experimental_flags::IsReadingListUIRebootEnabled()
-             ? [TableViewURLCell class]
-             : [ReadingListCell class];
-}
-
-// The class displaying the reading list.
-Class ReadingListViewControllerClass() {
-  return experimental_flags::IsReadingListUIRebootEnabled()
-             ? [ReadingListTableViewController class]
-             : [ReadingListCollectionViewController class];
-}
-
 // Scroll to the top of the Reading List.
 void ScrollToTop() {
   NSError* error = nil;
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
-                                          [ReadingListViewControllerClass()
-                                              accessibilityIdentifier])]
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID([
+                                          [ReadingListTableViewController class]
+                                          accessibilityIdentifier])]
       performAction:grey_scrollToContentEdgeWithStartPoint(kGREYContentEdgeTop,
                                                            0.5, 0.5)
               error:&error];
@@ -156,7 +130,7 @@
       selectElementWithMatcher:
           grey_allOf(
               grey_accessibilityID(kReadingListToolbarMarkButtonID),
-              grey_ancestor(grey_kindOfClass(ToolbarButtonAncestorClass())),
+              grey_ancestor(grey_kindOfClass([UIToolbar class])),
               chrome_test_util::ButtonWithAccessibilityLabelId(a11y_label_id),
               nil)] assertWithMatcher:grey_sufficientlyVisible()];
 }
@@ -166,7 +140,7 @@
   [[EarlGrey
       selectElementWithMatcher:grey_allOf(grey_accessibilityID(button_id),
                                           grey_ancestor(grey_kindOfClass(
-                                              ToolbarButtonAncestorClass())),
+                                              [UIToolbar class])),
                                           nil)]
       assertWithMatcher:grey_notVisible()];
 }
@@ -176,7 +150,7 @@
   [[EarlGrey
       selectElementWithMatcher:grey_allOf(grey_accessibilityID(button_id),
                                           grey_ancestor(grey_kindOfClass(
-                                              ToolbarButtonAncestorClass())),
+                                              [UIToolbar class])),
                                           nil)]
       assertWithMatcher:grey_sufficientlyVisible()];
 }
@@ -202,12 +176,12 @@
   id<GREYMatcher> matcher =
       grey_allOf(chrome_test_util::StaticTextWithAccessibilityLabel(
                      base::SysUTF8ToNSString(entryTitle)),
-                 grey_ancestor(grey_kindOfClass(ReadingListCellClass())),
+                 grey_ancestor(grey_kindOfClass([TableViewURLCell class])),
                  grey_sufficientlyVisible(), nil);
   [[[EarlGrey selectElementWithMatcher:matcher]
          usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 100)
       onElementWithMatcher:grey_accessibilityID(
-                               ReadingListViewControllerClass())]
+                               [ReadingListTableViewController class])]
       performAction:action];
 }
 
@@ -229,11 +203,11 @@
       selectElementWithMatcher:
           grey_allOf(chrome_test_util::StaticTextWithAccessibilityLabel(
                          base::SysUTF8ToNSString(entryTitle)),
-                     grey_ancestor(grey_kindOfClass(ReadingListCellClass())),
+                     grey_ancestor(grey_kindOfClass([TableViewURLCell class])),
                      grey_sufficientlyVisible(), nil)]
          usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 100)
       onElementWithMatcher:grey_accessibilityID(
-                               [ReadingListViewControllerClass()
+                               [[ReadingListTableViewController class]
                                    accessibilityIdentifier])]
       assertWithMatcher:grey_notNil()];
 }
@@ -262,11 +236,11 @@
       selectElementWithMatcher:
           grey_allOf(chrome_test_util::StaticTextWithAccessibilityLabel(
                          base::SysUTF8ToNSString(title)),
-                     grey_ancestor(grey_kindOfClass(ReadingListCellClass())),
+                     grey_ancestor(grey_kindOfClass([TableViewURLCell class])),
                      grey_sufficientlyVisible(), nil)]
          usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 100)
       onElementWithMatcher:grey_accessibilityID(
-                               [ReadingListViewControllerClass()
+                               [[ReadingListTableViewController class]
                                    accessibilityIdentifier])]
       assertWithMatcher:grey_notNil()
                   error:&error];
@@ -320,38 +294,17 @@
 
 // Returns a match for the Reading List Empty Collection Background.
 id<GREYMatcher> EmptyBackground() {
-  Class empty_background_class =
-      experimental_flags::IsReadingListUIRebootEnabled()
-          ? [TableViewEmptyView class]
-          : [EmptyReadingListBackgroundView class];
-  return grey_accessibilityID([empty_background_class accessibilityIdentifier]);
+  return grey_accessibilityID(
+      [[TableViewEmptyView class] accessibilityIdentifier]);
 }
 
 // Adds the current page to the Reading List.
 void AddCurrentPageToReadingList() {
   // Add the page to the reading list.
-  if (IsUIRefreshPhase1Enabled()) {
-    [ChromeEarlGreyUI openToolsMenu];
-    [ChromeEarlGreyUI
-        tapToolsMenuButton:chrome_test_util::ButtonWithAccessibilityLabelId(
-                               IDS_IOS_SHARE_MENU_READING_LIST_ACTION)];
-  } else if (base::ios::IsRunningOnIOS11OrLater()) {
-    // On iOS 11, it is not possible to interact with the share menu in EG.
-    // Send directly the command instead. This is the closest behavior we can
-    // have from the normal behavior.
-    web::WebState* web_state = chrome_test_util::GetCurrentWebState();
-    ReadingListAddCommand* command = [[ReadingListAddCommand alloc]
-        initWithURL:web_state->GetVisibleURL()
-              title:base::SysUTF16ToNSString(web_state->GetTitle())];
-    [chrome_test_util::DispatcherForActiveBrowserViewController()
-        addToReadingList:command];
-  } else {
-    [ChromeEarlGreyUI openShareMenu];
-    [[EarlGrey selectElementWithMatcher:
-                   chrome_test_util::ButtonWithAccessibilityLabelId(
-                       IDS_IOS_SHARE_MENU_READING_LIST_ACTION)]
-        performAction:grey_tap()];
-  }
+  [ChromeEarlGreyUI openToolsMenu];
+  [ChromeEarlGreyUI
+      tapToolsMenuButton:chrome_test_util::ButtonWithAccessibilityLabelId(
+                             IDS_IOS_SHARE_MENU_READING_LIST_ACTION)];
 
   // Wait for the snackbar to appear.
   id<GREYMatcher> snackbar_matcher =
@@ -388,9 +341,7 @@
 // Wait until one element is distilled.
 void WaitForDistillation() {
   NSString* a11y_id =
-      experimental_flags::IsReadingListUIRebootEnabled()
-          ? [TableViewURLCellFaviconBadgeView accessibilityIdentifier]
-          : @"Reading List Item distillation date";
+      [TableViewURLCellFaviconBadgeView accessibilityIdentifier];
   ConditionBlock wait_for_distillation_date = ^{
     NSError* error = nil;
     [[EarlGrey selectElementWithMatcher:grey_accessibilityID(a11y_id)]
@@ -429,17 +380,11 @@
 
 // Opens the page security info bubble.
 void OpenPageSecurityInfoBubble() {
-  if (IsUIRefreshPhase1Enabled()) {
-    // In UI Refresh, the security info is accessed through the tools menu.
-    [ChromeEarlGreyUI openToolsMenu];
-    // Tap on the Page Info button.
-    [ChromeEarlGreyUI
-        tapToolsMenuButton:grey_accessibilityID(kToolsMenuSiteInformation)];
-  } else {
-    [[EarlGrey
-        selectElementWithMatcher:chrome_test_util::PageSecurityInfoIndicator()]
-        performAction:grey_tap()];
-  }
+  // In UI Refresh, the security info is accessed through the tools menu.
+  [ChromeEarlGreyUI openToolsMenu];
+  // Tap on the Page Info button.
+  [ChromeEarlGreyUI
+      tapToolsMenuButton:grey_accessibilityID(kToolsMenuSiteInformation)];
 }
 
 // Tests that the correct version of kDistillableURL is displayed.
@@ -479,22 +424,12 @@
   }
 
   // Test the presence of the omnibox offline chip.
-  if (IsRefreshLocationBarEnabled()) {
-    [[EarlGrey selectElementWithMatcher:
-                   grey_allOf(chrome_test_util::PageSecurityInfoIndicator(),
-                              chrome_test_util::ImageViewWithImageNamed(
-                                  @"location_bar_offline"),
-                              nil)]
-        assertWithMatcher:online ? grey_nil() : grey_notNil()];
-  } else {
-    [[EarlGrey
-        selectElementWithMatcher:grey_allOf(
-                                     chrome_test_util::PageSecurityInfoButton(),
-                                     chrome_test_util::ButtonWithImage(
-                                         IDR_IOS_OMNIBOX_OFFLINE),
-                                     nil)]
-        assertWithMatcher:online ? grey_nil() : grey_notNil()];
-  }
+  [[EarlGrey selectElementWithMatcher:
+                 grey_allOf(chrome_test_util::PageSecurityInfoIndicator(),
+                            chrome_test_util::ImageViewWithImageNamed(
+                                @"location_bar_offline"),
+                            nil)]
+      assertWithMatcher:online ? grey_nil() : grey_notNil()];
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.h b/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.h
index ab76c21..60886f3 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.h
+++ b/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.h
@@ -15,15 +15,6 @@
 // Factory object that produces ListItems for Reading List.
 @interface ReadingListListItemFactory : NSObject
 
-// A factory that produces ReadingListTableViewItems.
-+ (instancetype)tableViewItemFactory;
-
-// A factory that produces ReadingListCollectionViewItems.
-+ (instancetype)collectionViewItemFactory;
-
-// Use either |+tableViewItemFactory| or |+collectionViewItemFactory|.
-- (instancetype)init NS_UNAVAILABLE;
-
 // The accessibility delegate to use for the created items.
 @property(nonatomic, weak) id<ReadingListListItemAccessibilityDelegate>
     accessibilityDelegate;
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.mm b/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.mm
index 5ca6401..4ed4051 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.mm
@@ -9,7 +9,6 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/reading_list/core/reading_list_entry.h"
 #include "components/url_formatter/url_formatter.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_custom_action_factory.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_util.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_table_view_item.h"
@@ -19,32 +18,19 @@
 #error "This file requires ARC support."
 #endif
 
-namespace {
-// The different types of items to be vended by the factory.
-enum class ItemFactoryType { TABLE, COLLECTION };
-}  // namespace
-
 @interface ReadingListListItemFactory ()
 
-// The factory type.
-@property(nonatomic, assign) ItemFactoryType factoryType;
 // The factory supplying custom accessibility actions to the items.
 @property(nonatomic, readonly, strong)
     ReadingListListItemCustomActionFactory* customActionFactory;
 
-// Initializer for a factory of |factoryType|.
-- (instancetype)initWithFactoryType:(ItemFactoryType)factoryType
-    NS_DESIGNATED_INITIALIZER;
-
 @end
 
 @implementation ReadingListListItemFactory
-@synthesize factoryType = _factoryType;
 @synthesize customActionFactory = _customActionFactory;
 
-- (instancetype)initWithFactoryType:(ItemFactoryType)factoryType {
+- (instancetype)init {
   if (self = [super init]) {
-    _factoryType = factoryType;
     _customActionFactory =
         [[ReadingListListItemCustomActionFactory alloc] init];
   }
@@ -64,22 +50,10 @@
 
 #pragma mark Public
 
-+ (instancetype)tableViewItemFactory {
-  return [[ReadingListListItemFactory alloc]
-      initWithFactoryType:ItemFactoryType::TABLE];
-}
-
-+ (instancetype)collectionViewItemFactory {
-  return [[ReadingListListItemFactory alloc]
-      initWithFactoryType:ItemFactoryType::COLLECTION];
-}
-
 - (ListItem<ReadingListListItem>*)cellItemForReadingListEntry:
     (const ReadingListEntry*)entry {
   ListItem<ReadingListListItem>* item =
-      self.factoryType == ItemFactoryType::TABLE
-          ? [[ReadingListTableViewItem alloc] initWithType:0]
-          : [[ReadingListCollectionViewItem alloc] initWithType:0];
+      [[ReadingListTableViewItem alloc] initWithType:0];
   item.title = base::SysUTF8ToNSString(entry->Title());
   const GURL& URL = entry->URL();
   item.entryURL = URL;
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory_unittest.mm b/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory_unittest.mm
index 08845a42..bc32f67 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory_unittest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory_unittest.mm
@@ -6,7 +6,6 @@
 
 #include "base/time/time.h"
 #include "components/reading_list/core/reading_list_entry.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_accessibility_delegate.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_custom_action_factory.h"
@@ -39,25 +38,8 @@
   id<ReadingListListItemAccessibilityDelegate> mockDelegate =
       OCMProtocolMock(@protocol(ReadingListListItemAccessibilityDelegate));
   ReadingListListItemFactory* factory =
-      [ReadingListListItemFactory tableViewItemFactory];
+      [[ReadingListListItemFactory alloc] init];
   factory.accessibilityDelegate = mockDelegate;
   id<ReadingListListItem> item = [factory cellItemForReadingListEntry:&entry_];
   EXPECT_EQ(item.customActionFactory.accessibilityDelegate, mockDelegate);
 }
-
-// Tests that |+tableViewItemFactory| returns ReadingListTableViewItems.
-TEST_F(ReadingListListItemFactoryTest, TableViewItem) {
-  ReadingListListItemFactory* factory =
-      [ReadingListListItemFactory tableViewItemFactory];
-  id<ReadingListListItem> item = [factory cellItemForReadingListEntry:&entry_];
-  EXPECT_TRUE([item isKindOfClass:[ReadingListTableViewItem class]]);
-}
-
-// Tests that |+collectionViewItemFactory| returns
-// ReadingListCollectionViewItems.
-TEST_F(ReadingListListItemFactoryTest, CollectionViewItem) {
-  ReadingListListItemFactory* factory =
-      [ReadingListListItemFactory collectionViewItemFactory];
-  id<ReadingListListItem> item = [factory cellItemForReadingListEntry:&entry_];
-  EXPECT_TRUE([item isKindOfClass:[ReadingListCollectionViewItem class]]);
-}
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_mediator.mm b/ios/chrome/browser/ui/reading_list/reading_list_mediator.mm
index 0bbc81d..ab607f1 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_mediator.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_mediator.mm
@@ -16,7 +16,6 @@
 #import "ios/chrome/browser/favicon/favicon_loader.h"
 #include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h"
 #import "ios/chrome/browser/ui/favicon/favicon_attributes_provider.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_data_sink.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.h"
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm b/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
index bb2d103..b3100f9 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
@@ -14,10 +14,10 @@
 #include "components/url_formatter/url_formatter.h"
 #import "ios/chrome/browser/favicon/favicon_loader.h"
 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_accessibility_delegate.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_custom_action_factory.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.h"
+#import "ios/chrome/browser/ui/reading_list/reading_list_table_view_item.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -75,14 +75,12 @@
       mediator_ = [[ReadingListMediator alloc]
             initWithModel:model_.get()
             faviconLoader:favicon_loader.get()
-          listItemFactory:[ReadingListListItemFactory
-                              collectionViewItemFactory]];
+          listItemFactory:[[ReadingListListItemFactory alloc] init]];
     } else {
       mediator_ = [[ReadingListMediator alloc]
              initWithModel:model_.get()
           largeIconService:large_icon_service_.get()
-           listItemFactory:[ReadingListListItemFactory
-                               collectionViewItemFactory]];
+           listItemFactory:[[ReadingListListItemFactory alloc] init]];
     }
   }
 
@@ -111,8 +109,8 @@
   // Tests.
   EXPECT_EQ(3U, [unreadArray count]);
   EXPECT_EQ(2U, [readArray count]);
-  NSArray<ReadingListCollectionViewItem*>* rlReadArray = [readArray copy];
-  NSArray<ReadingListCollectionViewItem*>* rlUneadArray = [unreadArray copy];
+  NSArray<ReadingListTableViewItem*>* rlReadArray = [readArray copy];
+  NSArray<ReadingListTableViewItem*>* rlUneadArray = [unreadArray copy];
   EXPECT_TRUE([rlUneadArray[0].title isEqualToString:@""]);
   EXPECT_TRUE([rlReadArray[0].title isEqualToString:@"read2"]);
   EXPECT_TRUE([rlReadArray[1].title isEqualToString:@"read1"]);
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_utils.h b/ios/chrome/browser/ui/reading_list/reading_list_utils.h
index 08ebdb6..471e9e5 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_utils.h
+++ b/ios/chrome/browser/ui/reading_list/reading_list_utils.h
@@ -6,7 +6,7 @@
 #define IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_UTILS_H_
 
 #include "components/reading_list/core/reading_list_entry.h"
-#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_cell.h"
+#import "ios/chrome/browser/ui/reading_list/reading_list_ui_distillation_status.h"
 
 namespace reading_list {
 
diff --git a/ios/chrome/browser/ui/reading_list/resources/BUILD.gn b/ios/chrome/browser/ui/reading_list/resources/BUILD.gn
index f21f50bd..ade93f74 100644
--- a/ios/chrome/browser/ui/reading_list/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/reading_list/resources/BUILD.gn
@@ -4,15 +4,6 @@
 
 import("//build/config/ios/asset_catalog.gni")
 
-imageset("distillation_fail") {
-  sources = [
-    "distillation_fail.imageset/Contents.json",
-    "distillation_fail.imageset/distillation_fail.png",
-    "distillation_fail.imageset/distillation_fail@2x.png",
-    "distillation_fail.imageset/distillation_fail@3x.png",
-  ]
-}
-
 imageset("distillation_fail_new") {
   sources = [
     "distillation_fail_new.imageset/Contents.json",
@@ -22,15 +13,6 @@
   ]
 }
 
-imageset("distillation_success") {
-  sources = [
-    "distillation_success.imageset/Contents.json",
-    "distillation_success.imageset/distillation_success.png",
-    "distillation_success.imageset/distillation_success@2x.png",
-    "distillation_success.imageset/distillation_success@3x.png",
-  ]
-}
-
 imageset("reading_list_empty_state") {
   sources = [
     "reading_list_empty_state.imageset/Contents.json",
@@ -49,15 +31,6 @@
   ]
 }
 
-imageset("reading_list_share_icon") {
-  sources = [
-    "reading_list_share_icon.imageset/Contents.json",
-    "reading_list_share_icon.imageset/reading_list_share_icon.png",
-    "reading_list_share_icon.imageset/reading_list_share_icon@2x.png",
-    "reading_list_share_icon.imageset/reading_list_share_icon@3x.png",
-  ]
-}
-
 imageset("reading_list_side_swipe") {
   sources = [
     "reading_list_side_swipe.imageset/Contents.json",
@@ -67,15 +40,6 @@
   ]
 }
 
-imageset("reading_list_toolbar_icon") {
-  sources = [
-    "reading_list_toolbar_icon.imageset/Contents.json",
-    "reading_list_toolbar_icon.imageset/reading_list_toolbar_icon.png",
-    "reading_list_toolbar_icon.imageset/reading_list_toolbar_icon@2x.png",
-    "reading_list_toolbar_icon.imageset/reading_list_toolbar_icon@3x.png",
-  ]
-}
-
 imageset("reading_list_tools_icon") {
   sources = [
     "reading_list_tools_icon.imageset/Contents.json",
diff --git a/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/Contents.json b/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/Contents.json
deleted file mode 100644
index 03a4054f..0000000
--- a/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "distillation_fail.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "distillation_fail@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "distillation_fail@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/distillation_fail.png b/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/distillation_fail.png
deleted file mode 100644
index dc403ea..0000000
--- a/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/distillation_fail.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/distillation_fail@2x.png b/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/distillation_fail@2x.png
deleted file mode 100644
index 804ed571..0000000
--- a/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/distillation_fail@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/distillation_fail@3x.png b/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/distillation_fail@3x.png
deleted file mode 100644
index e48983a..0000000
--- a/ios/chrome/browser/ui/reading_list/resources/distillation_fail.imageset/distillation_fail@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/Contents.json b/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/Contents.json
deleted file mode 100644
index e608ccb..0000000
--- a/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "distillation_success.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "distillation_success@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "distillation_success@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/distillation_success.png b/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/distillation_success.png
deleted file mode 100644
index 368452e..0000000
--- a/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/distillation_success.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/distillation_success@2x.png b/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/distillation_success@2x.png
deleted file mode 100644
index 719d6576d..0000000
--- a/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/distillation_success@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/distillation_success@3x.png b/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/distillation_success@3x.png
deleted file mode 100644
index df30dbe0..0000000
--- a/ios/chrome/browser/ui/reading_list/resources/distillation_success.imageset/distillation_success@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/reading_list/resources/reading_list_share_icon.imageset/Contents.json b/ios/chrome/browser/ui/reading_list/resources/reading_list_share_icon.imageset/Contents.json
deleted file mode 100644
index 259992d..0000000
--- a/ios/chrome/browser/ui/reading_list/resources/reading_list_share_icon.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "reading_list_share_icon.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "reading_list_share_icon@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "reading_list_share_icon@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/reading_list/resources/reading_list_toolbar_icon.imageset/Contents.json b/ios/chrome/browser/ui/reading_list/resources/reading_list_toolbar_icon.imageset/Contents.json
deleted file mode 100644
index f1f5ab81..0000000
--- a/ios/chrome/browser/ui/reading_list/resources/reading_list_toolbar_icon.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "reading_list_toolbar_icon.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "reading_list_toolbar_icon@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "reading_list_toolbar_icon@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/reading_list/text_badge_view.mm b/ios/chrome/browser/ui/reading_list/text_badge_view.mm
index 095b706..aa9e933 100644
--- a/ios/chrome/browser/ui/reading_list/text_badge_view.mm
+++ b/ios/chrome/browser/ui/reading_list/text_badge_view.mm
@@ -5,9 +5,7 @@
 #import "ios/chrome/browser/ui/reading_list/text_badge_view.h"
 
 #include "base/logging.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #include "ios/chrome/browser/ui/ui_util.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -15,7 +13,6 @@
 
 namespace {
 const CGFloat kFontSize = 11.0f;
-const CGFloat kLegacyFontSize = 10.0f;
 // The margin between the top and bottom of the label and the badge.
 const CGFloat kLabelVerticalMargin = 2.5f;
 // The default value for the margin between the sides of the label and the
@@ -63,14 +60,10 @@
     [self addSubview:self.label];
     self.didAddSubviews = YES;
     [self activateConstraints];
-    if (IsUIRefreshPhase1Enabled()) {
-      [self setBackgroundColor:[UIColor colorWithRed:0.101
-                                               green:0.45
-                                                blue:0.909
-                                               alpha:0.1]];
-    } else {
-      [self setBackgroundColor:[[MDCPalette cr_bluePalette] tint500]];
-    }
+    [self setBackgroundColor:[UIColor colorWithRed:0.101
+                                             green:0.45
+                                              blue:0.909
+                                             alpha:0.1]];
     [self setAccessibilityLabel:self.label.text];
   }
   [super willMoveToSuperview:newSuperview];
@@ -99,17 +92,10 @@
 // Return a label that displays text in white with center alignment.
 + (UILabel*)labelWithText:(NSString*)text {
   UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero];
-  if (IsUIRefreshPhase1Enabled()) {
-    [label setFont:[UIFont systemFontOfSize:kFontSize
-                                     weight:UIFontWeightSemibold]];
-    [label setTextColor:[UIColor colorWithRed:0.101
-                                        green:0.45
-                                         blue:0.909
-                                        alpha:1]];
-  } else {
-    [label setFont:[[MDCTypography fontLoader] boldFontOfSize:kLegacyFontSize]];
-    [label setTextColor:[UIColor whiteColor]];
-  }
+  [label
+      setFont:[UIFont systemFontOfSize:kFontSize weight:UIFontWeightSemibold]];
+  [label
+      setTextColor:[UIColor colorWithRed:0.101 green:0.45 blue:0.909 alpha:1]];
   [label setTranslatesAutoresizingMaskIntoConstraints:NO];
   [label setText:text];
   [label setTextAlignment:NSTextAlignmentCenter];
diff --git a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
index 36ca586..7642ae6 100644
--- a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
@@ -121,7 +121,7 @@
     _passwordForm = passwordForm;
     if (!_passwordForm.blacklisted_by_user) {
       _username = base::SysUTF16ToNSString(_passwordForm.username_value);
-      if (_passwordForm.federation_origin.unique()) {
+      if (_passwordForm.federation_origin.opaque()) {
         _password = base::SysUTF16ToNSString(_passwordForm.password_value);
       } else {
         _federation =
@@ -198,7 +198,7 @@
     [model addItem:[self usernameCopyButtonItem]
         toSectionWithIdentifier:SectionIdentifierUsername];
 
-    if (_passwordForm.federation_origin.unique()) {
+    if (_passwordForm.federation_origin.opaque()) {
       [model addSectionWithIdentifier:SectionIdentifierPassword];
       SettingsTextItem* passwordHeader =
           [[SettingsTextItem alloc] initWithType:ItemTypeHeader];
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index 974c3d5c..9a7340ad 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -304,21 +304,42 @@
   // scrolling.
   self.topToolbar.pageControl.userInteractionEnabled = NO;
   self.pageChangeInteraction = PageChangeInteractionScrollDrag;
-  [self updatePageViewAccessibilityVisibility];
 }
 
 - (void)scrollViewDidEndDragging:(UIScrollView*)scrollView
                   willDecelerate:(BOOL)decelerate {
   // Re-enable the page control since the user isn't dragging anymore.
   self.topToolbar.pageControl.userInteractionEnabled = YES;
-  [self updatePageViewAccessibilityVisibility];
 }
 
 - (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView {
   // Mark the interaction as ended, so that scrolls that don't change page don't
   // cause other interactions to be mislabeled.
   self.pageChangeInteraction = PageChangeInteractionNone;
-  [self updatePageViewAccessibilityVisibility];
+
+  // Update _currentPage if scroll view has moved to a new page. Especially
+  // important here for 3-finger accessibility swipes since it's not registered
+  // as dragging in scrollViewDidScroll:
+  TabGridPage page = GetPageFromScrollView(scrollView);
+  if (page != _currentPage) {
+    // Original current page is about to not be visible. Disable it from being
+    // focused by VoiceOver.
+    self.currentPageViewController.view.accessibilityElementsHidden = YES;
+    _currentPage = page;
+    // Allow VoiceOver to focus on the new current page's elements.
+    self.currentPageViewController.view.accessibilityElementsHidden = NO;
+    [self broadcastIncognitoContentVisibility];
+    [self configureButtonsForActiveAndCurrentPage];
+
+    // TODO(crbug.com/872303) : This is a workaround because TabRestoreService
+    // does not notify observers when entries are removed. When close all tabs
+    // removes entries, the remote tabs page in the tab grid are not updated.
+    // This ensures that the table is updated whenever scrolling to it.
+    if (_currentPage == TabGridPageRemoteTabs) {
+      [self.remoteTabsViewController loadModel];
+      [self.remoteTabsViewController.tableView reloadData];
+    }
+  }
 }
 
 - (void)scrollViewDidEndScrollingAnimation:(UIScrollView*)scrollView {
@@ -531,9 +552,15 @@
   // the ivar may have been set before the scroll view could be updated. Calling
   // this method should always update the scroll view's offset if possible.
 
+  // Original current page is about to not be visible. Disable it from being
+  // focused by VoiceOver.
+  self.currentPageViewController.view.accessibilityElementsHidden = YES;
+
   // If the view isn't loaded yet, just do bookkeeping on _currentPage.
   if (!self.viewLoaded) {
     _currentPage = currentPage;
+    // Allow VoiceOver to focus on the new current page's elements.
+    self.currentPageViewController.view.accessibilityElementsHidden = NO;
     return;
   }
   CGFloat pageWidth = self.scrollView.frame.size.width;
@@ -556,6 +583,9 @@
       _currentPage = currentPage;
     }
   }
+  // Allow VoiceOver to focus on the new current page's elements.
+  self.currentPageViewController.view.accessibilityElementsHidden = NO;
+
   // TODO(crbug.com/872303) : This is a workaround because TabRestoreService
   // does not notify observers when entries are removed. When close all tabs
   // removes entries, the remote tabs page in the tab grid are not updated. This
@@ -582,7 +612,6 @@
   if (_scrollViewAnimatingContentOffset == scrollViewAnimatingContentOffset)
     return;
   _scrollViewAnimatingContentOffset = scrollViewAnimatingContentOffset;
-  [self updatePageViewAccessibilityVisibility];
 }
 
 // Adds the scroll view and sets constraints.
@@ -908,19 +937,6 @@
       kTabGridCloseAllButtonIdentifier;
 }
 
-// Updates the visibility of the pages' accessibility elements.  When
-// |scrollView| is scrolling, all pages should be visible.  When stationary,
-// however, the accessibility elements of off-screen pages should be hidden.
-- (void)updatePageViewAccessibilityVisibility {
-  BOOL scrolling = self.scrollView.dragging || self.scrollView.decelerating ||
-                   self.scrollViewAnimatingContentOffset;
-  UIViewController* currentPageViewController = self.currentPageViewController;
-  for (UIViewController* pageViewController in self.pageViewControllers) {
-    pageViewController.view.accessibilityElementsHidden =
-        !scrolling && pageViewController != currentPageViewController;
-  }
-}
-
 // Shows the two toolbars and the floating button. Suitable for use in
 // animations.
 - (void)showToolbars {
diff --git a/ios/third_party/material_sprited_animation_view_ios/README.chromium b/ios/third_party/material_sprited_animation_view_ios/README.chromium
index a1f29d9..451f5399 100644
--- a/ios/third_party/material_sprited_animation_view_ios/README.chromium
+++ b/ios/third_party/material_sprited_animation_view_ios/README.chromium
@@ -1,7 +1,7 @@
 Name: Material Sprited Animation View
 URL: https://github.com/material-foundation/material-sprited-animation-view-ios
 Version: 0
-Revision: c6e16d06bdafd95540c62b3402d9414692fbca81
+Revision: 8af9adaa182044cf2920dfb620b863669e1aeb7c
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/ios/web/web_state/web_frame_util_unittest.mm b/ios/web/web_state/web_frame_util_unittest.mm
index 404b7f31..dfa93dd1 100644
--- a/ios/web/web_state/web_frame_util_unittest.mm
+++ b/ios/web/web_state/web_frame_util_unittest.mm
@@ -103,6 +103,9 @@
   EXPECT_EQ(nullptr, GetWebFrameWithId(&test_web_state, "iframe"));
   EXPECT_EQ(nullptr, GetWebFrameWithId(&test_web_state, "main_frame"));
   EXPECT_EQ(nullptr, GetWebFrameWithId(&test_web_state, "unused"));
+
+  // Test that GetWebFrameWithId returns nullptr for the empty string.
+  EXPECT_EQ(nullptr, GetWebFrameWithId(&test_web_state, ""));
 }
 
 // Tests the GetWebFrameId GetWebFrameId function.
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 591d5ee..33b6fd5 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -384,6 +384,7 @@
     "internal/cwv_preview_element_info_unittest.mm",
     "internal/cwv_scroll_view_unittest.mm",
     "internal/signin/cwv_identity_unittest.mm",
+    "internal/sync/cwv_sync_controller_unittest.mm",
     "internal/translate/cwv_translation_controller_unittest.mm",
     "internal/translate/cwv_translation_language_unittest.mm",
     "internal/translate/cwv_translation_policy_unittest.mm",
@@ -399,7 +400,10 @@
     "//components/autofill/core/browser:test_support",
     "//components/autofill/ios/browser:test_support",
     "//components/autofill/ios/form_util:test_support",
+    "//components/browser_sync:test_support",
     "//components/prefs:test_support",
+    "//components/signin/core/browser:test_support",
+    "//components/sync:test_support_driver",
     "//ios/web/public/test",
     "//ios/web/public/test/fakes",
     "//testing/gtest",
diff --git a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
new file mode 100644
index 0000000..7b248e30
--- /dev/null
+++ b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
@@ -0,0 +1,117 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web_view/internal/sync/cwv_sync_controller_internal.h"
+
+#include <memory>
+#include <set>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "components/browser_sync/profile_sync_service_mock.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/device_id_helper.h"
+#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
+#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "components/signin/core/browser/test_signin_client.h"
+#include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
+#include "components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h"
+#include "components/sync/driver/fake_sync_client.h"
+#import "ios/web/public/test/fakes/test_web_state.h"
+#include "ios/web/public/test/test_web_thread_bundle.h"
+#include "ios/web_view/internal/web_view_browser_state.h"
+#import "ios/web_view/public/cwv_identity.h"
+#import "ios/web_view/public/cwv_sync_controller_data_source.h"
+#import "ios/web_view/public/cwv_sync_controller_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace ios_web_view {
+
+class CWVSyncControllerTest : public PlatformTest {
+ protected:
+  CWVSyncControllerTest()
+      : browser_state_(/*off_the_record=*/false),
+        signin_client_(browser_state_.GetPrefs()),
+        token_service_(browser_state_.GetPrefs()),
+        gaia_cookie_manager_service_(&token_service_,
+                                     "cookie-source",
+                                     &signin_client_),
+        signin_manager_(&signin_client_,
+                        &token_service_,
+                        &account_tracker_service_,
+                        &gaia_cookie_manager_service_) {
+    web_state_.SetBrowserState(&browser_state_);
+
+    browser_sync::ProfileSyncService::InitParams init_params;
+    init_params.start_behavior = browser_sync::ProfileSyncService::MANUAL_START;
+    init_params.sync_client = std::make_unique<syncer::FakeSyncClient>();
+    init_params.url_loader_factory = browser_state_.GetSharedURLLoaderFactory();
+    init_params.network_time_update_callback = base::DoNothing();
+    init_params.signin_scoped_device_id_callback = base::BindRepeating(
+        &signin::GetSigninScopedDeviceId, browser_state_.GetPrefs());
+    profile_sync_service_ =
+        std::make_unique<browser_sync::ProfileSyncServiceMock>(&init_params);
+
+    account_tracker_service_.Initialize(browser_state_.GetPrefs(),
+                                        base::FilePath());
+
+    sync_controller_ = [[CWVSyncController alloc]
+        initWithProfileSyncService:profile_sync_service_.get()
+             accountTrackerService:&account_tracker_service_
+                     signinManager:&signin_manager_
+                      tokenService:&token_service_];
+  };
+
+  web::TestWebThreadBundle web_thread_bundle_;
+  ios_web_view::WebViewBrowserState browser_state_;
+  web::TestWebState web_state_;
+  std::unique_ptr<browser_sync::ProfileSyncServiceMock> profile_sync_service_;
+  AccountTrackerService account_tracker_service_;
+  TestSigninClient signin_client_;
+  FakeProfileOAuth2TokenService token_service_;
+  FakeGaiaCookieManagerService gaia_cookie_manager_service_;
+  FakeSigninManager signin_manager_;
+  CWVSyncController* sync_controller_;
+};
+
+// Verifies CWVSyncControllerDataSource methods are invoked with the correct
+// parameters.
+TEST_F(CWVSyncControllerTest, DataSourceCallbacks) {
+  // [delegate expect] returns an autoreleased object, but it must be destroyed
+  // before this test exits to avoid holding on to |sync_controller_|.
+  @autoreleasepool {
+    id data_source = OCMProtocolMock(@protocol(CWVSyncControllerDataSource));
+
+    [[data_source expect]
+                 syncController:sync_controller_
+        getAccessTokenForScopes:[OCMArg checkWithBlock:^BOOL(NSArray* scopes) {
+          return [scopes containsObject:@"scope1.chromium.org"] &&
+                 [scopes containsObject:@"scope2.chromium.org"];
+        }]
+              completionHandler:[OCMArg any]];
+
+    CWVIdentity* identity =
+        [[CWVIdentity alloc] initWithEmail:@"johndoe@chromium.org"
+                                  fullName:@"John Doe"
+                                    gaiaID:@"1337"];
+    [sync_controller_ startSyncWithIdentity:identity dataSource:data_source];
+
+    std::set<std::string> scopes = {"scope1.chromium.org",
+                                    "scope2.chromium.org"};
+    ProfileOAuth2TokenServiceIOSProvider::AccessTokenCallback callback;
+    [sync_controller_ fetchAccessTokenForScopes:scopes callback:callback];
+
+    [data_source verify];
+  }
+}
+
+}  // namespace ios_web_view
diff --git a/media/base/android/android_cdm_factory.cc b/media/base/android/android_cdm_factory.cc
index 2da000b..87f1755c 100644
--- a/media/base/android/android_cdm_factory.cc
+++ b/media/base/android/android_cdm_factory.cc
@@ -55,7 +55,7 @@
   // Bound |cdm_created_cb| so we always fire it asynchronously.
   CdmCreatedCB bound_cdm_created_cb = BindToCurrentLoop(cdm_created_cb);
 
-  if (security_origin.unique()) {
+  if (security_origin.opaque()) {
     bound_cdm_created_cb.Run(nullptr, "Invalid origin.");
     return;
   }
diff --git a/media/base/android/media_drm_bridge_factory.cc b/media/base/android/media_drm_bridge_factory.cc
index 90ac867..024449d30 100644
--- a/media/base/android/media_drm_bridge_factory.cc
+++ b/media/base/android/media_drm_bridge_factory.cc
@@ -39,7 +39,7 @@
     const CdmCreatedCB& cdm_created_cb) {
   DCHECK(MediaDrmBridge::IsKeySystemSupported(key_system));
   DCHECK(MediaDrmBridge::IsAvailable());
-  DCHECK(!security_origin.unique());
+  DCHECK(!security_origin.opaque());
   DCHECK(scheme_uuid_.empty()) << "This factory can only be used once.";
 
   scheme_uuid_ = MediaDrmBridge::GetUUID(key_system);
diff --git a/media/cdm/cdm_adapter_factory.cc b/media/cdm/cdm_adapter_factory.cc
index 997dd987..1118ce8f 100644
--- a/media/cdm/cdm_adapter_factory.cc
+++ b/media/cdm/cdm_adapter_factory.cc
@@ -31,7 +31,7 @@
     const CdmCreatedCB& cdm_created_cb) {
   DVLOG(1) << __func__ << ": key_system=" << key_system;
 
-  if (security_origin.unique()) {
+  if (security_origin.opaque()) {
     LOG(ERROR) << "Invalid Origin: " << security_origin;
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(cdm_created_cb, nullptr, "Invalid origin."));
diff --git a/media/cdm/default_cdm_factory.cc b/media/cdm/default_cdm_factory.cc
index da698c3..8d818cf 100644
--- a/media/cdm/default_cdm_factory.cc
+++ b/media/cdm/default_cdm_factory.cc
@@ -41,7 +41,7 @@
     const SessionKeysChangeCB& session_keys_change_cb,
     const SessionExpirationUpdateCB& session_expiration_update_cb,
     const CdmCreatedCB& cdm_created_cb) {
-  if (security_origin.unique()) {
+  if (security_origin.opaque()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(cdm_created_cb, nullptr, "Invalid origin."));
     return;
diff --git a/media/formats/mp4/avc.cc b/media/formats/mp4/avc.cc
index 235795f7..99a0b4e2 100644
--- a/media/formats/mp4/avc.cc
+++ b/media/formats/mp4/avc.cc
@@ -331,10 +331,11 @@
 
 AVCBitstreamConverter::~AVCBitstreamConverter() = default;
 
-bool AVCBitstreamConverter::ConvertFrame(
+bool AVCBitstreamConverter::ConvertAndAnalyzeFrame(
     std::vector<uint8_t>* frame_buf,
     bool is_keyframe,
-    std::vector<SubsampleEntry>* subsamples) const {
+    std::vector<SubsampleEntry>* subsamples,
+    AnalysisResult* analysis_result) const {
   // Convert the AVC NALU length fields to Annex B headers, as expected by
   // decoding libraries. Since this may enlarge the size of the buffer, we also
   // update the clear byte count for each subsample if encryption is used to
@@ -343,7 +344,13 @@
   RCHECK(AVC::ConvertFrameToAnnexB(avc_config_->length_size, frame_buf,
                                    subsamples));
 
-  if (is_keyframe) {
+  // |is_keyframe| may be incorrect. Analyze the frame to see if it is a
+  // keyframe. |is_keyframe| will be used if the analysis is inconclusive.
+  // Also, provide the analysis result to the caller via out parameter
+  // |analysis_result|.
+  *analysis_result = Analyze(frame_buf, subsamples);
+
+  if (analysis_result->is_keyframe.value_or(is_keyframe)) {
     // If this is a keyframe, we (re-)inject SPS and PPS headers at the start of
     // a frame. If subsample info is present, we also update the clear byte
     // count for that first subsample.
diff --git a/media/formats/mp4/avc.h b/media/formats/mp4/avc.h
index 444d219..e83f561 100644
--- a/media/formats/mp4/avc.h
+++ b/media/formats/mp4/avc.h
@@ -80,16 +80,16 @@
 #endif  // BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
 
   // BitstreamConverter interface
-  bool ConvertFrame(std::vector<uint8_t>* frame_buf,
-                    bool is_keyframe,
-                    std::vector<SubsampleEntry>* subsamples) const override;
-
-  AnalysisResult Analyze(
-      std::vector<uint8_t>* frame_buf,
-      std::vector<SubsampleEntry>* subsamples) const override;
+  bool ConvertAndAnalyzeFrame(std::vector<uint8_t>* frame_buf,
+                              bool is_keyframe,
+                              std::vector<SubsampleEntry>* subsamples,
+                              AnalysisResult* analysis_result) const override;
 
  private:
   ~AVCBitstreamConverter() override;
+  AnalysisResult Analyze(
+      std::vector<uint8_t>* frame_buf,
+      std::vector<SubsampleEntry>* subsamples) const override;
   std::unique_ptr<AVCDecoderConfigurationRecord> avc_config_;
 
 #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
diff --git a/media/formats/mp4/bitstream_converter.h b/media/formats/mp4/bitstream_converter.h
index 5d3c360..b6ad4a47 100644
--- a/media/formats/mp4/bitstream_converter.h
+++ b/media/formats/mp4/bitstream_converter.h
@@ -47,9 +47,17 @@
   // of input frame are encrypted and should update |subsamples| if necessary,
   // to make sure it correctly describes the converted output frame. See
   // SubsampleEntry definition in media/base/decrypt_config.h for more info.
-  virtual bool ConvertFrame(std::vector<uint8_t>* frame_buf,
-                            bool is_keyframe,
-                            std::vector<SubsampleEntry>* subsamples) const = 0;
+  // |analysis_result| is an output parameter that contains the AnalysisResult
+  // found during conversion.
+  virtual bool ConvertAndAnalyzeFrame(
+      std::vector<uint8_t>* frame_buf,
+      bool is_keyframe,
+      std::vector<SubsampleEntry>* subsamples,
+      AnalysisResult* analysis_result) const = 0;
+
+ protected:
+  friend class base::RefCountedThreadSafe<BitstreamConverter>;
+  virtual ~BitstreamConverter();
 
   // Inspects an already converted frame for conformance. If conformant,
   // inspects further to see if the converted frame appears to be a keyframe.
@@ -57,10 +65,6 @@
   virtual AnalysisResult Analyze(
       std::vector<uint8_t>* frame_buf,
       std::vector<SubsampleEntry>* subsamples) const = 0;
-
- protected:
-  friend class base::RefCountedThreadSafe<BitstreamConverter>;
-  virtual ~BitstreamConverter();
 };
 
 }  // namespace mp4
diff --git a/media/formats/mp4/hevc.cc b/media/formats/mp4/hevc.cc
index 8e8c8ea..b2f606db 100644
--- a/media/formats/mp4/hevc.cc
+++ b/media/formats/mp4/hevc.cc
@@ -236,14 +236,20 @@
 HEVCBitstreamConverter::~HEVCBitstreamConverter() {
 }
 
-bool HEVCBitstreamConverter::ConvertFrame(
+bool HEVCBitstreamConverter::ConvertAndAnalyzeFrame(
     std::vector<uint8_t>* frame_buf,
     bool is_keyframe,
-    std::vector<SubsampleEntry>* subsamples) const {
+    std::vector<SubsampleEntry>* subsamples,
+    AnalysisResult* analysis_result) const {
   RCHECK(AVC::ConvertFrameToAnnexB(hevc_config_->lengthSizeMinusOne + 1,
                                    frame_buf, subsamples));
+  // |is_keyframe| may be incorrect. Analyze the frame to see if it is a
+  // keyframe. |is_keyframe| will be used if the analysis is inconclusive.
+  // Also, provide the analysis result to the caller via out parameter
+  // |analysis_result|.
+  *analysis_result = Analyze(frame_buf, subsamples);
 
-  if (is_keyframe) {
+  if (analysis_result->is_keyframe.value_or(is_keyframe)) {
     // If this is a keyframe, we (re-)inject HEVC params headers at the start of
     // a frame. If subsample info is present, we also update the clear byte
     // count for that first subsample.
diff --git a/media/formats/mp4/hevc.h b/media/formats/mp4/hevc.h
index 87ec4ff..7ec661a 100644
--- a/media/formats/mp4/hevc.h
+++ b/media/formats/mp4/hevc.h
@@ -95,16 +95,16 @@
       std::unique_ptr<HEVCDecoderConfigurationRecord> hevc_config);
 
   // BitstreamConverter interface
-  bool ConvertFrame(std::vector<uint8_t>* frame_buf,
-                    bool is_keyframe,
-                    std::vector<SubsampleEntry>* subsamples) const override;
-
-  AnalysisResult Analyze(
-      std::vector<uint8_t>* frame_buf,
-      std::vector<SubsampleEntry>* subsamples) const override;
+  bool ConvertAndAnalyzeFrame(std::vector<uint8_t>* frame_buf,
+                              bool is_keyframe,
+                              std::vector<SubsampleEntry>* subsamples,
+                              AnalysisResult* analysis_result) const override;
 
  private:
   ~HEVCBitstreamConverter() override;
+  AnalysisResult Analyze(
+      std::vector<uint8_t>* frame_buf,
+      std::vector<SubsampleEntry>* subsamples) const override;
   std::unique_ptr<HEVCDecoderConfigurationRecord> hevc_config_;
 };
 
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index 14c437af..5337c1ff 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -809,15 +809,15 @@
         runs_->video_description().video_codec == kCodecHEVC ||
         runs_->video_description().video_codec == kCodecDolbyVision) {
       DCHECK(runs_->video_description().frame_bitstream_converter);
-      if (!runs_->video_description().frame_bitstream_converter->ConvertFrame(
-              &frame_buf, is_keyframe, &subsamples)) {
+      BitstreamConverter::AnalysisResult analysis;
+      if (!runs_->video_description()
+               .frame_bitstream_converter->ConvertAndAnalyzeFrame(
+                   &frame_buf, is_keyframe, &subsamples, &analysis)) {
         MEDIA_LOG(ERROR, media_log_)
             << "Failed to prepare video sample for decode";
         return ParseResult::kError;
       }
-      BitstreamConverter::AnalysisResult analysis =
-          runs_->video_description().frame_bitstream_converter->Analyze(
-              &frame_buf, &subsamples);
+
       // If conformance analysis was not actually performed, assume the frame is
       // conformant.  If it was performed and found to be non-conformant, log
       // it.
diff --git a/media/mojo/clients/mojo_cdm_factory.cc b/media/mojo/clients/mojo_cdm_factory.cc
index 63564aa..4250576 100644
--- a/media/mojo/clients/mojo_cdm_factory.cc
+++ b/media/mojo/clients/mojo_cdm_factory.cc
@@ -38,7 +38,7 @@
     const CdmCreatedCB& cdm_created_cb) {
   DVLOG(2) << __func__ << ": " << key_system;
 
-  if (security_origin.unique()) {
+  if (security_origin.opaque()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(cdm_created_cb, nullptr, "Invalid origin."));
     return;
diff --git a/net/url_request/url_fetcher_core.cc b/net/url_request/url_fetcher_core.cc
index 92fce88..b5a587e 100644
--- a/net/url_request/url_fetcher_core.cc
+++ b/net/url_request/url_fetcher_core.cc
@@ -574,7 +574,7 @@
   request_->SetReferrer(referrer_);
   request_->set_referrer_policy(referrer_policy_);
   request_->set_site_for_cookies(initiator_.has_value() &&
-                                         !initiator_.value().unique()
+                                         !initiator_.value().opaque()
                                      ? initiator_.value().GetURL()
                                      : original_url_);
   request_->set_initiator(initiator_);
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 3b3a7e2..825a96b3 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -479,7 +479,7 @@
 
 void URLRequest::set_initiator(const base::Optional<url::Origin>& initiator) {
   DCHECK(!is_pending_);
-  DCHECK(!initiator.has_value() || initiator.value().unique() ||
+  DCHECK(!initiator.has_value() || initiator.value().opaque() ||
          initiator.value().GetURL().is_valid());
   initiator_ = initiator;
 }
diff --git a/pdf/pdfium/pdfium_print.cc b/pdf/pdfium/pdfium_print.cc
index 8645c558..b440ed2 100644
--- a/pdf/pdfium/pdfium_print.cc
+++ b/pdf/pdfium/pdfium_print.cc
@@ -174,31 +174,27 @@
 // Performs N-up PDF generation for |doc| based on |pages_per_sheet| and
 // the parameters in |print_settings|.
 // On success, returns the N-up version of |doc|. On failure, returns nullptr.
-ScopedFPDFDocument NupPdfToPdf(FPDF_DOCUMENT doc,
+ScopedFPDFDocument NupPdfToPdf(ScopedFPDFDocument doc,
                                uint32_t pages_per_sheet,
                                const PP_PrintSettings_Dev& print_settings) {
   DCHECK(doc);
   DCHECK(ShouldDoNup(pages_per_sheet));
 
-  PP_Size page_size = print_settings.paper_size;
-
   printing::NupParameters nup_params;
-  bool is_landscape = PDFiumPrint::IsSourcePdfLandscape(doc);
+  bool is_landscape = PDFiumPrint::IsSourcePdfLandscape(doc.get());
   nup_params.SetParameters(pages_per_sheet, is_landscape);
 
-  // Import n pages to one.
+  PP_Size page_size = print_settings.paper_size;
   bool paper_is_landscape = page_size.width > page_size.height;
   if (nup_params.landscape() != paper_is_landscape)
     std::swap(page_size.width, page_size.height);
 
-  ScopedFPDFDocument output_doc_nup(FPDF_ImportNPagesToOne(
-      doc, page_size.width, page_size.height, nup_params.num_pages_on_x_axis(),
-      nup_params.num_pages_on_y_axis()));
-  if (output_doc_nup) {
-    FitContentsToPrintableAreaIfRequired(output_doc_nup.get(), 1.0f,
-                                         print_settings);
-  }
-  return output_doc_nup;
+  ScopedFPDFDocument nup_doc(FPDF_ImportNPagesToOne(
+      doc.get(), page_size.width, page_size.height,
+      nup_params.num_pages_on_x_axis(), nup_params.num_pages_on_y_axis()));
+  if (nup_doc)
+    FitContentsToPrintableAreaIfRequired(nup_doc.get(), 1.0f, print_settings);
+  return nup_doc;
 }
 
 int GetBlockForJpeg(void* param,
@@ -311,19 +307,17 @@
     return nullptr;
   }
 
-  uint32_t pages_per_sheet = pdf_print_settings.pages_per_sheet;
-  if (ShouldDoNup(pages_per_sheet)) {
-    if (!FlattenPrintData(output_doc.get()))
-      return nullptr;
-    return NupPdfToPdf(output_doc.get(), pages_per_sheet, print_settings);
-  }
-
   double scale_factor = pdf_print_settings.scale_factor / 100.0;
   FitContentsToPrintableAreaIfRequired(output_doc.get(), scale_factor,
                                        print_settings);
   if (!FlattenPrintData(output_doc.get()))
     return nullptr;
-  return output_doc;
+
+  uint32_t pages_per_sheet = pdf_print_settings.pages_per_sheet;
+  if (!ShouldDoNup(pages_per_sheet))
+    return output_doc;
+
+  return NupPdfToPdf(std::move(output_doc), pages_per_sheet, print_settings);
 }
 
 ScopedFPDFDocument PDFiumPrint::CreateRasterPdf(
diff --git a/printing/backend/printing_restrictions.cc b/printing/backend/printing_restrictions.cc
index a9b41e4..b284818a 100644
--- a/printing/backend/printing_restrictions.cc
+++ b/printing/backend/printing_restrictions.cc
@@ -7,6 +7,7 @@
 namespace printing {
 
 const char kAllowedColorModes[] = "allowedColorModes";
+const char kAllowedDuplexModes[] = "allowedDuplexModes";
 const char kPageWidthUm[] = "WidthUm";
 const char kPageHeightUm[] = "HeightUm";
 
@@ -52,6 +53,9 @@
   if (mode_name == "any")
     return DuplexModeRestriction::kNone;
 
+  if (mode_name == "simplex")
+    return DuplexModeRestriction::kSimplex;
+
   if (mode_name == "duplex")
     return DuplexModeRestriction::kDuplex;
 
diff --git a/printing/backend/printing_restrictions.h b/printing/backend/printing_restrictions.h
index fd818ad..d9ef7fef 100644
--- a/printing/backend/printing_restrictions.h
+++ b/printing/backend/printing_restrictions.h
@@ -49,6 +49,7 @@
 // Must coincide with the name of field in |print_preview.Policies| in
 // chrome/browser/resources/print_preview/native_layer.js
 PRINTING_EXPORT extern const char kAllowedColorModes[];
+PRINTING_EXPORT extern const char kAllowedDuplexModes[];
 
 // Dictionary keys to be used with |kPrintingAllowedPageSizes| and
 // |kPrintingSizeDefault| policies.
diff --git a/printing/page_setup.cc b/printing/page_setup.cc
index fb342d5..3a856545 100644
--- a/printing/page_setup.cc
+++ b/printing/page_setup.cc
@@ -10,6 +10,29 @@
 
 namespace printing {
 
+namespace {
+
+// Checks whether |printable_area| can be used to form a valid symmetrical
+// printable area, so that margin_left equals margin_right, and margin_top
+// equals margin_bottom.  For example if
+// printable_area.x() * 2 >= page_size.width(), then the
+// content_width = page_size.width() - 2 * printable_area.x() would be zero or
+// negative, which is invalid.
+// |page_size| is the physical page size that includes margins.
+bool IsValidPrintableArea(const gfx::Size& page_size,
+                          const gfx::Rect& printable_area) {
+  return !printable_area.IsEmpty() && printable_area.x() >= 0 &&
+         printable_area.y() >= 0 &&
+         printable_area.right() <= page_size.width() &&
+         printable_area.bottom() <= page_size.height() &&
+         printable_area.x() * 2 < page_size.width() &&
+         printable_area.y() * 2 < page_size.height() &&
+         printable_area.right() * 2 > page_size.width() &&
+         printable_area.bottom() * 2 > page_size.height();
+}
+
+}  // namespace
+
 PageMargins::PageMargins()
     : header(0),
       footer(0),
@@ -45,6 +68,26 @@
 
 PageSetup::~PageSetup() = default;
 
+// static
+gfx::Rect PageSetup::GetSymmetricalPrintableArea(
+    const gfx::Size& page_size,
+    const gfx::Rect& printable_area) {
+  if (!IsValidPrintableArea(page_size, printable_area))
+    return gfx::Rect();
+
+  int left_right_margin =
+      std::max(printable_area.x(), page_size.width() - printable_area.right());
+  int top_bottom_margin = std::max(
+      printable_area.y(), page_size.height() - printable_area.bottom());
+  int width = page_size.width() - 2 * left_right_margin;
+  int height = page_size.height() - 2 * top_bottom_margin;
+
+  gfx::Rect symmetrical_printable_area = gfx::Rect(page_size);
+  symmetrical_printable_area.ClampToCenteredSize(gfx::Size(width, height));
+
+  return symmetrical_printable_area;
+}
+
 void PageSetup::Clear() {
   physical_size_.SetSize(0, 0);
   printable_area_.SetRect(0, 0, 0, 0);
diff --git a/printing/page_setup.h b/printing/page_setup.h
index 4126bea..f02ee056 100644
--- a/printing/page_setup.h
+++ b/printing/page_setup.h
@@ -39,6 +39,10 @@
   PageSetup(const PageSetup& other);
   ~PageSetup();
 
+  // Gets a symmetrical printable area.
+  static gfx::Rect GetSymmetricalPrintableArea(const gfx::Size& page_size,
+                                               const gfx::Rect& printable_area);
+
   void Clear();
 
   // Equality operator.
diff --git a/printing/page_setup_unittest.cc b/printing/page_setup_unittest.cc
index 50aa639f..83b1d83 100644
--- a/printing/page_setup_unittest.cc
+++ b/printing/page_setup_unittest.cc
@@ -11,13 +11,15 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace printing {
+
 TEST(PageSetupTest, Random) {
   time_t seed = time(NULL);
   int kMax = 10;
   srand(static_cast<unsigned>(seed));
 
   // Margins.
-  printing::PageMargins margins;
+  PageMargins margins;
   margins.header = rand() % kMax;
   margins.footer = rand() % kMax;
   margins.left = rand() % kMax;
@@ -35,12 +37,12 @@
                             printable_area.y());
 
   // Make the calculations.
-  printing::PageSetup setup;
+  PageSetup setup;
   setup.SetRequestedMargins(margins);
   setup.Init(page_size, printable_area, kTextHeight);
 
   // Calculate the effective margins.
-  printing::PageMargins effective_margins;
+  PageMargins effective_margins;
   effective_margins.header = std::max(margins.header, printable_area.y());
   effective_margins.left = std::max(margins.left, printable_area.x());
   effective_margins.top = std::max(margins.top,
@@ -101,7 +103,7 @@
 
 TEST(PageSetupTest, HardCoded) {
   // Margins.
-  printing::PageMargins margins;
+  PageMargins margins;
   margins.header = 2;
   margins.footer = 2;
   margins.left = 4;
@@ -115,12 +117,12 @@
   gfx::Rect printable_area(3, 3, 94, 94);
 
   // Make the calculations.
-  printing::PageSetup setup;
+  PageSetup setup;
   setup.SetRequestedMargins(margins);
   setup.Init(page_size, printable_area, kTextHeight);
 
   // Calculate the effective margins.
-  printing::PageMargins effective_margins;
+  PageMargins effective_margins;
   effective_margins.header = 3;
   effective_margins.left = 4;
   effective_margins.top = 6;
@@ -165,7 +167,7 @@
 }
 
 TEST(PageSetupTest, OutOfRangeMargins) {
-  printing::PageMargins margins;
+  PageMargins margins;
   margins.header = 0;
   margins.footer = 0;
   margins.left = -10;
@@ -177,7 +179,7 @@
   gfx::Rect printable_area(1, 2, 96, 94);
 
   // Make the calculations.
-  printing::PageSetup setup;
+  PageSetup setup;
   setup.SetRequestedMargins(margins);
   setup.Init(page_size, printable_area, 0);
 
@@ -195,7 +197,7 @@
 
 TEST(PageSetupTest, FlipOrientation) {
   // Margins.
-  printing::PageMargins margins;
+  PageMargins margins;
   margins.header = 2;
   margins.footer = 3;
   margins.left = 4;
@@ -209,7 +211,7 @@
   gfx::Rect printable_area(8, 9, 92, 50);
 
   // Make the calculations.
-  printing::PageSetup setup;
+  PageSetup setup;
   setup.SetRequestedMargins(margins);
   setup.Init(page_size, printable_area, kTextHeight);
 
@@ -274,3 +276,34 @@
   EXPECT_EQ(setup.effective_margins().right, 6);
   EXPECT_EQ(setup.effective_margins().bottom, 7);
 }
+
+TEST(PageSetupTest, GetSymmetricalPrintableArea) {
+  gfx::Rect printable_area = PageSetup::GetSymmetricalPrintableArea(
+      gfx::Size(612, 792), gfx::Rect(0, 0, 560, 750));
+  EXPECT_EQ(gfx::Rect(52, 42, 508, 708), printable_area);
+
+  printable_area = PageSetup::GetSymmetricalPrintableArea(
+      gfx::Size(612, 792), gfx::Rect(50, 60, 550, 700));
+  EXPECT_EQ(gfx::Rect(50, 60, 512, 672), printable_area);
+
+  printable_area = PageSetup::GetSymmetricalPrintableArea(
+      gfx::Size(612, 792), gfx::Rect(-1, 60, 520, 700));
+  EXPECT_EQ(gfx::Rect(), printable_area);
+  printable_area = PageSetup::GetSymmetricalPrintableArea(
+      gfx::Size(612, 792), gfx::Rect(50, -1, 520, 700));
+  EXPECT_EQ(gfx::Rect(), printable_area);
+  printable_area = PageSetup::GetSymmetricalPrintableArea(
+      gfx::Size(612, 792), gfx::Rect(100, 60, 520, 700));
+  EXPECT_EQ(gfx::Rect(), printable_area);
+  printable_area = PageSetup::GetSymmetricalPrintableArea(
+      gfx::Size(612, 792), gfx::Rect(50, 100, 520, 700));
+  EXPECT_EQ(gfx::Rect(), printable_area);
+  printable_area = PageSetup::GetSymmetricalPrintableArea(
+      gfx::Size(612, 792), gfx::Rect(400, 60, 212, 700));
+  EXPECT_EQ(gfx::Rect(), printable_area);
+  printable_area = PageSetup::GetSymmetricalPrintableArea(
+      gfx::Size(612, 792), gfx::Rect(40, 600, 212, 192));
+  EXPECT_EQ(gfx::Rect(), printable_area);
+}
+
+}  // namespace printing
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
index 754fe5a..b00a88cf 100644
--- a/sandbox/linux/BUILD.gn
+++ b/sandbox/linux/BUILD.gn
@@ -417,7 +417,6 @@
 source_set("sandbox_services_headers") {
   sources = [
     "system_headers/arm64_linux_syscalls.h",
-    "system_headers/arm64_linux_ucontext.h",
     "system_headers/arm_linux_syscalls.h",
     "system_headers/arm_linux_ucontext.h",
     "system_headers/i386_linux_ucontext.h",
@@ -429,12 +428,9 @@
     "system_headers/linux_time.h",
     "system_headers/linux_ucontext.h",
     "system_headers/mips64_linux_syscalls.h",
-    "system_headers/mips64_linux_ucontext.h",
     "system_headers/mips_linux_syscalls.h",
-    "system_headers/mips_linux_ucontext.h",
     "system_headers/x86_32_linux_syscalls.h",
     "system_headers/x86_64_linux_syscalls.h",
-    "system_headers/x86_64_linux_ucontext.h",
   ]
 }
 
diff --git a/sandbox/linux/system_headers/arm64_linux_ucontext.h b/sandbox/linux/system_headers/arm64_linux_ucontext.h
deleted file mode 100644
index 48303ba..0000000
--- a/sandbox/linux/system_headers/arm64_linux_ucontext.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_UCONTEXT_H_
-#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_UCONTEXT_H_
-
-#if !defined(__BIONIC_HAVE_UCONTEXT_T)
-#include <asm/sigcontext.h>
-#include <signal.h>
-#include <stdint.h>
-// We also need greg_t for the sandbox, include it in this header as well.
-typedef uint64_t greg_t;
-
-struct ucontext_t {
-  unsigned long uc_flags;
-  struct ucontext* uc_link;
-  stack_t uc_stack;
-  sigset_t uc_sigmask;
-  /* glibc uses a 1024-bit sigset_t */
-  uint8_t unused[1024 / 8 - sizeof(sigset_t)];
-  /* last for future expansion */
-  struct sigcontext uc_mcontext;
-};
-
-#else
-#include <sys/ucontext.h>
-#endif  // __BIONIC_HAVE_UCONTEXT_T
-
-#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/arm_linux_ucontext.h b/sandbox/linux/system_headers/arm_linux_ucontext.h
index 35208fa..2b2090e 100644
--- a/sandbox/linux/system_headers/arm_linux_ucontext.h
+++ b/sandbox/linux/system_headers/arm_linux_ucontext.h
@@ -7,10 +7,6 @@
 
 #include <stddef.h>
 
-#if !defined(__BIONIC_HAVE_UCONTEXT_T)
-#if !defined(__native_client_nonsfi__)
-#include <asm/sigcontext.h>
-#else
 // In PNaCl toolchain, sigcontext and stack_t is not defined. So here declare
 // them.
 struct sigcontext {
@@ -43,7 +39,6 @@
   size_t ss_size;
 } stack_t;
 
-#endif
 
 // We also need greg_t for the sandbox, include it in this header as well.
 typedef unsigned long greg_t;
@@ -62,8 +57,4 @@
   unsigned long uc_regspace[128] __attribute__((__aligned__(8)));
 } ucontext_t;
 
-#else
-#include <sys/ucontext.h>
-#endif  // __BIONIC_HAVE_UCONTEXT_T
-
 #endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/i386_linux_ucontext.h b/sandbox/linux/system_headers/i386_linux_ucontext.h
index f438033..1a7b975 100644
--- a/sandbox/linux/system_headers/i386_linux_ucontext.h
+++ b/sandbox/linux/system_headers/i386_linux_ucontext.h
@@ -8,22 +8,15 @@
 #include <stddef.h>
 #include <stdint.h>
 
-// We do something compatible with glibc. Hopefully, at some point Android will
-// provide that for us, and __BIONIC_HAVE_UCONTEXT_T should be defined.
 // This is mostly copied from breakpad (common/android/include/sys/ucontext.h),
 // except we do use sigset_t for uc_sigmask instead of a custom type.
 
-#if !defined(__BIONIC_HAVE_UCONTEXT_T)
-#if !defined(__native_client_nonsfi__)
-#include <asm/sigcontext.h>
-#else
 // In PNaCl toolchain, sigcontext is not defined. So here declare it.
 typedef struct sigaltstack {
   void* ss_sp;
   int ss_flags;
   size_t ss_size;
 } stack_t;
-#endif
 
 /* 80-bit floating-point register */
 struct _libc_fpreg {
@@ -89,8 +82,4 @@
   struct _libc_fpstate __fpregs_mem;
 } ucontext_t;
 
-#else
-#include <sys/ucontext.h>
-#endif  // __BIONIC_HAVE_UCONTEXT_T
-
 #endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/linux_signal.h b/sandbox/linux/system_headers/linux_signal.h
index 5ac4fdb..e4fd3461 100644
--- a/sandbox/linux/system_headers/linux_signal.h
+++ b/sandbox/linux/system_headers/linux_signal.h
@@ -108,11 +108,6 @@
 
 typedef siginfo_t LinuxSigInfo;
 
-#if defined(__ANDROID__)
-// Android's signal.h doesn't define ucontext etc.
-#include "sandbox/linux/system_headers/linux_ucontext.h"
-#endif  // defined(__ANDROID__)
-
 #endif  // !defined(__native_client_nonsfi__)
 
 // struct sigset_t is different size in PNaCl from the Linux's.
diff --git a/sandbox/linux/system_headers/linux_ucontext.h b/sandbox/linux/system_headers/linux_ucontext.h
index e97d727..22ce780 100644
--- a/sandbox/linux/system_headers/linux_ucontext.h
+++ b/sandbox/linux/system_headers/linux_ucontext.h
@@ -5,26 +5,18 @@
 #ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
 #define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
 
-#if defined(__ANDROID__) || defined(__native_client_nonsfi__)
+#if defined(__native_client_nonsfi__)
 
 #if defined(__arm__)
 #include "sandbox/linux/system_headers/arm_linux_ucontext.h"
 #elif defined(__i386__)
 #include "sandbox/linux/system_headers/i386_linux_ucontext.h"
-#elif defined(__x86_64__)
-#include "sandbox/linux/system_headers/x86_64_linux_ucontext.h"
-#elif defined(__mips32__)
-#include "sandbox/linux/system_headers/mips_linux_ucontext.h"
-#elif defined(__mips64__)
-#include "sandbox/linux/system_headers/mips64_linux_ucontext.h"
-#elif defined(__aarch64__)
-#include "sandbox/linux/system_headers/arm64_linux_ucontext.h"
 #else
-#error "No support for your architecture in Android or PNaCl header"
+#error "No support for your architecture in PNaCl header"
 #endif
 
-#else  // defined(__ANDROID__) || defined(__native_client_nonsfi__)
-#error "The header file included on non Android and non PNaCl."
-#endif  // defined(__ANDROID__) || defined(__native_client_nonsfi__)
+#else  // defined(__native_client_nonsfi__)
+#error "The header file included on non PNaCl."
+#endif  // defined(__native_client_nonsfi__)
 
 #endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/mips64_linux_ucontext.h b/sandbox/linux/system_headers/mips64_linux_ucontext.h
deleted file mode 100644
index 3d10479..0000000
--- a/sandbox/linux/system_headers/mips64_linux_ucontext.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_UCONTEXT_H_
-#define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_UCONTEXT_H_
-
-#include <stdint.h>
-
-// This is mostly copied from breakpad (common/android/include/sys/ucontext.h),
-// except we do use sigset_t for uc_sigmask instead of a custom type.
-#if !defined(__BIONIC_HAVE_UCONTEXT_T)
-// Ensure that 'stack_t' is defined.
-#include <asm/signal.h>
-
-// We also need greg_t for the sandbox, include it in this header as well.
-typedef unsigned long greg_t;
-
-typedef struct {
-  uint64_t gregs[32];
-  uint64_t fpregs[32];
-  uint64_t mdhi;
-  uint64_t hi1;
-  uint64_t hi2;
-  uint64_t hi3;
-  uint64_t mdlo;
-  uint64_t lo1;
-  uint64_t lo2;
-  uint64_t lo3;
-  uint64_t pc;
-  uint32_t fpc_csr;
-  uint32_t used_math;
-  uint32_t dsp;
-  uint32_t reserved;
-} mcontext_t;
-
-typedef struct ucontext {
-  uint32_t uc_flags;
-  struct ucontext* uc_link;
-  stack_t uc_stack;
-  mcontext_t uc_mcontext;
-  sigset_t uc_sigmask;
-  // Other fields are not used by Google Breakpad. Don't define them.
-} ucontext_t;
-
-#else
-#include <sys/ucontext.h>
-#endif  // __BIONIC_HAVE_UCONTEXT_T
-
-#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/mips_linux_ucontext.h b/sandbox/linux/system_headers/mips_linux_ucontext.h
deleted file mode 100644
index 774bf312..0000000
--- a/sandbox/linux/system_headers/mips_linux_ucontext.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_UCONTEXT_H_
-#define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_UCONTEXT_H_
-
-#include <stdint.h>
-
-// This is mostly copied from breakpad (common/android/include/sys/ucontext.h),
-// except we do use sigset_t for uc_sigmask instead of a custom type.
-#if !defined(__BIONIC_HAVE_UCONTEXT_T)
-// Ensure that 'stack_t' is defined.
-#include <asm/signal.h>
-
-// We also need greg_t for the sandbox, include it in this header as well.
-typedef unsigned long greg_t;
-
-typedef struct {
-  uint32_t regmask;
-  uint32_t status;
-  uint64_t pc;
-  uint64_t gregs[32];
-  uint64_t fpregs[32];
-  uint32_t acx;
-  uint32_t fpc_csr;
-  uint32_t fpc_eir;
-  uint32_t used_math;
-  uint32_t dsp;
-  uint64_t mdhi;
-  uint64_t mdlo;
-  uint32_t hi1;
-  uint32_t lo1;
-  uint32_t hi2;
-  uint32_t lo2;
-  uint32_t hi3;
-  uint32_t lo3;
-} mcontext_t;
-
-typedef struct ucontext {
-  uint32_t uc_flags;
-  struct ucontext* uc_link;
-  stack_t uc_stack;
-  mcontext_t uc_mcontext;
-  sigset_t uc_sigmask;
-  // Other fields are not used by Google Breakpad. Don't define them.
-} ucontext_t;
-
-#else
-#include <sys/ucontext.h>
-#endif  // __BIONIC_HAVE_UCONTEXT_T
-
-#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/x86_64_linux_ucontext.h b/sandbox/linux/system_headers/x86_64_linux_ucontext.h
deleted file mode 100644
index 1f1abe6..0000000
--- a/sandbox/linux/system_headers/x86_64_linux_ucontext.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_UCONTEXT_H_
-#define SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_UCONTEXT_H_
-
-#include <stdint.h>
-
-// We do something compatible with glibc. Hopefully, at some point Android will
-// provide that for us, and __BIONIC_HAVE_UCONTEXT_T should be defined.
-// Spec:
-// http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-AMD64/LSB-Core-AMD64/libc-ddefs.html#AEN5668
-
-#if !defined(__BIONIC_HAVE_UCONTEXT_T)
-#include <asm/sigcontext.h>
-
-struct _libc_fpxreg {
-  unsigned short significand[4];
-  unsigned short exponent;
-  unsigned short padding[3];
-};
-
-struct _libc_xmmreg {
-  uint32_t element[4];
-};
-
-struct _libc_fpstate {
-  uint16_t cwd;
-  uint16_t swd;
-  uint16_t twd;
-  uint16_t fop;
-  uint64_t rip;
-  uint64_t rdp;
-  uint32_t mxcsr;
-  uint32_t mxcsr_mask;
-  struct _libc_fpxreg _st[8];
-  struct _libc_xmmreg _xmm[16];
-  uint32_t padding[24];
-};
-
-typedef uint64_t greg_t;
-
-typedef struct {
-  greg_t gregs[23];
-  struct _libc_fpstate* fpregs;
-  unsigned long __reserved1[8];
-} mcontext_t;
-
-enum {
-  REG_R8 = 0,
-  REG_R9,
-  REG_R10,
-  REG_R11,
-  REG_R12,
-  REG_R13,
-  REG_R14,
-  REG_R15,
-  REG_RDI,
-  REG_RSI,
-  REG_RBP,
-  REG_RBX,
-  REG_RDX,
-  REG_RAX,
-  REG_RCX,
-  REG_RSP,
-  REG_RIP,
-  REG_EFL,
-  REG_CSGSFS,
-  REG_ERR,
-  REG_TRAPNO,
-  REG_OLDMASK,
-  REG_CR2,
-  NGREG,
-};
-
-typedef struct ucontext {
-  unsigned long uc_flags;
-  struct ucontext* uc_link;
-  stack_t uc_stack;
-  mcontext_t uc_mcontext;
-  sigset_t uc_sigmask;
-  struct _libc_fpstate __fpregs_mem;
-} ucontext_t;
-
-#else
-#include <sys/ucontext.h>
-#endif  // __BIONIC_HAVE_UCONTEXT_T
-
-#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_UCONTEXT_H_
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index a89ac86..920a6fd 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -463,8 +463,8 @@
   // In the future blob URLs will not come here because there will be a
   // separate URLLoaderFactory for blobs.
   // TODO(yhirano): Remove this logic at the time.
-  if (request_.url.SchemeIsBlob() && request_.request_initiator->unique() &&
-      url::Origin::Create(request_.url).unique()) {
+  if (request_.url.SchemeIsBlob() && request_.request_initiator->opaque() &&
+      url::Origin::Create(request_.url).opaque()) {
     return;
   }
 
diff --git a/services/network/public/cpp/cors/origin_access_list.cc b/services/network/public/cpp/cors/origin_access_list.cc
index 96420a3..36b4e4a 100644
--- a/services/network/public/cpp/cors/origin_access_list.cc
+++ b/services/network/public/cpp/cors/origin_access_list.cc
@@ -49,7 +49,7 @@
 
 bool OriginAccessList::IsAllowed(const url::Origin& source_origin,
                                  const GURL& destination) const {
-  if (source_origin.unique())
+  if (source_origin.opaque())
     return false;
   std::string source = source_origin.Serialize();
   url::Origin destination_origin = url::Origin::Create(destination);
@@ -63,7 +63,7 @@
     const std::vector<mojom::CorsOriginPatternPtr>& patterns,
     PatternMap* map) {
   DCHECK(map);
-  DCHECK(!source_origin.unique());
+  DCHECK(!source_origin.opaque());
 
   std::string source = source_origin.Serialize();
   map->erase(source);
@@ -86,7 +86,7 @@
                                     bool allow_subdomains,
                                     PatternMap* map) {
   DCHECK(map);
-  DCHECK(!source_origin.unique());
+  DCHECK(!source_origin.opaque());
 
   std::string source = source_origin.Serialize();
   (*map)[source].push_back(OriginAccessEntry(
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index e0b94df..2b14077 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -171,6 +171,8 @@
 #define SK_SUPPORT_LEGACY_AAA_CHOICE
 #endif
 
+#define SK_LEGACY_COLORSPACE_XFORM_STEPS_IMPL
+
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
 /* In some places Skia can use static initializers for global initialization,
diff --git a/storage/browser/fileapi/quota/quota_backend_impl.cc b/storage/browser/fileapi/quota/quota_backend_impl.cc
index 0b71123..19236d1 100644
--- a/storage/browser/fileapi/quota/quota_backend_impl.cc
+++ b/storage/browser/fileapi/quota/quota_backend_impl.cc
@@ -40,7 +40,7 @@
                                     int64_t delta,
                                     const ReserveQuotaCallback& callback) {
   DCHECK(file_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   if (!delta) {
     callback.Run(base::File::FILE_OK, 0);
     return;
@@ -57,7 +57,7 @@
                                             FileSystemType type,
                                             int64_t size) {
   DCHECK(file_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   DCHECK_LE(0, size);
   if (!size)
     return;
@@ -68,7 +68,7 @@
                                         FileSystemType type,
                                         int64_t delta) {
   DCHECK(file_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   if (!delta)
     return;
   ReserveQuotaInternal(QuotaReservationInfo(origin, type, delta));
@@ -82,7 +82,7 @@
 void QuotaBackendImpl::IncrementDirtyCount(const url::Origin& origin,
                                            FileSystemType type) {
   DCHECK(file_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   base::FilePath path;
   if (GetUsageCachePath(origin, type, &path) != base::File::FILE_OK)
     return;
@@ -93,7 +93,7 @@
 void QuotaBackendImpl::DecrementDirtyCount(const url::Origin& origin,
                                            FileSystemType type) {
   DCHECK(file_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   base::FilePath path;
   if (GetUsageCachePath(origin, type, &path) != base::File::FILE_OK)
     return;
@@ -108,7 +108,7 @@
     int64_t usage,
     int64_t quota) {
   DCHECK(file_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!info.origin.unique());
+  DCHECK(!info.origin.opaque());
   DCHECK_LE(0, usage);
   DCHECK_LE(0, quota);
   if (status != blink::mojom::QuotaStatusCode::kOk) {
@@ -138,7 +138,7 @@
 
 void QuotaBackendImpl::ReserveQuotaInternal(const QuotaReservationInfo& info) {
   DCHECK(file_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!info.origin.unique());
+  DCHECK(!info.origin.opaque());
   DCHECK(quota_manager_proxy_.get());
   quota_manager_proxy_->NotifyStorageModified(
       storage::QuotaClient::kFileSystem, info.origin,
@@ -150,7 +150,7 @@
     FileSystemType type,
     base::FilePath* usage_file_path) {
   DCHECK(file_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   DCHECK(usage_file_path);
   base::File::Error error = base::File::FILE_OK;
   *usage_file_path =
diff --git a/storage/browser/fileapi/quota/quota_reservation_buffer.cc b/storage/browser/fileapi/quota/quota_reservation_buffer.cc
index 9aa294e0..802f054 100644
--- a/storage/browser/fileapi/quota/quota_reservation_buffer.cc
+++ b/storage/browser/fileapi/quota/quota_reservation_buffer.cc
@@ -25,7 +25,7 @@
       origin_(origin),
       type_(type),
       reserved_quota_(0) {
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   DCHECK(sequence_checker_.CalledOnValidSequence());
   reservation_manager_->IncrementDirtyCount(origin, type);
 }
@@ -101,7 +101,7 @@
     FileSystemType type,
     base::File::Error error,
     int64_t delta_unused) {
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   if (error == base::File::FILE_OK && reservation_manager) {
     reservation_manager->DecrementDirtyCount(origin, type);
     return true;
diff --git a/storage/browser/fileapi/quota/quota_reservation_manager.cc b/storage/browser/fileapi/quota/quota_reservation_manager.cc
index c00bdc9e..d8702ca 100644
--- a/storage/browser/fileapi/quota/quota_reservation_manager.cc
+++ b/storage/browser/fileapi/quota/quota_reservation_manager.cc
@@ -29,33 +29,33 @@
     FileSystemType type,
     int64_t size,
     const ReserveQuotaCallback& callback) {
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   backend_->ReserveQuota(origin, type, size, callback);
 }
 
 void QuotaReservationManager::ReleaseReservedQuota(const url::Origin& origin,
                                                    FileSystemType type,
                                                    int64_t size) {
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   backend_->ReleaseReservedQuota(origin, type, size);
 }
 
 void QuotaReservationManager::CommitQuotaUsage(const url::Origin& origin,
                                                FileSystemType type,
                                                int64_t delta) {
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   backend_->CommitQuotaUsage(origin, type, delta);
 }
 
 void QuotaReservationManager::IncrementDirtyCount(const url::Origin& origin,
                                                   FileSystemType type) {
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   backend_->IncrementDirtyCount(origin, type);
 }
 
 void QuotaReservationManager::DecrementDirtyCount(const url::Origin& origin,
                                                   FileSystemType type) {
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   backend_->DecrementDirtyCount(origin, type);
 }
 
@@ -63,7 +63,7 @@
 QuotaReservationManager::GetReservationBuffer(const url::Origin& origin,
                                               FileSystemType type) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   QuotaReservationBuffer** buffer =
       &reservation_buffers_[std::make_pair(origin, type)];
   if (!*buffer) {
@@ -85,7 +85,7 @@
 scoped_refptr<QuotaReservation> QuotaReservationManager::CreateReservation(
     const url::Origin& origin,
     FileSystemType type) {
-  DCHECK(!origin.unique());
+  DCHECK(!origin.opaque());
   return GetReservationBuffer(origin, type)->CreateReservation();
 }
 
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index cfc72399..8c05148 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -3087,6 +3087,21 @@
         "test": "base_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ],
+          "hard_timeout": 3600,
+          "io_timeout": 3600
+        },
+        "test": "chrome_login_tast_tests"
+      },
+      {
         "args": [
           "--dbus-stub",
           "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.chromeos_unittests.filter"
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 96cdbf66..642a9683 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -193,6 +193,102 @@
       }
     ]
   },
+  "Android FYI 32 Vk Release (Pixel XL)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "P",
+              "device_type": "marlin",
+              "os": "Android",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "angle_end2end_tests"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "P",
+              "device_type": "marlin",
+              "os": "Android",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "angle_unittests"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "-v",
+          "--one-frame-only"
+        ],
+        "isolate_name": "angle_perftests",
+        "name": "angle_perftests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "P",
+              "device_type": "marlin",
+              "os": "Android",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        }
+      }
+    ]
+  },
   "Android FYI 32 dEQP Vk Release (Nexus 5X)": {
     "gtest_tests": [
       {
@@ -281,6 +377,50 @@
       }
     ]
   },
+  "Android FYI 32 dEQP Vk Release (Pixel XL)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--deqp-egl-display-type=angle-vulkan",
+          "--enable-xml-result-parsing",
+          "--shard-timeout=500",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "name": "angle_deqp_gles2_vulkan_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "P",
+              "device_type": "marlin",
+              "os": "Android",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "angle_deqp_gles2_tests"
+      }
+    ]
+  },
   "Android FYI 64 Vk Release (Nexus 5X)": {
     "gtest_tests": [
       {
@@ -473,6 +613,102 @@
       }
     ]
   },
+  "Android FYI 64 Vk Release (Pixel XL)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "P",
+              "device_type": "marlin",
+              "os": "Android",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "angle_end2end_tests"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "P",
+              "device_type": "marlin",
+              "os": "Android",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "angle_unittests"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "-v",
+          "--one-frame-only"
+        ],
+        "isolate_name": "angle_perftests",
+        "name": "angle_perftests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "P",
+              "device_type": "marlin",
+              "os": "Android",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        }
+      }
+    ]
+  },
   "Android FYI 64 dEQP Vk Release (Nexus 5X)": {
     "gtest_tests": [
       {
@@ -561,6 +797,50 @@
       }
     ]
   },
+  "Android FYI 64 dEQP Vk Release (Pixel XL)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--deqp-egl-display-type=angle-vulkan",
+          "--enable-xml-result-parsing",
+          "--shard-timeout=500",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "name": "angle_deqp_gles2_vulkan_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "P",
+              "device_type": "marlin",
+              "os": "Android",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "angle_deqp_gles2_tests"
+      }
+    ]
+  },
   "Android FYI Release (NVIDIA Shield TV)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter b/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
index 07a57dfb..e76edb77 100644
--- a/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
+++ b/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
@@ -173,7 +173,7 @@
 # Default extension tests.
 -DefaultProfileExtensionBrowserTest.NoExtensionHosts
 
-# Encrypted media tests are flaky due to race condition. crbug.com/880584
+# Encrypted media tests are failing on Asan/Lsan bot due to memory leak. crbug.com/889993
 -ECKEncryptedMediaTest.*
 -EncryptedMediaTest.*
 -CDM_9/ECKEncryptedMediaTest.*
@@ -205,12 +205,6 @@
 -ManagedWithoutPermission/ManagedWithoutPermissionPlatformKeysTest.*
 -ManagedWithPermission/ManagedWithPermissionPlatformKeysTest.*
 
-# Needs video surface layer support. Should be fixed when renderers don't use
-# the window service for embedding.
-# https://crbug.com/884589 https://crbug.com/881574
--MediaEngagementBrowserTest.*
--MediaEngagementAutoplayBrowserTest.*
-
 # Flaky https://crbug.com/887175
 -PrerenderBrowserTest.PrerenderHTML5VideoJs
 
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 72c6974..fa59232 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -299,6 +299,10 @@
     "label": "//chrome/android:chrome_junit_tests",
     "type": "junit_test",
   },
+  "chrome_login_tast_tests": {
+    "label": "//chromeos:chrome_login_tast_tests",
+    "type": "raw",
+  },
   "chrome_official_builder": {
     "label": "//:chrome_official_builder",
     "type": "additional_compile_target",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index e215548c..3452e14c 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -430,6 +430,7 @@
 
     'chromeos_gtests_experimental': {
       'base_unittests': {},
+      'chrome_login_tast_tests': {},
       'chromeos_unittests': {
         'args': [
           # TODO(crbug.com/865693): Don't stub out dbus clients.
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 5c357eab..e805d246 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1764,6 +1764,24 @@
           'isolated_scripts': 'gpu_fyi_and_optional_isolated_scripts',
         },
       },
+      'Android FYI 32 Vk Release (Pixel XL)': {
+        'os_type': 'android',
+        'skip_merge_script': True,
+        'swarming': {
+          'dimension_sets': [
+            {
+              'device_type': 'marlin',
+              'device_os': 'P',
+              'os': 'Android',
+              'pool': 'Chrome-GPU',
+            },
+          ],
+        },
+        'test_suites': {
+          'gtest_tests': 'gpu_angle_gtests',
+          'isolated_scripts': 'gpu_fyi_and_optional_isolated_scripts',
+        },
+      },
       'Android FYI 32 dEQP Vk Release (Nexus 5X)': {
         'os_type': 'android',
         'skip_merge_script': True,
@@ -1798,6 +1816,23 @@
           'gtest_tests': 'gpu_angle_deqp_gles2_vulkan_tests',
         },
       },
+      'Android FYI 32 dEQP Vk Release (Pixel XL)': {
+        'os_type': 'android',
+        'skip_merge_script': True,
+        'swarming': {
+          'dimension_sets': [
+            {
+              'device_type': 'marlin',
+              'device_os': 'P',
+              'os': 'Android',
+              'pool': 'Chrome-GPU',
+            },
+          ],
+        },
+        'test_suites': {
+          'gtest_tests': 'gpu_angle_deqp_gles2_vulkan_tests',
+        },
+      },
       'Android FYI 64 Vk Release (Nexus 5X)': {
         'os_type': 'android',
         'skip_merge_script': True,
@@ -1834,6 +1869,24 @@
           'isolated_scripts': 'gpu_fyi_and_optional_isolated_scripts',
         },
       },
+      'Android FYI 64 Vk Release (Pixel XL)': {
+        'os_type': 'android',
+        'skip_merge_script': True,
+        'swarming': {
+          'dimension_sets': [
+            {
+              'device_type': 'marlin',
+              'device_os': 'P',
+              'os': 'Android',
+              'pool': 'Chrome-GPU',
+            },
+          ],
+        },
+        'test_suites': {
+          'gtest_tests': 'gpu_angle_gtests',
+          'isolated_scripts': 'gpu_fyi_and_optional_isolated_scripts',
+        },
+      },
       'Android FYI 64 dEQP Vk Release (Nexus 5X)': {
         'os_type': 'android',
         'skip_merge_script': True,
@@ -1868,6 +1921,23 @@
           'gtest_tests': 'gpu_angle_deqp_gles2_vulkan_tests',
         },
       },
+      'Android FYI 64 dEQP Vk Release (Pixel XL)': {
+        'os_type': 'android',
+        'skip_merge_script': True,
+        'swarming': {
+          'dimension_sets': [
+            {
+              'device_type': 'marlin',
+              'device_os': 'P',
+              'os': 'Android',
+              'pool': 'Chrome-GPU',
+            },
+          ],
+        },
+        'test_suites': {
+          'gtest_tests': 'gpu_angle_deqp_gles2_vulkan_tests',
+        },
+      },
       'Android FYI Release (NVIDIA Shield TV)': {
         'browser_config': 'android-chromium',
         'os_type': 'android',
diff --git a/testing/libfuzzer/gen_fuzzer_owners.py b/testing/libfuzzer/gen_fuzzer_owners.py
index af0f04f..c9590a3d 100755
--- a/testing/libfuzzer/gen_fuzzer_owners.py
+++ b/testing/libfuzzer/gen_fuzzer_owners.py
@@ -59,10 +59,11 @@
     return
 
   for source in sources:
-    if not os.path.exists(source):
+    full_source_path = os.path.join(CHROMIUM_SRC_DIR, source)
+    if not os.path.exists(full_source_path):
       continue
 
-    with open(source, 'r') as source_file_handle:
+    with open(full_source_path, 'r') as source_file_handle:
       source_content = source_file_handle.read()
 
     if SubStringExistsIn(
@@ -72,10 +73,11 @@
 
       git_dir = os.path.join(CHROMIUM_SRC_DIR, '.git')
       is_git_file = bool(subprocess.check_output(
-          ['git', '--git-dir', git_dir, 'ls-files', source]))
+          ['git', '--git-dir', git_dir, 'ls-files', source],
+          cwd=CHROMIUM_SRC_DIR))
       if not is_git_file:
         # File is not in working tree. Return owners for third_party.
-        return GetOwnersIfThirdParty(source)
+        return GetOwnersIfThirdParty(full_source_path)
 
       # git log --follow and --reverse don't work together and using just
       # --follow is too slow. Make a best estimate with an assumption that
@@ -83,7 +85,8 @@
       # copyright line and does not change even with file rename / move.
       blame_output = subprocess.check_output(
           ['git', '--git-dir', git_dir,
-           'blame', '--porcelain', '-L1,1', source])
+           'blame', '--porcelain', '-L1,1', source],
+          cwd=CHROMIUM_SRC_DIR)
       return GetAuthorFromGitBlame(blame_output)
 
   return None
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index ce496d42..3873cd8 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -623,6 +623,33 @@
             ]
         }
     ],
+    "AutofillPreviewStyleExperiment": [
+        {
+            "platforms": [],
+            "experiments": [
+                {
+                    "name": "Enabled_BlackOnGoogleBlue050_V2",
+                    "params": {
+                        "bg_color": "#E8F0FE",
+                        "color": "#000000"
+                    },
+                    "enable_features": [
+                        "AutofillPreviewStyleExperiment"
+                    ]
+                },
+                {
+                    "name": "Enabled_BlackOnGoogleYellow050_V2",
+                    "params": {
+                        "bg_color": "#E6F4EA",
+                        "color": "#000000"
+                    },
+                    "enable_features": [
+                        "AutofillPreviewStyleExperiment"
+                    ]
+                }
+            ]
+        }
+    ],
     "AutofillResetFullServerCardsOnAuthError": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 50e48e24..f02b50b3 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -359,7 +359,6 @@
 crbug.com/591099 fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
 crbug.com/591099 fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
 crbug.com/591099 fast/forms/placeholder-position.html [ Failure ]
-crbug.com/890135 fast/forms/select/menulist-appearance-rtl.html [ Failure ]
 crbug.com/591099 fast/frames/crash-frameset-CSS-content-property.html [ Crash Pass ]
 crbug.com/835484 fast/inline/continuation-outlines-with-layers.html [ Failure ]
 crbug.com/835484 fast/inline/continuation-outlines.html [ Failure ]
@@ -393,7 +392,6 @@
 crbug.com/591099 fast/writing-mode/fieldsets.html [ Failure ]
 crbug.com/591099 fast/writing-mode/percentage-height-orthogonal-writing-modes.html [ Failure ]
 crbug.com/591099 fast/writing-mode/table-percent-width-quirk.html [ Pass ]
-crbug.com/890135 fragmentation/transformed-clip-before-second-column.html [ Failure ]
 crbug.com/591099 hittesting/inline-with-clip-path.html [ Failure ]
 crbug.com/855039 html/details_summary/details-writing-mode-align-center.html [ Failure ]
 crbug.com/855039 html/details_summary/details-writing-mode-align-left.html [ Failure ]
@@ -415,8 +413,6 @@
 crbug.com/591099 http/tests/security/setDomainRelaxationForbiddenForURLScheme.html [ Crash ]
 crbug.com/591099 idle-callback/test-runner-run-idle-tasks.html [ Pass ]
 crbug.com/591099 images/color-profile-image-filter-all.html [ Failure ]
-crbug.com/890135 images/rendering-broken-block-flow-images.html [ Failure ]
-crbug.com/890135 images/rendering-broken-images.html [ Failure ]
 crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element.js [ Failure ]
 crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot.js [ Failure ]
 crbug.com/714962 inspector-protocol/layout-fonts/languages-emoji-rare-glyphs.js [ Failure ]
@@ -491,8 +487,6 @@
 crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
 crbug.com/591099 virtual/feature-policy-vibrate/ [ Skip ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-filter-all.html [ Failure ]
-crbug.com/890135 virtual/gpu-rasterization/images/rendering-broken-block-flow-images.html [ Failure ]
-crbug.com/890135 virtual/gpu-rasterization/images/rendering-broken-images.html [ Failure ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-arc-circumference.html [ Failure Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-color-over-image.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-gradient-over-pattern.html [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index f58124e..d98c073 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -332,6 +332,7 @@
 crbug.com/863454 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-multicol-002.html [ Failure ]
 crbug.com/863454 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-multicol-003.html [ Failure ]
 crbug.com/882333 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-001.html [ Failure ]
+crbug.com/882333 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-flex-001.html [ Failure ]
 
 # [css-align]
 
@@ -411,7 +412,6 @@
 # Tests for LayoutNG to pass, but not planned to fix for pre-LayoutNG.
 crbug.com/774229 editing/pasteboard/copy-paste-white-space.html [ Failure ]
 crbug.com/855279 fast/css/text-overflow-ellipsis-vertical-hittest.html [ Failure ]
-crbug.com/591099 fast/dom/inner-text-first-letter.html [ Failure ]
 crbug.com/591099 fast/dom/nodesFromRect/nodesFromRect-basic.html [ Failure ]
 crbug.com/796943 fast/text/international/shape-across-elements-simple.html [ Failure ]
 crbug.com/877946 external/wpt/css/CSS2/linebox/anonymous-inline-inherit-001.html [ Failure ]
@@ -787,7 +787,7 @@
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-floats.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-float-with-margin-top-and-line-after-break-2.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-float-with-margin-top-and-line-after-break-3.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-float-with-margin-top-and-line-after-break.html [ Failure ]
+crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-float-with-margin-top-and-line-after-break.html [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-float-with-margin-top-and-line-before-break.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-line-overflow.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-line-underflow-2.html [ Failure ]
@@ -822,6 +822,7 @@
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/composited-with-child-layer-in-next-column.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/composited-with-overflow-in-next-column.html [ Failure ]
 crbug.com/714962 virtual/layout_ng_experimental/fast/multicol/content-change-same-height.html [ Failure ]
+crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/cssom-view.html [ Crash ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/doubly-nested-with-top-padding-crossing-row-boundaries.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/abspos-becomes-spanner.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/abspos-multicol-with-spanner-becomes-spanner.html [ Failure ]
@@ -850,7 +851,7 @@
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/insert-spanner-pseudo-before.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/invalid-spanner-container-becomes-valid.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/relpos-becomes-static-has-abspos.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/remove-abspos-next-to-spanner.html [ Failure ]
+crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/remove-abspos-next-to-spanner.html [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/remove-and-insert-block-after-spanner.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/remove-and-insert-block-before-spanner.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/remove-and-insert-block-between-spanners.html [ Failure ]
@@ -876,6 +877,7 @@
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/flexbox.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/flexbox-starts-at-column-boundary.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/flexbox-starts-at-column-boundary-with-block.html [ Failure ]
+crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/flexbox-with-overflow-auto-child-crash.html [ Crash ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/flipped-blocks-border-after.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/flipped-blocks-hit-test.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/float-after-break-after.html [ Failure ]
@@ -2789,6 +2791,11 @@
 crbug.com/800898 external/wpt/FileAPI/url/url-in-tags-revoke.window.html [ Timeout ]
 crbug.com/800898 external/wpt/workers/worker-from-blob-url.window.html [ Timeout ]
 
+crbug.com/854474 external/wpt/console/console-label-conversion.any.html [ Skip ]
+crbug.com/854474 external/wpt/console/console-label-conversion.any.worker.html [ Skip ]
+crbug.com/854474 external/wpt/console/idlharness.any.html [ Skip ]
+crbug.com/854474 external/wpt/console/idlharness.any.worker.html [ Skip ]
+
 crbug.com/849737 virtual/mojo-blob-urls/external/wpt/FileAPI/url/sandboxed-iframe.html [ Pass Timeout ]
 crbug.com/849737 virtual/mojo-blob-urls/external/wpt/FileAPI/url/url-format.any.html [ Pass Timeout ]
 crbug.com/849737 virtual/mojo-blob-urls/external/wpt/FileAPI/url/url-format.any.worker.html [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
index ff307897..558b5ad 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
@@ -36119,6 +36119,18 @@
      {}
     ]
    ],
+   "css/css-contain/contain-layout-button-001.html": [
+    [
+     "/css/css-contain/contain-layout-button-001.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-button-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-contain/contain-layout-cell-001.html": [
     [
      "/css/css-contain/contain-layout-cell-001.html",
@@ -36143,6 +36155,30 @@
      {}
     ]
    ],
+   "css/css-contain/contain-layout-flexbox-001.html": [
+    [
+     "/css/css-contain/contain-layout-flexbox-001.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-flexbox-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-grid-001.html": [
+    [
+     "/css/css-contain/contain-layout-grid-001.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-grid-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-contain/contain-layout-ifc-022.html": [
     [
      "/css/css-contain/contain-layout-ifc-022.html",
@@ -45631,6 +45667,18 @@
      {}
     ]
    ],
+   "css/css-grid/alignment/grid-gutters-013.html": [
+    [
+     "/css/css-grid/alignment/grid-gutters-013.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-001.html": [
     [
      "/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-001.html",
@@ -54607,18 +54655,6 @@
      {}
     ]
    ],
-   "css/css-scoping/host-specificity-003.html": [
-    [
-     "/css/css-scoping/host-specificity-003.html",
-     [
-      [
-       "/css/css-scoping/reference/green-box.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "css/css-scoping/host-specificity.html": [
     [
      "/css/css-scoping/host-specificity.html",
@@ -91427,6 +91463,18 @@
      {}
     ]
    ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001.html": [
+    [
+     "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-flex-basis-content-001a.html": [
     [
      "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-flex-basis-content-001a.html",
@@ -119734,11 +119782,26 @@
      {}
     ]
    ],
+   "css/css-contain/reference/contain-layout-button-001-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-contain/reference/contain-layout-cell-001-ref.html": [
     [
      {}
     ]
    ],
+   "css/css-contain/reference/contain-layout-flexbox-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-layout-grid-001-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-contain/reference/contain-layout-ifc-022-ref.html": [
     [
      {}
@@ -145364,6 +145427,11 @@
      {}
     ]
    ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-flex-basis-content-001-ref.html": [
     [
      {}
@@ -177054,16 +177122,6 @@
      {}
     ]
    ],
-   "webaudio/the-audio-api/the-analysernode-interface/ctor-analyser-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "webaudio/the-audio-api/the-analysernode-interface/test-analysernode-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "webaudio/the-audio-api/the-audiobuffer-interface/.gitkeep": [
     [
      {}
@@ -196928,12 +196986,6 @@
      {}
     ]
    ],
-   "css/css-flexbox/flex-minimum-height-flex-items-009.html": [
-    [
-     "/css/css-flexbox/flex-minimum-height-flex-items-009.html",
-     {}
-    ]
-   ],
    "css/css-flexbox/flexbox_first-letter.html": [
     [
      "/css/css-flexbox/flexbox_first-letter.html",
@@ -286816,7 +286868,7 @@
    "support"
   ],
   "README.md": [
-   "684f4617f689d0611b18ce1b338bfdeb8d5886b7",
+   "6f9436bc3e4261e2f6813253e1709cbb60763ca2",
    "support"
   ],
   "WebCryptoAPI/META.yml": [
@@ -288516,11 +288568,11 @@
    "testharness"
   ],
   "background-fetch/fetch.https.window-expected.txt": [
-   "500f09d50ac7ca9b190618313cc5550b37cbefa9",
+   "8066dd23d555ca290cf54306cfd9e4c261812686",
    "support"
   ],
   "background-fetch/fetch.https.window.js": [
-   "98ecdfa3933c40b909793100b4b9f9cccb35cb86",
+   "b8b1ff0983cdce1c799d03c7f1856548fa649b17",
    "testharness"
   ],
   "background-fetch/get-ids.https.window.js": [
@@ -288552,7 +288604,7 @@
    "support"
   ],
   "background-fetch/mixed-content-and-allowed-schemes.https.window.js": [
-   "9f24f13581819ef444a89cb7549de900f5b98ef6",
+   "05b32501228fbb765a5c782102660ebd476f0168",
    "testharness"
   ],
   "background-fetch/port-blocking.https.window.js": [
@@ -288576,7 +288628,7 @@
    "support"
   ],
   "background-fetch/service_workers/sw.js": [
-   "43d778c08914da6c8ff75acb819676895adbc180",
+   "af4655dbad4ef6ad6b17d79bb2645aee98ce1102",
    "support"
   ],
   "background-fetch/update-ui.https.window.js": [
@@ -290120,7 +290172,7 @@
    "testharness"
   ],
   "console/console-label-conversion.any-expected.txt": [
-   "b12067a3f50dbb1faf9359770de01b994a2be564",
+   "1fde3cad9bdf9b8817ae1af6c7b823edb00f0dc5",
    "support"
   ],
   "console/console-label-conversion.any.js": [
@@ -290128,7 +290180,7 @@
    "testharness"
   ],
   "console/console-label-conversion.any.worker-expected.txt": [
-   "b12067a3f50dbb1faf9359770de01b994a2be564",
+   "1fde3cad9bdf9b8817ae1af6c7b823edb00f0dc5",
    "support"
   ],
   "console/console-number-format-specifiers-symbol-manual.html": [
@@ -290148,7 +290200,7 @@
    "manual"
   ],
   "console/idlharness.any-expected.txt": [
-   "1c02b8e703c6a55fca9425254f5d92a1064c894c",
+   "3b3bae18dfea489adf03e139283fce6ae117edf2",
    "support"
   ],
   "console/idlharness.any.js": [
@@ -290156,7 +290208,7 @@
    "testharness"
   ],
   "console/idlharness.any.worker-expected.txt": [
-   "1c02b8e703c6a55fca9425254f5d92a1064c894c",
+   "3b3bae18dfea489adf03e139283fce6ae117edf2",
    "support"
   ],
   "content-security-policy/META.yml": [
@@ -314991,6 +315043,10 @@
    "fadb3c41c5363742eb88bdf803eac7cdbf5e7a8f",
    "reftest"
   ],
+  "css/css-contain/contain-layout-button-001.html": [
+   "e8beef7c0edfa20258b9600376d3ab245ca63f32",
+   "reftest"
+  ],
   "css/css-contain/contain-layout-cell-001.html": [
    "fa1af0eee6848a34c61f47861c22d9efb56ab059",
    "reftest"
@@ -314999,6 +315055,14 @@
    "331a0e6519b0af23ba91355584f0c37dfcf6a88e",
    "reftest"
   ],
+  "css/css-contain/contain-layout-flexbox-001.html": [
+   "2b206edb57f46f3baa9dcfbcc24591b852cf8697",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-grid-001.html": [
+   "a6bcc4dbc2adda58602281eac5c2c0b2c0a9de61",
+   "reftest"
+  ],
   "css/css-contain/contain-layout-ifc-022.html": [
    "3e4f3dafbf213c18a09cfd2a7512dd485c13f839",
    "reftest"
@@ -315332,7 +315396,7 @@
    "reftest"
   ],
   "css/css-contain/contain-size-button-001.html": [
-   "1e4965e9daf380aec19cf43902c409ad6b457370",
+   "4b2ecd7b76e421ea5dfffce6654d722142b5823c",
    "reftest"
   ],
   "css/css-contain/contain-size-fieldset-001.html": [
@@ -315340,11 +315404,11 @@
    "reftest"
   ],
   "css/css-contain/contain-size-flexbox-001.html": [
-   "31e82f5d24c4aa673291a2ce25c660cf10977e28",
+   "16ba62eda041abe11424f63c65d6dfd46aa82570",
    "reftest"
   ],
   "css/css-contain/contain-size-grid-001.html": [
-   "f67f0e118e00b3426986b39226310c59b14a3755",
+   "4510c1e55368aeea38a79ba66059acd4d7660ddb",
    "reftest"
   ],
   "css/css-contain/contain-size-grid-002.html": [
@@ -315459,10 +315523,22 @@
    "c68bee1d0aa4f9201fb6e48cc25199f373128ca8",
    "support"
   ],
+  "css/css-contain/reference/contain-layout-button-001-ref.html": [
+   "11a784b213cbc05d10cdcc199a11055fe0c0fdfa",
+   "support"
+  ],
   "css/css-contain/reference/contain-layout-cell-001-ref.html": [
    "9ff7f45e39ca741b4b334c1c9b3d1d5ee6759b73",
    "support"
   ],
+  "css/css-contain/reference/contain-layout-flexbox-001-ref.html": [
+   "832e4c72c2cef426f2d759e77435290fff2f0d55",
+   "support"
+  ],
+  "css/css-contain/reference/contain-layout-grid-001-ref.html": [
+   "b5ff8e0e0dad0cd586e7b899d8a7905b26063233",
+   "support"
+  ],
   "css/css-contain/reference/contain-layout-ifc-022-ref.html": [
    "682af7d4f44b22f987c069dbbee370520612bc10",
    "support"
@@ -315580,7 +315656,7 @@
    "support"
   ],
   "css/css-contain/reference/contain-size-button-001-ref.html": [
-   "1cbaaccd1a0751c5dadf913e1fc31d130ff95259",
+   "eff64aa8e2ef0c7fbce03858e90ef0d9e2a7ee6b",
    "support"
   ],
   "css/css-contain/reference/contain-size-fieldset-001-ref.html": [
@@ -315588,11 +315664,11 @@
    "support"
   ],
   "css/css-contain/reference/contain-size-flexbox-001-ref.html": [
-   "85628b59c48f7931e7d3e5a498da60cc264dc363",
+   "70f408643007d8338f401ef947f7bb24f1eaedc9",
    "support"
   ],
   "css/css-contain/reference/contain-size-grid-001-ref.html": [
-   "d71636bd5f4a344352249b50563eb03d249484c6",
+   "cf4f8076650928dfd0cefc18665ef1e8ab52d7b6",
    "support"
   ],
   "css/css-contain/reference/contain-size-monolithic-001-ref.html": [
@@ -316815,10 +316891,6 @@
    "ead7a424b374fddb247046d2a36a37a11669baae",
    "reftest"
   ],
-  "css/css-flexbox/flex-minimum-height-flex-items-009.html": [
-   "718386af02069fa1a3fff0ee5aaa10415ef4b23a",
-   "testharness"
-  ],
   "css/css-flexbox/flex-minimum-width-flex-items-001.xht": [
    "b8e2866edaa46af46900c287238894cd8ddef24c",
    "reftest"
@@ -327915,6 +327987,10 @@
    "1e56e708dfb45f1dd1e48d7779818d244eb25f3d",
    "reftest"
   ],
+  "css/css-grid/alignment/grid-gutters-013.html": [
+   "e72814725d2cb90fba6f3bd4d1e8370f37382fbb",
+   "reftest"
+  ],
   "css/css-grid/alignment/grid-row-axis-alignment-positioned-items-001.html": [
    "e350f972357cfdc9559c5a86116e538d87c9ce61",
    "testharness"
@@ -333983,10 +334059,6 @@
    "3132d3a3455241347d6fe421f3434c361e424493",
    "reftest"
   ],
-  "css/css-scoping/host-specificity-003.html": [
-   "54a22599d8f83f612d7fc9ff91abfe650114c6e2",
-   "reftest"
-  ],
   "css/css-scoping/host-specificity.html": [
    "3ef61d4135fe7dbf846feb82540ca1a213ce7987",
    "reftest"
@@ -363831,6 +363903,14 @@
    "cf54aabe9936b3963e7343d566d957633fc26c69",
    "reftest"
   ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001-ref.html": [
+   "5e5561cadf2ddbd6dfd2c7b4819f146f61be006b",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001.html": [
+   "d64c4bdf28ecb783af4f342d515dcf63134602c6",
+   "reftest"
+  ],
   "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-flex-basis-content-001-ref.html": [
    "b5377110201d1de21a966c8a7f1a7d60dfff4126",
    "support"
@@ -395264,7 +395344,7 @@
    "support"
   ],
   "interfaces/screen-capture.idl": [
-   "668f4588ba2a24a909dc7f44b24628c56631296d",
+   "b79d09d19dced9e3b77e791e2d543fc9f44742ee",
    "support"
   ],
   "interfaces/screen-orientation.idl": [
@@ -426831,10 +426911,6 @@
    "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
    "support"
   ],
-  "webaudio/the-audio-api/the-analysernode-interface/ctor-analyser-expected.txt": [
-   "b335e1bde0cf91dfa3f541b48b2927cf58f52083",
-   "support"
-  ],
   "webaudio/the-audio-api/the-analysernode-interface/ctor-analyser.html": [
    "a9aa4831516c6a5cefa7c8b4f67f3ef246d24777",
    "testharness"
@@ -426867,10 +426943,6 @@
    "04fe48096459dd0bbf4b3b0fd206c90c0bcae0f0",
    "testharness"
   ],
-  "webaudio/the-audio-api/the-analysernode-interface/test-analysernode-expected.txt": [
-   "09df255c35c3d4b156167684aee019c0a318b572",
-   "support"
-  ],
   "webaudio/the-audio-api/the-analysernode-interface/test-analysernode.html": [
    "a8b5a7154e94479460c1085c6b5cb584e9b6976c",
    "testharness"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/README.md b/third_party/WebKit/LayoutTests/external/wpt/README.md
index 684f461..6f9436b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/README.md
+++ b/third_party/WebKit/LayoutTests/external/wpt/README.md
@@ -432,11 +432,11 @@
 
 Search filters to find things to review:
 
-* [Open PRs (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+-label%3A%22mozilla%3Agecko-sync%22+-label%3A%22chromium-export%22+-label%3A%22webkit-export%22+-label%3A%22servo-export%22)
-* [Reviewed but still open PRs (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+-label%3Amozilla%3Agecko-sync+-label%3Achromium-export+-label%3Awebkit-export+-label%3Aservo-export+review%3Aapproved+-label%3A%22do+not+merge+yet%22+-label%3A%22status%3Aneeds-spec-decision%22) (Merge? Something left to fix? Ping other reviewer?)
+* [Open PRs (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+-label%3A%22mozilla%3Agecko-sync%22+-label%3A%22chromium-export%22+-label%3A%22webkit-export%22+-label%3A%22servo-export%22+-label%3Avendor-imports)
+* [Reviewed but still open PRs (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+-label%3Amozilla%3Agecko-sync+-label%3Achromium-export+-label%3Awebkit-export+-label%3Aservo-export+-label%3Avendor-imports+review%3Aapproved+-label%3A%22do+not+merge+yet%22+-label%3A%22status%3Aneeds-spec-decision%22) (Merge? Something left to fix? Ping other reviewer?)
 * [Open PRs without reviewers](https://github.com/web-platform-tests/wpt/pulls?q=is%3Apr+is%3Aopen+label%3Astatus%3Aneeds-reviewers)
-* [Open PRs with label `infra` (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+label%3Ainfra+-label%3A%22mozilla%3Agecko-sync%22+-label%3A%22chromium-export%22+-label%3A%22webkit-export%22+-label%3A%22servo-export%22)
-* [Open PRs with label `docs` (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+label%3Adocs+-label%3A%22mozilla%3Agecko-sync%22+-label%3A%22chromium-export%22+-label%3A%22webkit-export%22+-label%3A%22servo-export%22)
+* [Open PRs with label `infra` (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+label%3Ainfra+-label%3A%22mozilla%3Agecko-sync%22+-label%3A%22chromium-export%22+-label%3A%22webkit-export%22+-label%3A%22servo-export%22+-label%3Avendor-imports)
+* [Open PRs with label `docs` (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+label%3Adocs+-label%3A%22mozilla%3Agecko-sync%22+-label%3A%22chromium-export%22+-label%3A%22webkit-export%22+-label%3A%22servo-export%22+-label%3Avendor-imports)
 
 Getting Involved
 ================
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt
index 500f09d..8066dd2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt
@@ -2,11 +2,13 @@
 PASS Background Fetch requires an activated Service Worker
 PASS Argument verification is done for BackgroundFetchManager.fetch()
 PASS IDs must be unique among active Background Fetch registrations
+PASS Empty URL is OK.
 PASS Using Background Fetch to successfully fetch a single resource
 PASS Background Fetch that exceeds the quota throws a QuotaExceededError
 FAIL Fetches can have requests with duplicate URLs promise_test: Unhandled rejection with value: object "TypeError: Fetches with duplicate requests are not yet supported. Consider adding query params to make the requests unique. For updates check http://crbug.com/871174"
 FAIL Fetches can have requests with a body promise_test: Unhandled rejection with value: object "TypeError: Requests with a body are not yet supported. For updates check http://crbug.com/774054"
 PASS recordsAvailable is false after onbackgroundfetchsuccess finishes execution.
 PASS Using Background Fetch to fetch a non-existent resource should fail.
+PASS Fetches with mixed content should fail.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js
index 98ecdfa3..b8b1ff09 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js
@@ -70,6 +70,21 @@
 backgroundFetchTest(async (test, backgroundFetch) => {
   const registrationId = uniqueId();
   const registration =
+    await backgroundFetch.fetch(registrationId, '');
+
+  assert_equals(registration.id, registrationId);
+
+  const {type, eventRegistration, results} = await getMessageFromServiceWorker();
+
+  assert_equals('backgroundfetchsuccess', type);
+  assert_equals(eventRegistration.result, 'success');
+  assert_equals(eventRegistration.failureReason, '');
+
+}, 'Empty URL is OK.');
+
+backgroundFetchTest(async (test, backgroundFetch) => {
+  const registrationId = uniqueId();
+  const registration =
     await backgroundFetch.fetch(registrationId, 'resources/feature-name.txt');
 
   assert_equals(registration.id, registrationId);
@@ -190,4 +205,20 @@
   assert_equals(eventRegistration.result, 'failure');
   assert_equals(eventRegistration.failureReason, 'bad-status');
 
-}, 'Using Background Fetch to fetch a non-existent resource should fail.');
\ No newline at end of file
+}, 'Using Background Fetch to fetch a non-existent resource should fail.');
+
+backgroundFetchTest(async (test, backgroundFetch) => {
+  const registration = await backgroundFetch.fetch(
+                         'my-id',
+                         ['https://example.com', 'http://example.com']);
+
+  const {type, eventRegistration, results} = await getMessageFromServiceWorker();
+
+  assert_equals('backgroundfetchfail', type);
+  assert_equals(eventRegistration.failureReason, 'fetch-error');
+
+  assert_equals(results.length, 2);
+  assert_true(results[0].url.includes('https://example.com'));
+  assert_equals(results[1].url, '');
+
+}, 'Fetches with mixed content should fail.');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/mixed-content-and-allowed-schemes.https.window.js b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/mixed-content-and-allowed-schemes.https.window.js
index 9f24f13..05b3250 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/mixed-content-and-allowed-schemes.https.window.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/mixed-content-and-allowed-schemes.https.window.js
@@ -32,34 +32,6 @@
 
 backgroundFetchTest((t, bgFetch) => {
   return promise_rejects(t, new TypeError(),
-                         bgFetch.fetch(uniqueId(), 'http://example.com'));
-}, 'non-loopback http: fetch should reject');
-
-backgroundFetchTest((t, bgFetch) => {
-  return promise_rejects(t, new TypeError(),
-                         bgFetch.fetch(uniqueId(), 'http://192.0.2.0'));
-}, 'non-loopback IPv4 http: fetch should reject');
-
-backgroundFetchTest((t, bgFetch) => {
-  return promise_rejects(t, new TypeError(),
-                         bgFetch.fetch(uniqueId(), 'http://[2001:db8::1]'));
-}, 'non-loopback IPv6 http: fetch should reject');
-
-backgroundFetchTest((t, bgFetch) => {
-  return promise_rejects(t, new TypeError(),
-                         bgFetch.fetch(uniqueId(), ['https://example.com',
-                                                    'http://example.com']));
-}, 'https: and non-loopback http: fetch should reject');
-
-backgroundFetchTest((t, bgFetch) => {
-  return promise_rejects(t, new TypeError(),
-                         bgFetch.fetch(uniqueId(), ['http://example.com',
-                                                    'https://example.com']));
-}, 'non-loopback http: and https: fetch should reject');
-
-
-backgroundFetchTest((t, bgFetch) => {
-  return promise_rejects(t, new TypeError(),
                          bgFetch.fetch(uniqueId(), 'wss:127.0.0.1'));
 }, 'wss: fetch should reject');
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/service_workers/sw.js b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/service_workers/sw.js
index 43d778c0..af4655d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/service_workers/sw.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/service_workers/sw.js
@@ -27,5 +27,3 @@
 
 self.addEventListener('backgroundfetchsuccess', handleBackgroundFetchUpdateEvent);
 self.addEventListener('backgroundfetchfail', handleBackgroundFetchUpdateEvent);
-
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/console/console-label-conversion.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/console/console-label-conversion.any-expected.txt
index b12067a..1fde3cad 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/console/console-label-conversion.any-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/console/console-label-conversion.any-expected.txt
@@ -23,14 +23,14 @@
         }
       });
     }" did not throw
-FAIL console.timeLog()'s label gets converted to string via label.toString() when label is an object console[method] is not a function
+FAIL console.timeLog()'s label gets converted to string via label.toString() when label is an object assert_true: timeLog() must call toString() on label when label is an object expected true got false
 FAIL console.timeLog() throws exceptions generated by erroneous label.toString() conversion assert_throws: timeLog must re-throw any exceptions thrown by label.toString() conversion function "() => {
       console[method]({
         toString() {
           throw new Error('conversion error');
         }
       });
-    }" threw object "TypeError: console[method] is not a function" ("TypeError") expected object "[object Object]" ("Error")
+    }" did not throw
 FAIL console.timeEnd()'s label gets converted to string via label.toString() when label is an object assert_true: timeEnd() must call toString() on label when label is an object expected true got false
 FAIL console.timeEnd() throws exceptions generated by erroneous label.toString() conversion assert_throws: timeEnd must re-throw any exceptions thrown by label.toString() conversion function "() => {
       console[method]({
diff --git a/third_party/WebKit/LayoutTests/external/wpt/console/console-label-conversion.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/console/console-label-conversion.any.worker-expected.txt
index b12067a..1fde3cad 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/console/console-label-conversion.any.worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/console/console-label-conversion.any.worker-expected.txt
@@ -23,14 +23,14 @@
         }
       });
     }" did not throw
-FAIL console.timeLog()'s label gets converted to string via label.toString() when label is an object console[method] is not a function
+FAIL console.timeLog()'s label gets converted to string via label.toString() when label is an object assert_true: timeLog() must call toString() on label when label is an object expected true got false
 FAIL console.timeLog() throws exceptions generated by erroneous label.toString() conversion assert_throws: timeLog must re-throw any exceptions thrown by label.toString() conversion function "() => {
       console[method]({
         toString() {
           throw new Error('conversion error');
         }
       });
-    }" threw object "TypeError: console[method] is not a function" ("TypeError") expected object "[object Object]" ("Error")
+    }" did not throw
 FAIL console.timeEnd()'s label gets converted to string via label.toString() when label is an object assert_true: timeEnd() must call toString() on label when label is an object expected true got false
 FAIL console.timeEnd() throws exceptions generated by erroneous label.toString() conversion assert_throws: timeEnd must re-throw any exceptions thrown by label.toString() conversion function "() => {
       console[method]({
diff --git a/third_party/WebKit/LayoutTests/external/wpt/console/idlharness.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/console/idlharness.any-expected.txt
index 1c02b8e70..3b3bae1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/console/idlharness.any-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/console/idlharness.any-expected.txt
@@ -17,7 +17,7 @@
 FAIL console namespace: operation groupCollapsed(any...) assert_equals: operation has wrong .length expected 0 but got 1
 FAIL console namespace: operation groupEnd() assert_equals: operation has wrong .length expected 0 but got 1
 FAIL console namespace: operation time(DOMString) assert_equals: operation has wrong .length expected 0 but got 1
-FAIL console namespace: operation timeLog(DOMString, any...) assert_own_property: namespace object missing operation "timeLog" expected property "timeLog" missing
+FAIL console namespace: operation timeLog(DOMString, any...) assert_equals: operation has wrong .length expected 0 but got 1
 FAIL console namespace: operation timeEnd(DOMString) assert_equals: operation has wrong .length expected 0 but got 1
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/console/idlharness.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/console/idlharness.any.worker-expected.txt
index 1c02b8e70..3b3bae1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/console/idlharness.any.worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/console/idlharness.any.worker-expected.txt
@@ -17,7 +17,7 @@
 FAIL console namespace: operation groupCollapsed(any...) assert_equals: operation has wrong .length expected 0 but got 1
 FAIL console namespace: operation groupEnd() assert_equals: operation has wrong .length expected 0 but got 1
 FAIL console namespace: operation time(DOMString) assert_equals: operation has wrong .length expected 0 but got 1
-FAIL console namespace: operation timeLog(DOMString, any...) assert_own_property: namespace object missing operation "timeLog" expected property "timeLog" missing
+FAIL console namespace: operation timeLog(DOMString, any...) assert_equals: operation has wrong .length expected 0 but got 1
 FAIL console namespace: operation timeEnd(DOMString) assert_equals: operation has wrong .length expected 0 but got 1
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-button-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-button-001.html
new file mode 100644
index 0000000..e8beef7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-button-001.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment on button</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-layout-button-001-ref.html">
+<meta name=assert content="Layout containment does apply to buttons, thus their baseline is the same than if they don't have contents.">
+<style>
+button {
+  border: 5px solid green;
+  padding: 0;
+  contain: layout;
+  color: transparent;
+  width: 0;
+  height: 0;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the bottom, and then the word "after".</p>
+before<button>b</button>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-flexbox-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-flexbox-001.html
new file mode 100644
index 0000000..2b206ed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-flexbox-001.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment on flexbox container</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-layout-flexbox-001-ref.html">
+<meta name=assert content="Layout containment does apply to flexbox containers, thus their baseline is the same than if they don't have contents.">
+<style>
+div {
+  display: inline-flex;
+  border: 5px solid green;
+  contain: layout;
+  color: transparent;
+  width: 0;
+  height: 0;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the bottom, and then the word "after".</p>
+before<div>f</div>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-grid-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-grid-001.html
new file mode 100644
index 0000000..a6bcc4d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-grid-001.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment on grid container</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-layout-grid-001-ref.html">
+<meta name=assert content="Layout containment does apply to grid containers, thus their baseline is the same than if they don't have contents.">
+<style>
+div {
+  display: inline-grid;
+  border: 5px solid green;
+  contain: layout;
+  color: transparent;
+  width: 0;
+  height: 0;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the bottom, and then the word "after".</p>
+before<div>g</div>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-button-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-button-001.html
index 1e4965e..4b2ecd7b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-button-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-button-001.html
@@ -4,15 +4,16 @@
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
 <link rel="match" href="reference/contain-size-button-001-ref.html">
-<meta name=assert content="Size containment does apply to buttons, thus their size and baseline is the same than if they don't have contents.">
+<meta name=assert content="Size containment does apply to buttons, thus their size is the same than if they don't have contents.">
 <style>
 button {
   border: 5px solid green;
   padding: 0;
   contain: size;
   color: transparent;
+  font-size: 2em;
 }
 </style>
 
-<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square, and then the word "after".</p>
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
 before<button>flex</button>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-flexbox-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-flexbox-001.html
index 31e82f5..16ba62e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-flexbox-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-flexbox-001.html
@@ -4,15 +4,16 @@
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
 <link rel="match" href="reference/contain-size-flexbox-001-ref.html">
-<meta name=assert content="Size containment does apply to flexbox containers, thus their size and baseline is the same than if they don't have contents.">
+<meta name=assert content="Size containment does apply to flexbox containers, thus their size is the same than if they don't have contents.">
 <style>
 div {
   display: inline-flex;
   border: 5px solid green;
   contain: size;
   color: transparent;
+  font-size: 2em;
 }
 </style>
 
-<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square, and then the word "after".</p>
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
 before<div>flex</div>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-grid-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-grid-001.html
index f67f0e11..4510c1e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-grid-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-grid-001.html
@@ -4,15 +4,16 @@
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
 <link rel="match" href="reference/contain-size-grid-001-ref.html">
-<meta name=assert content="Size containment does apply to grid containers, thus their size and baseline is the same than if they don't have contents.">
+<meta name=assert content="Size containment does apply to grid containers, thus their size is the same than if they don't have contents.">
 <style>
 div {
   display: inline-grid;
   border: 5px solid green;
   contain: size;
   color: transparent;
+  font-size: 2em;
 }
 </style>
 
-<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square, and then the word "after".</p>
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
 before<div>grid</div>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-button-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-button-001-ref.html
new file mode 100644
index 0000000..11a784b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-button-001-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+button {
+  border: 5px solid green;
+  padding: 0;
+  color: transparent;
+  width: 0;
+  height: 0px;
+  /* Layout containment creates a stacking context, the following lines simuluate the same in the reference file. */
+  position: relative;
+  z-index: 1;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the bottom, and then the word "after".</p>
+before<button></button>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-flexbox-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-flexbox-001-ref.html
new file mode 100644
index 0000000..832e4c7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-flexbox-001-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+div {
+  display: inline-flex;
+  border: 5px solid green;
+  /* Layout containment creates a stacking context, the following lines simuluate the same in the reference file. */
+  position: relative;
+  z-index: 1;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the bottom, and then the word "after".</p>
+before<div></div>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-grid-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-grid-001-ref.html
new file mode 100644
index 0000000..b5ff8e0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-grid-001-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+div {
+  display: inline-grid;
+  border: 5px solid green;
+  /* Layout containment creates a stacking context, the following lines simuluate the same in the reference file. */
+  position: relative;
+  z-index: 1;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the bottom, and then the word "after".</p>
+before<div></div>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-button-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-button-001-ref.html
index 1cbaaccd..eff64aa 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-button-001-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-button-001-ref.html
@@ -6,8 +6,12 @@
 button {
   border: 5px solid green;
   padding: 0;
+  color: transparent;
+  width: 0;
+  height: 0;
+  font-size: 2em;
 }
 </style>
 
-<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square, and then the word "after".</p>
-before<button></button>after
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
+before<button>b</button>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-flexbox-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-flexbox-001-ref.html
index 85628b5..70f4086 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-flexbox-001-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-flexbox-001-ref.html
@@ -6,8 +6,12 @@
 div {
   display: inline-flex;
   border: 5px solid green;
+  color: transparent;
+  width: 0;
+  height: 0;
+  font-size: 2em;
 }
 </style>
 
-<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square, and then the word "after".</p>
-before<div></div>after
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
+before<div>f</div>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-grid-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-grid-001-ref.html
index d71636b..cf4f8076 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-grid-001-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-grid-001-ref.html
@@ -6,8 +6,12 @@
 div {
   display: inline-grid;
   border: 5px solid green;
+  color: transparent;
+  width: 0;
+  height: 0;
+  font-size: 2em;
 }
 </style>
 
-<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square, and then the word "after".</p>
-before<div></div>after
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
+before<div>g</div>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001-ref.html
new file mode 100644
index 0000000..5e5561c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001-ref.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>
+    CSS Reftest Reference
+  </title>
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <style>
+    .container {
+      width: 100px;
+      display: flex;
+      border: 1px solid purple;
+      margin-bottom: 15px;
+    }
+    .item {
+       margin: 2px;
+       background: lightblue;
+    }
+    .inline-box {
+      display: inline-block;
+      height: 10px;
+      width: 10px;
+      background: lightgray;
+      border: 1px solid black;
+     }
+    #change-width {
+      /* Using hardcoded CSS as reference for testcase's tweak: */
+      width: 300px;
+    }
+    #change-flex {
+      /* Using hardcoded CSS as reference for testcase's tweak: */
+      flex: 0 0 75px;
+    }
+  </style>
+</head>
+<body>
+  <div class="container">
+    <div class="item" id="change-width">
+      <div class="inline-box"></div><div class="inline-box"></div>
+    </div>
+    <div class="item">
+      <div class="inline-box"></div><div class="inline-box"></div>
+    </div>
+  </div>
+
+  <div class="container">
+    <div class="item" id="change-flex">
+      <div class="inline-box"></div><div class="inline-box"></div>
+    </div>
+    <div class="item">
+      <div class="inline-box"></div><div class="inline-box"></div>
+    </div>
+  </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001.html
new file mode 100644
index 0000000..d64c4bdf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>
+    CSS Test: Testing how a sizing change to one flex item impacts its sibling
+  </title>
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#layout-algorithm">
+  <link rel="match" href="flexbox-dyn-resize-001-ref.html">
+  <style>
+    .container {
+      width: 100px;
+      display: flex;
+      border: 1px solid purple;
+      margin-bottom: 15px;
+    }
+    .item {
+       margin: 2px;
+       background: lightblue;
+    }
+    .inline-box {
+      display: inline-block;
+      height: 10px;
+      width: 10px;
+      background: lightgray;
+      border: 1px solid black;
+     }
+  </style>
+  <script>
+  function go() {
+    // Make this item steal all the spare width (forcing its sibling to shrink)
+    // by giving it a huge 'width' and therefore huge flex-basis:
+    document.getElementById("change-width").style.width = "300px";
+
+    // Make this item steal all the spare width (forcing its sibling to shrink)
+    // by giving it a pretty big flex-basis and no shrinkability:
+    document.getElementById("change-flex").style.flex = "0 0 75px"
+  }
+  </script>
+</head>
+<body onload="go()">
+  <div class="container">
+    <div class="item" id="change-width">
+      <div class="inline-box"></div><div class="inline-box"></div>
+    </div>
+    <div class="item">
+      <div class="inline-box"></div><div class="inline-box"></div>
+    </div>
+  </div>
+
+  <div class="container">
+    <div class="item" id="change-flex">
+      <div class="inline-box"></div><div class="inline-box"></div>
+    </div>
+    <div class="item">
+      <div class="inline-box"></div><div class="inline-box"></div>
+    </div>
+  </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/screen-capture.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/screen-capture.idl
index 668f4588..b79d09d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/screen-capture.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/screen-capture.idl
@@ -7,12 +7,24 @@
     Promise<MediaStream> getDisplayMedia(optional MediaStreamConstraints constraints);
 };
 
+partial dictionary MediaTrackSupportedConstraints {
+             boolean displaySurface = true;
+             boolean logicalSurface = true;
+             boolean cursor = true;
+};
+
 partial dictionary MediaTrackConstraintSet {
              ConstrainDOMString displaySurface;
              ConstrainBoolean logicalSurface;
              ConstrainDOMString cursor;
 };
 
+partial dictionary MediaTrackSettings {
+             DOMString displaySurface;
+             boolean logicalSurface;
+             DOMString cursor;
+};
+
 enum DisplayCaptureSurfaceType {
     "monitor",
     "window",
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/speech-api.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/speech-api.idl
index 8e998df..0b5c866 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/speech-api.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/speech-api.idl
@@ -137,7 +137,8 @@
     attribute EventHandler onboundary;
 };
 
-[Exposed=Window]
+[Exposed=Window,
+  Constructor(DOMString type, SpeechSynthesisEventInit eventInitDict)]
 interface SpeechSynthesisEvent : Event {
     readonly attribute SpeechSynthesisUtterance utterance;
     readonly attribute unsigned long charIndex;
@@ -145,6 +146,13 @@
     readonly attribute DOMString name;
 };
 
+dictionary SpeechSynthesisEventInit : EventInit {
+    required SpeechSynthesisUtterance utterance;
+    unsigned long charIndex = 0;
+    float elapsedTime = 0;
+    DOMString name = "";
+};
+
 enum SpeechSynthesisErrorCode {
     "canceled",
     "interrupted",
@@ -160,11 +168,16 @@
     "not-allowed",
 };
 
-[Exposed=Window]
+[Exposed=Window,
+  Constructor(DOMString type, SpeechSynthesisErrorEventInit eventInitDict)]
 interface SpeechSynthesisErrorEvent : SpeechSynthesisEvent {
     readonly attribute SpeechSynthesisErrorCode error;
 };
 
+dictionary SpeechSynthesisErrorEventInit : SpeechSynthesisEventInit {
+    required SpeechSynthesisErrorCode error;
+};
+
 [Exposed=Window]
 interface SpeechSynthesisVoice {
     readonly attribute DOMString voiceURI;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesis-speak-without-activation-fails.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesis-speak-without-activation-fails.tentative.html
index acf0d7d..1b86552 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesis-speak-without-activation-fails.tentative.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesis-speak-without-activation-fails.tentative.html
@@ -8,7 +8,7 @@
 async_test(t => {
   const utter = new SpeechSynthesisUtterance('1');
   utter.onerror = t.step_func_done((e) => {
-    assert_equals(e.name, "not-allowed");
+    assert_equals(e.error, "not-allowed");
   });
   utter.onend = t.step_func_done(() => assert_unreached());
   speechSynthesis.speak(utter);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisErrorEvent-constructor.html b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisErrorEvent-constructor.html
new file mode 100644
index 0000000..61e179c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisErrorEvent-constructor.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+/*
+[Exposed=Window,
+ Constructor(DOMString type, SpeechSynthesisErrorEventInit eventInitDict)]
+interface SpeechSynthesisErrorEvent : SpeechSynthesisErrorEvent {
+    readonly attribute SpeechSynthesisErrorCode error;
+};
+*/
+test(() => {
+  assert_throws(new TypeError(), () => {
+    new SpeechSynthesisErrorEvent();
+  });
+}, "SpeechSynthesisErrorEvent with no arguments throws TypeError");
+
+test(() => {
+  assert_throws(new TypeError(), () => {
+    new SpeechSynthesisErrorEvent("type");
+  });
+}, "SpeechSynthesisErrorEvent with no eventInitDict throws TypeError");
+
+test(() => {
+  assert_throws(new TypeError(), () => {
+    new SpeechSynthesisErrorEvent("type", {});
+  });
+}, `SpeechSynthesisErrorEvent with empty eventInitDict throws TypeError (requires
+    utterance and error)`);
+
+test(() => {
+  assert_throws(new TypeError(), () => {
+    new SpeechSynthesisErrorEvent("type", {error:"not-allowed"});
+  });
+}, `SpeechSynthesisErrorEvent with eventInitDict without utterance throws
+    TypeError`);
+
+test(() => {
+  assert_throws(new TypeError(), () => {
+    new SpeechSynthesisErrorEvent("type", {utterance: new SpeechSynthesisUtterance()});
+  });
+}, `SpeechSynthesisErrorEvent with eventInitDict without error throws
+    TypeError`);
+
+test(() => {
+  const utterance = new SpeechSynthesisUtterance("foo");
+  const event = new SpeechSynthesisErrorEvent("type", {utterance: utterance, error:"not-allowed"});
+  assert_equals(event.utterance, utterance);
+  assert_equals(event.error, "not-allowed");
+  assert_equals(event.charIndex, 0);
+  assert_equals(event.elapsedTime, 0);
+  assert_equals(event.name, "");
+}, "SpeechSynthesisErrorEvent with eventInitDict having utterance and error");
+
+test(() => {
+  const utterance = new SpeechSynthesisUtterance("foo");
+  const event = new SpeechSynthesisErrorEvent("type", {
+    utterance: utterance,
+    charIndex: 5,
+    elapsedTime: 100,
+    name: "foo",
+    error: "synthesis-failed"
+  });
+  assert_equals(event.bubbles, false);
+  assert_equals(event.cancelable, false);
+  assert_equals(event.type, "type");
+  assert_equals(event.utterance, utterance);
+  assert_equals(event.charIndex, 5);
+  assert_equals(event.elapsedTime, 100);
+  assert_equals(event.name, "foo");
+  assert_equals(event.error, "synthesis-failed");
+}, "SpeechSynthesisErrorEvent with custom eventInitDict");
+
+test(() => {
+  function createEventFunc(error) {
+    return () => {
+      new SpeechSynthesisErrorEvent("type", {
+        utterance: new SpeechSynthesisUtterance(),
+        error: error
+      });
+    };
+  };
+  assert_throws(new TypeError(), createEventFunc(""));
+  assert_throws(new TypeError(), createEventFunc("foo"));
+  assert_throws(new TypeError(), createEventFunc("bar"));
+}, "SpeechSynthesisErrorEvent with wrong error enum");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisEvent-constructor.html b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisEvent-constructor.html
new file mode 100644
index 0000000..47a37d25
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisEvent-constructor.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+/*
+[Exposed=Window,
+ Constructor(DOMString type, SpeechSynthesisEventInit eventInitDict)]
+interface SpeechSynthesisEvent : Event {
+    readonly attribute SpeechSynthesisUtterance utterance;
+    readonly attribute unsigned long charIndex;
+    readonly attribute float elapsedTime;
+    readonly attribute DOMString name;
+};
+*/
+test(() => {
+  assert_throws(new TypeError(), () => {
+    new SpeechSynthesisEvent();
+  });
+}, "SpeechSynthesisEvent with no arguments throws TypeError");
+
+test(() => {
+  assert_throws(new TypeError(), () => {
+    new SpeechSynthesisEvent("type");
+  });
+}, "SpeechSynthesisEvent with no eventInitDict throws TypeError");
+
+test(() => {
+  assert_throws(new TypeError(), () => {
+    new SpeechSynthesisEvent("type", {});
+  });
+}, `SpeechSynthesisEvent with empty eventInitDict throws TypeError (requires
+    utterance)`);
+
+test(() => {
+  assert_throws(new TypeError(), () => {
+    new SpeechSynthesisEvent("type", {charIndex: 10, elapsedTime: 50, name:"foo"});
+  });
+}, `SpeechSynthesisEvent with eventInitDict not having utterance throws
+    TypeError`);
+
+test(() => {
+  const utterance = new SpeechSynthesisUtterance("foo");
+  const event = new SpeechSynthesisEvent("type", {utterance: utterance});
+  assert_equals(event.utterance, utterance);
+  assert_equals(event.charIndex, 0);
+  assert_equals(event.elapsedTime, 0);
+  assert_equals(event.name, "");
+}, "SpeechSynthesisEvent with eventInitDict having an utterance");
+
+test(() => {
+  const utterance = new SpeechSynthesisUtterance("foo");
+  const event = new SpeechSynthesisEvent("type", {
+    utterance: utterance,
+    charIndex: 5,
+    elapsedTime: 100,
+    name: "foo"
+  });
+  assert_equals(event.bubbles, false);
+  assert_equals(event.cancelable, false);
+  assert_equals(event.type, "type");
+  assert_equals(event.utterance, utterance);
+  assert_equals(event.charIndex, 5);
+  assert_equals(event.elapsedTime, 100);
+  assert_equals(event.name, "foo");
+}, "SpeechSynthesisEvent with custom eventInitDict");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window-expected.txt
index 12eedaf..e913d754 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 216 tests; 60 PASS, 156 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 216 tests; 67 PASS, 149 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface Window: original interface defined
 FAIL SpeechRecognition interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
@@ -195,13 +195,13 @@
 PASS SpeechSynthesisEvent interface: attribute charIndex
 PASS SpeechSynthesisEvent interface: attribute elapsedTime
 PASS SpeechSynthesisEvent interface: attribute name
-FAIL SpeechSynthesisErrorEvent interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
-FAIL SpeechSynthesisErrorEvent interface object length assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
-FAIL SpeechSynthesisErrorEvent interface object name assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
-FAIL SpeechSynthesisErrorEvent interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
-FAIL SpeechSynthesisErrorEvent interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
-FAIL SpeechSynthesisErrorEvent interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
-FAIL SpeechSynthesisErrorEvent interface: attribute error assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
+PASS SpeechSynthesisErrorEvent interface: existence and properties of interface object
+PASS SpeechSynthesisErrorEvent interface object length
+PASS SpeechSynthesisErrorEvent interface object name
+PASS SpeechSynthesisErrorEvent interface: existence and properties of interface prototype object
+PASS SpeechSynthesisErrorEvent interface: existence and properties of interface prototype object's "constructor" property
+PASS SpeechSynthesisErrorEvent interface: existence and properties of interface prototype object's @@unscopables property
+PASS SpeechSynthesisErrorEvent interface: attribute error
 FAIL SpeechSynthesisVoice interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
 FAIL SpeechSynthesisVoice interface object length assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
 FAIL SpeechSynthesisVoice interface object name assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/menulist-appearance-rtl-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/menulist-appearance-rtl-expected.txt
index d8d65a9..361d4f6 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/menulist-appearance-rtl-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/menulist-appearance-rtl-expected.txt
@@ -14,7 +14,7 @@
         LayoutNGBlockFlow {DD} at (40,20) size 744x40
           LayoutNGBlockFlow (anonymous) at (0,0) size 744x20
             LayoutMenuList {SELECT} at (0,0) size 100x20 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-              LayoutNGBlockFlow (anonymous) at (1,1) size 98x18
+              LayoutBlockFlow (anonymous) at (1,1) size 98x18
                 LayoutText (anonymous) at (26,1) size 68x16
                   text run at (26,1) width 47 RTL: "\x{5D0}\x{5E4}\x{5E8}\x{5E1}\x{5DE}\x{5D5}\x{5DF}"
                   text run at (73,1) width 21: "abc"
@@ -29,7 +29,7 @@
         LayoutNGBlockFlow {DD} at (40,80) size 744x40
           LayoutNGBlockFlow (anonymous) at (0,0) size 744x20
             LayoutMenuList {SELECT} at (0,0) size 200x20 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-              LayoutNGBlockFlow (anonymous) at (1,1) size 198x18
+              LayoutBlockFlow (anonymous) at (1,1) size 198x18
                 LayoutText (anonymous) at (4,1) size 68x16
                   text run at (4,1) width 21: "abc"
                   text run at (25,1) width 47 RTL: "\x{5D0}\x{5E4}\x{5E8}\x{5E1}\x{5DE}\x{5D5}\x{5DF}"
@@ -44,7 +44,7 @@
         LayoutNGBlockFlow {DD} at (40,140) size 744x40
           LayoutNGBlockFlow (anonymous) at (0,0) size 744x20
             LayoutMenuList {SELECT} at (0,0) size 100x20 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-              LayoutNGBlockFlow (anonymous) at (1,1) size 98x18
+              LayoutBlockFlow (anonymous) at (1,1) size 98x18
                 LayoutText (anonymous) at (4,1) size 68x16
                   text run at (4,1) width 21: "abc"
                   text run at (25,1) width 47 RTL: "\x{5D0}\x{5E4}\x{5E8}\x{5E1}\x{5DE}\x{5D5}\x{5DF}"
@@ -62,7 +62,7 @@
             text run at (0,0) width 139: "\x{627}\x{644}\x{627}\x{642}\x{62A}\x{631}\x{627}\x{62D}\x{627}\x{62A} / \x{627}\x{644}\x{634}\x{643}\x{627}\x{648}\x{64A}"
         LayoutNGBlockFlow (anonymous) at (0,39) size 784x20
           LayoutMenuList {SELECT} at (0,0) size 137x20 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-            LayoutNGBlockFlow (anonymous) at (1,1) size 135x18
+            LayoutBlockFlow (anonymous) at (1,1) size 135x18
               LayoutText (anonymous) at (4,1) size 115x16
                 text run at (4,1) width 115 RTL: "\x{627}\x{644}\x{627}\x{642}\x{62A}\x{631}\x{627}\x{62D}\x{627}\x{62A} / \x{627}\x{644}\x{634}\x{643}\x{627}\x{648}\x{64A}"
           LayoutText {#text} at (0,0) size 0x0
@@ -76,11 +76,11 @@
 layer at (8,399) size 784x160
   LayoutBlockFlow {DIV} at (0,383) size 784x160
     LayoutMultiColumnSet (anonymous) at (0,0) size 784x160
-layer at (8,399) size 384x320 backgroundClip at (0,0) size 400x559 clip at (0,0) size 400x559
+layer at (8,399) size 384x320 backgroundClip at (0,0) size 800x559 clip at (0,0) size 800x559
   LayoutMultiColumnFlowThread (anonymous) at (0,0) size 384x320
     LayoutBlockFlow {DIV} at (0,0) size 384x160
       LayoutMenuList {SELECT} at (0,0) size 350x22 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-        LayoutNGBlockFlow (anonymous) at (1,1) size 348x21
+        LayoutBlockFlow (anonymous) at (1,1) size 348x21
           LayoutText (anonymous) at (4,1) size 179x18
             text run at (4,1) width 35: "First "
             text run at (39,1) width 56 RTL: ") \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA}"
@@ -95,7 +95,7 @@
           text run at (82,1) width 30 RTL: "\x{5E9}\x{5E0}\x{5D9}\x{5D4} ("
           text run at (112,1) width 26: " fifth"
       LayoutMenuList {SELECT} at (0,40) size 350x22 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-        LayoutNGBlockFlow (anonymous) at (1,1) size 348x21
+        LayoutBlockFlow (anonymous) at (1,1) size 348x21
           LayoutText (anonymous) at (4,1) size 179x18
             text run at (4,1) width 25: "fifth"
             text run at (29,1) width 60 RTL: ") \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} "
@@ -110,14 +110,14 @@
           text run at (81,1) width 33 RTL: " \x{5E9}\x{5E0}\x{5D9}\x{5D4} ("
           text run at (114,1) width 24: "First"
       LayoutMenuList {SELECT} at (0,80) size 350x22 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-        LayoutNGBlockFlow (anonymous) at (1,1) size 348x21
+        LayoutBlockFlow (anonymous) at (1,1) size 348x21
           LayoutText (anonymous) at (4,1) size 179x18
             text run at (4,1) width 179 LTR override: "First \x{5E9}\x{5E0}\x{5D9}\x{5D4} (03) \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} fifth"
       LayoutBlockFlow {DIV} at (0,102) size 352x18
         LayoutText {#text} at (1,1) size 137x15
           text run at (1,1) width 137 LTR override: "First \x{5E9}\x{5E0}\x{5D9}\x{5D4} (03) \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} fifth"
       LayoutMenuList {SELECT} at (0,120) size 350x22 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-        LayoutNGBlockFlow (anonymous) at (1,1) size 348x21
+        LayoutBlockFlow (anonymous) at (1,1) size 348x21
           LayoutText (anonymous) at (4,1) size 179x18
             text run at (4,1) width 179 RTL override: "First \x{5E9}\x{5E0}\x{5D9}\x{5D4} (03) \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} fifth"
       LayoutBlockFlow {DIV} at (0,142) size 352x18
@@ -125,7 +125,7 @@
           text run at (1,1) width 137 RTL override: "First \x{5E9}\x{5E0}\x{5D9}\x{5D4} (03) \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} fifth"
     LayoutBlockFlow {DIV} at (0,160) size 384x160
       LayoutMenuList {SELECT} at (0,0) size 350x22 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-        LayoutNGBlockFlow (anonymous) at (1,1) size 348x21
+        LayoutBlockFlow (anonymous) at (1,1) size 348x21
           LayoutText (anonymous) at (165,1) size 179x18
             text run at (165,1) width 35: "First "
             text run at (200,1) width 56 RTL: ") \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA}"
@@ -140,7 +140,7 @@
           text run at (295,1) width 30 RTL: "\x{5E9}\x{5E0}\x{5D9}\x{5D4} ("
           text run at (325,1) width 26: " fifth"
       LayoutMenuList {SELECT} at (0,40) size 350x22 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-        LayoutNGBlockFlow (anonymous) at (1,1) size 348x21
+        LayoutBlockFlow (anonymous) at (1,1) size 348x21
           LayoutText (anonymous) at (165,1) size 179x18
             text run at (165,1) width 25: "fifth"
             text run at (190,1) width 60 RTL: ") \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} "
@@ -155,14 +155,14 @@
           text run at (294,1) width 33 RTL: " \x{5E9}\x{5E0}\x{5D9}\x{5D4} ("
           text run at (327,1) width 24: "First"
       LayoutMenuList {SELECT} at (0,80) size 350x22 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-        LayoutNGBlockFlow (anonymous) at (1,1) size 348x21
+        LayoutBlockFlow (anonymous) at (1,1) size 348x21
           LayoutText (anonymous) at (165,1) size 179x18
             text run at (165,1) width 179 LTR override: "First \x{5E9}\x{5E0}\x{5D9}\x{5D4} (03) \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} fifth"
       LayoutBlockFlow {DIV} at (0,102) size 352x18
         LayoutText {#text} at (214,1) size 137x15
           text run at (214,1) width 137 LTR override: "First \x{5E9}\x{5E0}\x{5D9}\x{5D4} (03) \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} fifth"
       LayoutMenuList {SELECT} at (0,120) size 350x22 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
-        LayoutNGBlockFlow (anonymous) at (1,1) size 348x21
+        LayoutBlockFlow (anonymous) at (1,1) size 348x21
           LayoutText (anonymous) at (165,1) size 179x18
             text run at (165,1) width 179 RTL override: "First \x{5E9}\x{5E0}\x{5D9}\x{5D4} (03) \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} fifth"
       LayoutBlockFlow {DIV} at (0,142) size 352x18
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fragmentation/transformed-clip-before-second-column-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fragmentation/transformed-clip-before-second-column-expected.txt
deleted file mode 100644
index de54a1fd..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fragmentation/transformed-clip-before-second-column-expected.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x86
-  LayoutNGBlockFlow {HTML} at (0,0) size 800x86
-    LayoutNGBlockFlow {BODY} at (8,8) size 784x70
-layer at (8,8) size 784x70
-  LayoutBlockFlow {DIV} at (0,0) size 784x70
-    LayoutMultiColumnSet (anonymous) at (0,0) size 784x70
-layer at (8,8) size 384x140 backgroundClip at (0,0) size 400x78 clip at (0,0) size 400x78
-  LayoutMultiColumnFlowThread (anonymous) at (0,0) size 384x140
-    LayoutBlockFlow {DIV} at (0,0) size 384x100
-layer at (408,38) size 384x40 scrollHeight 41
-  LayoutBlockFlow {DIV} at (0,100) size 384x40
-    LayoutBlockFlow (anonymous) at (0,0) size 384x20
-      LayoutText {#text} at (0,0) size 312x19
-        text run at (0,0) width 312: "There should be a black rectangle below this text."
-layer at (408,58) size 384x20
-  LayoutBlockFlow {DIV} at (0,20) size 384x20
-    LayoutInline {<pseudo:before>} at (0,0) size 10x19
-      LayoutTextFragment (anonymous) at (0,0) size 10x19
-        text run at (0,0) width 10: "\x{E8A7}"
-    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/rendering-broken-block-flow-images-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/rendering-broken-block-flow-images-expected.txt
deleted file mode 100644
index 097bcaf..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/rendering-broken-block-flow-images-expected.txt
+++ /dev/null
@@ -1,363 +0,0 @@
-layer at (0,0) size 800x600 clip at (0,0) size 785x585 scrollWidth 973 scrollHeight 860
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 785x860 backgroundClip at (0,0) size 785x585 clip at (0,0) size 785x585
-  LayoutNGBlockFlow {HTML} at (0,0) size 785x860
-    LayoutNGBlockFlow {BODY} at (8,16) size 769x836
-      LayoutNGBlockFlow {P} at (0,0) size 769x20
-        LayoutText {#text} at (0,0) size 315x19
-          text run at (0,0) width 315: "crbug.com/644802: Render alt text per html5 spec"
-layer at (8,52) size 769x800 backgroundClip at (0,0) size 785x585 clip at (0,0) size 785x585
-  LayoutBlockFlow {DIV} at (0,36) size 769x800
-    LayoutMultiColumnSet (anonymous) at (0,0) size 769x800
-layer at (8,52) size 180x3621 backgroundClip at (0,0) size 196x585 clip at (0,0) size 196x585
-  LayoutMultiColumnFlowThread (anonymous) at (0,0) size 180.25x3621
-    LayoutBlockFlow {DIV} at (0,16) size 180.25x401
-      LayoutBlockFlow {P} at (0,0) size 180.25x20
-        LayoutText {#text} at (0,0) size 132x19
-          text run at (0,0) width 132: "Different dimensions"
-      LayoutNGBlockFlow (anonymous) at (0,36) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,56) size 25x25 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 23x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 23x39
-            LayoutText {#text} at (0,16) size 23x39
-              text run at (0,16) width 15: "alt"
-              text run at (0,36) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,81) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,121) size 50x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,171) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,211) size 50x40 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,251) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,291) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-      LayoutNGBlockFlow (anonymous) at (0,341) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,381) size 180.25x20 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-    LayoutBlockFlow {DIV} at (0,433) size 180.25x361
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 175x39
-          text run at (0,0) width 175: "Different dimensions, no alt"
-          text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,231) size 50x0 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,231) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,271) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,321) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,361) size 180.25x0
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutImage (floating) {IMG} at (0,6) size 16x16
-          LayoutInline {SPAN} at (0,0) size 0x0
-    LayoutBlockFlow {DIV} at (0,800) size 180.25x381
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (16,0) size 172x39
-          text run at (16,0) width 156: "Different dimensions, no"
-          text run at (0,20) width 50: "alt text, "
-          text run at (50,20) width 49: "src = \"\""
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,231) size 50x0 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,231) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,271) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,321) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,361) size 180.25x0
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,361) size 180.25x20
-        LayoutBR {BR} at (0,0) size 0x19
-    LayoutBlockFlow {DIV} at (0,1197) size 180.25x361
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 175x39
-          text run at (0,0) width 175: "Different dimensions, no alt"
-          text run at (0,20) width 69: "text, no src"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutImage {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutImage {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutImage {IMG} at (0,231) size 50x0 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,231) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutImage {IMG} at (0,271) size 0x50 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,321) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutImage {IMG} at (0,361) size 0x0
-    LayoutBlockFlow {DIV} at (0,1600) size 180.25x421
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 31: "text, "
-          text run at (31,20) width 49: "src = \"\""
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 23x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 23x39
-            LayoutText {#text} at (0,16) size 23x39
-              text run at (0,16) width 15: "alt"
-              text run at (0,36) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,231) size 50x40 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,271) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,311) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-      LayoutNGBlockFlow (anonymous) at (0,361) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,401) size 180.25x0
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,401) size 180.25x20
-        LayoutBR {BR} at (0,0) size 0x19
-    LayoutBlockFlow {DIV} at (0,2400) size 180.25x441
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 69: "text, no src"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 23x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 23x39
-            LayoutText {#text} at (0,16) size 23x39
-              text run at (0,16) width 15: "alt"
-              text run at (0,36) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,231) size 50x40 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,271) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,311) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-      LayoutNGBlockFlow (anonymous) at (0,361) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,401) size 180.25x20
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-      LayoutNGBlockFlow (anonymous) at (0,421) size 180.25x20
-        LayoutBR {BR} at (0,0) size 0x19
-    LayoutBlockFlow {DIV} at (0,3200) size 180.25x421
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 31: "text, "
-          text run at (31,20) width 31: "src ="
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 23x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 23x39
-            LayoutText {#text} at (0,16) size 23x39
-              text run at (0,16) width 15: "alt"
-              text run at (0,36) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,231) size 50x40 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,271) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,311) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-      LayoutNGBlockFlow (anonymous) at (0,361) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,401) size 180.25x0
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,401) size 180.25x20
-        LayoutBR {BR} at (0,0) size 0x19
-layer at (8,561) size 25x25 backgroundClip at (8,561) size 25x24 clip at (9,562) size 23x23
-  LayoutBlockFlow {SPAN} at (0,0) size 25x25 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (8,626) size 50x50 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow {SPAN} at (0,0) size 50x50 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (204,128) size 25x25 clip at (205,129) size 23x23
-  LayoutBlockFlow {SPAN} at (0,0) size 25x25 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (204,193) size 50x50 clip at (205,194) size 48x48
-  LayoutBlockFlow {SPAN} at (0,0) size 50x50 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/rendering-broken-images-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/rendering-broken-images-expected.txt
deleted file mode 100644
index 6fa9db3..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/rendering-broken-images-expected.txt
+++ /dev/null
@@ -1,364 +0,0 @@
-layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 860
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 785x860 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
-  LayoutNGBlockFlow {HTML} at (0,0) size 785x860
-    LayoutNGBlockFlow {BODY} at (8,16) size 769x836
-      LayoutNGBlockFlow {P} at (0,0) size 769x20
-        LayoutText {#text} at (0,0) size 315x19
-          text run at (0,0) width 315: "crbug.com/644802: Render alt text per html5 spec"
-layer at (8,52) size 769x800 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
-  LayoutBlockFlow {DIV} at (0,36) size 769x800
-    LayoutMultiColumnSet (anonymous) at (0,0) size 769x408
-layer at (8,52) size 180x1552 backgroundClip at (0,0) size 196x460 clip at (0,0) size 196x460
-  LayoutMultiColumnFlowThread (anonymous) at (0,0) size 180.25x1552
-    LayoutBlockFlow {DIV} at (0,16) size 180.25x136
-      LayoutBlockFlow {P} at (0,0) size 180.25x20
-        LayoutText {#text} at (0,0) size 132x19
-          text run at (0,0) width 132: "Different dimensions"
-      LayoutNGBlockFlow (anonymous) at (0,36) size 180.25x100
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,0) size 4x19
-          text run at (70,0) width 4: " "
-        LayoutBR {BR} at (74,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,20) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,20) size 4x19
-          text run at (70,20) width 4: " "
-        LayoutBR {BR} at (74,20) size 0x19
-        LayoutText {#text} at (0,40) size 12x19
-          text run at (0,40) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,40) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutBR {BR} at (70,40) size 0x19
-        LayoutText {#text} at (0,60) size 12x19
-          text run at (0,60) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,60) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutBR {BR} at (70,60) size 0x19
-        LayoutText {#text} at (0,80) size 12x19
-          text run at (0,80) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,80) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (0,0) size 0x0
-    LayoutBlockFlow {DIV} at (0,168) size 180.25x204
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 175x39
-          text run at (0,0) width 175: "Different dimensions, no alt"
-          text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x148
-        LayoutText {#text} at (0,10) size 12x19
-          text run at (0,10) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 25x25 [bgcolor=#008000]
-        LayoutBR {BR} at (37,10) size 0x19
-        LayoutText {#text} at (0,65) size 12x19
-          text run at (0,65) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,30) size 50x50 [bgcolor=#008000]
-        LayoutBR {BR} at (62,65) size 0x19
-        LayoutText {#text} at (0,86) size 12x19
-          text run at (0,86) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,85) size 16x16 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutBR {BR} at (28,86) size 0x19
-        LayoutText {#text} at (0,107) size 12x19
-          text run at (0,107) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,106) size 16x16 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutBR {BR} at (28,107) size 0x19
-        LayoutText {#text} at (0,128) size 12x19
-          text run at (0,128) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,127) size 16x16
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutText {#text} at (0,0) size 0x0
-    LayoutBlockFlow {DIV} at (0,408) size 180.25x201
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 175x39
-          text run at (0,0) width 175: "Different dimensions, no alt"
-          text run at (0,20) width 31: "text, "
-          text run at (31,20) width 49: "src = \"\""
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x145
-        LayoutText {#text} at (0,10) size 12x19
-          text run at (0,10) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 25x25 [bgcolor=#008000]
-        LayoutBR {BR} at (37,10) size 0x19
-        LayoutText {#text} at (0,65) size 12x19
-          text run at (0,65) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,30) size 50x50 [bgcolor=#008000]
-        LayoutBR {BR} at (62,65) size 0x19
-        LayoutText {#text} at (0,85) size 12x19
-          text run at (0,85) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,100) size 0x0 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutBR {BR} at (12,85) size 0x19
-        LayoutText {#text} at (0,105) size 12x19
-          text run at (0,105) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,120) size 0x0 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutBR {BR} at (12,105) size 0x19
-        LayoutText {#text} at (0,125) size 12x19
-          text run at (0,125) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,140) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutBR {BR} at (12,125) size 0x19
-    LayoutBlockFlow {DIV} at (0,816) size 180.25x236
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 175x39
-          text run at (0,0) width 175: "Different dimensions, no alt"
-          text run at (0,20) width 69: "text, no src"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x180
-        LayoutText {#text} at (0,10) size 12x19
-          text run at (0,10) width 12: "1."
-        LayoutImage {IMG} at (12,0) size 25x25 [bgcolor=#008000]
-        LayoutText {#text} at (37,10) size 4x19
-          text run at (37,10) width 4: " "
-        LayoutBR {BR} at (41,10) size 0x19
-        LayoutText {#text} at (0,65) size 12x19
-          text run at (0,65) width 12: "2."
-        LayoutImage {IMG} at (12,30) size 50x50 [bgcolor=#008000]
-        LayoutText {#text} at (62,65) size 4x19
-          text run at (62,65) width 4: " "
-        LayoutBR {BR} at (66,65) size 0x19
-        LayoutText {#text} at (0,85) size 12x19
-          text run at (0,85) width 12: "3."
-        LayoutImage {IMG} at (12,100) size 50x0 [bgcolor=#008000]
-        LayoutText {#text} at (62,85) size 4x19
-          text run at (62,85) width 4: " "
-        LayoutBR {BR} at (66,85) size 0x19
-        LayoutText {#text} at (0,140) size 12x19
-          text run at (0,140) width 12: "4."
-        LayoutImage {IMG} at (12,105) size 0x50 [bgcolor=#008000]
-        LayoutText {#text} at (12,140) size 4x19
-          text run at (12,140) width 4: " "
-        LayoutBR {BR} at (16,140) size 0x19
-        LayoutText {#text} at (0,160) size 12x19
-          text run at (0,160) width 12: "5."
-        LayoutImage {IMG} at (12,175) size 0x0
-        LayoutText {#text} at (0,0) size 0x0
-    LayoutBlockFlow {DIV} at (0,1068) size 180.25x156
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 31: "text, "
-          text run at (31,20) width 49: "src = \"\""
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x100
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,0) size 4x19
-          text run at (70,0) width 4: " "
-        LayoutBR {BR} at (74,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,20) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,20) size 4x19
-          text run at (70,20) width 4: " "
-        LayoutBR {BR} at (74,20) size 0x19
-        LayoutText {#text} at (0,40) size 12x19
-          text run at (0,40) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,40) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,40) size 4x19
-          text run at (70,40) width 4: " "
-        LayoutBR {BR} at (74,40) size 0x19
-        LayoutText {#text} at (0,60) size 12x19
-          text run at (0,60) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,60) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,60) size 4x19
-          text run at (70,60) width 4: " "
-        LayoutBR {BR} at (74,60) size 0x19
-        LayoutText {#text} at (0,80) size 12x19
-          text run at (0,80) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,95) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutText {#text} at (12,80) size 4x19
-          text run at (12,80) width 4: " "
-        LayoutBR {BR} at (16,80) size 0x19
-    LayoutBlockFlow {DIV} at (0,1224) size 180.25x156
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 69: "text, no src"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x100
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,0) size 4x19
-          text run at (70,0) width 4: " "
-        LayoutBR {BR} at (74,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,20) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,20) size 4x19
-          text run at (70,20) width 4: " "
-        LayoutBR {BR} at (74,20) size 0x19
-        LayoutText {#text} at (0,40) size 12x19
-          text run at (0,40) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,40) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,40) size 4x19
-          text run at (70,40) width 4: " "
-        LayoutBR {BR} at (74,40) size 0x19
-        LayoutText {#text} at (0,60) size 12x19
-          text run at (0,60) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,60) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,60) size 4x19
-          text run at (70,60) width 4: " "
-        LayoutBR {BR} at (74,60) size 0x19
-        LayoutText {#text} at (0,80) size 12x19
-          text run at (0,80) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,80) size 58x20
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,80) size 4x19
-          text run at (70,80) width 4: " "
-        LayoutBR {BR} at (74,80) size 0x19
-    LayoutBlockFlow {DIV} at (0,1396) size 180.25x156
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 31: "text, "
-          text run at (31,20) width 31: "src ="
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x100
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,0) size 4x19
-          text run at (70,0) width 4: " "
-        LayoutBR {BR} at (74,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,20) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,20) size 4x19
-          text run at (70,20) width 4: " "
-        LayoutBR {BR} at (74,20) size 0x19
-        LayoutText {#text} at (0,40) size 12x19
-          text run at (0,40) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,40) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,40) size 4x19
-          text run at (70,40) width 4: " "
-        LayoutBR {BR} at (74,40) size 0x19
-        LayoutText {#text} at (0,60) size 12x19
-          text run at (0,60) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,60) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,60) size 4x19
-          text run at (70,60) width 4: " "
-        LayoutBR {BR} at (74,60) size 0x19
-        LayoutText {#text} at (0,80) size 12x19
-          text run at (0,80) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,95) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutText {#text} at (12,80) size 4x19
-          text run at (12,80) width 4: " "
-        LayoutBR {BR} at (16,80) size 0x19
-layer at (20,276) size 25x25 clip at (21,277) size 23x23
-  LayoutBlockFlow {SPAN} at (0,0) size 25x25 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (20,306) size 50x50 clip at (21,307) size 48x48
-  LayoutBlockFlow {SPAN} at (0,0) size 50x50 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (216,108) size 25x25 clip at (217,109) size 23x23
-  LayoutBlockFlow {SPAN} at (0,0) size 25x25 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (216,138) size 50x50 clip at (217,139) size 48x48
-  LayoutBlockFlow {SPAN} at (0,0) size 50x50 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/rendering-broken-block-flow-images-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/rendering-broken-block-flow-images-expected.txt
deleted file mode 100644
index 097bcaf..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/rendering-broken-block-flow-images-expected.txt
+++ /dev/null
@@ -1,363 +0,0 @@
-layer at (0,0) size 800x600 clip at (0,0) size 785x585 scrollWidth 973 scrollHeight 860
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 785x860 backgroundClip at (0,0) size 785x585 clip at (0,0) size 785x585
-  LayoutNGBlockFlow {HTML} at (0,0) size 785x860
-    LayoutNGBlockFlow {BODY} at (8,16) size 769x836
-      LayoutNGBlockFlow {P} at (0,0) size 769x20
-        LayoutText {#text} at (0,0) size 315x19
-          text run at (0,0) width 315: "crbug.com/644802: Render alt text per html5 spec"
-layer at (8,52) size 769x800 backgroundClip at (0,0) size 785x585 clip at (0,0) size 785x585
-  LayoutBlockFlow {DIV} at (0,36) size 769x800
-    LayoutMultiColumnSet (anonymous) at (0,0) size 769x800
-layer at (8,52) size 180x3621 backgroundClip at (0,0) size 196x585 clip at (0,0) size 196x585
-  LayoutMultiColumnFlowThread (anonymous) at (0,0) size 180.25x3621
-    LayoutBlockFlow {DIV} at (0,16) size 180.25x401
-      LayoutBlockFlow {P} at (0,0) size 180.25x20
-        LayoutText {#text} at (0,0) size 132x19
-          text run at (0,0) width 132: "Different dimensions"
-      LayoutNGBlockFlow (anonymous) at (0,36) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,56) size 25x25 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 23x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 23x39
-            LayoutText {#text} at (0,16) size 23x39
-              text run at (0,16) width 15: "alt"
-              text run at (0,36) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,81) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,121) size 50x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,171) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,211) size 50x40 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,251) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,291) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-      LayoutNGBlockFlow (anonymous) at (0,341) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,381) size 180.25x20 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-    LayoutBlockFlow {DIV} at (0,433) size 180.25x361
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 175x39
-          text run at (0,0) width 175: "Different dimensions, no alt"
-          text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,231) size 50x0 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,231) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,271) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,321) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,361) size 180.25x0
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutImage (floating) {IMG} at (0,6) size 16x16
-          LayoutInline {SPAN} at (0,0) size 0x0
-    LayoutBlockFlow {DIV} at (0,800) size 180.25x381
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (16,0) size 172x39
-          text run at (16,0) width 156: "Different dimensions, no"
-          text run at (0,20) width 50: "alt text, "
-          text run at (50,20) width 49: "src = \"\""
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,231) size 50x0 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,231) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,271) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,321) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,361) size 180.25x0
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,361) size 180.25x20
-        LayoutBR {BR} at (0,0) size 0x19
-    LayoutBlockFlow {DIV} at (0,1197) size 180.25x361
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 175x39
-          text run at (0,0) width 175: "Different dimensions, no alt"
-          text run at (0,20) width 69: "text, no src"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutImage {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutImage {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutImage {IMG} at (0,231) size 50x0 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,231) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutImage {IMG} at (0,271) size 0x50 [bgcolor=#008000]
-      LayoutNGBlockFlow (anonymous) at (0,321) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutImage {IMG} at (0,361) size 0x0
-    LayoutBlockFlow {DIV} at (0,1600) size 180.25x421
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 31: "text, "
-          text run at (31,20) width 49: "src = \"\""
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 23x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 23x39
-            LayoutText {#text} at (0,16) size 23x39
-              text run at (0,16) width 15: "alt"
-              text run at (0,36) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,231) size 50x40 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,271) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,311) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-      LayoutNGBlockFlow (anonymous) at (0,361) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,401) size 180.25x0
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,401) size 180.25x20
-        LayoutBR {BR} at (0,0) size 0x19
-    LayoutBlockFlow {DIV} at (0,2400) size 180.25x441
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 69: "text, no src"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 23x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 23x39
-            LayoutText {#text} at (0,16) size 23x39
-              text run at (0,16) width 15: "alt"
-              text run at (0,36) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,231) size 50x40 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,271) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,311) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-      LayoutNGBlockFlow (anonymous) at (0,361) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,401) size 180.25x20
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-      LayoutNGBlockFlow (anonymous) at (0,421) size 180.25x20
-        LayoutBR {BR} at (0,0) size 0x19
-    LayoutBlockFlow {DIV} at (0,3200) size 180.25x421
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 31: "text, "
-          text run at (31,20) width 31: "src ="
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x20
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-      LayoutNGBlockFlow {IMG} at (0,76) size 25x25 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 23x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 23x39
-            LayoutText {#text} at (0,16) size 23x39
-              text run at (0,16) width 15: "alt"
-              text run at (0,36) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,101) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-      LayoutNGBlockFlow {IMG} at (0,141) size 50x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,191) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "3."
-      LayoutNGBlockFlow {IMG} at (0,231) size 50x40 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 31x39
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 31x39
-            LayoutText {#text} at (16,0) size 31x39
-              text run at (16,0) width 15: "alt"
-              text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,271) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "4."
-      LayoutNGBlockFlow {IMG} at (0,311) size 180.25x50 [bgcolor=#008000]
-        LayoutInline {SPAN} at (0,0) size 42x19
-          LayoutImage (floating) {IMG} at (0,0) size 16x16
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutText {#text} at (16,0) size 42x19
-              text run at (16,0) width 42: "alt text"
-      LayoutNGBlockFlow (anonymous) at (0,361) size 180.25x40
-        LayoutBR {BR} at (0,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "5."
-      LayoutNGBlockFlow {IMG} at (0,401) size 180.25x0
-        LayoutInline {SPAN} at (0,0) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,401) size 180.25x20
-        LayoutBR {BR} at (0,0) size 0x19
-layer at (8,561) size 25x25 backgroundClip at (8,561) size 25x24 clip at (9,562) size 23x23
-  LayoutBlockFlow {SPAN} at (0,0) size 25x25 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (8,626) size 50x50 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow {SPAN} at (0,0) size 50x50 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (204,128) size 25x25 clip at (205,129) size 23x23
-  LayoutBlockFlow {SPAN} at (0,0) size 25x25 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (204,193) size 50x50 clip at (205,194) size 48x48
-  LayoutBlockFlow {SPAN} at (0,0) size 50x50 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/rendering-broken-images-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/rendering-broken-images-expected.txt
deleted file mode 100644
index 6fa9db3..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/rendering-broken-images-expected.txt
+++ /dev/null
@@ -1,364 +0,0 @@
-layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 860
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 785x860 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
-  LayoutNGBlockFlow {HTML} at (0,0) size 785x860
-    LayoutNGBlockFlow {BODY} at (8,16) size 769x836
-      LayoutNGBlockFlow {P} at (0,0) size 769x20
-        LayoutText {#text} at (0,0) size 315x19
-          text run at (0,0) width 315: "crbug.com/644802: Render alt text per html5 spec"
-layer at (8,52) size 769x800 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
-  LayoutBlockFlow {DIV} at (0,36) size 769x800
-    LayoutMultiColumnSet (anonymous) at (0,0) size 769x408
-layer at (8,52) size 180x1552 backgroundClip at (0,0) size 196x460 clip at (0,0) size 196x460
-  LayoutMultiColumnFlowThread (anonymous) at (0,0) size 180.25x1552
-    LayoutBlockFlow {DIV} at (0,16) size 180.25x136
-      LayoutBlockFlow {P} at (0,0) size 180.25x20
-        LayoutText {#text} at (0,0) size 132x19
-          text run at (0,0) width 132: "Different dimensions"
-      LayoutNGBlockFlow (anonymous) at (0,36) size 180.25x100
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,0) size 4x19
-          text run at (70,0) width 4: " "
-        LayoutBR {BR} at (74,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,20) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,20) size 4x19
-          text run at (70,20) width 4: " "
-        LayoutBR {BR} at (74,20) size 0x19
-        LayoutText {#text} at (0,40) size 12x19
-          text run at (0,40) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,40) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutBR {BR} at (70,40) size 0x19
-        LayoutText {#text} at (0,60) size 12x19
-          text run at (0,60) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,60) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutBR {BR} at (70,60) size 0x19
-        LayoutText {#text} at (0,80) size 12x19
-          text run at (0,80) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,80) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (0,0) size 0x0
-    LayoutBlockFlow {DIV} at (0,168) size 180.25x204
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 175x39
-          text run at (0,0) width 175: "Different dimensions, no alt"
-          text run at (0,20) width 23: "text"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x148
-        LayoutText {#text} at (0,10) size 12x19
-          text run at (0,10) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 25x25 [bgcolor=#008000]
-        LayoutBR {BR} at (37,10) size 0x19
-        LayoutText {#text} at (0,65) size 12x19
-          text run at (0,65) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,30) size 50x50 [bgcolor=#008000]
-        LayoutBR {BR} at (62,65) size 0x19
-        LayoutText {#text} at (0,86) size 12x19
-          text run at (0,86) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,85) size 16x16 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutBR {BR} at (28,86) size 0x19
-        LayoutText {#text} at (0,107) size 12x19
-          text run at (0,107) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,106) size 16x16 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutBR {BR} at (28,107) size 0x19
-        LayoutText {#text} at (0,128) size 12x19
-          text run at (0,128) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,127) size 16x16
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutText {#text} at (0,0) size 0x0
-    LayoutBlockFlow {DIV} at (0,408) size 180.25x201
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 175x39
-          text run at (0,0) width 175: "Different dimensions, no alt"
-          text run at (0,20) width 31: "text, "
-          text run at (31,20) width 49: "src = \"\""
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x145
-        LayoutText {#text} at (0,10) size 12x19
-          text run at (0,10) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 25x25 [bgcolor=#008000]
-        LayoutBR {BR} at (37,10) size 0x19
-        LayoutText {#text} at (0,65) size 12x19
-          text run at (0,65) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,30) size 50x50 [bgcolor=#008000]
-        LayoutBR {BR} at (62,65) size 0x19
-        LayoutText {#text} at (0,85) size 12x19
-          text run at (0,85) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,100) size 0x0 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutBR {BR} at (12,85) size 0x19
-        LayoutText {#text} at (0,105) size 12x19
-          text run at (0,105) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,120) size 0x0 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutBR {BR} at (12,105) size 0x19
-        LayoutText {#text} at (0,125) size 12x19
-          text run at (0,125) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,140) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutBR {BR} at (12,125) size 0x19
-    LayoutBlockFlow {DIV} at (0,816) size 180.25x236
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 175x39
-          text run at (0,0) width 175: "Different dimensions, no alt"
-          text run at (0,20) width 69: "text, no src"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x180
-        LayoutText {#text} at (0,10) size 12x19
-          text run at (0,10) width 12: "1."
-        LayoutImage {IMG} at (12,0) size 25x25 [bgcolor=#008000]
-        LayoutText {#text} at (37,10) size 4x19
-          text run at (37,10) width 4: " "
-        LayoutBR {BR} at (41,10) size 0x19
-        LayoutText {#text} at (0,65) size 12x19
-          text run at (0,65) width 12: "2."
-        LayoutImage {IMG} at (12,30) size 50x50 [bgcolor=#008000]
-        LayoutText {#text} at (62,65) size 4x19
-          text run at (62,65) width 4: " "
-        LayoutBR {BR} at (66,65) size 0x19
-        LayoutText {#text} at (0,85) size 12x19
-          text run at (0,85) width 12: "3."
-        LayoutImage {IMG} at (12,100) size 50x0 [bgcolor=#008000]
-        LayoutText {#text} at (62,85) size 4x19
-          text run at (62,85) width 4: " "
-        LayoutBR {BR} at (66,85) size 0x19
-        LayoutText {#text} at (0,140) size 12x19
-          text run at (0,140) width 12: "4."
-        LayoutImage {IMG} at (12,105) size 0x50 [bgcolor=#008000]
-        LayoutText {#text} at (12,140) size 4x19
-          text run at (12,140) width 4: " "
-        LayoutBR {BR} at (16,140) size 0x19
-        LayoutText {#text} at (0,160) size 12x19
-          text run at (0,160) width 12: "5."
-        LayoutImage {IMG} at (12,175) size 0x0
-        LayoutText {#text} at (0,0) size 0x0
-    LayoutBlockFlow {DIV} at (0,1068) size 180.25x156
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 31: "text, "
-          text run at (31,20) width 49: "src = \"\""
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x100
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,0) size 4x19
-          text run at (70,0) width 4: " "
-        LayoutBR {BR} at (74,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,20) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,20) size 4x19
-          text run at (70,20) width 4: " "
-        LayoutBR {BR} at (74,20) size 0x19
-        LayoutText {#text} at (0,40) size 12x19
-          text run at (0,40) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,40) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,40) size 4x19
-          text run at (70,40) width 4: " "
-        LayoutBR {BR} at (74,40) size 0x19
-        LayoutText {#text} at (0,60) size 12x19
-          text run at (0,60) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,60) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,60) size 4x19
-          text run at (70,60) width 4: " "
-        LayoutBR {BR} at (74,60) size 0x19
-        LayoutText {#text} at (0,80) size 12x19
-          text run at (0,80) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,95) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutText {#text} at (12,80) size 4x19
-          text run at (12,80) width 4: " "
-        LayoutBR {BR} at (16,80) size 0x19
-    LayoutBlockFlow {DIV} at (0,1224) size 180.25x156
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 69: "text, no src"
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x100
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,0) size 4x19
-          text run at (70,0) width 4: " "
-        LayoutBR {BR} at (74,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,20) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,20) size 4x19
-          text run at (70,20) width 4: " "
-        LayoutBR {BR} at (74,20) size 0x19
-        LayoutText {#text} at (0,40) size 12x19
-          text run at (0,40) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,40) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,40) size 4x19
-          text run at (70,40) width 4: " "
-        LayoutBR {BR} at (74,40) size 0x19
-        LayoutText {#text} at (0,60) size 12x19
-          text run at (0,60) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,60) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,60) size 4x19
-          text run at (70,60) width 4: " "
-        LayoutBR {BR} at (74,60) size 0x19
-        LayoutText {#text} at (0,80) size 12x19
-          text run at (0,80) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,80) size 58x20
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,80) size 4x19
-          text run at (70,80) width 4: " "
-        LayoutBR {BR} at (74,80) size 0x19
-    LayoutBlockFlow {DIV} at (0,1396) size 180.25x156
-      LayoutBlockFlow {P} at (0,0) size 180.25x40
-        LayoutText {#text} at (0,0) size 155x39
-          text run at (0,0) width 155: "Different dimensions, alt"
-          text run at (0,20) width 31: "text, "
-          text run at (31,20) width 31: "src ="
-      LayoutNGBlockFlow (anonymous) at (0,56) size 180.25x100
-        LayoutText {#text} at (0,0) size 12x19
-          text run at (0,0) width 12: "1."
-        LayoutNGBlockFlow {IMG} at (12,0) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,0) size 4x19
-          text run at (70,0) width 4: " "
-        LayoutBR {BR} at (74,0) size 0x19
-        LayoutText {#text} at (0,20) size 12x19
-          text run at (0,20) width 12: "2."
-        LayoutNGBlockFlow {IMG} at (12,20) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,20) size 4x19
-          text run at (70,20) width 4: " "
-        LayoutBR {BR} at (74,20) size 0x19
-        LayoutText {#text} at (0,40) size 12x19
-          text run at (0,40) width 12: "3."
-        LayoutNGBlockFlow {IMG} at (12,40) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,40) size 4x19
-          text run at (70,40) width 4: " "
-        LayoutBR {BR} at (74,40) size 0x19
-        LayoutText {#text} at (0,60) size 12x19
-          text run at (0,60) width 12: "4."
-        LayoutNGBlockFlow {IMG} at (12,60) size 58x20 [bgcolor=#008000]
-          LayoutInline {SPAN} at (0,0) size 42x19
-            LayoutImage (floating) {IMG} at (0,0) size 16x16
-            LayoutInline {SPAN} at (0,0) size 42x19
-              LayoutText {#text} at (16,0) size 42x19
-                text run at (16,0) width 42: "alt text"
-        LayoutText {#text} at (70,60) size 4x19
-          text run at (70,60) width 4: " "
-        LayoutBR {BR} at (74,60) size 0x19
-        LayoutText {#text} at (0,80) size 12x19
-          text run at (0,80) width 12: "5."
-        LayoutNGBlockFlow {IMG} at (12,95) size 0x0
-          LayoutInline {SPAN} at (0,0) size 0x0
-            LayoutInline {SPAN} at (0,0) size 0x0
-        LayoutText {#text} at (12,80) size 4x19
-          text run at (12,80) width 4: " "
-        LayoutBR {BR} at (16,80) size 0x19
-layer at (20,276) size 25x25 clip at (21,277) size 23x23
-  LayoutBlockFlow {SPAN} at (0,0) size 25x25 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (20,306) size 50x50 clip at (21,307) size 48x48
-  LayoutBlockFlow {SPAN} at (0,0) size 50x50 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (216,108) size 25x25 clip at (217,109) size 23x23
-  LayoutBlockFlow {SPAN} at (0,0) size 25x25 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
-layer at (216,138) size 50x50 clip at (217,139) size 48x48
-  LayoutBlockFlow {SPAN} at (0,0) size 50x50 [border: (1px solid #C0C0C0)]
-    LayoutImage (floating) {IMG} at (2,2) size 16x16
-    LayoutInline {SPAN} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-svg-attribute-ns-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-svg-attribute-ns-expected.txt
new file mode 100644
index 0000000..5d4c4a02
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-svg-attribute-ns-expected.txt
@@ -0,0 +1,6 @@
+Test that namespaced attributes can be modified.
+Original attribute:
+xlink:href=fake_original_image.png
+Modified attribute:
+xlink:href=fake_modified_image.png
+
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-svg-attribute-ns.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-svg-attribute-ns.js
new file mode 100644
index 0000000..d92f1e0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-svg-attribute-ns.js
@@ -0,0 +1,22 @@
+(async function(testRunner) {
+  var {page, session, dp} = await testRunner.startHTML(`
+    <svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
+      <image id='main' xlink:href="fake_original_image.png"/>
+    </svg>
+  `, 'Test that namespaced attributes can be modified.');
+
+  var response = await dp.DOM.getDocument();
+  var rootNodeId = response.result.root.nodeId;
+
+  response = await dp.DOM.querySelector({nodeId: rootNodeId, selector: '#main'})
+  var nodeId = response.result.nodeId;
+  testRunner.log('Original attribute:');
+  response = await dp.DOM.getAttributes({nodeId});
+  testRunner.log(response.result.attributes[2] + '=' + response.result.attributes[3]);
+
+  dp.DOM.setAttributesAsText({nodeId, name: 'xlink:href', text: 'xlink:href="fake_modified_image.png"'});
+  response = await dp.DOM.onceAttributeModified();
+  testRunner.log('Modified attribute:');
+  testRunner.log(response.params.name + '=' + response.params.value);
+  testRunner.completeTest();
+})
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 9e80ac5..43dbaff5 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -6335,6 +6335,10 @@
     method constructor
     setter onaddsourcebuffer
     setter onremovesourcebuffer
+interface SpeechSynthesisErrorEvent : SpeechSynthesisEvent
+    attribute @@toStringTag
+    getter error
+    method constructor
 interface SpeechSynthesisEvent : Event
     attribute @@toStringTag
     getter charIndex
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 8defe0ac..13266312 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -7070,6 +7070,10 @@
     method constructor
     setter onaddsourcebuffer
     setter onremovesourcebuffer
+interface SpeechSynthesisErrorEvent : SpeechSynthesisEvent
+    attribute @@toStringTag
+    getter error
+    method constructor
 interface SpeechSynthesisEvent : Event
     attribute @@toStringTag
     getter charIndex
diff --git a/third_party/blink/common/feature_policy/feature_policy.cc b/third_party/blink/common/feature_policy/feature_policy.cc
index 1ac1240..164578ba 100644
--- a/third_party/blink/common/feature_policy/feature_policy.cc
+++ b/third_party/blink/common/feature_policy/feature_policy.cc
@@ -83,7 +83,7 @@
   if (matches_all_origins_)
     return true;
   for (const auto& targetOrigin : origins_) {
-    if (!origin.unique() && targetOrigin.IsSameOriginWith(origin))
+    if (!origin.opaque() && targetOrigin.IsSameOriginWith(origin))
       return true;
   }
   return false;
@@ -168,7 +168,7 @@
 FeaturePolicy::FeaturePolicy(url::Origin origin,
                              const FeatureList& feature_list)
     : origin_(std::move(origin)), feature_list_(feature_list) {
-  if (origin_.unique()) {
+  if (origin_.opaque()) {
     // FeaturePolicy was written expecting opaque Origins to be indistinct, but
     // this has changed. Split out a new opaque origin here, to defend against
     // origin-equality.
@@ -223,7 +223,7 @@
     // must not.
     inherited_policy = false;
     if (parent_policy->IsFeatureEnabled(feature)) {
-      if (parsed_declaration.matches_opaque_src && origin_.unique()) {
+      if (parsed_declaration.matches_opaque_src && origin_.opaque()) {
         // If the child frame has an opaque origin, and the declared container
         // policy indicates that the feature should be enabled, enable it for
         // the child frame.
diff --git a/third_party/blink/common/origin_trials/trial_token.cc b/third_party/blink/common/origin_trials/trial_token.cc
index 1f17fcb..44be9a6a 100644
--- a/third_party/blink/common/origin_trials/trial_token.cc
+++ b/third_party/blink/common/origin_trials/trial_token.cc
@@ -181,9 +181,9 @@
   datadict->GetString("feature", &feature_name);
   datadict->GetInteger("expiry", &expiry_timestamp);
 
-  // Ensure that the origin is a valid (non-unique) origin URL.
+  // Ensure that the origin is a valid (non-opaque) origin URL.
   url::Origin origin = url::Origin::Create(GURL(origin_string));
-  if (origin.unique()) {
+  if (origin.opaque()) {
     return nullptr;
   }
 
diff --git a/third_party/blink/public/mojom/loader/code_cache.mojom b/third_party/blink/public/mojom/loader/code_cache.mojom
index 7bd7041..d08a2f3 100644
--- a/third_party/blink/public/mojom/loader/code_cache.mojom
+++ b/third_party/blink/public/mojom/loader/code_cache.mojom
@@ -8,22 +8,29 @@
 import "url/mojom/origin.mojom";
 import "url/mojom/url.mojom";
 
+// Enumeration of distinct code cache types.
+enum CodeCacheType {
+  kJavascript,          // Javascript bytecode.
+  kWebAssembly,         // WebAssembly compiled module code.
+};
+
 // Interface to the code cache in the browser process. Renderer processes
 // can use this interface to persistently store and retrieve executable code
 // generated for a URL.
 interface CodeCacheHost {
   // Requests that the browser cache |data| associated with |url| and
   // |expected_response_time|.
-  DidGenerateCacheableMetadata(url.mojom.Url url,
+  DidGenerateCacheableMetadata(CodeCacheType cache_type,
+                               url.mojom.Url url,
                                mojo_base.mojom.Time expected_response_time,
                                array<uint8> data);
 
   // TODO(crbug.com/867848) Pass the data as mojo data_pipe instead of
   // array<unit8>.
-  FetchCachedCode(url.mojom.Url url) => (mojo_base.mojom.Time response_time,
-                                         array<uint8> data);
+  FetchCachedCode(CodeCacheType cache_type, url.mojom.Url url) =>
+      (mojo_base.mojom.Time response_time, array<uint8> data);
 
-  ClearCodeCacheEntry(url.mojom.Url url);
+  ClearCodeCacheEntry(CodeCacheType cache_type, url.mojom.Url url);
 
   // Requests that the browser cache |data| for the specified CacheStorage entry.
   // TODO(https://crbug.com/779444): Verify or remove |cache_storage_origin|.
diff --git a/third_party/blink/public/platform/code_cache_loader.h b/third_party/blink/public/platform/code_cache_loader.h
index 2d5741e..85509ef 100644
--- a/third_party/blink/public/platform/code_cache_loader.h
+++ b/third_party/blink/public/platform/code_cache_loader.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_CODE_CACHE_LOADER_H_
 
 #include "base/callback.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom-shared.h"
 #include "url/gurl.h"
 
 namespace blink {
@@ -25,7 +26,9 @@
       const GURL& url,
       base::Time* response_time_out,
       std::vector<uint8_t>* data_out) = 0;
-  virtual void FetchFromCodeCache(const GURL& url, FetchCodeCacheCallback) = 0;
+  virtual void FetchFromCodeCache(blink::mojom::CodeCacheType cache_type,
+                                  const GURL& url,
+                                  FetchCodeCacheCallback) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index 8dfa718..5a98eaf6 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -47,6 +47,7 @@
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "third_party/blink/public/common/feature_policy/feature_policy.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom-shared.h"
 #include "third_party/blink/public/platform/blame_context.h"
 #include "third_party/blink/public/platform/code_cache_loader.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_factory.h"
@@ -385,16 +386,19 @@
   virtual WebString UserAgent() { return WebString(); }
 
   // A suggestion to cache this metadata in association with this URL.
-  virtual void CacheMetadata(const WebURL&,
+  virtual void CacheMetadata(blink::mojom::CodeCacheType cache_type,
+                             const WebURL&,
                              base::Time response_time,
                              const char* data,
                              size_t data_size) {}
 
   // A request to fetch contents associated with this URL from metadata cache.
   virtual void FetchCachedCode(
+      blink::mojom::CodeCacheType cache_type,
       const GURL&,
       base::OnceCallback<void(base::Time, const std::vector<uint8_t>&)>) {}
-  virtual void ClearCodeCacheEntry(const GURL&) {}
+  virtual void ClearCodeCacheEntry(blink::mojom::CodeCacheType cache_type,
+                                   const GURL&) {}
 
   // A suggestion to cache this metadata in association with this URL which
   // resource is in CacheStorage.
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index 9ca5760a..9d9007f5 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1999,6 +1999,12 @@
   kSerialRequestPort = 2546,
   kSerialPortOpen = 2547,
   kSerialPortClose = 2548,
+  kBackgroundFetchManagerFetch = 2549,
+  kBackgroundFetchManagerGet = 2550,
+  kBackgroundFetchManagerGetIds = 2551,
+  kBackgroundFetchRegistrationAbort = 2552,
+  kBackgroundFetchRegistrationMatch = 2553,
+  kBackgroundFetchRegistrationMatchAll = 2554,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/bindings/modules/BUILD.gn b/third_party/blink/renderer/bindings/modules/BUILD.gn
index a8b704c..b242546 100644
--- a/third_party/blink/renderer/bindings/modules/BUILD.gn
+++ b/third_party/blink/renderer/bindings/modules/BUILD.gn
@@ -52,6 +52,7 @@
     "//third_party/blink/renderer/modules/service_worker/install_event.idl",
     "//third_party/blink/renderer/modules/speech/speech_recognition_error.idl",
     "//third_party/blink/renderer/modules/speech/speech_recognition_event.idl",
+    "//third_party/blink/renderer/modules/speech/speech_synthesis_error_event.idl",
     "//third_party/blink/renderer/modules/speech/speech_synthesis_event.idl",
     "//third_party/blink/renderer/modules/storage/storage_event.idl",
     "//third_party/blink/renderer/modules/vr/vr_display_event.idl",
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 92e43fd..084832bb 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -2043,6 +2043,7 @@
     "layout/shapes/box_shape_test.cc",
     "layout/svg/layout_svg_foreign_object_test.cc",
     "layout/svg/layout_svg_root_test.cc",
+    "layout/svg/layout_svg_text_test.cc",
     "layout/text_autosizer_test.cc",
     "layout/visual_rect_mapping_test.cc",
     "loader/allowed_by_nosniff_test.cc",
diff --git a/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.cc b/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.cc
index 4d9db874..4459b43 100644
--- a/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.cc
+++ b/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.cc
@@ -5,6 +5,9 @@
 #include "third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.h"
 
 #include "third_party/blink/renderer/core/fetch/response.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
@@ -21,4 +24,20 @@
   return url_list;
 }
 
+int WorkerInternalsFetch::getResourcePriority(
+    WorkerInternals& internals,
+    const String& url,
+    WorkerGlobalScope* worker_global) {
+  if (!worker_global)
+    return static_cast<int>(ResourceLoadPriority::kUnresolved);
+
+  Resource* resource = worker_global->Fetcher()->AllResources().at(
+      URLTestHelpers::ToKURL(url.Utf8().data()));
+
+  if (!resource)
+    return static_cast<int>(ResourceLoadPriority::kUnresolved);
+
+  return static_cast<int>(resource->GetResourceRequest().Priority());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.h b/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.h
index c61d826..424de4f 100644
--- a/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.h
+++ b/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.h
@@ -11,6 +11,7 @@
 
 namespace blink {
 
+class WorkerGlobalScope;
 class WorkerInternals;
 class Response;
 
@@ -19,6 +20,9 @@
 
  public:
   static Vector<String> getInternalResponseURLList(WorkerInternals&, Response*);
+  static int getResourcePriority(WorkerInternals&,
+                                 const String& url,
+                                 WorkerGlobalScope*);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.idl b/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.idl
index 9115908..db8f48b 100644
--- a/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.idl
+++ b/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.idl
@@ -6,4 +6,5 @@
     ImplementedAs=WorkerInternalsFetch
 ] partial interface WorkerInternals {
     sequence<USVString> getInternalResponseURLList(Response response);
+    unsigned long getResourcePriority(DOMString url, WorkerGlobalScope worker_global);
 };
diff --git a/third_party/blink/renderer/core/html/html_iframe_element_test.cc b/third_party/blink/renderer/core/html/html_iframe_element_test.cc
index 3ca5e96a..8b33cdd 100644
--- a/third_party/blink/renderer/core/html/html_iframe_element_test.cc
+++ b/third_party/blink/renderer/core/html/html_iframe_element_test.cc
@@ -269,7 +269,7 @@
   EXPECT_FALSE(container_policy[0].matches_all_origins);
   EXPECT_FALSE(container_policy[0].matches_opaque_src);
   EXPECT_EQ(1UL, container_policy[0].origins.size());
-  EXPECT_FALSE(container_policy[0].origins[0].unique());
+  EXPECT_FALSE(container_policy[0].origins[0].opaque());
   EXPECT_EQ("http://example.net", container_policy[0].origins[0].Serialize());
 }
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
index 92fe32db..bc124ce6 100644
--- a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
@@ -77,6 +77,7 @@
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/page/frame_tree.h"
 #include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/svg/svg_svg_element.h"
 #include "third_party/blink/renderer/core/xml/document_xpath_evaluator.h"
 #include "third_party/blink/renderer/core/xml/xpath_result.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -752,11 +753,15 @@
       element->GetDocument().IsHTMLDocument() && element->IsHTMLElement();
   // Not all elements can represent the context (i.e. IFRAME), hence using
   // document.body.
-  if (should_ignore_case && element->GetDocument().body())
+  if (should_ignore_case && element->GetDocument().body()) {
     fragment->ParseHTML(markup, element->GetDocument().body(),
                         kAllowScriptingContent);
-  else
-    fragment->ParseXML(markup, nullptr, kAllowScriptingContent);
+  } else {
+    Element* contextElement = nullptr;
+    if (element->IsSVGElement())
+      contextElement = ToSVGElement(element)->ownerSVGElement();
+    fragment->ParseXML(markup, contextElement, kAllowScriptingContent);
+  }
 
   Element* parsed_element =
       fragment->firstChild() && fragment->firstChild()->IsElementNode()
diff --git a/third_party/blink/renderer/core/layout/hit_test_location.cc b/third_party/blink/renderer/core/layout/hit_test_location.cc
index 8d795de..37b7080 100644
--- a/third_party/blink/renderer/core/layout/hit_test_location.cc
+++ b/third_party/blink/renderer/core/layout/hit_test_location.cc
@@ -121,13 +121,23 @@
 }
 
 bool HitTestLocation::Intersects(const FloatRect& rect) const {
-  return IntersectsRect(rect, FloatRect(bounding_box_));
+  if (is_rect_based_)
+    return transformed_rect_.IntersectsRect(rect);
+  return rect.Contains(transformed_point_);
 }
 
 bool HitTestLocation::Intersects(const FloatRoundedRect& rect) const {
   return rect.IntersectsQuad(transformed_rect_);
 }
 
+bool HitTestLocation::Intersects(const FloatQuad& quad) const {
+  // TODO(chrishtr): if the quads are not rectilinear, calling Intersects
+  // has false positives.
+  if (is_rect_based_)
+    return Intersects(quad.BoundingBox());
+  return quad.ContainsPoint(FloatPoint(point_));
+}
+
 bool HitTestLocation::ContainsPoint(const FloatPoint& point) const {
   return transformed_rect_.ContainsPoint(point);
 }
diff --git a/third_party/blink/renderer/core/layout/hit_test_location.h b/third_party/blink/renderer/core/layout/hit_test_location.h
index 26704ce..3bd5f17 100644
--- a/third_party/blink/renderer/core/layout/hit_test_location.h
+++ b/third_party/blink/renderer/core/layout/hit_test_location.h
@@ -70,8 +70,11 @@
   }
 
   bool Intersects(const LayoutRect&) const;
+  // Uses floating-point intersection, which uses inclusive intersection
+  // (see LayoutRect::InclusiveIntersect for a definition)
   bool Intersects(const FloatRect&) const;
   bool Intersects(const FloatRoundedRect&) const;
+  bool Intersects(const FloatQuad&) const;
   bool ContainsPoint(const FloatPoint&) const;
 
   const FloatPoint& TransformedPoint() const { return transformed_point_; }
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index f1415c0..0c7748b 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -179,7 +179,7 @@
 
 LayoutUnit LayoutFlexibleBox::FirstLineBoxBaseline() const {
   if (IsWritingModeRoot() || number_of_in_flow_children_on_first_line_ <= 0 ||
-      ShouldApplySizeContainment())
+      ShouldApplyLayoutContainment())
     return LayoutUnit(-1);
   LayoutBox* baseline_child = nullptr;
   int child_number = 0;
diff --git a/third_party/blink/renderer/core/layout/layout_grid.cc b/third_party/blink/renderer/core/layout/layout_grid.cc
index f4abe07c..34066a6 100644
--- a/third_party/blink/renderer/core/layout/layout_grid.cc
+++ b/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -1633,7 +1633,7 @@
 
 LayoutUnit LayoutGrid::FirstLineBoxBaseline() const {
   if (IsWritingModeRoot() || !grid_->HasGridItems() ||
-      ShouldApplySizeContainment())
+      ShouldApplyLayoutContainment())
     return LayoutUnit(-1);
   const LayoutBox* baseline_child = nullptr;
   const LayoutBox* first_child = nullptr;
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 8ac913c9..0e68b248 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -3818,13 +3818,6 @@
   return AffineTransform();
 }
 
-bool LayoutObject::NodeAtFloatPoint(HitTestResult&,
-                                    const FloatPoint&,
-                                    HitTestAction) {
-  NOTREACHED();
-  return false;
-}
-
 bool LayoutObject::IsRelayoutBoundaryForInspector() const {
   return ObjectIsRelayoutBoundary(this);
 }
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 74f68cb..e99bb88 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -794,13 +794,6 @@
     return LocalSVGTransform();
   }
 
-  // SVG uses FloatPoint precise hit testing, and passes the point in parent
-  // coordinates instead of in paint invalidation container coordinates.
-  // Eventually the rest of the layout tree will move to a similar model.
-  virtual bool NodeAtFloatPoint(HitTestResult&,
-                                const FloatPoint& point_in_parent,
-                                HitTestAction);
-
   // End of SVG-specific methods.
 
   bool IsAnonymous() const { return bitfields_.IsAnonymous(); }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
index 0e73358c..daf08f2 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
@@ -321,6 +321,7 @@
   space_builder.SetPercentageResolutionSize(column_size);
   space_builder.SetIsNewFormattingContext(true);
   space_builder.SetIsAnonymous(true);
+  space_builder.SetIsIntermediateLayout(true);
 
   return space_builder.ToConstraintSpace(Style().GetWritingMode());
 }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
index ee9bba3..f025dab 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
@@ -25,6 +25,7 @@
 
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
 #include "third_party/blink/renderer/core/layout/layout_analyzer.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
@@ -173,37 +174,49 @@
   GetElement()->SetNeedsResizeObserverUpdate();
 }
 
-bool LayoutSVGContainer::NodeAtFloatPoint(HitTestResult& result,
-                                          const FloatPoint& point_in_parent,
-                                          HitTestAction hit_test_action) {
-  FloatPoint local_point;
+bool LayoutSVGContainer::NodeAtPoint(
+    HitTestResult& result,
+    const HitTestLocation& location_in_container,
+    const LayoutPoint& accumulated_offset,
+    HitTestAction hit_test_action) {
+  DCHECK_EQ(accumulated_offset, LayoutPoint());
+  HitTestLocation local_location;
   if (!SVGLayoutSupport::TransformToUserSpaceAndCheckClipping(
-          *this, LocalToSVGParentTransform(), point_in_parent, local_point))
+          *this, LocalToSVGParentTransform(), location_in_container,
+          local_location))
     return false;
 
   for (LayoutObject* child = LastChild(); child;
        child = child->PreviousSibling()) {
-    if (child->NodeAtFloatPoint(result, local_point, hit_test_action)) {
-      const LayoutPoint& local_layout_point = LayoutPoint(local_point);
+    bool found = false;
+    if (child->IsSVGForeignObject()) {
+      found = ToLayoutSVGForeignObject(child)->NodeAtPointFromSVG(
+          result, local_location, accumulated_offset, hit_test_action);
+    } else {
+      found = child->NodeAtPoint(result, local_location, accumulated_offset,
+                                 hit_test_action);
+    }
+    if (found) {
+      const LayoutPoint& local_layout_point =
+          LayoutPoint(local_location.TransformedPoint());
       UpdateHitTestResult(result, local_layout_point);
-      HitTestLocation location(local_layout_point);
-      if (result.AddNodeToListBasedTestResult(child->GetNode(), location) ==
-          kStopHitTesting)
+      if (result.AddNodeToListBasedTestResult(
+              child->GetNode(), local_location) == kStopHitTesting) {
         return true;
+      }
     }
   }
-
   // pointer-events: bounding-box makes it possible for containers to be direct
   // targets.
   if (StyleRef().PointerEvents() == EPointerEvents::kBoundingBox) {
     // Check for a valid bounding box because it will be invalid for empty
     // containers.
     if (IsObjectBoundingBoxValid() &&
-        ObjectBoundingBox().Contains(local_point)) {
-      const LayoutPoint& local_layout_point = LayoutPoint(local_point);
+        local_location.Intersects(ObjectBoundingBox())) {
+      const LayoutPoint& local_layout_point =
+          LayoutPoint(local_location.TransformedPoint());
       UpdateHitTestResult(result, local_layout_point);
-      HitTestLocation location(local_layout_point);
-      if (result.AddNodeToListBasedTestResult(GetElement(), location) ==
+      if (result.AddNodeToListBasedTestResult(GetElement(), local_location) ==
           kStopHitTesting)
         return true;
     }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
index 76b501fd..a12b7cf 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
@@ -82,9 +82,10 @@
 
   FloatRect StrokeBoundingBox() const final { return stroke_bounding_box_; }
 
-  bool NodeAtFloatPoint(HitTestResult&,
-                        const FloatPoint& point_in_parent,
-                        HitTestAction) override;
+  bool NodeAtPoint(HitTestResult&,
+                   const HitTestLocation& location_in_container,
+                   const LayoutPoint& accumulated_offset,
+                   HitTestAction) override;
 
   // Called during layout to update the local transform.
   virtual SVGTransformChange CalculateLocalTransform();
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
index 007629c..4ef7808b 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
@@ -124,21 +124,33 @@
     SVGResourcesCache::ClientLayoutChanged(*this);
 }
 
-bool LayoutSVGForeignObject::NodeAtFloatPoint(HitTestResult& result,
-                                              const FloatPoint& point_in_parent,
-                                              HitTestAction hit_test_action) {
+bool LayoutSVGForeignObject::NodeAtPointFromSVG(
+    HitTestResult& result,
+    const HitTestLocation& location_in_parent,
+    const LayoutPoint& accumulated_offset,
+    HitTestAction) {
+  DCHECK_EQ(accumulated_offset, LayoutPoint());
   AffineTransform local_transform = LocalSVGTransform();
   if (!local_transform.IsInvertible())
     return false;
 
-  FloatPoint local_point = local_transform.Inverse().MapPoint(point_in_parent);
-  LayoutPoint point_in_foreign_object(local_point);
+  AffineTransform inverse = local_transform.Inverse();
+  base::Optional<HitTestLocation> local_location;
+  if (location_in_parent.IsRectBasedTest()) {
+    local_location.emplace(
+        inverse.MapPoint(location_in_parent.TransformedPoint()),
+        inverse.MapQuad(location_in_parent.TransformedRect()));
+  } else {
+    local_location.emplace(
+        (inverse.MapPoint(location_in_parent.TransformedPoint())));
+  }
+
   // |local_point| already includes the offset of the <foreignObject> element,
   // but PaintLayer::HitTestLayer assumes it has not been.
-  point_in_foreign_object.MoveBy(-Layer()->LayoutBoxLocation());
-  HitTestLocation location(point_in_foreign_object);
-  HitTestResult layer_result(result.GetHitTestRequest(), location);
-  bool retval = Layer()->HitTest(location, layer_result,
+  HitTestLocation local_without_offset(
+      *local_location, -ToLayoutSize(Layer()->LayoutBoxLocation()));
+  HitTestResult layer_result(result.GetHitTestRequest(), local_without_offset);
+  bool retval = Layer()->HitTest(local_without_offset, layer_result,
                                  LayoutRect(LayoutRect::InfiniteIntRect()));
 
   // Preserve the "point in inner node frame" from the original request,
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
index 084e043..c302e8f 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
@@ -65,9 +65,15 @@
                    const LayoutPoint&,
                    HitTestAction) override;
 
-  bool NodeAtFloatPoint(HitTestResult&,
-                        const FloatPoint& point_in_parent,
-                        HitTestAction) override;
+  // A method to call when recursively hit testing from an SVG parent.
+  // Since LayoutSVGRoot has a PaintLayer always, this will cause a
+  // trampoline through PaintLayer::HitTest and back to a call to NodeAtPoint
+  // on this object. This is why there are two methods.
+  bool NodeAtPointFromSVG(HitTestResult&,
+                          const HitTestLocation&,
+                          const LayoutPoint&,
+                          HitTestAction);
+
   bool IsOfType(LayoutObjectType type) const override {
     return type == kLayoutObjectSVGForeignObject ||
            LayoutSVGBlock::IsOfType(type);
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
index fe6dd083..8ba8bf6b 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
@@ -68,6 +68,17 @@
   EXPECT_EQ(div.GetNode(), HitTest(349, 249));
   EXPECT_EQ(foreign, HitTest(350, 250));
   EXPECT_EQ(svg, HitTest(450, 350));
+
+  // Rect based hit testing
+  auto results = RectBasedHitTest(LayoutRect(0, 0, 300, 300));
+  int count = 0;
+  EXPECT_EQ(3u, results.size());
+  for (auto result : results) {
+    Node* node = result.Get();
+    if (node == svg || node == div.GetNode() || node == foreign)
+      count++;
+  }
+  EXPECT_EQ(3, count);
 }
 
 TEST_F(LayoutSVGForeignObjectTest, IframeInForeignObject) {
@@ -75,7 +86,7 @@
     <style>body { margin: 0 }</style>
     <svg id='svg' style='width: 500px; height: 450px'>
       <foreignObject id='foreign' x='100' y='100' width='300' height='250'>
-        <iframe style='border: none; margin: 30px;
+        <iframe id=iframe style='border: none; margin: 30px;
              width: 240px; height: 190px'></iframe>
       </foreignObject>
     </svg>
@@ -92,6 +103,7 @@
   const auto& svg = *GetDocument().getElementById("svg");
   const auto& foreign = *GetDocument().getElementById("foreign");
   const auto& foreign_object = *GetLayoutObjectByElementId("foreign");
+  const auto& iframe = *GetDocument().getElementById("iframe");
   const auto& div = *ChildDocument().getElementById("div")->GetLayoutObject();
 
   EXPECT_EQ(FloatRect(100, 100, 300, 250), foreign_object.ObjectBoundingBox());
@@ -136,6 +148,18 @@
   EXPECT_EQ(ChildDocument().documentElement(), HitTest(369, 319));
   EXPECT_EQ(foreign, HitTest(370, 320));
   EXPECT_EQ(svg, HitTest(450, 400));
+
+  // Rect based hit testing
+  auto results = RectBasedHitTest(LayoutRect(0, 0, 300, 300));
+  int count = 0;
+  EXPECT_EQ(7u, results.size());
+  for (auto result : results) {
+    Node* node = result.Get();
+    if (node == svg || node == div.GetNode() || node == foreign ||
+        node == iframe)
+      count++;
+  }
+  EXPECT_EQ(4, count);
 }
 
 TEST_F(LayoutSVGForeignObjectTest, HitTestZoomedForeignObject) {
@@ -184,6 +208,17 @@
   EXPECT_EQ(svg, HitTest(20, 20));
   EXPECT_EQ(foreign, HitTest(280, 280));
   EXPECT_EQ(div, HitTest(290, 290));
+
+  // Rect based hit testing
+  auto results = RectBasedHitTest(LayoutRect(0, 0, 300, 300));
+  int count = 0;
+  EXPECT_EQ(3u, results.size());
+  for (auto result : results) {
+    Node* node = result.Get();
+    if (node == svg || node == &div || node == foreign)
+      count++;
+  }
+  EXPECT_EQ(3, count);
 }
 
 TEST_F(LayoutSVGForeignObjectTest, HitTestViewBoxForeignObject) {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.cc
index 45e5419..40afa1ffd 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.cc
@@ -43,9 +43,10 @@
   ClearNeedsLayout();
 }
 
-bool LayoutSVGHiddenContainer::NodeAtFloatPoint(HitTestResult&,
-                                                const FloatPoint&,
-                                                HitTestAction) {
+bool LayoutSVGHiddenContainer::NodeAtPoint(HitTestResult&,
+                                           const HitTestLocation&,
+                                           const LayoutPoint&,
+                                           HitTestAction) {
   return false;
 }
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
index 961dc03..52d9d9f 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
@@ -55,9 +55,10 @@
   void AbsoluteQuads(Vector<FloatQuad>&,
                      MapCoordinatesFlags mode = 0) const final {}
 
-  bool NodeAtFloatPoint(HitTestResult&,
-                        const FloatPoint& point_in_parent,
-                        HitTestAction) final;
+  bool NodeAtPoint(HitTestResult&,
+                   const HitTestLocation& location_in_container,
+                   const LayoutPoint& accumulated_offset,
+                   HitTestAction) final;
 };
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
index 0bd47f43..2c52cf4 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
@@ -166,9 +166,11 @@
   SVGImagePainter(*this).Paint(paint_info);
 }
 
-bool LayoutSVGImage::NodeAtFloatPoint(HitTestResult& result,
-                                      const FloatPoint& point_in_parent,
-                                      HitTestAction hit_test_action) {
+bool LayoutSVGImage::NodeAtPoint(HitTestResult& result,
+                                 const HitTestLocation& location_in_container,
+                                 const LayoutPoint& accumulated_offset,
+                                 HitTestAction hit_test_action) {
+  DCHECK(accumulated_offset == LayoutPoint());
   // We only draw in the forground phase, so we only hit-test then.
   if (hit_test_action != kHitTestForeground)
     return false;
@@ -180,17 +182,18 @@
   if (hit_rules.require_visible && style.Visibility() != EVisibility::kVisible)
     return false;
 
-  FloatPoint local_point;
+  HitTestLocation local_location;
   if (!SVGLayoutSupport::TransformToUserSpaceAndCheckClipping(
-          *this, LocalToSVGParentTransform(), point_in_parent, local_point))
+          *this, LocalToSVGParentTransform(), location_in_container,
+          local_location))
     return false;
 
   if (hit_rules.can_hit_fill || hit_rules.can_hit_bounding_box) {
-    if (object_bounding_box_.Contains(local_point)) {
-      const LayoutPoint& local_layout_point = LayoutPoint(local_point);
-      HitTestLocation location(local_layout_point);
+    if (local_location.Intersects(object_bounding_box_)) {
+      const LayoutPoint& local_layout_point =
+          LayoutPoint(local_location.TransformedPoint());
       UpdateHitTestResult(result, local_layout_point);
-      if (result.AddNodeToListBasedTestResult(GetElement(), location) ==
+      if (result.AddNodeToListBasedTestResult(GetElement(), local_location) ==
           kStopHitTesting)
         return true;
     }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_image.h b/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
index 15ed057..e6b4ed3 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
@@ -67,9 +67,10 @@
 
   bool UpdateBoundingBox();
 
-  bool NodeAtFloatPoint(HitTestResult&,
-                        const FloatPoint& point_in_parent,
-                        HitTestAction) override;
+  bool NodeAtPoint(HitTestResult&,
+                   const HitTestLocation& location_in_parent,
+                   const LayoutPoint& accumulated_offset,
+                   HitTestAction) override;
 
   AffineTransform LocalSVGTransform() const override {
     return local_transform_;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
index a0e790fc..f988fbf 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
@@ -158,12 +158,4 @@
   SVGResourcesCache::ClientStyleChanged(*this, diff, StyleRef());
 }
 
-bool LayoutSVGModelObject::NodeAtPoint(HitTestResult&,
-                                       const HitTestLocation&,
-                                       const LayoutPoint&,
-                                       HitTestAction) {
-  NOTREACHED();
-  return false;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
index bd663b8..b28f725 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
@@ -95,11 +95,6 @@
   // LayoutSVGModelObject subclasses should use GetElement() instead.
   void GetNode() const = delete;
 
-  // This method should never be called, SVG uses a different nodeAtPoint method
-  bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
-                   const LayoutPoint& accumulated_offset,
-                   HitTestAction) final;
   void AddOutlineRects(Vector<LayoutRect>&,
                        const LayoutPoint& additional_offset,
                        NGOutlineType) const final;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
index 4353b24..0cc835c0 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
@@ -252,14 +252,15 @@
        Traversal<SVGElement>::ChildrenOf(*GetElement())) {
     if (!ContributesToClip(child_element))
       continue;
-    HitTestLocation location((LayoutPoint()));
+    HitTestLocation location(point);
     HitTestResult result(HitTestRequest::kSVGClipContent, location);
     LayoutObject* layout_object = child_element.GetLayoutObject();
 
     DCHECK(!layout_object->IsBoxModelObject() ||
            !ToLayoutBoxModelObject(layout_object)->HasSelfPaintingLayer());
 
-    if (layout_object->NodeAtFloatPoint(result, point, kHitTestForeground))
+    if (layout_object->NodeAtPoint(result, location, LayoutPoint(),
+                                   kHitTestForeground))
       return true;
   }
   return false;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
index 49519a4..504e451 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -30,6 +30,7 @@
 #include "third_party/blink/renderer/core/layout/layout_analyzer.h"
 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
@@ -509,9 +510,10 @@
                                 const HitTestLocation& location_in_container,
                                 const LayoutPoint& accumulated_offset,
                                 HitTestAction hit_test_action) {
-  LayoutPoint point_in_parent =
-      location_in_container.Point() - ToLayoutSize(accumulated_offset);
-  LayoutPoint point_in_border_box = point_in_parent - ToLayoutSize(Location());
+  LayoutPoint adjusted_location = accumulated_offset + Location();
+
+  HitTestLocation local_border_box_location(location_in_container,
+                                            ToLayoutSize(-adjusted_location));
 
   // Only test SVG content if the point is in our content box, or in case we
   // don't clip to the viewport, the visual overflow rect.
@@ -519,23 +521,44 @@
   // supported by nodeAtFloatPoint.
   bool skip_children = (result.GetHitTestRequest().GetStopNode() == this);
   if (!skip_children &&
-      (PhysicalContentBoxRect().Contains(point_in_border_box) ||
+      (local_border_box_location.Intersects(PhysicalContentBoxRect()) ||
        (!ShouldApplyViewportClip() &&
-        VisualOverflowRect().Contains(point_in_border_box)))) {
-    const AffineTransform& local_to_parent_transform =
-        LocalToSVGParentTransform();
-    if (local_to_parent_transform.IsInvertible()) {
-      FloatPoint local_point = local_to_parent_transform.Inverse().MapPoint(
-          FloatPoint(point_in_parent));
+        local_border_box_location.Intersects(VisualOverflowRect())))) {
+    const AffineTransform& local_to_border_box_transform =
+        LocalToBorderBoxTransform();
+    if (local_to_border_box_transform.IsInvertible()) {
+      FloatPoint local_point = local_to_border_box_transform.Inverse().MapPoint(
+          local_border_box_location.TransformedPoint());
+
+      base::Optional<HitTestLocation> local_location;
+      if (location_in_container.IsRectBasedTest()) {
+        FloatQuad quad_in_container =
+            local_border_box_location.TransformedRect();
+
+        local_location.emplace(
+            local_point,
+            local_to_border_box_transform.Inverse().MapQuad(quad_in_container));
+      } else {
+        local_location.emplace(local_point);
+      }
 
       for (LayoutObject* child = LastChild(); child;
            child = child->PreviousSibling()) {
-        // FIXME: nodeAtFloatPoint() doesn't handle rect-based hit tests yet.
-        if (child->NodeAtFloatPoint(result, local_point, hit_test_action)) {
-          UpdateHitTestResult(result, point_in_border_box);
+        bool found = false;
+        if (child->IsSVGForeignObject()) {
+          found = ToLayoutSVGForeignObject(child)->NodeAtPointFromSVG(
+              result, *local_location, LayoutPoint(), hit_test_action);
+        } else {
+          found = child->NodeAtPoint(result, *local_location, LayoutPoint(),
+                                     hit_test_action);
+        }
+
+        if (found) {
+          UpdateHitTestResult(result, local_border_box_location.Point());
           if (result.AddNodeToListBasedTestResult(
-                  child->GetNode(), location_in_container) == kStopHitTesting)
+                  child->GetNode(), location_in_container) == kStopHitTesting) {
             return true;
+          }
         }
       }
     }
@@ -556,7 +579,7 @@
     // detect these hits anymore.
     LayoutRect bounds_rect(accumulated_offset + Location(), Size());
     if (location_in_container.Intersects(bounds_rect)) {
-      UpdateHitTestResult(result, point_in_border_box);
+      UpdateHitTestResult(result, local_border_box_location.Point());
       if (result.AddNodeToListBasedTestResult(GetNode(), location_in_container,
                                               bounds_rect) == kStopHitTesting)
         return true;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
index c336a13..e310f9c 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
@@ -132,4 +132,33 @@
   EXPECT_FALSE(root.PaintedOutputOfObjectHasNoEffectRegardlessOfSize());
 }
 
+TEST_F(LayoutSVGRootTest, RectBasedHitTestPartialOverlap) {
+  SetBodyInnerHTML(R"HTML(
+    <style>body { margin: 0 }</style>
+    <svg id='svg' style='width: 300px; height: 300px; position: relative;
+        top: 200px; left: 200px;'>
+    </svg>
+  )HTML");
+
+  const auto& svg = *GetDocument().getElementById("svg");
+  const auto& body = *GetDocument().body();
+
+  // This is the center of the rect-based hit test below.
+  EXPECT_EQ(body, *HitTest(150, 150));
+
+  EXPECT_EQ(svg, *HitTest(200, 200));
+
+  // The center of this rect does not overlap the SVG element, but the
+  // rect itself does.
+  auto results = RectBasedHitTest(LayoutRect(0, 0, 300, 300));
+  int count = 0;
+  EXPECT_EQ(2u, results.size());
+  for (auto result : results) {
+    Node* node = result.Get();
+    if (node == svg || node == body)
+      count++;
+  }
+  EXPECT_EQ(2, count);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
index 931ccd8..ec54c4a9 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
@@ -347,27 +347,29 @@
   SVGShapePainter(*this).Paint(paint_info);
 }
 
-bool LayoutSVGShape::NodeAtFloatPoint(HitTestResult& result,
-                                      const FloatPoint& point_in_parent,
-                                      HitTestAction hit_test_action) {
+bool LayoutSVGShape::NodeAtPoint(HitTestResult& result,
+                                 const HitTestLocation& location_in_parent,
+                                 const LayoutPoint& accumulated_offset,
+                                 HitTestAction hit_test_action) {
+  DCHECK_EQ(accumulated_offset, LayoutPoint());
   // We only draw in the foreground phase, so we only hit-test then.
   if (hit_test_action != kHitTestForeground)
     return false;
 
-  FloatPoint local_point;
+  HitTestLocation local_location;
   if (!SVGLayoutSupport::TransformToUserSpaceAndCheckClipping(
-          *this, LocalToSVGParentTransform(), point_in_parent, local_point))
+          *this, LocalToSVGParentTransform(), location_in_parent,
+          local_location))
     return false;
 
   PointerEventsHitRules hit_rules(
       PointerEventsHitRules::SVG_GEOMETRY_HITTESTING,
       result.GetHitTestRequest(), StyleRef().PointerEvents());
-  if (NodeAtFloatPointInternal(result.GetHitTestRequest(), local_point,
-                               hit_rules)) {
-    const LayoutPoint& local_layout_point = LayoutPoint(local_point);
+  if (NodeAtPointInternal(result.GetHitTestRequest(), local_location,
+                          hit_rules)) {
+    const LayoutPoint local_layout_point(local_location.TransformedPoint());
     UpdateHitTestResult(result, local_layout_point);
-    HitTestLocation location(local_layout_point);
-    if (result.AddNodeToListBasedTestResult(GetElement(), location) ==
+    if (result.AddNodeToListBasedTestResult(GetElement(), local_location) ==
         kStopHitTesting)
       return true;
   }
@@ -375,26 +377,30 @@
   return false;
 }
 
-bool LayoutSVGShape::NodeAtFloatPointInternal(const HitTestRequest& request,
-                                              const FloatPoint& local_point,
-                                              PointerEventsHitRules hit_rules) {
+bool LayoutSVGShape::NodeAtPointInternal(const HitTestRequest& request,
+                                         const HitTestLocation& local_location,
+                                         PointerEventsHitRules hit_rules) {
   const ComputedStyle& style = StyleRef();
   if (hit_rules.require_visible && style.Visibility() != EVisibility::kVisible)
     return false;
   if (hit_rules.can_hit_bounding_box &&
-      ObjectBoundingBox().Contains(local_point))
+      local_location.Intersects(ObjectBoundingBox()))
     return true;
+
+  // TODO(chrishtr): support rect-based intersections in the cases below.
   const SVGComputedStyle& svg_style = style.SvgStyle();
   if (hit_rules.can_hit_stroke &&
       (svg_style.HasStroke() || !hit_rules.require_stroke) &&
-      StrokeContains(local_point, hit_rules.require_stroke))
+      StrokeContains(local_location.TransformedPoint(),
+                     hit_rules.require_stroke))
     return true;
   WindRule fill_rule = svg_style.FillRule();
   if (request.SvgClipContent())
     fill_rule = svg_style.ClipRule();
   if (hit_rules.can_hit_fill &&
       (svg_style.HasFill() || !hit_rules.require_fill) &&
-      FillContains(local_point, hit_rules.require_fill, fill_rule))
+      FillContains(local_location.TransformedPoint(), hit_rules.require_fill,
+                   fill_rule))
     return true;
   return false;
 }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
index c291ae4..098fe31 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
@@ -65,9 +65,9 @@
   void SetNeedsBoundariesUpdate() final { needs_boundaries_update_ = true; }
   void SetNeedsTransformUpdate() final { needs_transform_update_ = true; }
 
-  bool NodeAtFloatPointInternal(const HitTestRequest&,
-                                const FloatPoint&,
-                                PointerEventsHitRules);
+  bool NodeAtPointInternal(const HitTestRequest&,
+                           const HitTestLocation&,
+                           PointerEventsHitRules);
 
   Path& GetPath() const {
     DCHECK(path_);
@@ -157,9 +157,10 @@
   void UpdateLayout() final;
   void Paint(const PaintInfo&) const final;
 
-  bool NodeAtFloatPoint(HitTestResult&,
-                        const FloatPoint& point_in_parent,
-                        HitTestAction) final;
+  bool NodeAtPoint(HitTestResult&,
+                   const HitTestLocation& location_in_parent,
+                   const LayoutPoint& accumulated_offset,
+                   HitTestAction) override;
 
   FloatRect StrokeBoundingBox() const final { return stroke_bounding_box_; }
   FloatRect CalculateObjectBoundingBox() const;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
index dbff4629..891b4651 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -305,31 +305,33 @@
   return box;
 }
 
-bool LayoutSVGText::NodeAtFloatPoint(HitTestResult& result,
-                                     const FloatPoint& point_in_parent,
-                                     HitTestAction hit_test_action) {
+bool LayoutSVGText::NodeAtPoint(HitTestResult& result,
+                                const HitTestLocation& location_in_parent,
+                                const LayoutPoint& accumulated_offset,
+                                HitTestAction hit_test_action) {
+  DCHECK_EQ(accumulated_offset, LayoutPoint());
   // We only draw in the foreground phase, so we only hit-test then.
   if (hit_test_action != kHitTestForeground)
     return false;
 
-  FloatPoint local_point;
+  HitTestLocation local_location;
   if (!SVGLayoutSupport::TransformToUserSpaceAndCheckClipping(
-          *this, LocalToSVGParentTransform(), point_in_parent, local_point))
+          *this, LocalToSVGParentTransform(), location_in_parent,
+          local_location))
     return false;
 
-  HitTestLocation hit_test_location(local_point);
-  if (LayoutBlock::NodeAtPoint(result, hit_test_location, LayoutPoint(),
+  if (LayoutBlock::NodeAtPoint(result, local_location, accumulated_offset,
                                hit_test_action))
     return true;
 
   // Consider the bounding box if requested.
   if (StyleRef().PointerEvents() == EPointerEvents::kBoundingBox) {
     if (IsObjectBoundingBoxValid() &&
-        ObjectBoundingBox().Contains(local_point)) {
-      const LayoutPoint& local_layout_point = LayoutPoint(local_point);
+        local_location.Intersects(ObjectBoundingBox())) {
+      const LayoutPoint& local_layout_point =
+          LayoutPoint(local_location.TransformedPoint());
       UpdateHitTestResult(result, local_layout_point);
-      HitTestLocation location(local_layout_point);
-      if (result.AddNodeToListBasedTestResult(GetElement(), location) ==
+      if (result.AddNodeToListBasedTestResult(GetElement(), local_location) ==
           kStopHitTesting)
         return true;
     }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.h b/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
index 86d88bbe..ce40fa6 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
@@ -72,9 +72,10 @@
   }
 
   void Paint(const PaintInfo&) const override;
-  bool NodeAtFloatPoint(HitTestResult&,
-                        const FloatPoint& point_in_parent,
-                        HitTestAction) override;
+  bool NodeAtPoint(HitTestResult&,
+                   const HitTestLocation& location_in_parent,
+                   const LayoutPoint& accumulated_offset,
+                   HitTestAction) override;
   PositionWithAffinity PositionForPoint(const LayoutPoint&) const override;
 
   void UpdateLayout() override;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text_test.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_text_test.cc
new file mode 100644
index 0000000..150e6ff
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text_test.cc
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/layout_geometry_map.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+
+namespace blink {
+
+class LayoutSVGTextTest : public RenderingTest {
+ public:
+  LayoutSVGTextTest() : RenderingTest(SingleChildLocalFrameClient::Create()) {}
+};
+
+TEST_F(LayoutSVGTextTest, RectBasedHitTest) {
+  SetBodyInnerHTML(R"HTML(
+    <style>body { margin: 0 }</style>
+    <svg id=svg width="300" height="300">
+      <a id="link">
+        <text id="text" y="20">text</text>
+      </a>
+    </svg>
+  )HTML");
+
+  const auto& svg = *GetDocument().getElementById("svg");
+  const auto& text = *GetDocument().getElementById("text")->firstChild();
+
+  // Rect based hit testing
+  auto results = RectBasedHitTest(LayoutRect(0, 0, 300, 300));
+  int count = 0;
+  EXPECT_EQ(2u, results.size());
+  for (auto result : results) {
+    Node* node = result.Get();
+    if (node == svg || node == text)
+      count++;
+  }
+  EXPECT_EQ(2, count);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.cc
index e03a672e..99fd0f0 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.cc
@@ -75,16 +75,18 @@
   return change_detector.ComputeChange(local_to_parent_transform_);
 }
 
-bool LayoutSVGViewportContainer::NodeAtFloatPoint(
+bool LayoutSVGViewportContainer::NodeAtPoint(
     HitTestResult& result,
-    const FloatPoint& point_in_parent,
+    const HitTestLocation& location_in_parent,
+    const LayoutPoint& accumulated_offset,
     HitTestAction action) {
   // Respect the viewport clip which is in parent coordinates.
   if (SVGLayoutSupport::IsOverflowHidden(*this)) {
-    if (!viewport_.Contains(point_in_parent))
+    if (!location_in_parent.Intersects(viewport_))
       return false;
   }
-  return LayoutSVGContainer::NodeAtFloatPoint(result, point_in_parent, action);
+  return LayoutSVGContainer::NodeAtPoint(result, location_in_parent,
+                                         accumulated_offset, action);
 }
 
 void LayoutSVGViewportContainer::StyleDidChange(
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h
index 8a78177..40bc375 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h
@@ -56,9 +56,10 @@
 
   SVGTransformChange CalculateLocalTransform() override;
 
-  bool NodeAtFloatPoint(HitTestResult&,
-                        const FloatPoint& point_in_parent,
-                        HitTestAction) override;
+  bool NodeAtPoint(HitTestResult&,
+                   const HitTestLocation& location_in_parent,
+                   const LayoutPoint& accumulated_offset,
+                   HitTestAction) final;
 
   void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
 
diff --git a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
index 6965c06..0c9e8cf 100644
--- a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
@@ -308,10 +308,9 @@
       DCHECK(line_layout_item.ScalingFactor());
       float baseline = font_data->GetFontMetrics().FloatAscent() /
                        line_layout_item.ScalingFactor();
-      FloatPoint float_location = FloatPoint(location_in_container.Point());
       for (const SVGTextFragment& fragment : text_fragments_) {
         FloatQuad fragment_quad = fragment.BoundingQuad(baseline);
-        if (fragment_quad.ContainsPoint(float_location)) {
+        if (location_in_container.Intersects(fragment_quad)) {
           line_layout_item.UpdateHitTestResult(
               result,
               location_in_container.Point() - ToLayoutSize(accumulated_offset));
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
index 02b022f..3b27c60 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
@@ -432,12 +432,21 @@
 bool SVGLayoutSupport::TransformToUserSpaceAndCheckClipping(
     const LayoutObject& object,
     const AffineTransform& local_transform,
-    const FloatPoint& point_in_parent,
-    FloatPoint& local_point) {
+    const HitTestLocation& location_in_parent,
+    HitTestLocation& local_location) {
   if (!local_transform.IsInvertible())
     return false;
-  local_point = local_transform.Inverse().MapPoint(point_in_parent);
-  return PointInClippingArea(object, local_point);
+  const AffineTransform inverse = local_transform.Inverse();
+  if (location_in_parent.IsRectBasedTest()) {
+    local_location =
+        HitTestLocation(inverse.MapPoint(location_in_parent.TransformedPoint()),
+                        inverse.MapQuad(location_in_parent.TransformedRect()));
+  } else {
+    local_location = HitTestLocation(
+        inverse.MapPoint(location_in_parent.TransformedPoint()));
+  }
+
+  return PointInClippingArea(object, local_location.TransformedPoint());
 }
 
 DashArray SVGLayoutSupport::ResolveSVGDashArray(
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_support.h b/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
index 98abb7c..d4f11ef1 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
@@ -82,8 +82,8 @@
   static bool TransformToUserSpaceAndCheckClipping(
       const LayoutObject&,
       const AffineTransform& local_transform,
-      const FloatPoint& point_in_parent,
-      FloatPoint& local_point);
+      const HitTestLocation& location_in_parent,
+      HitTestLocation& local_location);
 
   static void ComputeContainerBoundingBoxes(const LayoutObject* container,
                                             FloatRect& object_bounding_box,
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
index c2a44df0..8f8ce7a 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
@@ -429,6 +429,7 @@
     DetachScrollbarLayer(scrollbar_graphics_layer);
     return;
   }
+
   scrollbar_layer_group->scrollbar_layer->SetScrollElementId(
       scrolling_layer->element_id());
   scrollbar_graphics_layer->SetContentsToCcLayer(
@@ -475,6 +476,7 @@
       DetachScrollbarLayer(scrollbar_graphics_layer);
       scrollbar_graphics_layer->CcLayer()->AddMainThreadScrollingReasons(
           MainThreadScrollingReason::kCustomScrollbarScrolling);
+      scrollbar_graphics_layer->CcLayer()->SetIsScrollbar(true);
       return;
     }
 
diff --git a/third_party/blink/renderer/core/svg/svg_geometry_element.cc b/third_party/blink/renderer/core/svg/svg_geometry_element.cc
index 78b2eabe..d5f452f 100644
--- a/third_party/blink/renderer/core/svg/svg_geometry_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_geometry_element.cc
@@ -97,8 +97,9 @@
       PointerEventsHitRules::SVG_GEOMETRY_HITTESTING, request,
       GetLayoutObject()->StyleRef().PointerEvents());
   hit_rules.can_hit_stroke = false;
+  HitTestLocation location(point->Target()->Value());
   return ToLayoutSVGShape(GetLayoutObject())
-      ->NodeAtFloatPointInternal(request, point->Target()->Value(), hit_rules);
+      ->NodeAtPointInternal(request, location, hit_rules);
 }
 
 bool SVGGeometryElement::isPointInStroke(SVGPointTearOff* point) const {
@@ -114,8 +115,9 @@
       PointerEventsHitRules::SVG_GEOMETRY_HITTESTING, request,
       GetLayoutObject()->StyleRef().PointerEvents());
   hit_rules.can_hit_fill = false;
+  HitTestLocation location(point->Target()->Value());
   return ToLayoutSVGShape(GetLayoutObject())
-      ->NodeAtFloatPointInternal(request, point->Target()->Value(), hit_rules);
+      ->NodeAtPointInternal(request, location, hit_rules);
 }
 
 Path SVGGeometryElement::ToClipPath() const {
diff --git a/third_party/blink/renderer/core/testing/core_unit_test_helper.cc b/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
index 19983aa6..b85216b 100644
--- a/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
+++ b/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
@@ -52,6 +52,17 @@
   return result.InnerNode();
 }
 
+HitTestResult::NodeSet RenderingTest::RectBasedHitTest(LayoutRect rect) {
+  HitTestLocation location(rect);
+  HitTestResult result(
+      HitTestRequest(HitTestRequest::kReadOnly | HitTestRequest::kActive |
+                     HitTestRequest::kAllowChildFrameContent |
+                     HitTestRequest::kListBased),
+      location);
+  GetLayoutView().HitTest(location, result);
+  return result.ListBasedTestResult();
+}
+
 void RenderingTest::SetUp() {
   Page::PageClients page_clients;
   FillWithEmptyClients(page_clients);
diff --git a/third_party/blink/renderer/core/testing/core_unit_test_helper.h b/third_party/blink/renderer/core/testing/core_unit_test_helper.h
index 1708ced4..2f2c44d 100644
--- a/third_party/blink/renderer/core/testing/core_unit_test_helper.h
+++ b/third_party/blink/renderer/core/testing/core_unit_test_helper.h
@@ -79,6 +79,7 @@
   explicit RenderingTest(LocalFrameClient* = nullptr);
 
   const Node* HitTest(int x, int y);
+  HitTestResult::NodeSet RectBasedHitTest(LayoutRect rect);
 
  protected:
   void SetUp() override;
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
index 0bf6695a..500e8a6 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
-#include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h"
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.h"
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_options.h"
@@ -84,14 +83,6 @@
          !request_url.ProtocolIs(WTF::g_https_atom);
 }
 
-bool ShouldBlockMixedContent(ExecutionContext* execution_context,
-                             const KURL& request_url) {
-  // TODO(crbug.com/757441): Using MixedContentChecker::ShouldBlockFetch would
-  // log better metrics.
-  return MixedContentChecker::IsMixedContent(
-      execution_context->GetSecurityOrigin(), request_url);
-}
-
 bool ShouldBlockDanglingMarkup(const KURL& request_url) {
   // "If request's url's potentially-dangling-markup flag is set, and request's
   // url's scheme is an HTTP(S) scheme, then set response to a network error."
@@ -201,14 +192,6 @@
   // the Download Service in the browser process can use it without having to
   // spin up a renderer process.
   for (const WebServiceWorkerRequest& web_request : web_requests) {
-    // TODO(crbug.com/757441): Decide whether to support upgrading requests to
-    // potentially secure URLs (https://w3c.github.io/webappsec-upgrade-
-    // insecure-requests/) and/or HSTS rewriting. Since this is a new API only
-    // exposed on Secure Contexts, and the Mixed Content check below will block
-    // any requests to insecure contexts, it'd be cleanest not to support it.
-    // Depends how closely compatible with Fetch we want to be. If support is
-    // added, make sure to report CSP violations before upgrading the URL.
-
     KURL request_url(web_request.Url());
 
     if (!request_url.IsValid()) {
@@ -225,7 +208,7 @@
     }
 
     // Check this before mixed content, so that if mixed content is blocked by
-    // CSP they get a CSP warning rather than a mixed content warning.
+    // CSP they get a CSP warning rather than a mixed content failure.
     if (ShouldBlockDueToCSP(execution_context, request_url)) {
       return RejectWithTypeError(script_state, request_url,
                                  "it violates the Content Security Policy");
@@ -247,13 +230,6 @@
                                  "for loopback IPs");
     }
 
-    // Blocking fetches due to mixed content is done after Content Security
-    // Policy to prioritize warnings caused by the latter.
-    if (ShouldBlockMixedContent(execution_context, request_url)) {
-      return RejectWithTypeError(script_state, request_url,
-                                 "it is insecure; use https instead");
-    }
-
     if (ShouldBlockDanglingMarkup(request_url)) {
       return RejectWithTypeError(script_state, request_url,
                                  "it contains dangling markup");
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl
index 12e59cc..d62ceda 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl
@@ -8,7 +8,7 @@
     Exposed=(Window,Worker),
     RuntimeEnabled=BackgroundFetch
 ] interface BackgroundFetchManager {
-    [CallWith=ScriptState, RaisesException] Promise<BackgroundFetchRegistration> fetch(DOMString id, (RequestInfo or sequence<RequestInfo>) requests, optional BackgroundFetchOptions options);
-    [CallWith=ScriptState] Promise<BackgroundFetchRegistration?> get(DOMString id);
-    [CallWith=ScriptState] Promise<FrozenArray<DOMString>> getIds();
+    [CallWith=ScriptState, RaisesException, MeasureAs=BackgroundFetchManagerFetch] Promise<BackgroundFetchRegistration> fetch(DOMString id, (RequestInfo or sequence<RequestInfo>) requests, optional BackgroundFetchOptions options);
+    [CallWith=ScriptState, MeasureAs=BackgroundFetchManagerGet] Promise<BackgroundFetchRegistration?> get(DOMString id);
+    [CallWith=ScriptState, MeasureAs=BackgroundFetchManagerGetIds] Promise<FrozenArray<DOMString>> getIds();
 };
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl
index 2e389e8a..e277b8e 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl
@@ -35,10 +35,10 @@
 
     attribute EventHandler onprogress;
 
-    [CallWith=ScriptState] Promise<boolean> abort();
+    [CallWith=ScriptState, MeasureAs=BackgroundFetchRegistrationAbort] Promise<boolean> abort();
 
     // TODO(crbug.com/875201): Change to (Window,Worker) once we support
     // match() and matchAll() for active fetches.
-    [CallWith=ScriptState, Exposed=ServiceWorker, RaisesException] Promise<BackgroundFetchRecord> match(RequestInfo request, optional CacheQueryOptions options);
-    [CallWith=ScriptState, Exposed=ServiceWorker, RaisesException] Promise<sequence<BackgroundFetchRecord>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
+    [CallWith=ScriptState, Exposed=ServiceWorker, RaisesException, MeasureAs=BackgroundFetchRegistrationMatch] Promise<BackgroundFetchRecord> match(RequestInfo request, optional CacheQueryOptions options);
+    [CallWith=ScriptState, Exposed=ServiceWorker, RaisesException, MeasureAs=BackgroundFetchRegistrationMatchAll] Promise<sequence<BackgroundFetchRecord>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
 };
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index 928eb865..c598bc8 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -302,6 +302,7 @@
           "speech/speech_recognition_result_list.idl",
           "speech/speech_synthesis.idl",
           "speech/speech_synthesis_event.idl",
+          "speech/speech_synthesis_error_event.idl",
           "speech/speech_synthesis_utterance.idl",
           "speech/speech_synthesis_voice.idl",
           "storage/storage.idl",
@@ -477,6 +478,8 @@
           "app_banner/before_install_prompt_event_init.idl",
           "background_fetch/background_fetch_event_init.idl",
           "background_fetch/background_fetch_options.idl",
+          "speech/speech_synthesis_error_event_init.idl",
+          "speech/speech_synthesis_event_init.idl",
           "background_fetch/background_fetch_ui_options.idl",
           "background_sync/sync_event_init.idl",
           "bluetooth/bluetooth_le_scan_filter_init.idl",
diff --git a/third_party/blink/renderer/modules/speech/BUILD.gn b/third_party/blink/renderer/modules/speech/BUILD.gn
index df1bbde..5597ba5fa 100644
--- a/third_party/blink/renderer/modules/speech/BUILD.gn
+++ b/third_party/blink/renderer/modules/speech/BUILD.gn
@@ -30,6 +30,8 @@
     "speech_recognition_result_list.h",
     "speech_synthesis.cc",
     "speech_synthesis.h",
+    "speech_synthesis_error_event.cc",
+    "speech_synthesis_error_event.h",
     "speech_synthesis_event.cc",
     "speech_synthesis_event.h",
     "speech_synthesis_utterance.cc",
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis.cc b/third_party/blink/renderer/modules/speech/speech_synthesis.cc
index b873d8e..d07e54d5 100644
--- a/third_party/blink/renderer/modules/speech/speech_synthesis.cc
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis.cc
@@ -32,7 +32,10 @@
 #include "third_party/blink/renderer/core/html/media/autoplay_policy.h"
 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
 #include "third_party/blink/renderer/core/timing/performance.h"
+#include "third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h"
+#include "third_party/blink/renderer/modules/speech/speech_synthesis_error_event_init.h"
 #include "third_party/blink/renderer/modules/speech/speech_synthesis_event.h"
+#include "third_party/blink/renderer/modules/speech/speech_synthesis_event_init.h"
 #include "third_party/blink/renderer/platform/speech/platform_speech_synthesis_voice.h"
 
 namespace blink {
@@ -158,9 +161,28 @@
   if (!GetElapsedTimeMillis(&millis))
     return;
 
-  double elapsed_time_millis = millis - utterance->StartTime() * 1000.0;
-  utterance->DispatchEvent(*SpeechSynthesisEvent::Create(
-      type, utterance, char_index, elapsed_time_millis, name));
+  SpeechSynthesisEventInit init;
+  init.setUtterance(utterance);
+  init.setCharIndex(char_index);
+  init.setElapsedTime(millis - (utterance->StartTime() * 1000.0));
+  init.setName(name);
+  utterance->DispatchEvent(*SpeechSynthesisEvent::Create(type, init));
+}
+
+void SpeechSynthesis::FireErrorEvent(SpeechSynthesisUtterance* utterance,
+                                     unsigned long char_index,
+                                     const String& error) {
+  double millis;
+  if (!GetElapsedTimeMillis(&millis))
+    return;
+
+  SpeechSynthesisErrorEventInit init;
+  init.setUtterance(utterance);
+  init.setCharIndex(char_index);
+  init.setElapsedTime(millis - (utterance->StartTime() * 1000.0));
+  init.setError(error);
+  utterance->DispatchEvent(
+      *SpeechSynthesisErrorEvent::Create(EventTypeNames::error, init));
 }
 
 void SpeechSynthesis::HandleSpeakingCompleted(
@@ -180,8 +202,13 @@
   // sent an event on an utterance before it got the message that we
   // canceled it, and we should always report to the user what actually
   // happened.
-  FireEvent(error_occurred ? EventTypeNames::error : EventTypeNames::end,
-            utterance, 0, String());
+  if (error_occurred) {
+    // TODO(csharrison): Actually pass the correct message. For now just use a
+    // generic error.
+    FireErrorEvent(utterance, 0, "synthesis-failed");
+  } else {
+    FireEvent(EventTypeNames::end, utterance, 0, String());
+  }
 
   // Start the next utterance if we just finished one and one was pending.
   if (should_start_speaking && !utterance_queue_.IsEmpty())
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis.h b/third_party/blink/renderer/modules/speech/speech_synthesis.h
index 4b87c237..ff767def 100644
--- a/third_party/blink/renderer/modules/speech/speech_synthesis.h
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis.h
@@ -92,6 +92,10 @@
                  unsigned long char_index,
                  const String& name);
 
+  void FireErrorEvent(SpeechSynthesisUtterance*,
+                      unsigned long char_index,
+                      const String& error);
+
   // Returns the utterance at the front of the queue.
   SpeechSynthesisUtterance* CurrentSpeechUtterance() const;
 
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.cc b/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.cc
new file mode 100644
index 0000000..4080142
--- /dev/null
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.cc
@@ -0,0 +1,26 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h"
+
+namespace blink {
+
+// static
+SpeechSynthesisErrorEvent* SpeechSynthesisErrorEvent::Create(
+    const AtomicString& type,
+    const SpeechSynthesisErrorEventInit& init) {
+  return new SpeechSynthesisErrorEvent(type, init);
+}
+
+SpeechSynthesisErrorEvent::SpeechSynthesisErrorEvent(
+    const AtomicString& type,
+    const SpeechSynthesisErrorEventInit& init)
+    : SpeechSynthesisEvent(type,
+                           init.utterance(),
+                           init.charIndex(),
+                           init.elapsedTime(),
+                           init.name()),
+      error_(init.error()) {}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h b/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h
new file mode 100644
index 0000000..24be960
--- /dev/null
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_ERROR_EVENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_ERROR_EVENT_H_
+
+#include "third_party/blink/renderer/modules/event_modules.h"
+#include "third_party/blink/renderer/modules/speech/speech_synthesis_error_event_init.h"
+#include "third_party/blink/renderer/modules/speech/speech_synthesis_event.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class SpeechSynthesisErrorEvent : public SpeechSynthesisEvent {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static SpeechSynthesisErrorEvent* Create(
+      const AtomicString& type,
+      const SpeechSynthesisErrorEventInit& init);
+
+  const String error() const { return error_; }
+
+ private:
+  SpeechSynthesisErrorEvent(const AtomicString& type,
+                            const SpeechSynthesisErrorEventInit& init);
+  const String error_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_ERROR_EVENT_H_
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.idl b/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.idl
new file mode 100644
index 0000000..03ba7d7
--- /dev/null
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.idl
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/speech-api/#enumdef-speechsynthesiserrorcode
+enum SpeechSynthesisErrorCode {
+    "canceled",
+    "interrupted",
+    "audio-busy",
+    "audio-hardware",
+    "network",
+    "synthesis-unavailable",
+    "synthesis-failed",
+    "language-unavailable",
+    "voice-unavailable",
+    "text-too-long",
+    "invalid-argument",
+    "not-allowed",
+};
+
+// https://w3c.github.io/speech-api/#enumdef-speechsynthesiserrorcode
+[
+    Exposed=Window,
+    Constructor(DOMString type, SpeechSynthesisErrorEventInit eventInitDict),
+    RuntimeEnabled=ScriptedSpeech
+] interface SpeechSynthesisErrorEvent : SpeechSynthesisEvent {
+    readonly attribute SpeechSynthesisErrorCode error;
+};
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis_error_event_init.idl b/third_party/blink/renderer/modules/speech/speech_synthesis_error_event_init.idl
new file mode 100644
index 0000000..bb22c8c7
--- /dev/null
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis_error_event_init.idl
@@ -0,0 +1,7 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+dictionary SpeechSynthesisErrorEventInit : SpeechSynthesisEventInit {
+    required SpeechSynthesisErrorCode error;
+};
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis_event.cc b/third_party/blink/renderer/modules/speech/speech_synthesis_event.cc
index d8e51cd..6e0ab68 100644
--- a/third_party/blink/renderer/modules/speech/speech_synthesis_event.cc
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis_event.cc
@@ -27,22 +27,13 @@
 
 namespace blink {
 
-SpeechSynthesisEvent* SpeechSynthesisEvent::Create() {
-  return new SpeechSynthesisEvent;
-}
-
 SpeechSynthesisEvent* SpeechSynthesisEvent::Create(
     const AtomicString& type,
-    SpeechSynthesisUtterance* utterance,
-    unsigned char_index,
-    float elapsed_time,
-    const String& name) {
-  return new SpeechSynthesisEvent(type, utterance, char_index, elapsed_time,
-                                  name);
+    const SpeechSynthesisEventInit& init) {
+  return new SpeechSynthesisEvent(type, init.utterance(), init.charIndex(),
+                                  init.elapsedTime(), init.name());
 }
 
-SpeechSynthesisEvent::SpeechSynthesisEvent() = default;
-
 SpeechSynthesisEvent::SpeechSynthesisEvent(const AtomicString& type,
                                            SpeechSynthesisUtterance* utterance,
                                            unsigned char_index,
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis_event.h b/third_party/blink/renderer/modules/speech/speech_synthesis_event.h
index 2a55b6f..71fbf3e3 100644
--- a/third_party/blink/renderer/modules/speech/speech_synthesis_event.h
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis_event.h
@@ -27,20 +27,17 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_EVENT_H_
 
 #include "third_party/blink/renderer/modules/event_modules.h"
+#include "third_party/blink/renderer/modules/speech/speech_synthesis_event_init.h"
 #include "third_party/blink/renderer/modules/speech/speech_synthesis_utterance.h"
 
 namespace blink {
 
-class SpeechSynthesisEvent final : public Event {
+class SpeechSynthesisEvent : public Event {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SpeechSynthesisEvent* Create();
   static SpeechSynthesisEvent* Create(const AtomicString& type,
-                                      SpeechSynthesisUtterance*,
-                                      unsigned char_index,
-                                      float elapsed_time,
-                                      const String& name);
+                                      const SpeechSynthesisEventInit& init);
 
   SpeechSynthesisUtterance* utterance() const { return utterance_; }
   unsigned charIndex() const { return char_index_; }
@@ -53,14 +50,14 @@
 
   void Trace(blink::Visitor*) override;
 
- private:
-  SpeechSynthesisEvent();
+ protected:
   SpeechSynthesisEvent(const AtomicString& type,
                        SpeechSynthesisUtterance*,
                        unsigned char_index,
                        float elapsed_time,
                        const String& name);
 
+ private:
   Member<SpeechSynthesisUtterance> utterance_;
   unsigned char_index_;
   float elapsed_time_;
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis_event.idl b/third_party/blink/renderer/modules/speech/speech_synthesis_event.idl
index 4c35b5d..0f9e01be 100644
--- a/third_party/blink/renderer/modules/speech/speech_synthesis_event.idl
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis_event.idl
@@ -23,10 +23,10 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-// https://dvcs.w3.org/hg/speech-api/raw-file/tip/webspeechapi.html#tts-section
-
+// https://w3c.github.io/speech-api/#speechsynthesisevent
 [
-    RuntimeEnabled=ScriptedSpeech
+    RuntimeEnabled=ScriptedSpeech,
+    Constructor(DOMString type, SpeechSynthesisEventInit eventInitDict)
 ] interface SpeechSynthesisEvent : Event {
     readonly attribute SpeechSynthesisUtterance utterance;
     readonly attribute unsigned long charIndex;
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis_event_init.idl b/third_party/blink/renderer/modules/speech/speech_synthesis_event_init.idl
new file mode 100644
index 0000000..741c408c
--- /dev/null
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis_event_init.idl
@@ -0,0 +1,10 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+dictionary SpeechSynthesisEventInit : EventInit {
+    required SpeechSynthesisUtterance utterance;
+    unsigned long charIndex = 0;
+    float elapsedTime = 0;
+    DOMString name = "";
+};
diff --git a/third_party/blink/renderer/platform/feature_policy/feature_policy.cc b/third_party/blink/renderer/platform/feature_policy/feature_policy.cc
index 97fc9a2..c5cc628 100644
--- a/third_party/blink/renderer/platform/feature_policy/feature_policy.cc
+++ b/third_party/blink/renderer/platform/feature_policy/feature_policy.cc
@@ -131,7 +131,7 @@
         } else {
           url::Origin target_origin = url::Origin::Create(
               GURL(StringUTF8Adaptor(tokens[i]).AsStringPiece()));
-          if (!target_origin.unique())
+          if (!target_origin.opaque())
             origins.push_back(target_origin);
           else if (messages)
             messages->push_back("Unrecognized origin: '" + tokens[i] + "'.");
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.cc b/third_party/blink/renderer/platform/loader/fetch/resource.cc
index 39713be..9ac50f8 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.cc
@@ -125,16 +125,20 @@
  private:
   const KURL response_url_;
   const Time response_time_;
+  const ResourceType resource_type_;
 };
 
 CachedMetadataSenderImpl::CachedMetadataSenderImpl(const Resource* resource)
     : response_url_(resource->GetResponse().Url()),
-      response_time_(resource->GetResponse().ResponseTime()) {
+      response_time_(resource->GetResponse().ResponseTime()),
+      resource_type_(resource->GetType()) {
   DCHECK(resource->GetResponse().CacheStorageCacheName().IsNull());
 }
 
 void CachedMetadataSenderImpl::Send(const char* data, size_t size) {
-  Platform::Current()->CacheMetadata(response_url_, response_time_, data, size);
+  Platform::Current()->CacheMetadata(
+      Resource::ResourceTypeToCodeCacheType(resource_type_), response_url_,
+      response_time_, data, size);
 }
 
 // This is a CachedMetadataSender implementation that does nothing.
@@ -1232,6 +1236,20 @@
   return InitiatorTypeNameToString(fetch_initiator_name);
 }
 
+// static
+blink::mojom::CodeCacheType Resource::ResourceTypeToCodeCacheType(
+    ResourceType resource_type) {
+  // Cacheable WebAssembly modules are fetched, so raw resource type.
+  if (resource_type == ResourceType::kRaw)
+    return blink::mojom::CodeCacheType::kWebAssembly;
+  // Cacheable Javascript is a script or a document resource. Also accept mock
+  // resources for testing.
+  DCHECK(resource_type == ResourceType::kScript ||
+         resource_type == ResourceType::kMainResource ||
+         resource_type == ResourceType::kMock);
+  return blink::mojom::CodeCacheType::kJavascript;
+}
+
 bool Resource::ShouldBlockLoadEvent() const {
   return !link_preload_ && IsLoadEventBlockingResourceType();
 }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.h b/third_party/blink/renderer/platform/loader/fetch/resource.h
index 308592a..ddececf 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -28,6 +28,7 @@
 #include "base/auto_reset.h"
 #include "base/optional.h"
 #include "base/single_thread_task_runner.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom-shared.h"
 #include "third_party/blink/public/platform/web_data_consumer_handle.h"
 #include "third_party/blink/public/platform/web_scoped_virtual_time_pauser.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.h"
@@ -405,6 +406,8 @@
       ResourceType,
       const AtomicString& fetch_initiator_name);
 
+  static blink::mojom::CodeCacheType ResourceTypeToCodeCacheType(ResourceType);
+
   class ProhibitAddRemoveClientInScope : public base::AutoReset<bool> {
    public:
     ProhibitAddRemoveClientInScope(Resource* resource)
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index 7215f00b..8b6f57c 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -166,7 +166,8 @@
   CodeCacheLoader::FetchCodeCacheCallback callback =
       base::BindOnce(&ResourceLoader::CodeCacheRequest::DidReceiveCachedCode,
                      weak_ptr_factory_.GetWeakPtr(), resource_loader);
-  code_cache_loader_->FetchFromCodeCache(gurl_, std::move(callback));
+  code_cache_loader_->FetchFromCodeCache(
+      blink::mojom::CodeCacheType::kJavascript, gurl_, std::move(callback));
   return true;
 }
 
@@ -247,7 +248,7 @@
   }
 
   if (resource_response_time_ != cached_code_response_time_) {
-    Platform::Current()->ClearCodeCacheEntry(gurl_);
+    resource_loader->ClearCachedCode();
     return;
   }
 
@@ -695,6 +696,12 @@
   resource_->SetSerializedCachedMetadata(data, length);
 }
 
+void ResourceLoader::ClearCachedCode() {
+  Platform::Current()->ClearCodeCacheEntry(
+      Resource::ResourceTypeToCodeCacheType(resource_->GetType()),
+      resource_->Url());
+}
+
 void ResourceLoader::DidSendData(unsigned long long bytes_sent,
                                  unsigned long long total_bytes_to_be_sent) {
   resource_->DidSendData(bytes_sent, total_bytes_to_be_sent);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
index 67f891a..bed1aacf 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
@@ -131,6 +131,7 @@
                int64_t decoded_body_length) override;
 
   void SendCachedCodeToResource(const char* data, int size);
+  void ClearCachedCode();
 
   void HandleError(const ResourceError&);
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
index b70b58b..34e50e9 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
@@ -27,7 +27,11 @@
   ~MockPlatform() override = default;
 
   // From blink::Platform:
-  void CacheMetadata(const WebURL& url, Time, const char*, size_t) override {
+  void CacheMetadata(blink::mojom::CodeCacheType cache_type,
+                     const WebURL& url,
+                     Time,
+                     const char*,
+                     size_t) override {
     cached_urls_.push_back(url);
   }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler_test.cc b/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler_test.cc
index c67276f2..2746de6 100644
--- a/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler_test.cc
@@ -88,7 +88,8 @@
 
   WebCrypto* Crypto() override { return &mock_web_crypto_; }
 
-  void CacheMetadata(const WebURL& url,
+  void CacheMetadata(blink::mojom::CodeCacheType cache_type,
+                     const WebURL& url,
                      base::Time response_time,
                      const char* data,
                      size_t data_size) override {
@@ -125,7 +126,8 @@
   MockCachedMetadataSender(KURL response_url) : response_url_(response_url) {}
 
   void Send(const char* data, size_t size) override {
-    Platform::Current()->CacheMetadata(response_url_, response_time_, data,
+    Platform::Current()->CacheMetadata(blink::mojom::CodeCacheType::kJavascript,
+                                       response_url_, response_time_, data,
                                        size);
   }
 
diff --git a/third_party/blink/renderer/platform/testing/code_cache_loader_mock.cc b/third_party/blink/renderer/platform/testing/code_cache_loader_mock.cc
index a4e9fb3..d57078d 100644
--- a/third_party/blink/renderer/platform/testing/code_cache_loader_mock.cc
+++ b/third_party/blink/renderer/platform/testing/code_cache_loader_mock.cc
@@ -15,6 +15,7 @@
 }
 
 void CodeCacheLoaderMock::FetchFromCodeCache(
+    blink::mojom::CodeCacheType cache_type,
     const GURL& kurl,
     CodeCacheLoader::FetchCodeCacheCallback callback) {
   std::move(callback).Run(base::Time(), std::vector<uint8_t>());
diff --git a/third_party/blink/renderer/platform/testing/code_cache_loader_mock.h b/third_party/blink/renderer/platform/testing/code_cache_loader_mock.h
index 0459e8e..3fc9db1 100644
--- a/third_party/blink/renderer/platform/testing/code_cache_loader_mock.h
+++ b/third_party/blink/renderer/platform/testing/code_cache_loader_mock.h
@@ -22,6 +22,7 @@
                                        base::Time* response_time_out,
                                        std::vector<uint8_t>* data_out) override;
   void FetchFromCodeCache(
+      blink::mojom::CodeCacheType cache_type,
       const GURL& url,
       CodeCacheLoader::FetchCodeCacheCallback callback) override;
 
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin.cc b/third_party/blink/renderer/platform/weborigin/security_origin.cc
index f51f1bb1..6a91910 100644
--- a/third_party/blink/renderer/platform/weborigin/security_origin.cc
+++ b/third_party/blink/renderer/platform/weborigin/security_origin.cc
@@ -201,7 +201,7 @@
 
 scoped_refptr<SecurityOrigin> SecurityOrigin::CreateFromUrlOrigin(
     const url::Origin& origin) {
-  if (origin.unique())
+  if (origin.opaque())
     return CreateUniqueOpaque();
 
   DCHECK(String::FromUTF8(origin.scheme().c_str()).ContainsOnlyASCII());
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin_test.cc b/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
index 3b31fc5..65471a6 100644
--- a/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
+++ b/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
@@ -580,8 +580,8 @@
     url::Origin origin_roundtrip_via_gurl =
         security_origin_via_gurl->ToUrlOrigin();
 
-    EXPECT_EQ(test_case.opaque, origin_roundtrip_via_kurl.unique());
-    EXPECT_EQ(test_case.opaque, origin_roundtrip_via_gurl.unique());
+    EXPECT_EQ(test_case.opaque, origin_roundtrip_via_kurl.opaque());
+    EXPECT_EQ(test_case.opaque, origin_roundtrip_via_gurl.opaque());
     if (!test_case.opaque) {
       EXPECT_EQ(origin_via_gurl, origin_roundtrip_via_kurl);
       EXPECT_EQ(origin_roundtrip_via_kurl, origin_roundtrip_via_gurl);
diff --git a/third_party/blink/tools/blinkpy/third_party/README.chromium b/third_party/blink/tools/blinkpy/third_party/README.chromium
index fda8e7ea..9ac6c94a 100644
--- a/third_party/blink/tools/blinkpy/third_party/README.chromium
+++ b/third_party/blink/tools/blinkpy/third_party/README.chromium
@@ -32,7 +32,7 @@
 Name: web-platform-tests - Test Suites for Web Platform specifications
 Short Name: wpt
 URL: https://github.com/web-platform-tests/wpt/
-Version: ab64b78a8f6777a1d95d8d1d4bba9ccdbecf94ea
+Version: c757432db546a30c1e6ef833df0b597df2dad6bd
 License: LICENSES FOR W3C TEST SUITES (http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html)
 License File: wpt/wpt/LICENSE.md
 Security Critical: no
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
index 360eaad5..f605cbf 100755
--- a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
@@ -9,7 +9,7 @@
 
 TARGET_DIR=$DIR/wpt
 REMOTE_REPO="https://chromium.googlesource.com/external/github.com/web-platform-tests/wpt.git"
-WPT_HEAD=ab64b78a8f6777a1d95d8d1d4bba9ccdbecf94ea
+WPT_HEAD=c757432db546a30c1e6ef833df0b597df2dad6bd
 
 function clone {
   # Remove existing repo if already exists.
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py
index b2e4bce41..59e2d93 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py
@@ -216,7 +216,8 @@
         elif source_file.name_is_reference:
             ref_files[source_file.name].add(path)
         else:
-            test_files[source_file.name].add(path)
+            name = source_file.name.replace('-manual', '')
+            test_files[name].add(path)
 
     errors = []
 
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py
index 61919fc..ddf046a 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py
@@ -234,7 +234,7 @@
     item_type = "stub"
 
 
-class WebdriverSpecTest(URLManifestItem):
+class WebDriverSpecTest(URLManifestItem):
     item_type = "wdspec"
 
     def __init__(self, source_file, url, url_base="/", timeout=None, manifest=None):
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py
index 42a8e1ce..9b2f0a1 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py
@@ -4,7 +4,7 @@
 from collections import defaultdict
 from six import iteritems, itervalues, viewkeys, string_types
 
-from .item import ManualTest, WebdriverSpecTest, Stub, RefTestNode, RefTest, TestharnessTest, SupportFile, ConformanceCheckerTest, VisualTest
+from .item import ManualTest, WebDriverSpecTest, Stub, RefTestNode, RefTest, TestharnessTest, SupportFile, ConformanceCheckerTest, VisualTest
 from .log import get_logger
 from .utils import from_os_path, to_os_path
 
@@ -193,7 +193,7 @@
                         "reftest_node": RefTestNode,
                         "manual": ManualTest,
                         "stub": Stub,
-                        "wdspec": WebdriverSpecTest,
+                        "wdspec": WebDriverSpecTest,
                         "conformancechecker": ConformanceCheckerTest,
                         "visual": VisualTest,
                         "support": SupportFile}
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/sourcefile.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/sourcefile.py
index 133f8b5..1f08088eb 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/sourcefile.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/sourcefile.py
@@ -12,7 +12,7 @@
 import html5lib
 
 from . import XMLParser
-from .item import Stub, ManualTest, WebdriverSpecTest, RefTestNode, TestharnessTest, SupportFile, ConformanceCheckerTest, VisualTest
+from .item import Stub, ManualTest, WebDriverSpecTest, RefTestNode, TestharnessTest, SupportFile, ConformanceCheckerTest, VisualTest
 from .utils import rel_path_to_url, ContextManagerBytesIO, cached_property
 
 wd_pattern = "*.py"
@@ -267,6 +267,7 @@
                 self.name_prefix("MANIFEST") or
                 self.filename == "META.yml" or
                 self.filename.startswith(".") or
+                self.filename.endswith(".headers") or
                 self.type_flag == "support" or
                 self.in_non_test_dir())
 
@@ -645,7 +646,7 @@
             rv = TestharnessTest.item_type, tests
 
         elif self.name_is_webdriver:
-            rv = WebdriverSpecTest.item_type, [WebdriverSpecTest(self, self.url,
+            rv = WebDriverSpecTest.item_type, [WebDriverSpecTest(self, self.url,
                                                                  timeout=self.timeout)]
 
         elif self.content_is_css_manual and not self.name_is_reference:
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py
index 42e98637..675eb017 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py
@@ -1,5 +1,6 @@
 import os
 import subprocess
+import platform
 
 from .sourcefile import SourceFile
 
@@ -16,9 +17,12 @@
             full_cmd = ["git", cmd] + list(args)
             try:
                 return subprocess.check_output(full_cmd, cwd=repo_path, stderr=subprocess.STDOUT)
-            except WindowsError:
-                full_cmd[0] = "git.bat"
-                return subprocess.check_output(full_cmd, cwd=repo_path, stderr=subprocess.STDOUT)
+            except Exception as e:
+                if platform.uname()[0] == "Windows" and isinstance(e, WindowsError):
+                        full_cmd[0] = "git.bat"
+                        return subprocess.check_output(full_cmd, cwd=repo_path, stderr=subprocess.STDOUT)
+                else:
+                    raise
         return git
 
     @classmethod
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
index 97a5063c..c4afc69 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
@@ -100,9 +100,12 @@
         :param request: The Request being processed.
         """
         path = self._get_path(filesystem_path(self.base_path, request, self.url_base), False)
-        with open(path, "rb") as f:
-            for key, value in read_script_metadata(f, js_meta_re):
-                yield key, value
+        try:
+            with open(path, "rb") as f:
+                for key, value in read_script_metadata(f, js_meta_re):
+                    yield key, value
+        except IOError:
+            raise HTTPException(404)
 
     def _get_meta(self, request):
         """Get an iterator over strings to inject into the wrapper document
@@ -378,15 +381,17 @@
 
 
 class ServerProc(object):
-    def __init__(self):
+    def __init__(self, scheme=None):
         self.proc = None
         self.daemon = None
         self.stop = Event()
+        self.scheme = scheme
 
     def start(self, init_func, host, port, paths, routes, bind_address, config, **kwargs):
         self.proc = Process(target=self.create_daemon,
                             args=(init_func, host, port, paths, routes, bind_address,
                                   config),
+                            name='%s on port %s' % (self.scheme, port),
                             kwargs=kwargs)
         self.proc.daemon = True
         self.proc.start()
@@ -507,7 +512,7 @@
                          "ws":start_ws_server,
                          "wss":start_wss_server}[scheme]
 
-            server_proc = ServerProc()
+            server_proc = ServerProc(scheme=scheme)
             server_proc.start(init_func, host, port, paths, routes, bind_address,
                               config, **kwargs)
             servers[scheme].append((port, server_proc))
@@ -624,10 +629,22 @@
         self.server = None
 
 
+def release_mozlog_lock():
+    try:
+        from mozlog.structuredlog import StructuredLogger
+        try:
+            StructuredLogger._lock.release()
+        except threading.ThreadError:
+            pass
+    except ImportError:
+        pass
+
+
 def start_ws_server(host, port, paths, routes, bind_address, config, **kwargs):
-    # Ensure that when we start this in a new process we don't inherit the
-    # global lock in the logging module
+    # Ensure that when we start this in a new process we have the global lock
+    # in the logging module unlocked
     reload_module(logging)
+    release_mozlog_lock()
     return WebSocketDaemon(host,
                            str(port),
                            repo_root,
@@ -638,9 +655,10 @@
 
 
 def start_wss_server(host, port, paths, routes, bind_address, config, **kwargs):
-    # Ensure that when we start this in a new process we don't inherit the
-    # global lock in the logging module
+    # Ensure that when we start this in a new process we have the global lock
+    # in the logging module unlocked
     reload_module(logging)
+    release_mozlog_lock()
     return WebSocketDaemon(host,
                            str(port),
                            repo_root,
@@ -828,9 +846,16 @@
             servers = start(config, build_routes(config["aliases"]), **kwargs)
 
             try:
-                while any(item.is_alive() for item in iter_procs(servers)):
+                while all(item.is_alive() for item in iter_procs(servers)):
                     for item in iter_procs(servers):
                         item.join(1)
+                exited = [item for item in iter_procs(servers) if not item.is_alive()]
+                subject = "subprocess" if len(exited) == 1 else "subprocesses"
+
+                logger.info("%s %s exited:" % (len(exited), subject))
+
+                for item in iter_procs(servers):
+                    logger.info("Status of %s:\t%s" % (item.name, "running" if item.is_alive() else "not running"))
             except KeyboardInterrupt:
                 logger.info("Shutting down")
 
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
index 9834e5d..052ec66 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
@@ -26,12 +26,12 @@
         return NotImplemented
 
     @abstractmethod
-    def install_webdriver(self, dest=None):
+    def install_webdriver(self, dest=None, channel=None):
         """Install the WebDriver implementation for this browser."""
         return NotImplemented
 
     @abstractmethod
-    def find_binary(self):
+    def find_binary(self, venv_path=None, channel=None):
         """Find the binary of the browser.
 
         If the WebDriver for the browser is able to find the binary itself, this
@@ -84,9 +84,32 @@
 
         return "%s%s" % (platform, bits)
 
-    def install(self, dest=None):
+    def install(self, dest=None, channel="nightly"):
         """Install Firefox."""
 
+        branch = {
+            "nightly": "mozilla-central",
+            "beta": "mozilla-beta",
+            "stable": "mozilla-stable"
+        }
+        scraper = {
+            "nightly": "daily",
+            "beta": "release",
+            "stable": "release"
+        }
+        version = {
+            "stable": "latest",
+            "beta": "latest-beta",
+            "nightly": "latest"
+        }
+        application_name = {
+            "stable": "Firefox.app",
+            "beta": "Firefox.app",
+            "nightly": "Firefox Nightly.app"
+        }
+        if channel not in branch:
+            raise ValueError("Unrecognised release channel: %s" % channel)
+
         from mozdownload import FactoryScraper
         import mozinstall
 
@@ -103,17 +126,20 @@
             # os.getcwd() doesn't include the venv path
             dest = os.path.join(os.getcwd(), "_venv")
 
-        dest = os.path.join(dest, "browsers")
+        dest = os.path.join(dest, "browsers", channel)
 
-        filename = FactoryScraper("daily", branch="mozilla-central", destination=dest).download()
+        filename = FactoryScraper(scraper[channel],
+                                  branch=branch[channel],
+                                  version=version[channel],
+                                  destination=dest).download()
 
         try:
             mozinstall.install(filename, dest)
         except mozinstall.mozinstall.InstallError:
-            if platform == "mac" and os.path.exists(os.path.join(dest, "Firefox Nightly.app")):
+            if platform == "mac" and os.path.exists(os.path.join(dest, application_name[channel])):
                 # mozinstall will fail if nightly is already installed in the venv because
                 # mac installation uses shutil.copy_tree
-                mozinstall.uninstall(os.path.join(dest, "Firefox Nightly.app"))
+                mozinstall.uninstall(os.path.join(dest, application_name[channel]))
                 mozinstall.install(filename, dest)
             else:
                 raise
@@ -121,7 +147,7 @@
         os.remove(filename)
         return self.find_binary_path(dest)
 
-    def find_binary_path(self, path=None):
+    def find_binary_path(self,path=None, channel="nightly"):
         """Looks for the firefox binary in the virtual environment"""
 
         platform = {
@@ -130,9 +156,15 @@
             "Darwin": "mac"
         }.get(uname[0])
 
+        application_name = {
+            "stable": "Firefox.app",
+            "beta": "Firefox.app",
+            "nightly": "Firefox Nightly.app"
+        }.get(channel)
+
         if path is None:
             #os.getcwd() doesn't include the venv path
-            path = os.path.join(os.getcwd(), "_venv", "browsers")
+            path = os.path.join(os.getcwd(), "_venv", "browsers", channel)
 
         binary = None
 
@@ -142,19 +174,24 @@
             import mozinstall
             binary = mozinstall.get_binary(path, "firefox")
         elif platform == "mac":
-            binary = find_executable("firefox", os.path.join(path, "Firefox Nightly.app", "Contents", "MacOS"))
+            binary = find_executable("firefox", os.path.join(path, application_name,
+                                                             "Contents", "MacOS"))
 
         return binary
 
-    def find_binary(self, venv_path=None):
+    def find_binary(self, venv_path=None, channel=None):
         if venv_path is None:
             venv_path = os.path.join(os.getcwd(), "_venv")
 
-        binary = self.find_binary_path(os.path.join(venv_path, "browsers"))
+        if channel is None:
+            channel = "nightly"
+
+        path = os.path.join(venv_path, "browsers", channel)
+        binary = self.find_binary_path(path, channel)
 
         if not binary and uname[0] == "Darwin":
-            macpaths = ["/Applications/FirefoxNightly.app/Contents/MacOS",
-                        os.path.expanduser("~/Applications/FirefoxNightly.app/Contents/MacOS"),
+            macpaths = ["/Applications/Firefox Nightly.app/Contents/MacOS",
+                        os.path.expanduser("~/Applications/Firefox Nightly.app/Contents/MacOS"),
                         "/Applications/Firefox Developer Edition.app/Contents/MacOS",
                         os.path.expanduser("~/Applications/Firefox Developer Edition.app/Contents/MacOS"),
                         "/Applications/Firefox.app/Contents/MacOS",
@@ -190,6 +227,18 @@
         if channel == "stable":
             repo = "https://hg.mozilla.org/releases/mozilla-release"
             tag = "FIREFOX_%s_RELEASE" % version.replace(".", "_")
+        elif channel == "beta":
+            repo = "https://hg.mozilla.org/releases/mozilla-beta"
+            major_version = version.split(".", 1)[0]
+            # For beta we have a different format for betas that are now in stable releases
+            # vs those that are not
+            tags = get("https://hg.mozilla.org/releases/mozilla-beta/json-tags").json()["tags"]
+            tags = {item["tag"] for item in tags}
+            end_tag = "FIREFOX_BETA_%s_END" % major_version
+            if end_tag in tags:
+                tag = end_tag
+            else:
+                tag = "tip"
         else:
             repo = "https://hg.mozilla.org/mozilla-central"
             if channel == "beta":
@@ -202,8 +251,14 @@
 
         return "%s/archive/%s.zip/testing/profiles/" % (repo, tag)
 
-    def install_prefs(self, binary, dest=None):
-        version, channel = self.get_version_and_channel(binary)
+    def install_prefs(self, binary, dest=None, channel=None):
+        version, channel_ = self.get_version_and_channel(binary)
+        if channel is not None and channel != channel_:
+            # Beta doesn't always seem to have the b in the version string, so allow the
+            # manually supplied value to override the one from the binary
+            logger.warning("Supplied channel doesn't match binary, using supplied channel")
+        elif channel is None:
+            channel = channel_
         if dest is None:
             dest = os.pwd
 
@@ -257,11 +312,18 @@
         assert latest_release != 0
         return "v%s.%s.%s" % tuple(str(item) for item in latest_release)
 
-    def install_webdriver(self, dest=None):
+    def install_webdriver(self, dest=None, channel=None):
         """Install latest Geckodriver."""
         if dest is None:
             dest = os.getcwd()
 
+        if channel == "nightly":
+            path = self.install_geckodriver_nightly(dest)
+            if path is not None:
+                return path
+            else:
+                logger.warning("Nightly webdriver not found; falling back to release")
+
         version = self._latest_geckodriver_version()
         format = "zip" if uname[0] == "Windows" else "tar.gz"
         logger.debug("Latest geckodriver release %s" % version)
@@ -273,9 +335,39 @@
             untar(get(url).raw, dest=dest)
         return find_executable(os.path.join(dest, "geckodriver"))
 
-    def version(self, binary=None):
+    def install_geckodriver_nightly(self, dest):
+        import tarfile
+        import mozdownload
+        logger.info("Attempting to install webdriver from nightly")
+        try:
+            s = mozdownload.DailyScraper(branch="mozilla-central",
+                                         extension="common.tests.tar.gz",
+                                         destination=dest)
+            package_path = s.download()
+        except mozdownload.errors.NotFoundError:
+            return
+
+        try:
+            exe_suffix = ".exe" if uname[0] == "Windows" else ""
+            with tarfile.open(package_path, "r") as f:
+                try:
+                    member = f.getmember("bin%sgeckodriver%s" % (os.path.sep,
+                                                                 exe_suffix))
+                except KeyError:
+                    return
+                # Remove bin/ from the path.
+                member.name = os.path.basename(member.name)
+                f.extractall(members=[member], path=dest)
+                path = os.path.join(dest, member.name)
+            logger.info("Extracted geckodriver to %s" % path)
+        finally:
+            os.unlink(package_path)
+
+        return path
+
+    def version(self, binary=None, channel=None):
         """Retrieve the release version of the installed browser."""
-        binary = binary or self.find_binary()
+        binary = binary or self.find_binary(channel)
         version_string = call(binary, "--version").strip()
         m = re.match(r"Mozilla Firefox (.*)", version_string)
         if not m:
@@ -289,16 +381,16 @@
     product = "fennec"
     requirements = "requirements_firefox.txt"
 
-    def install(self, dest=None):
+    def install(self, dest=None, channel=None):
         raise NotImplementedError
 
-    def find_binary(self, venv_path=None):
+    def find_binary(self, venv_path=None, channel=None):
         raise NotImplementedError
 
     def find_webdriver(self):
         raise NotImplementedError
 
-    def install_webdriver(self, dest=None):
+    def install_webdriver(self, dest=None, channel=None):
         raise NotImplementedError
 
     def version(self, binary=None):
@@ -324,7 +416,7 @@
         logger.warn("Unable to find the browser binary.")
         return None
 
-    def install(self, dest=None):
+    def install(self, dest=None, channel=None):
         raise NotImplementedError
 
     def platform_string(self):
@@ -346,13 +438,13 @@
 
         return "%s%s" % (platform, bits)
 
-    def find_binary(self):
+    def find_binary(self, venv_path=None, channel=None):
         raise NotImplementedError
 
     def find_webdriver(self):
         return find_executable("chromedriver")
 
-    def install_webdriver(self, dest=None):
+    def install_webdriver(self, dest=None, channel=None):
         if dest is None:
             dest = os.pwd
         latest = get("http://chromedriver.storage.googleapis.com/LATEST_RELEASE").text.strip()
@@ -391,22 +483,28 @@
     product = "chrome_android"
     requirements = "requirements_chrome_android.txt"
 
-    def install(self, dest=None):
+    def install(self, dest=None, channel=None):
         raise NotImplementedError
 
-    def find_binary(self):
+    def find_binary(self, venv_path=None, channel=None):
         raise NotImplementedError
 
     def find_webdriver(self):
         return find_executable("chromedriver")
 
-    def install_webdriver(self, dest=None):
+    def install_webdriver(self, dest=None, channel=None):
         chrome = Chrome()
-        return chrome.install_webdriver(dest)
+        return chrome.install_webdriver(dest, channel)
 
     def version(self, binary):
         return None
 
+class ChromeWebDriver(Chrome):
+    """Chrome-specific interface for chrome without using selenium.
+
+    Includes webdriver installation.
+    """
+    product = "chrome_webdriver"
 
 class Opera(Browser):
     """Opera-specific interface.
@@ -425,7 +523,7 @@
         logger.warn("Unable to find the browser binary.")
         return None
 
-    def install(self, dest=None):
+    def install(self, dest=None, channel=None):
         raise NotImplementedError
 
     def platform_string(self):
@@ -447,13 +545,13 @@
 
         return "%s%s" % (platform, bits)
 
-    def find_binary(self):
+    def find_binary(self, venv_path=None, channel=None):
         raise NotImplementedError
 
     def find_webdriver(self):
         return find_executable("operadriver")
 
-    def install_webdriver(self, dest=None):
+    def install_webdriver(self, dest=None, channel=None):
         if dest is None:
             dest = os.pwd
         latest = get("https://api.github.com/repos/operasoftware/operachromiumdriver/releases/latest").json()["tag_name"]
@@ -487,38 +585,42 @@
     product = "edge"
     requirements = "requirements_edge.txt"
 
-    def install(self, dest=None):
+    def install(self, dest=None, channel=None):
         raise NotImplementedError
 
-    def find_binary(self):
+    def find_binary(self, venv_path=None, channel=None):
         raise NotImplementedError
 
     def find_webdriver(self):
         return find_executable("MicrosoftWebDriver")
 
-    def install_webdriver(self, dest=None):
+    def install_webdriver(self, dest=None, channel=None):
         raise NotImplementedError
 
     def version(self, binary):
         return None
 
 
+class EdgeWebDriver(Edge):
+    product = "edge_webdriver"
+
+
 class InternetExplorer(Browser):
     """Internet Explorer-specific interface."""
 
     product = "ie"
     requirements = "requirements_ie.txt"
 
-    def install(self, dest=None):
+    def install(self, dest=None, channel=None):
         raise NotImplementedError
 
-    def find_binary(self):
+    def find_binary(self, venv_path=None, channel=None):
         raise NotImplementedError
 
     def find_webdriver(self):
         return find_executable("IEDriverServer.exe")
 
-    def install_webdriver(self, dest=None):
+    def install_webdriver(self, dest=None, channel=None):
         raise NotImplementedError
 
     def version(self, binary):
@@ -534,22 +636,26 @@
     product = "safari"
     requirements = "requirements_safari.txt"
 
-    def install(self, dest=None):
+    def install(self, dest=None, channel=None):
         raise NotImplementedError
 
-    def find_binary(self):
+    def find_binary(self, venv_path=None, channel=None):
         raise NotImplementedError
 
     def find_webdriver(self):
         return find_executable("safaridriver")
 
-    def install_webdriver(self):
+    def install_webdriver(self, dest=None, channel=None):
         raise NotImplementedError
 
     def version(self, binary):
         return None
 
 
+class SafariWebDriver(Safari):
+    product = "safari_webdriver"
+
+
 class Servo(Browser):
     """Servo-specific interface."""
 
@@ -574,8 +680,10 @@
 
         return (platform, extension, decompress)
 
-    def install(self, dest=None):
+    def install(self, dest=None, channel="nightly"):
         """Install latest Browser Engine."""
+        if channel != "nightly":
+            raise ValueError("Only nightly versions of Servo are available")
         if dest is None:
             dest = os.pwd
 
@@ -588,13 +696,16 @@
         os.chmod(path, st.st_mode | stat.S_IEXEC)
         return path
 
-    def find_binary(self):
-        return find_executable("servo")
+    def find_binary(self, venv_path=None, channel=None):
+        path = find_executable("servo", os.path.join(venv_path, "servo"))
+        if path is None:
+            path = find_executable("servo")
+        return path
 
     def find_webdriver(self):
         return None
 
-    def install_webdriver(self, dest=None):
+    def install_webdriver(self, dest=None, channel=None):
         raise NotImplementedError
 
     def version(self, binary):
@@ -609,16 +720,16 @@
     product = "sauce"
     requirements = "requirements_sauce.txt"
 
-    def install(self, dest=None):
+    def install(self, dest=None, channel=None):
         raise NotImplementedError
 
-    def find_binary(self):
+    def find_binary(self, venev_path=None, channel=None):
         raise NotImplementedError
 
     def find_webdriver(self):
         raise NotImplementedError
 
-    def install_webdriver(self, dest=None):
+    def install_webdriver(self, dest=None, channel=None):
         raise NotImplementedError
 
     def version(self, binary):
@@ -631,16 +742,16 @@
     product = "webkit"
     requirements = "requirements_webkit.txt"
 
-    def install(self, dest=None):
+    def install(self, dest=None, channel=None):
         raise NotImplementedError
 
-    def find_binary(self, path=None):
+    def find_binary(self, venv_path=None, channel=None):
         return None
 
     def find_webdriver(self):
         return None
 
-    def install_webdriver(self):
+    def install_webdriver(self, dest=None, channel=None):
         raise NotImplementedError
 
     def version(self, binary):
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py
index d779651..62c833aa 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py
@@ -2,20 +2,62 @@
 import browser
 import sys
 
+
+latest_channels = {
+    'firefox': 'nightly',
+    'chrome': 'dev',
+    'servo': 'nightly'
+}
+
+channel_by_name = {
+    'stable': 'stable',
+    'release': 'stable',
+    'beta': 'beta',
+    'nightly': latest_channels,
+    'dev': latest_channels,
+    'preview': latest_channels,
+    'experimental': latest_channels,
+}
+
+
 def get_parser():
-    parser = argparse.ArgumentParser()
-    parser.add_argument('browser', choices=['firefox', 'chrome'],
+    parser = argparse.ArgumentParser(description="""Install a given browser or webdriver frontend.
+
+    For convenience the release channel of the browser accepts various spellings,
+    but we actually support at most three variants; whatever the latest development
+    release is (e.g. Firefox nightly or Chrome dev), the latest beta release, and
+    the most recent stable release.""")
+    parser.add_argument('browser', choices=['firefox', 'chrome', 'servo'],
                         help='name of web browser product')
     parser.add_argument('component', choices=['browser', 'webdriver'],
                         help='name of component')
+    parser.add_argument('--channel', choices=channel_by_name.keys(),
+                        default="nightly", help='Name of browser release channel. '
+                        '"stable" and "release" are synonyms for the latest browser stable release,'
+                        '"nightly", "dev", "experimental", and "preview" are all synonyms for '
+                        'the latest available development release. For WebDriver installs, '
+                        'we attempt to select an appropriate, compatible, version for the '
+                        'latest browser release on the selected channel.')
     parser.add_argument('-d', '--destination',
                         help='filesystem directory to place the component')
     return parser
 
 
+def get_channel(browser, channel):
+    channel = channel_by_name[channel]
+    if isinstance(channel, dict):
+        channel = channel[browser]
+    return channel
+
+
 def run(venv, **kwargs):
     browser = kwargs["browser"]
     destination = kwargs["destination"]
+    channel = get_channel(browser, kwargs["channel"])
+
+    if channel != kwargs["channel"]:
+        print "Interpreting channel '%s' as '%s'" % (kwargs["channel"],
+                                                     channel)
 
     if destination is None:
         if venv:
@@ -27,10 +69,10 @@
             raise argparse.ArgumentError(None,
                                          "No --destination argument, and no default for the environment")
 
-    install(browser, kwargs["component"], destination)
+    install(browser, kwargs["component"], destination, channel)
 
 
-def install(name, component, destination):
+def install(name, component, destination, channel="nightly"):
     if component == 'webdriver':
         method = 'install_webdriver'
     else:
@@ -38,4 +80,6 @@
 
     subclass = getattr(browser, name.title())
     sys.stdout.write('Now installing %s %s...\n' % (name, component))
-    getattr(subclass(), method)(dest=destination)
+    path = getattr(subclass(), method)(dest=destination, channel=channel)
+    if path:
+        sys.stdout.write('Binary installed as %s\n' % (path,))
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py
index 6b098b4..d08b0f9 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py
@@ -7,7 +7,7 @@
 wpt_root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
 sys.path.insert(0, os.path.abspath(os.path.join(wpt_root, "tools")))
 
-from . import browser, utils, virtualenv
+from . import browser, install, utils, virtualenv
 from ..serve import serve
 
 logger = None
@@ -47,7 +47,17 @@
     parser.add_argument("--yes", "-y", dest="prompt", action="store_false", default=True,
                         help="Don't prompt before installing components")
     parser.add_argument("--install-browser", action="store_true",
-                        help="Install the latest development version of the browser")
+                        help="Install the browser from the release channel specified by --channel "
+                        "(or the nightly channel by default).")
+    parser.add_argument("--channel", action="store",
+                        choices=install.channel_by_name.keys(),
+                        default=None, help='Name of browser release channel. '
+                        '"stable" and "release" are synonyms for the latest browser stable '
+                        'release, "nightly", "dev", "experimental", and "preview" are all '
+                        'synonyms for the latest available development release. (For WebDriver '
+                        'installs, we attempt to select an appropriate, compatible version for '
+                        'the latest browser release on the selected channel.) '
+                        'This flag overrides --browser-channel.')
     parser._add_container_actions(wptcommandline.create_parser())
     return parser
 
@@ -105,7 +115,7 @@
 
         missing_hosts = set(expected_hosts)
         if is_windows:
-            hosts_path = "C:\Windows\System32\drivers\etc\hosts"
+            hosts_path = "%s\System32\drivers\etc\hosts" % os.environ.get("SystemRoot", "C:\Windows")
         else:
             hosts_path = "/etc/hosts"
 
@@ -120,7 +130,7 @@
                 if is_windows:
                     message = """Missing hosts file configuration. Run
 
-python wpt make-hosts-file | Out-File %SystemRoot%\System32\drivers\etc\hosts -Encoding ascii -Append
+python wpt make-hosts-file | Out-File %s -Encoding ascii -Append
 
 in PowerShell with Administrator privileges.""" % hosts_path
                 else:
@@ -150,9 +160,9 @@
             elif resp == "n":
                 return False
 
-    def install(self, venv):
+    def install(self, venv, channel=None):
         if self.prompt_install(self.name):
-            return self.browser.install(venv.path)
+            return self.browser.install(venv.path, channel)
 
     def install_requirements(self):
         self.venv.install_requirements(os.path.join(wpt_root, "tools", "wptrunner", self.browser.requirements))
@@ -167,7 +177,11 @@
 
     def setup_kwargs(self, kwargs):
         if kwargs["binary"] is None:
-            binary = self.browser.find_binary(self.venv.path)
+            if kwargs["browser_channel"] is None:
+                logger.info("No browser channel specified. Running nightly instead.")
+
+            binary = self.browser.find_binary(self.venv.path,
+                                              kwargs["browser_channel"])
             if binary is None:
                 raise WptrunError("""Firefox binary not found on $PATH.
 
@@ -205,9 +219,18 @@
                 kwargs["test_types"].remove("wdspec")
 
         if kwargs["prefs_root"] is None:
-            prefs_root = self.browser.install_prefs(kwargs["binary"], self.venv.path)
+            prefs_root = self.browser.install_prefs(kwargs["binary"],
+                                                    self.venv.path,
+                                                    channel=kwargs["browser_channel"])
             kwargs["prefs_root"] = prefs_root
 
+        if kwargs["headless"] is None:
+            kwargs["headless"] = True
+            logger.info("Running in headless mode, pass --no-headless to disable")
+
+        # Allow WebRTC tests to call getUserMedia.
+        kwargs["extra_prefs"].append("media.navigator.streams.fake=true")
+
 
 class Fennec(BrowserSetup):
     name = "fennec"
@@ -238,6 +261,12 @@
                 kwargs["webdriver_binary"] = webdriver_binary
             else:
                 raise WptrunError("Unable to locate or install chromedriver binary")
+        if kwargs["browser_channel"] == "dev":
+            logger.info("Automatically turning on experimental features for Chrome Dev")
+            kwargs["binary_args"].append("--enable-experimental-web-platform-features")
+
+        # Allow WebRTC tests to call getUserMedia.
+        kwargs["binary_args"] += ["--use-fake-ui-for-media-stream", "--use-fake-device-for-media-stream"]
 
 
 class ChromeAndroid(BrowserSetup):
@@ -263,6 +292,11 @@
                 raise WptrunError("Unable to locate or install chromedriver binary")
 
 
+class ChromeWebDriver(Chrome):
+    name = "chrome_webdriver"
+    browser_cls = browser.ChromeWebDriver
+
+
 class Opera(BrowserSetup):
     name = "opera"
     browser_cls = browser.Opera
@@ -290,7 +324,7 @@
     name = "edge"
     browser_cls = browser.Edge
 
-    def install(self, venv):
+    def install(self, venv, channel=None):
         raise NotImplementedError
 
     def setup_kwargs(self, kwargs):
@@ -307,11 +341,16 @@
             kwargs["webdriver_binary"] = webdriver_binary
 
 
+class EdgeWebDriver(Edge):
+    name = "edge_webdriver"
+    browser_cls = browser.EdgeWebDriver
+
+
 class InternetExplorer(BrowserSetup):
     name = "ie"
     browser_cls = browser.InternetExplorer
 
-    def install(self, venv):
+    def install(self, venv, channel=None):
         raise NotImplementedError
 
     def setup_kwargs(self, kwargs):
@@ -332,7 +371,7 @@
     name = "safari"
     browser_cls = browser.Safari
 
-    def install(self, venv):
+    def install(self, venv, channel=None):
         raise NotImplementedError
 
     def setup_kwargs(self, kwargs):
@@ -345,11 +384,16 @@
             kwargs["webdriver_binary"] = webdriver_binary
 
 
+class SafariWebDriver(Safari):
+    name = "safari_webdriver"
+    browser_cls = browser.SafariWebDriver
+
+
 class Sauce(BrowserSetup):
     name = "sauce"
     browser_cls = browser.Sauce
 
-    def install(self, venv):
+    def install(self, venv, channel=None):
         raise NotImplementedError
 
     def setup_kwargs(self, kwargs):
@@ -362,13 +406,13 @@
     name = "servo"
     browser_cls = browser.Servo
 
-    def install(self, venv):
+    def install(self, venv, channel=None):
         if self.prompt_install(self.name):
             return self.browser.install(venv.path)
 
     def setup_kwargs(self, kwargs):
         if kwargs["binary"] is None:
-            binary = self.browser.find_binary()
+            binary = self.browser.find_binary(self.venv.path, None)
 
             if binary is None:
                 raise WptrunError("Unable to find servo binary on the PATH")
@@ -379,7 +423,7 @@
     name = "webkit"
     browser_cls = browser.WebKit
 
-    def install(self, venv):
+    def install(self, venv, channel=None):
         raise NotImplementedError
 
     def setup_kwargs(self, kwargs):
@@ -391,9 +435,12 @@
     "firefox": Firefox,
     "chrome": Chrome,
     "chrome_android": ChromeAndroid,
+    "chrome_webdriver": ChromeWebDriver,
     "edge": Edge,
+    "edge_webdriver": EdgeWebDriver,
     "ie": InternetExplorer,
     "safari": Safari,
+    "safari_webdriver": SafariWebDriver,
     "servo": Servo,
     "sauce": Sauce,
     "opera": Opera,
@@ -401,7 +448,7 @@
 }
 
 
-def setup_wptrunner(venv, prompt=True, install=False, **kwargs):
+def setup_wptrunner(venv, prompt=True, install_browser=False, **kwargs):
     from wptrunner import wptrunner, wptcommandline
 
     global logger
@@ -424,9 +471,21 @@
     setup_cls = product_setup[kwargs["product"]](venv, prompt, sub_product)
     setup_cls.install_requirements()
 
-    if install:
+    if install_browser and not kwargs["channel"]:
+        logger.info("--install-browser is given but --channel is not set, default to nightly channel")
+        kwargs["channel"] = "nightly"
+
+    if kwargs["channel"]:
+        channel = install.get_channel(kwargs["product"], kwargs["channel"])
+        if channel != kwargs["channel"]:
+            logger.info("Interpreting channel '%s' as '%s'" % (kwargs["channel"],
+                                                               channel))
+        kwargs["browser_channel"] = channel
+    del kwargs["channel"]
+
+    if install_browser:
         logger.info("Installing browser")
-        kwargs["binary"] = setup_cls.install(venv)
+        kwargs["binary"] = setup_cls.install(venv, channel=channel)
 
     setup_cls.setup(kwargs)
 
@@ -441,13 +500,13 @@
 
 
 def run(venv, **kwargs):
-    #Remove arguments that aren't passed to wptrunner
+    # Remove arguments that aren't passed to wptrunner
     prompt = kwargs.pop("prompt", True)
     install_browser = kwargs.pop("install_browser", False)
 
     kwargs = setup_wptrunner(venv,
                              prompt=prompt,
-                             install=install_browser,
+                             install_browser=install_browser,
                              **kwargs)
 
     rv = run_single(venv, **kwargs) > 0
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/wpt.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/wpt.py
index f4eecce2..55802461 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/wpt.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/wpt.py
@@ -101,9 +101,6 @@
 
     main_args, command_args = parse_args(argv, commands)
 
-    if not(len(argv) and argv[0] in commands):
-        sys.exit(1)
-
     command = main_args.command
     props = commands[command]
     venv = None
diff --git a/third_party/boringssl/BUILD.generated_tests.gni b/third_party/boringssl/BUILD.generated_tests.gni
index ff5955f..02fa36c 100644
--- a/third_party/boringssl/BUILD.generated_tests.gni
+++ b/third_party/boringssl/BUILD.generated_tests.gni
@@ -70,6 +70,7 @@
   "src/crypto/refcount_test.cc",
   "src/crypto/rsa_extra/rsa_test.cc",
   "src/crypto/self_test.cc",
+  "src/crypto/stack/stack_test.cc",
   "src/crypto/test/file_test_gtest.cc",
   "src/crypto/test/gtest_main.cc",
   "src/crypto/thread_test.cc",
diff --git a/tools/binary_size/trybot_commit_size_checker.py b/tools/binary_size/trybot_commit_size_checker.py
index d93b46ae..5ef7939 100755
--- a/tools/binary_size/trybot_commit_size_checker.py
+++ b/tools/binary_size/trybot_commit_size_checker.py
@@ -29,6 +29,30 @@
     'binary_size/metrics.md#Normalized-APK-Size '
     'for an explanation of Normalized APK Size')
 
+_FAILURE_GUIDANCE = """
+Please look at the symbol diffs from the "Show Resource Sizes Diff",
+"Show Supersize Diff", and "Dex Method Count", and "Supersize HTML Report" bot
+steps. Try and understand the growth and see if it can be mitigated.
+
+There is guidance at:
+
+https://chromium.googlesource.com/chromium/src/+/master/docs/speed/apk_size_regressions.md#Debugging-Apk-Size-Increase
+
+If the growth is expected / justified, then you can bypass this bot failure by
+adding "Binary-Size: $JUSTIFICATION" to your commit description. Here are some
+examples:
+
+Binary-Size: Increase is due to translations and so cannot be avoided.
+Binary-Size: Increase is due to new images, which are already optimally encoded.
+Binary-Size: Increase is temporary due to a "new way" / "old way" refactoring.
+    It should go away once the "old way" is removed.
+Binary-Size: Increase is temporary and will be reverted before next branch cut.
+Binary-Size: Increase needed to reduce RAM of a common user flow.
+Binary-Size: Increase needed to reduce runtime of a common user flow.
+Binary-Size: Increase needed to implement a feature, and I've already spent a
+    non-trivial amount of time trying to reduce its size.
+"""
+
 
 class _SizeDelta(collections.namedtuple(
     'SizeDelta', ['name', 'units', 'expected', 'actual', 'details'])):
@@ -147,10 +171,10 @@
 
   # Normalized APK Size is the main metric we use to monitor binary size.
   logging.info('Creating sizes diff')
-  size_deltas.add(
-      _CreateAndWriteResourceSizesDelta(
+  resource_sizes_delta = _CreateAndWriteResourceSizesDelta(
           args.apk_name, args.before_dir, args.after_dir,
-          args.resource_sizes_diff_path))
+          args.resource_sizes_diff_path)
+  size_deltas.add(resource_sizes_delta)
 
   # .ndjson can be consumed by the html viewer.
   logging.info('Creating HTML Report')
@@ -165,8 +189,9 @@
 
   passing_deltas = set(m for m in size_deltas if m._IsAllowable())
   failing_deltas = size_deltas - passing_deltas
+  status_code = len(failing_deltas)
 
-  result = 'passed' if is_roller or len(failing_deltas) == 0 else 'failed'
+  result = 'passed' if is_roller or status_code == 0 else 'failed'
   message = """
 
 Binary size checks {}.
@@ -184,35 +209,23 @@
 
 *******************************************************************************
 
-Please look at the symbol diffs from the "Show Resource Sizes Diff",
-"Show Supersize Diff", and "Dex Method Count", and "Supersize HTML Report" bot
-steps. Try and understand the growth and see if it can be mitigated.
-
-There is guidance at:
-
-https://chromium.googlesource.com/chromium/src/+/master/docs/speed/apk_size_regressions.md#Debugging-Apk-Size-Increase
-
-If the growth is expected / justified, then you can bypass this bot failure by \
-adding "Binary-Size: $JUSTIFICATION" to your commit description. Here are some \
-examples:
-
-Binary-Size: Increase is due to translations and so cannot be avoided.
-Binary-Size: Increase is due to new images, which are already optimally encoded.
-Binary-Size: Increase is temporary due to a "new way" / "old way" refactoring.
-    It should go away once the "old way" is removed.
-Binary-Size: Increase is temporary and will be reverted before next branch cut.
-Binary-Size: Increase needed to reduce RAM of a common user flow.
-Binary-Size: Increase needed to reduce runtime of a common user flow.
-Binary-Size: Increase needed to implement a feature, and I've already spent a
-    non-trivial amount of time trying to reduce its size.
 """.format(result,
            '\n\n'.join(d.explanation for d in sorted(failing_deltas)),
            '\n\n'.join(d.explanation for d in sorted(passing_deltas)))
+
+  if status_code != 0:
+    message += _FAILURE_GUIDANCE
+
   # Make blank lines not blank prevent them from being stripped.
   # https://crbug.com/855671
   message.replace('\n\n', '\n.\n')
   with open(args.results_path, 'w') as f:
-    json.dump({'status_code': len(failing_deltas), 'details': message}, f)
+    results_json = {
+        'details': message,
+        'normalized_apk_size': resource_sizes_delta.actual,
+        'status_code': status_code
+    }
+    json.dump(results_json, f)
 
 
 if __name__ == '__main__':
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 3390c178..cf9084c 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -27,7 +27,7 @@
 # Do NOT CHANGE this if you don't know what you're doing -- see
 # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md
 # Reverting problematic clang rolls is safe, though.
-CLANG_REVISION = '343189'
+CLANG_REVISION = '342523'
 
 use_head_revision = bool(os.environ.get('LLVM_FORCE_HEAD_REVISION', '0')
                          in ('1', 'YES'))
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer.cc b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
index 0fe61ae..ec291e5 100644
--- a/tools/ipc_fuzzer/fuzzer/fuzzer.cc
+++ b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
@@ -1524,7 +1524,7 @@
 template <>
 struct FuzzTraits<url::Origin> {
   static bool Fuzz(url::Origin* p, Fuzzer* fuzzer) {
-    bool opaque = p->unique();
+    bool opaque = p->opaque();
     if (!FuzzParam(&opaque, fuzzer))
       return false;
     std::string scheme = p->GetTupleOrPrecursorTupleIfOpaque().scheme();
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 75cdcb8..8cc40b9 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -279,12 +279,16 @@
       'Android FYI Release (NVIDIA Shield TV)': 'android_release_trybot_arm64',
       'Android FYI 32 Vk Release (Nexus 5X)': 'gpu_tests_android_vulkan_release_trybot',
       'Android FYI 32 Vk Release (Pixel 2)': 'gpu_tests_android_vulkan_release_trybot',
+      'Android FYI 32 Vk Release (Pixel XL)': 'gpu_tests_android_vulkan_release_trybot',
       'Android FYI 64 Vk Release (Nexus 5X)': 'gpu_tests_android_vulkan_release_trybot_arm64',
       'Android FYI 64 Vk Release (Pixel 2)': 'gpu_tests_android_vulkan_release_trybot_arm64',
+      'Android FYI 64 Vk Release (Pixel XL)': 'gpu_tests_android_vulkan_release_trybot_arm64',
       'Android FYI 32 dEQP Vk Release (Nexus 5X)': 'deqp_android_vulkan_release_trybot',
       'Android FYI 32 dEQP Vk Release (Pixel 2)': 'deqp_android_vulkan_release_trybot',
+      'Android FYI 32 dEQP Vk Release (Pixel XL)': 'deqp_android_vulkan_release_trybot',
       'Android FYI 64 dEQP Vk Release (Nexus 5X)': 'deqp_android_vulkan_release_trybot_arm64',
       'Android FYI 64 dEQP Vk Release (Pixel 2)': 'deqp_android_vulkan_release_trybot_arm64',
+      'Android FYI 64 dEQP Vk Release (Pixel XL)': 'deqp_android_vulkan_release_trybot_arm64',
       'GPU FYI Linux Builder': 'gpu_fyi_tests_release_trybot',
       'GPU FYI Linux Ozone Builder': 'gpu_fyi_tests_ozone_linux_system_gbm_libdrm_release_trybot',
       'GPU FYI Linux Builder (dbg)': 'gpu_fyi_tests_debug_trybot',
@@ -560,6 +564,10 @@
       'gpu-manual-try-android-p-pixel-2-32-deqp': 'deqp_android_vulkan_release_trybot',
       'gpu-manual-try-android-p-pixel-2-64': 'gpu_tests_android_vulkan_release_trybot_arm64',
       'gpu-manual-try-android-p-pixel-2-64-deqp': 'deqp_android_vulkan_release_trybot_arm64',
+      'gpu-manual-try-android-p-pixel-xl-32': 'gpu_tests_android_vulkan_release_trybot',
+      'gpu-manual-try-android-p-pixel-xl-32-deqp': 'deqp_android_vulkan_release_trybot',
+      'gpu-manual-try-android-p-pixel-xl-64': 'gpu_tests_android_vulkan_release_trybot_arm64',
+      'gpu-manual-try-android-p-pixel-xl-64-deqp': 'deqp_android_vulkan_release_trybot_arm64',
       'linux_android_dbg_ng': 'android_debug_trybot',
       'try-nougat-phone-tester': 'android_debug_trybot_arm64',
     },
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 11f8dcc1..f6f891d2 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -4756,6 +4756,11 @@
   <int value="1" label="Connection's visitor is a nullptr"/>
 </enum>
 
+<enum name="BooleanOffered">
+  <int value="0" label="Not offered"/>
+  <int value="1" label="Offered"/>
+</enum>
+
 <enum name="BooleanOnBattery">
   <int value="0" label="Not on battery"/>
   <int value="1" label="On Battery"/>
@@ -4935,7 +4940,7 @@
 </enum>
 
 <enum name="BooleanSelected">
-  <int value="0" label="No selection"/>
+  <int value="0" label="Not selected"/>
   <int value="1" label="Selected"/>
 </enum>
 
@@ -16875,6 +16880,7 @@
   <int value="1280" label="AUTOTESTPRIVATE_LAUNCHAPP"/>
   <int value="1281" label="AUTOTESTPRIVATE_BOOTSTRAPMACHINELEARNINGSERVICE"/>
   <int value="1282" label="AUTOTESTPRIVATE_RUNCROSTINIUNINSTALLER"/>
+  <int value="1283" label="AUTOTESTPRIVATE_TAKESCREENSHOT"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -20239,6 +20245,12 @@
   <int value="2546" label="SerialRequestPort"/>
   <int value="2547" label="SerialPortOpen"/>
   <int value="2548" label="SerialPortClose"/>
+  <int value="2549" label="BackgroundFetchManagerFetch"/>
+  <int value="2550" label="BackgroundFetchManagerGet"/>
+  <int value="2551" label="BackgroundFetchManagerGetIds"/>
+  <int value="2552" label="BackgroundFetchRegistrationAbort"/>
+  <int value="2553" label="BackgroundFetchRegistrationMatch"/>
+  <int value="2554" label="BackgroundFetchRegistrationMatchAll"/>
 </enum>
 
 <enum name="FeaturePolicyFeature">
@@ -25133,6 +25145,10 @@
 </enum>
 
 <enum name="IE7LookupResultStatus">
+  <obsolete>
+    Deprecated as of 07/2018. The corresponding metric was deleted in
+    https://chromium-review.googlesource.com/c/chromium/src/+/1131495.
+  </obsolete>
   <int value="0" label="No stored passwords from IE7 found."/>
   <int value="1" label="Some stored passwords from IE7 found."/>
 </enum>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0d7799e..1db9907 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -68386,7 +68386,7 @@
   </summary>
 </histogram>
 
-<histogram name="Omnibox.SuggestionUsed.OfferedTabMatch" units="Boolean">
+<histogram name="Omnibox.SuggestionUsed.OfferedTabMatch" enum="BooleanOffered">
   <owner>krb@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -68518,7 +68518,8 @@
   </summary>
 </histogram>
 
-<histogram name="Omnibox.SuggestionUsed.SelectedTabMatch" units="Boolean">
+<histogram name="Omnibox.SuggestionUsed.SelectedTabMatch"
+    enum="BooleanSelected">
   <owner>krb@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 6146e8d..53fdd3d 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -90,6 +90,7 @@
  <item id="doodle_service" hash_code="41154842" type="0" deprecated="2017-08-28" content_hash_code="28273962" file_path=""/>
  <item id="download_internals_webui_source" hash_code="38670228" type="0" content_hash_code="129391056" os_list="linux,windows" file_path="chrome/browser/ui/webui/download_internals/download_internals_ui_message_handler.cc"/>
  <item id="download_manager_resume" hash_code="35380758" type="0" content_hash_code="41227674" os_list="linux,windows" file_path="components/download/internal/common/download_item_impl.cc"/>
+ <item id="download_recovery_component" hash_code="131711536" type="0" content_hash_code="110581751" os_list="windows" file_path="chrome/chrome_cleaner/components/recovery_component.cc"/>
  <item id="download_web_contents_frame" hash_code="56351037" type="0" content_hash_code="3657889" os_list="linux,windows" file_path="content/browser/web_contents/web_contents_impl.cc"/>
  <item id="downloads_api_run_async" hash_code="121068967" type="0" content_hash_code="87443585" os_list="linux,windows" file_path="chrome/browser/extensions/api/downloads/downloads_api.cc"/>
  <item id="drag_download_file" hash_code="95910019" type="0" content_hash_code="126492858" os_list="linux,windows" file_path="content/browser/download/drag_download_file.cc"/>
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc
index 4ca78b4..76f70cf 100644
--- a/ui/base/ui_base_features.cc
+++ b/ui/base/ui_base_features.cc
@@ -171,4 +171,6 @@
          IsMultiProcessMash();
 }
 
+const base::Feature kDarkMode = {"DarkMode", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h
index dce8a9f..45936e1 100644
--- a/ui/base/ui_base_features.h
+++ b/ui/base/ui_base_features.h
@@ -90,6 +90,10 @@
 UI_BASE_EXPORT extern const base::Feature kEnableOzoneDrmMojo;
 UI_BASE_EXPORT bool IsOzoneDrmMojo();
 
+// Whether default UI should use a dark mode color scheme, if enabled on
+// macOS Mojave/Windows 10, or the --force-dark-mode flag is provided.
+UI_BASE_EXPORT extern const base::Feature kDarkMode;
+
 }  // namespace features
 
 #endif  // UI_BASE_UI_BASE_FEATURES_H_
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 5135d30..e78872c 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -54,6 +54,11 @@
   all_dependent_configs = [ ":flags" ]
 
   public = [
+    # TODO(ccameron): Move these sources to the views_bridge_mac component
+    "../views_bridge_mac/bridge_factory_impl.h",
+    "../views_bridge_mac/bridged_native_widget_impl.h",
+    "../views_bridge_mac/native_widget_mac_nswindow.h",
+    "../views_bridge_mac/window_touch_bar_delegate.h",
     "accessibility/view_accessibility.h",
     "accessibility/view_accessibility_utils.h",
     "accessible_pane_view.h",
@@ -86,10 +91,6 @@
     "bubble/tooltip_icon.h",
     "button_drag_utils.h",
     "cocoa/bridge_factory_host.h",
-    "cocoa/bridge_factory_impl.h",
-    "cocoa/bridged_native_widget.h",
-    "cocoa/native_widget_mac_nswindow.h",
-    "cocoa/window_touch_bar_delegate.h",
     "color_chooser/color_chooser_listener.h",
     "color_chooser/color_chooser_view.h",
     "context_menu_controller.h",
@@ -260,6 +261,9 @@
   ]
 
   sources = [
+    # TODO(ccameron): Move these sources to the views_bridge_mac component
+    "../views_bridge_mac/bridged_native_widget_impl.mm",
+    "../views_bridge_mac/native_widget_mac_nswindow.mm",
     "accessibility/view_accessibility.cc",
     "accessibility/view_accessibility_utils.cc",
     "accessible_pane_view.cc",
@@ -286,8 +290,6 @@
     "bubble/info_bubble.cc",
     "bubble/tooltip_icon.cc",
     "button_drag_utils.cc",
-    "cocoa/bridged_native_widget.mm",
-    "cocoa/native_widget_mac_nswindow.mm",
     "color_chooser/color_chooser_view.cc",
     "controls/animated_icon_view.cc",
     "controls/button/blue_button.cc",
@@ -440,26 +442,27 @@
   # Internal sources. TODO(https://crbug.com/871123): Move more headers from
   # public into this list, along with the implementation file.
   sources += [
+    # TODO(ccameron): Move these sources to the views_bridge_mac component
+    "../views_bridge_mac/bridge_factory_impl.mm",
+    "../views_bridge_mac/bridged_content_view.h",
+    "../views_bridge_mac/bridged_content_view.mm",
+    "../views_bridge_mac/bridged_content_view_touch_bar.mm",
+    "../views_bridge_mac/bridged_native_widget_owner.h",
+    "../views_bridge_mac/cocoa_window_move_loop.h",
+    "../views_bridge_mac/cocoa_window_move_loop.mm",
+    "../views_bridge_mac/views_nswindow_delegate.h",
+    "../views_bridge_mac/views_nswindow_delegate.mm",
+    "../views_bridge_mac/views_scrollbar_bridge.h",
+    "../views_bridge_mac/views_scrollbar_bridge.mm",
+    "../views_bridge_mac/widget_owner_nswindow_adapter.h",
+    "../views_bridge_mac/widget_owner_nswindow_adapter.mm",
     "cocoa/bridge_factory_host.cc",
-    "cocoa/bridge_factory_impl.mm",
-    "cocoa/bridged_content_view.h",
-    "cocoa/bridged_content_view.mm",
-    "cocoa/bridged_content_view_touch_bar.mm",
     "cocoa/bridged_native_widget_host_impl.h",
     "cocoa/bridged_native_widget_host_impl.mm",
-    "cocoa/bridged_native_widget_owner.h",
-    "cocoa/cocoa_window_move_loop.h",
-    "cocoa/cocoa_window_move_loop.mm",
     "cocoa/drag_drop_client_mac.h",
     "cocoa/drag_drop_client_mac.mm",
     "cocoa/tooltip_manager_mac.h",
     "cocoa/tooltip_manager_mac.mm",
-    "cocoa/views_nswindow_delegate.h",
-    "cocoa/views_nswindow_delegate.mm",
-    "cocoa/views_scrollbar_bridge.h",
-    "cocoa/views_scrollbar_bridge.mm",
-    "cocoa/widget_owner_nswindow_adapter.h",
-    "cocoa/widget_owner_nswindow_adapter.mm",
     "controls/button/label_button_label.cc",
     "controls/button/label_button_label.h",
     "controls/menu/menu_pre_target_handler.h",
diff --git a/ui/views/DEPS b/ui/views/DEPS
index 020d58c..a2d0ab1 100644
--- a/ui/views/DEPS
+++ b/ui/views/DEPS
@@ -21,6 +21,7 @@
   "+ui/resources/grit/ui_resources.h",
   "+ui/strings/grit/ui_strings.h",
   "+ui/touch_selection",
+  "+ui/views_bridge_mac",
   "+ui/wm/core",
   "+ui/wm/public",
 
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.h b/ui/views/bubble/bubble_dialog_delegate_view.h
index 6ce0158..8d65614 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view.h
+++ b/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -186,8 +186,9 @@
   void UpdateAnchorWidgetRenderState(bool visible);
 
   // Update the button highlight, which may be the anchor view or an explicit
-  // view set in |highlighted_button_tracker_|.
-  void UpdateHighlightedButton(bool highlighted);
+  // view set in |highlighted_button_tracker_|. This can be overridden to
+  // provide different highlight effects.
+  virtual void UpdateHighlightedButton(bool highlighted);
 
   // A flag controlling bubble closure on deactivation.
   bool close_on_deactivate_;
diff --git a/ui/views/cocoa/DEPS b/ui/views/cocoa/DEPS
index fcaeee7..440d45f5 100644
--- a/ui/views/cocoa/DEPS
+++ b/ui/views/cocoa/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-  "+components/viz/common",
   "+ui/accelerated_widget_mac",
   "+ui/views_bridge_mac",
 ]
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.mm b/ui/views/cocoa/bridged_native_widget_host_impl.mm
index ebeed25..eb7c6016 100644
--- a/ui/views/cocoa/bridged_native_widget_host_impl.mm
+++ b/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -14,8 +14,6 @@
 #include "ui/display/screen.h"
 #include "ui/gfx/geometry/dip_util.h"
 #include "ui/native_theme/native_theme_mac.h"
-#include "ui/views/cocoa/bridged_native_widget.h"
-#include "ui/views/cocoa/native_widget_mac_nswindow.h"
 #include "ui/views/cocoa/tooltip_manager_mac.h"
 #include "ui/views/controls/menu/menu_config.h"
 #include "ui/views/controls/menu/menu_controller.h"
@@ -26,7 +24,9 @@
 #include "ui/views/window/dialog_client_view.h"
 #include "ui/views/window/dialog_delegate.h"
 #include "ui/views/word_lookup_client.h"
+#include "ui/views_bridge_mac/bridged_native_widget_impl.h"
 #include "ui/views_bridge_mac/cocoa_mouse_capture.h"
+#include "ui/views_bridge_mac/native_widget_mac_nswindow.h"
 
 using views_bridge_mac::mojom::BridgedNativeWidgetInitParams;
 using views_bridge_mac::mojom::WindowVisibilityState;
diff --git a/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm b/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
index 37c289d..38f7167 100644
--- a/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
+++ b/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 #import <Cocoa/Cocoa.h>
 
diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm
index d607ad8..3d3c149 100644
--- a/ui/views/cocoa/bridged_native_widget_unittest.mm
+++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 #import <Cocoa/Cocoa.h>
 
@@ -25,10 +25,7 @@
 #include "ui/base/test/material_design_controller_test_api.h"
 #include "ui/events/test/cocoa_test_event_utils.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
-#import "ui/views/cocoa/bridged_content_view.h"
 #import "ui/views/cocoa/bridged_native_widget_host_impl.h"
-#import "ui/views/cocoa/native_widget_mac_nswindow.h"
-#import "ui/views/cocoa/views_nswindow_delegate.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/controls/textfield/textfield_model.h"
@@ -38,6 +35,9 @@
 #include "ui/views/widget/root_view.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_observer.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
+#import "ui/views_bridge_mac/views_nswindow_delegate.h"
 
 using base::ASCIIToUTF16;
 using base::SysNSStringToUTF8;
diff --git a/ui/views/cocoa/drag_drop_client_mac.mm b/ui/views/cocoa/drag_drop_client_mac.mm
index 7a4741e..2df3335 100644
--- a/ui/views/cocoa/drag_drop_client_mac.mm
+++ b/ui/views/cocoa/drag_drop_client_mac.mm
@@ -10,9 +10,9 @@
 #import "ui/base/dragdrop/os_exchange_data_provider_mac.h"
 #include "ui/gfx/image/image_skia_util_mac.h"
 #include "ui/views/drag_utils.h"
-#import "ui/views/cocoa/bridged_content_view.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
 #include "ui/views/widget/native_widget_mac.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 @interface CocoaDragDropDataProvider ()
 - (id)initWithData:(const ui::OSExchangeData&)data;
diff --git a/ui/views/cocoa/drag_drop_client_mac_unittest.mm b/ui/views/cocoa/drag_drop_client_mac_unittest.mm
index 47c8ffe6..4202d53 100644
--- a/ui/views/cocoa/drag_drop_client_mac_unittest.mm
+++ b/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -13,12 +13,12 @@
 #include "base/threading/thread_task_runner_handle.h"
 #import "ui/base/clipboard/clipboard_util_mac.h"
 #include "ui/gfx/image/image_unittest_util.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
 #import "ui/views/cocoa/bridged_native_widget_host_impl.h"
 #include "ui/views/test/widget_test.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/native_widget_mac.h"
 #include "ui/views/widget/widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 using base::ASCIIToUTF16;
 
diff --git a/ui/views/cocoa/tooltip_manager_mac.mm b/ui/views/cocoa/tooltip_manager_mac.mm
index 3699ae9..8762de8 100644
--- a/ui/views/cocoa/tooltip_manager_mac.mm
+++ b/ui/views/cocoa/tooltip_manager_mac.mm
@@ -7,8 +7,8 @@
 #include "ui/base/cocoa/cocoa_base_utils.h"
 #include "ui/gfx/font_list.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
-#import "ui/views/cocoa/bridged_content_view.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 namespace {
 
diff --git a/ui/views/controls/scrollbar/cocoa_scroll_bar.h b/ui/views/controls/scrollbar/cocoa_scroll_bar.h
index a0c8872..c69087a 100644
--- a/ui/views/controls/scrollbar/cocoa_scroll_bar.h
+++ b/ui/views/controls/scrollbar/cocoa_scroll_bar.h
@@ -5,13 +5,13 @@
 #ifndef UI_VIEWS_CONTROLS_SCROLLBAR_COCOA_SCROLL_BAR_H_
 #define UI_VIEWS_CONTROLS_SCROLLBAR_COCOA_SCROLL_BAR_H_
 
-#include "base/macros.h"
 #import "base/mac/scoped_nsobject.h"
+#include "base/macros.h"
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/gfx/animation/slide_animation.h"
-#import "ui/views/cocoa/views_scrollbar_bridge.h"
 #include "ui/views/controls/scrollbar/base_scroll_bar.h"
 #include "ui/views/views_export.h"
+#import "ui/views_bridge_mac/views_scrollbar_bridge.h"
 
 namespace views {
 
diff --git a/ui/views/controls/webview/unhandled_keyboard_event_handler_mac.mm b/ui/views/controls/webview/unhandled_keyboard_event_handler_mac.mm
index ece41dd..e87f913 100644
--- a/ui/views/controls/webview/unhandled_keyboard_event_handler_mac.mm
+++ b/ui/views/controls/webview/unhandled_keyboard_event_handler_mac.mm
@@ -5,7 +5,7 @@
 #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
 
 #import "base/mac/foundation_util.h"
-#import "ui/views/cocoa/native_widget_mac_nswindow.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
 
 namespace views {
 
diff --git a/ui/views/test/platform_test_helper_cocoa.mm b/ui/views/test/platform_test_helper_cocoa.mm
index 5354cd4..50c91e9 100644
--- a/ui/views/test/platform_test_helper_cocoa.mm
+++ b/ui/views/test/platform_test_helper_cocoa.mm
@@ -9,9 +9,9 @@
 #import "base/mac/scoped_nsobject.h"
 #import "base/mac/scoped_objc_class_swizzler.h"
 #include "base/macros.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
 #include "ui/views/widget/native_widget_mac.h"
 #include "ui/views/widget/widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 namespace views {
 
diff --git a/ui/views/test/widget_test_mac.mm b/ui/views/test/widget_test_mac.mm
index f4f45c9..05bae8b 100644
--- a/ui/views/test/widget_test_mac.mm
+++ b/ui/views/test/widget_test_mac.mm
@@ -9,10 +9,10 @@
 #import "base/mac/scoped_nsobject.h"
 #import "base/mac/scoped_objc_class_swizzler.h"
 #include "base/macros.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
 #include "ui/views/cocoa/bridged_native_widget_host_impl.h"
 #include "ui/views/widget/native_widget_mac.h"
 #include "ui/views/widget/root_view.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 namespace views {
 namespace test {
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index e14e355..680434d5 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -24,15 +24,15 @@
 #import "ui/gfx/mac/nswindow_frame_controls.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/native_theme/native_theme_mac.h"
-#import "ui/views/cocoa/bridged_content_view.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
 #import "ui/views/cocoa/bridged_native_widget_host_impl.h"
 #import "ui/views/cocoa/drag_drop_client_mac.h"
-#import "ui/views/cocoa/native_widget_mac_nswindow.h"
-#import "ui/views/cocoa/views_nswindow_delegate.h"
 #include "ui/views/widget/drop_helper.h"
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/views/window/native_frame_view.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
+#import "ui/views_bridge_mac/views_nswindow_delegate.h"
 
 using views_bridge_mac::mojom::WindowVisibilityState;
 
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm
index b4ae028..6f9b147b 100644
--- a/ui/views/widget/native_widget_mac_unittest.mm
+++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -28,9 +28,6 @@
 #include "ui/events/test/event_generator.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
-#import "ui/views/cocoa/bridged_content_view.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
-#import "ui/views/cocoa/native_widget_mac_nswindow.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/native/native_view_host.h"
@@ -42,6 +39,9 @@
 #include "ui/views/widget/native_widget_private.h"
 #include "ui/views/window/dialog_client_view.h"
 #include "ui/views/window/dialog_delegate.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
 
 // Donates an implementation of -[NSAnimation stopAnimation] which calls the
 // original implementation, then quits a nested run loop.
diff --git a/ui/views/widget/widget_utils_mac.mm b/ui/views/widget/widget_utils_mac.mm
index 37eb7bf..990e17fa 100644
--- a/ui/views/widget/widget_utils_mac.mm
+++ b/ui/views/widget/widget_utils_mac.mm
@@ -4,7 +4,7 @@
 
 #include "ui/views/widget/widget_utils_mac.h"
 
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 namespace views {
 
diff --git a/ui/views_bridge_mac/DEPS b/ui/views_bridge_mac/DEPS
index 5022afb..612029d 100644
--- a/ui/views_bridge_mac/DEPS
+++ b/ui/views_bridge_mac/DEPS
@@ -1,5 +1,17 @@
 include_rules = [
+  "+components/crash/core/common/crash_key.h",
+  "+components/viz/common",
+  "+mojo/public/cpp/bindings",
+  "+skia/ext",
+  "+ui/accelerated_widget_mac",
   "+ui/base",
+  "+ui/compositor",
+  "+ui/display",
   "+ui/events",
   "+ui/gfx",
+  # TODO(ccameron): This can be removed when sources are moved to the
+  # views_bridge_mac component.
+  "+ui/views/views_export.h",
+  # TODO(ccameron): This file should be moved to forward declarations.
+  "+ui/views/widget/util_mac.h",
 ]
diff --git a/ui/views/cocoa/bridge_factory_impl.h b/ui/views_bridge_mac/bridge_factory_impl.h
similarity index 89%
rename from ui/views/cocoa/bridge_factory_impl.h
rename to ui/views_bridge_mac/bridge_factory_impl.h
index 1723c305..197820e5 100644
--- a/ui/views/cocoa/bridge_factory_impl.h
+++ b/ui/views_bridge_mac/bridge_factory_impl.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 UI_VIEWS_COCOA_BRIDGE_FACTORY_IMPL_H_
-#define UI_VIEWS_COCOA_BRIDGE_FACTORY_IMPL_H_
+#ifndef UI_VIEWS_BRIDGE_MAC_BRIDGE_FACTORY_IMPL_H_
+#define UI_VIEWS_BRIDGE_MAC_BRIDGE_FACTORY_IMPL_H_
 
 #include "mojo/public/cpp/bindings/binding.h"
 #include "ui/views/views_export.h"
@@ -38,4 +38,4 @@
 
 }  // namespace views_bridge_mac
 
-#endif  // UI_VIEWS_COCOA_BRIDGE_FACTORY_IMPL_H_
+#endif  // UI_VIEWS_BRIDGE_MAC_BRIDGE_FACTORY_IMPL_H_
diff --git a/ui/views/cocoa/bridge_factory_impl.mm b/ui/views_bridge_mac/bridge_factory_impl.mm
similarity index 95%
rename from ui/views/cocoa/bridge_factory_impl.mm
rename to ui/views_bridge_mac/bridge_factory_impl.mm
index f909e24..947249d 100644
--- a/ui/views/cocoa/bridge_factory_impl.mm
+++ b/ui/views_bridge_mac/bridge_factory_impl.mm
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/views/cocoa/bridge_factory_impl.h"
+#include "ui/views_bridge_mac/bridge_factory_impl.h"
 
 #include "base/no_destructor.h"
-#include "ui/views/cocoa/bridged_native_widget.h"
 #include "ui/views_bridge_mac/bridged_native_widget_host_helper.h"
+#include "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 namespace views_bridge_mac {
 
diff --git a/ui/views/cocoa/bridged_content_view.h b/ui/views_bridge_mac/bridged_content_view.h
similarity index 94%
rename from ui/views/cocoa/bridged_content_view.h
rename to ui/views_bridge_mac/bridged_content_view.h
index 46ee823..a4848e67 100644
--- a/ui/views/cocoa/bridged_content_view.h
+++ b/ui/views_bridge_mac/bridged_content_view.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 UI_VIEWS_COCOA_BRIDGED_CONTENT_VIEW_H_
-#define UI_VIEWS_COCOA_BRIDGED_CONTENT_VIEW_H_
+#ifndef UI_VIEWS_BRIDGE_MAC_BRIDGED_CONTENT_VIEW_H_
+#define UI_VIEWS_BRIDGE_MAC_BRIDGED_CONTENT_VIEW_H_
 
 #import <Cocoa/Cocoa.h>
 
@@ -82,4 +82,4 @@
 
 @end
 
-#endif  // UI_VIEWS_COCOA_BRIDGED_CONTENT_VIEW_H_
+#endif  // UI_VIEWS_BRIDGE_MAC_BRIDGED_CONTENT_VIEW_H_
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views_bridge_mac/bridged_content_view.mm
similarity index 98%
rename from ui/views/cocoa/bridged_content_view.mm
rename to ui/views_bridge_mac/bridged_content_view.mm
index 89b149b..d4115a0 100644
--- a/ui/views/cocoa/bridged_content_view.mm
+++ b/ui/views_bridge_mac/bridged_content_view.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ui/views/cocoa/bridged_content_view.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
 
 #include "base/logging.h"
 #import "base/mac/foundation_util.h"
@@ -31,9 +31,9 @@
 #include "ui/gfx/path.h"
 #import "ui/gfx/path_mac.h"
 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
-#import "ui/views/cocoa/drag_drop_client_mac.h"
 #include "ui/views_bridge_mac/bridged_native_widget_host_helper.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
+#import "ui/views_bridge_mac/drag_drop_client.h"
 #include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h"
 
 namespace {
@@ -48,9 +48,9 @@
 gfx::Point MovePointToWindow(const NSPoint& point,
                              NSWindow* source_window,
                              NSWindow* target_window) {
-  NSPoint point_in_screen = source_window
-      ? ui::ConvertPointFromWindowToScreen(source_window, point)
-      : point;
+  NSPoint point_in_screen =
+      source_window ? ui::ConvertPointFromWindowToScreen(source_window, point)
+                    : point;
 
   NSPoint point_in_window =
       ui::ConvertPointFromScreenToWindow(target_window, point_in_screen);
@@ -1338,8 +1338,9 @@
   // or (string, string).
   BOOL valid = textInputClient_ && ((canWrite && (canRead || !returnType)) ||
                                     (canRead && (canWrite || !sendType)));
-  return valid ? self : [super validRequestorForSendType:sendType
-                                              returnType:returnType];
+  return valid
+             ? self
+             : [super validRequestorForSendType:sendType returnType:returnType];
 }
 
 // NSServicesMenuRequestor protocol
@@ -1380,9 +1381,9 @@
 // |self|) that we're trying to invalidate in -setTextInputClient:.
 // See https://crbug.com/817097#c12 for further details on this atrocity.
 
-- (NSAttributedString*)
-    attributedSubstringForProposedRange:(NSRange)range
-                            actualRange:(NSRangePointer)actualRange {
+- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range
+                                               actualRange:
+                                                   (NSRangePointer)actualRange {
   // On TouchBar Macs, the IME subsystem sometimes sends an invalid range with a
   // non-zero length. This will cause a DCHECK in gfx::Range, so repair it here.
   // See https://crbug.com/888782.
diff --git a/ui/views/cocoa/bridged_content_view_touch_bar.mm b/ui/views_bridge_mac/bridged_content_view_touch_bar.mm
similarity index 96%
rename from ui/views/cocoa/bridged_content_view_touch_bar.mm
rename to ui/views_bridge_mac/bridged_content_view_touch_bar.mm
index 0c88d28..008f7ff 100644
--- a/ui/views/cocoa/bridged_content_view_touch_bar.mm
+++ b/ui/views_bridge_mac/bridged_content_view_touch_bar.mm
@@ -7,8 +7,8 @@
 #import "base/mac/sdk_forward_declarations.h"
 #include "base/strings/sys_string_conversions.h"
 #import "ui/base/cocoa/touch_bar_forward_declarations.h"
-#import "ui/views/cocoa/bridged_content_view.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 #include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h"
 
 namespace {
diff --git a/ui/views/cocoa/bridged_native_widget.h b/ui/views_bridge_mac/bridged_native_widget_impl.h
similarity index 97%
rename from ui/views/cocoa/bridged_native_widget.h
rename to ui/views_bridge_mac/bridged_native_widget_impl.h
index 8758fa4..450b3ef 100644
--- a/ui/views/cocoa/bridged_native_widget.h
+++ b/ui/views_bridge_mac/bridged_native_widget_impl.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 UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_H_
-#define UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_H_
+#ifndef UI_VIEWS_BRIDGE_MAC_BRIDGED_NATIVE_WIDGET_IMPL_H_
+#define UI_VIEWS_BRIDGE_MAC_BRIDGED_NATIVE_WIDGET_IMPL_H_
 
 #import <Cocoa/Cocoa.h>
 
@@ -18,8 +18,8 @@
 #include "ui/accelerated_widget_mac/display_ca_layer_tree.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/display/display_observer.h"
-#import "ui/views/cocoa/bridged_native_widget_owner.h"
 #include "ui/views/views_export.h"
+#import "ui/views_bridge_mac/bridged_native_widget_owner.h"
 #import "ui/views_bridge_mac/cocoa_mouse_capture_delegate.h"
 #include "ui/views_bridge_mac/mojo/bridged_native_widget.mojom.h"
 
@@ -346,4 +346,4 @@
 
 }  // namespace views
 
-#endif  // UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_H_
+#endif  // UI_VIEWS_BRIDGE_MAC_BRIDGED_NATIVE_WIDGET_IMPL_H_
diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views_bridge_mac/bridged_native_widget_impl.mm
similarity index 98%
rename from ui/views/cocoa/bridged_native_widget.mm
rename to ui/views_bridge_mac/bridged_native_widget_impl.mm
index 6a538dc..8766a0f 100644
--- a/ui/views/cocoa/bridged_native_widget.mm
+++ b/ui/views_bridge_mac/bridged_native_widget_impl.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 #import <objc/runtime.h>
 #include <stddef.h>
@@ -27,15 +27,14 @@
 #include "ui/gfx/geometry/dip_util.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
 #import "ui/gfx/mac/nswindow_frame_controls.h"
-#import "ui/views/cocoa/bridged_content_view.h"
-#import "ui/views/cocoa/cocoa_window_move_loop.h"
-#import "ui/views/cocoa/drag_drop_client_mac.h"
-#import "ui/views/cocoa/native_widget_mac_nswindow.h"
-#import "ui/views/cocoa/views_nswindow_delegate.h"
-#import "ui/views/cocoa/widget_owner_nswindow_adapter.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
 #import "ui/views_bridge_mac/bridged_native_widget_host_helper.h"
 #import "ui/views_bridge_mac/cocoa_mouse_capture.h"
+#import "ui/views_bridge_mac/cocoa_window_move_loop.h"
 #include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
+#import "ui/views_bridge_mac/views_nswindow_delegate.h"
+#import "ui/views_bridge_mac/widget_owner_nswindow_adapter.h"
 
 using views_bridge_mac::mojom::VisibilityTransition;
 using views_bridge_mac::mojom::WindowVisibilityState;
@@ -596,8 +595,7 @@
       parent_window_number = [parent_->GetNSWindow() windowNumber];
     }
 
-    [window_ orderWindow:NSWindowAbove
-              relativeTo:parent_window_number];
+    [window_ orderWindow:NSWindowAbove relativeTo:parent_window_number];
   }
   DCHECK(window_visible_);
 
@@ -1139,8 +1137,8 @@
 
 void BridgedNativeWidgetImpl::RemoveChildWindow(
     BridgedNativeWidgetImpl* child) {
-  auto location = std::find(
-      child_windows_.begin(), child_windows_.end(), child);
+  auto location =
+      std::find(child_windows_.begin(), child_windows_.end(), child);
   DCHECK(location != child_windows_.end());
   child_windows_.erase(location);
 
diff --git a/ui/views/cocoa/bridged_native_widget_owner.h b/ui/views_bridge_mac/bridged_native_widget_owner.h
similarity index 87%
rename from ui/views/cocoa/bridged_native_widget_owner.h
rename to ui/views_bridge_mac/bridged_native_widget_owner.h
index c9e15b5e..1e87e8dce 100644
--- a/ui/views/cocoa/bridged_native_widget_owner.h
+++ b/ui/views_bridge_mac/bridged_native_widget_owner.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 UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_OWNER_H_
-#define UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_OWNER_H_
+#ifndef UI_VIEWS_BRIDGE_MAC_BRIDGED_NATIVE_WIDGET_OWNER_H_
+#define UI_VIEWS_BRIDGE_MAC_BRIDGED_NATIVE_WIDGET_OWNER_H_
 
 namespace gfx {
 class Vector2d;
@@ -41,4 +41,4 @@
 
 }  // namespace views
 
-#endif  // UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_OWNER_H_
+#endif  // UI_VIEWS_BRIDGE_MAC_BRIDGED_NATIVE_WIDGET_OWNER_H_
diff --git a/ui/views_bridge_mac/cocoa_mouse_capture.h b/ui/views_bridge_mac/cocoa_mouse_capture.h
index 5ac379b..b7dedad 100644
--- a/ui/views_bridge_mac/cocoa_mouse_capture.h
+++ b/ui/views_bridge_mac/cocoa_mouse_capture.h
@@ -50,4 +50,4 @@
 
 }  // namespace views_bridge_mac
 
-#endif  // UI_VIEWS_COCOA_COCOA_MOUSE_CAPTURE_H_
+#endif  // UI_VIEWS_BRIDGE_MAC_COCOA_MOUSE_CAPTURE_H_
diff --git a/ui/views/cocoa/cocoa_window_move_loop.h b/ui/views_bridge_mac/cocoa_window_move_loop.h
similarity index 87%
rename from ui/views/cocoa/cocoa_window_move_loop.h
rename to ui/views_bridge_mac/cocoa_window_move_loop.h
index 68699ff..ff074d8 100644
--- a/ui/views/cocoa/cocoa_window_move_loop.h
+++ b/ui/views_bridge_mac/cocoa_window_move_loop.h
@@ -2,14 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_VIEWS_COCOA_COCOA_WINDOW_MOVE_LOOP_H_
-#define UI_VIEWS_COCOA_COCOA_WINDOW_MOVE_LOOP_H_
+#ifndef UI_VIEWS_BRIDGE_MAC_COCOA_WINDOW_MOVE_LOOP_H_
+#define UI_VIEWS_BRIDGE_MAC_COCOA_WINDOW_MOVE_LOOP_H_
 
 #import <Cocoa/Cocoa.h>
 
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
-#include "ui/views/widget/widget.h"
 
 namespace views {
 class BridgedNativeWidgetImpl;
@@ -51,4 +50,4 @@
 
 }  // namespace views
 
-#endif  // UI_VIEWS_COCOA_COCOA_WINDOW_MOVE_LOOP_H_
+#endif  // UI_VIEWS_BRIDGE_MAC_COCOA_WINDOW_MOVE_LOOP_H_
diff --git a/ui/views/cocoa/cocoa_window_move_loop.mm b/ui/views_bridge_mac/cocoa_window_move_loop.mm
similarity index 97%
rename from ui/views/cocoa/cocoa_window_move_loop.mm
rename to ui/views_bridge_mac/cocoa_window_move_loop.mm
index 2d7dfdc..4b2c64f0 100644
--- a/ui/views/cocoa/cocoa_window_move_loop.mm
+++ b/ui/views_bridge_mac/cocoa_window_move_loop.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/views/cocoa/cocoa_window_move_loop.h"
+#include "ui/views_bridge_mac/cocoa_window_move_loop.h"
 
 #include "base/debug/stack_trace.h"
 #include "base/run_loop.h"
@@ -10,7 +10,7 @@
 #include "components/crash/core/common/crash_key.h"
 #include "ui/display/screen.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 // When event monitors process the events the full list of monitors is cached,
 // and if we unregister the event monitor that's at the end of the list while
diff --git a/ui/views/cocoa/native_widget_mac_nswindow.h b/ui/views_bridge_mac/native_widget_mac_nswindow.h
similarity index 90%
rename from ui/views/cocoa/native_widget_mac_nswindow.h
rename to ui/views_bridge_mac/native_widget_mac_nswindow.h
index 8686a4f..ef8afe1 100644
--- a/ui/views/cocoa/native_widget_mac_nswindow.h
+++ b/ui/views_bridge_mac/native_widget_mac_nswindow.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 UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NSWINDOW_H_
-#define UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NSWINDOW_H_
+#ifndef UI_VIEWS_BRIDGE_MAC_NATIVE_WIDGET_MAC_NSWINDOW_H_
+#define UI_VIEWS_BRIDGE_MAC_NATIVE_WIDGET_MAC_NSWINDOW_H_
 
 #import <Cocoa/Cocoa.h>
 
@@ -53,4 +53,4 @@
 @property(assign, nonatomic) uint64_t bridgedNativeWidgetId;
 @end
 
-#endif  // UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NSWINDOW_H_
+#endif  // UI_VIEWS_BRIDGE_MAC_NATIVE_WIDGET_MAC_NSWINDOW_H_
diff --git a/ui/views/cocoa/native_widget_mac_nswindow.mm b/ui/views_bridge_mac/native_widget_mac_nswindow.mm
similarity index 97%
rename from ui/views/cocoa/native_widget_mac_nswindow.mm
rename to ui/views_bridge_mac/native_widget_mac_nswindow.mm
index 7af14d0..f0e7ac7 100644
--- a/ui/views/cocoa/native_widget_mac_nswindow.mm
+++ b/ui/views_bridge_mac/native_widget_mac_nswindow.mm
@@ -2,18 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ui/views/cocoa/native_widget_mac_nswindow.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
 
 #include "base/mac/foundation_util.h"
 #import "base/mac/sdk_forward_declarations.h"
 #import "ui/base/cocoa/user_interface_item_command_handler.h"
 #import "ui/base/cocoa/window_size_constants.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
-#import "ui/views/cocoa/views_nswindow_delegate.h"
-#import "ui/views/cocoa/window_touch_bar_delegate.h"
-#include "ui/views/controls/menu/menu_controller.h"
 #include "ui/views_bridge_mac/bridged_native_widget_host_helper.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 #include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h"
+#import "ui/views_bridge_mac/views_nswindow_delegate.h"
+#import "ui/views_bridge_mac/window_touch_bar_delegate.h"
 
 @interface NSWindow (Private)
 + (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle;
diff --git a/ui/views/cocoa/views_nswindow_delegate.h b/ui/views_bridge_mac/views_nswindow_delegate.h
similarity index 90%
rename from ui/views/cocoa/views_nswindow_delegate.h
rename to ui/views_bridge_mac/views_nswindow_delegate.h
index 98b41f3..bc9f33af 100644
--- a/ui/views/cocoa/views_nswindow_delegate.h
+++ b/ui/views_bridge_mac/views_nswindow_delegate.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 UI_VIEWS_COCOA_VIEWS_NSWINDOW_DELEGATE_H_
-#define UI_VIEWS_COCOA_VIEWS_NSWINDOW_DELEGATE_H_
+#ifndef UI_VIEWS_BRIDGE_MAC_VIEWS_NSWINDOW_DELEGATE_H_
+#define UI_VIEWS_BRIDGE_MAC_VIEWS_NSWINDOW_DELEGATE_H_
 
 #import <Cocoa/Cocoa.h>
 
@@ -47,4 +47,4 @@
 
 @end
 
-#endif  // UI_VIEWS_COCOA_VIEWS_NSWINDOW_DELEGATE_H_
+#endif  // UI_VIEWS_BRIDGE_MAC_VIEWS_NSWINDOW_DELEGATE_H_
diff --git a/ui/views/cocoa/views_nswindow_delegate.mm b/ui/views_bridge_mac/views_nswindow_delegate.mm
similarity index 96%
rename from ui/views/cocoa/views_nswindow_delegate.mm
rename to ui/views_bridge_mac/views_nswindow_delegate.mm
index 24ab2be..ca77131 100644
--- a/ui/views/cocoa/views_nswindow_delegate.mm
+++ b/ui/views_bridge_mac/views_nswindow_delegate.mm
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ui/views/cocoa/views_nswindow_delegate.h"
+#import "ui/views_bridge_mac/views_nswindow_delegate.h"
 
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/threading/thread_task_runner_handle.h"
-#import "ui/views/cocoa/bridged_content_view.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
 #include "ui/views_bridge_mac/bridged_native_widget_host_helper.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 #include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h"
 
 @implementation ViewsNSWindowDelegate
@@ -60,7 +60,7 @@
         break;
       currentWindow = parentWindow;
       if ([currentWindow isKeyWindow]) {
-        [(newCursor ? newCursor : [NSCursor arrowCursor]) set];
+        [(newCursor ? newCursor : [NSCursor arrowCursor])set];
         break;
       }
     }
diff --git a/ui/views/cocoa/views_scrollbar_bridge.h b/ui/views_bridge_mac/views_scrollbar_bridge.h
similarity index 88%
rename from ui/views/cocoa/views_scrollbar_bridge.h
rename to ui/views_bridge_mac/views_scrollbar_bridge.h
index eb070a1..7b5809e 100644
--- a/ui/views/cocoa/views_scrollbar_bridge.h
+++ b/ui/views_bridge_mac/views_scrollbar_bridge.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 UI_VIEWS_COCOA_VIEWS_SCROLLBAR_BRIDGE_DELEGATE_H_
-#define UI_VIEWS_COCOA_VIEWS_SCROLLBAR_BRIDGE_DELEGATE_H_
+#ifndef UI_VIEWS_BRIDGE_MAC_VIEWS_SCROLLBAR_BRIDGE_H_
+#define UI_VIEWS_BRIDGE_MAC_VIEWS_SCROLLBAR_BRIDGE_H_
 
 #import <Cocoa/Cocoa.h>
 
@@ -30,11 +30,11 @@
 - (id)initWithDelegate:(ViewsScrollbarBridgeDelegate*)delegate;
 
 // Sets |delegate_| to nullptr.
--(void)clearDelegate;
+- (void)clearDelegate;
 
 // Returns the style of scrollers that OSX is using.
 + (NSScrollerStyle)getPreferredScrollerStyle;
 
 @end
 
-#endif
\ No newline at end of file
+#endif
diff --git a/ui/views/cocoa/views_scrollbar_bridge.mm b/ui/views_bridge_mac/views_scrollbar_bridge.mm
similarity index 95%
rename from ui/views/cocoa/views_scrollbar_bridge.mm
rename to ui/views_bridge_mac/views_scrollbar_bridge.mm
index d80dece..c720483 100644
--- a/ui/views/cocoa/views_scrollbar_bridge.mm
+++ b/ui/views_bridge_mac/views_scrollbar_bridge.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ui/views/cocoa/views_scrollbar_bridge.h"
+#import "ui/views_bridge_mac/views_scrollbar_bridge.h"
 
 #import "base/mac/sdk_forward_declarations.h"
 
diff --git a/ui/views/cocoa/widget_owner_nswindow_adapter.h b/ui/views_bridge_mac/widget_owner_nswindow_adapter.h
similarity index 86%
rename from ui/views/cocoa/widget_owner_nswindow_adapter.h
rename to ui/views_bridge_mac/widget_owner_nswindow_adapter.h
index 76d84c5..715306d6 100644
--- a/ui/views/cocoa/widget_owner_nswindow_adapter.h
+++ b/ui/views_bridge_mac/widget_owner_nswindow_adapter.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_VIEWS_COCOA_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
-#define UI_VIEWS_COCOA_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
+#ifndef UI_VIEWS_BRIDGE_MAC_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
+#define UI_VIEWS_BRIDGE_MAC_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
 
 #import "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
-#import "ui/views/cocoa/bridged_native_widget_owner.h"
+#import "ui/views_bridge_mac/bridged_native_widget_owner.h"
 
 @class NSView;
 @class NSWindow;
@@ -51,4 +51,4 @@
 
 }  // namespace views
 
-#endif  // UI_VIEWS_COCOA_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
+#endif  // UI_VIEWS_BRIDGE_MAC_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
diff --git a/ui/views/cocoa/widget_owner_nswindow_adapter.mm b/ui/views_bridge_mac/widget_owner_nswindow_adapter.mm
similarity index 97%
rename from ui/views/cocoa/widget_owner_nswindow_adapter.mm
rename to ui/views_bridge_mac/widget_owner_nswindow_adapter.mm
index cbaabaf8..47ae95c3 100644
--- a/ui/views/cocoa/widget_owner_nswindow_adapter.mm
+++ b/ui/views_bridge_mac/widget_owner_nswindow_adapter.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ui/views/cocoa/widget_owner_nswindow_adapter.h"
+#import "ui/views_bridge_mac/widget_owner_nswindow_adapter.h"
 
 #import <Cocoa/Cocoa.h>
 
@@ -11,7 +11,7 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/vector2d.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
 // Bridges an AppKit observer to observe when the (non-views) NSWindow owning a
 // views::Widget will close or change occlusion state.
diff --git a/ui/views/cocoa/window_touch_bar_delegate.h b/ui/views_bridge_mac/window_touch_bar_delegate.h
similarity index 73%
rename from ui/views/cocoa/window_touch_bar_delegate.h
rename to ui/views_bridge_mac/window_touch_bar_delegate.h
index ad9ea8f9..9de8671 100644
--- a/ui/views/cocoa/window_touch_bar_delegate.h
+++ b/ui/views_bridge_mac/window_touch_bar_delegate.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 UI_VIEWS_COCOA_WINDOW_TOUCH_BAR_DELEGATE_H_
-#define UI_VIEWS_COCOA_WINDOW_TOUCH_BAR_DELEGATE_H_
+#ifndef UI_VIEWS_BRIDGE_MAC_WINDOW_TOUCH_BAR_DELEGATE_H_
+#define UI_VIEWS_BRIDGE_MAC_WINDOW_TOUCH_BAR_DELEGATE_H_
 
 #import <Cocoa/Cocoa.h>
 
@@ -18,4 +18,4 @@
 
 @end
 
-#endif  // UI_VIEWS_COCOA_WINDOW_TOUCH_BAR_DELEGATE_H_
+#endif  // UI_VIEWS_BRIDGE_MAC_WINDOW_TOUCH_BAR_DELEGATE_H_
diff --git a/url/mojom/url_gurl_mojom_traits_unittest.cc b/url/mojom/url_gurl_mojom_traits_unittest.cc
index cdacd51..a331ba2 100644
--- a/url/mojom/url_gurl_mojom_traits_unittest.cc
+++ b/url/mojom/url_gurl_mojom_traits_unittest.cc
@@ -78,7 +78,7 @@
   Origin output;
   EXPECT_TRUE(proxy->BounceOrigin(non_unique, &output));
   EXPECT_EQ(non_unique, output);
-  EXPECT_FALSE(output.unique());
+  EXPECT_FALSE(output.opaque());
 
   Origin unique1;
   Origin unique2 = non_unique.DeriveNewOpaqueOrigin();
@@ -86,7 +86,7 @@
   EXPECT_NE(unique2, unique1);
   EXPECT_NE(unique2, non_unique);
   EXPECT_TRUE(proxy->BounceOrigin(unique1, &output));
-  EXPECT_TRUE(output.unique());
+  EXPECT_TRUE(output.opaque());
   EXPECT_EQ(unique1, output);
   Origin output2;
   EXPECT_TRUE(proxy->BounceOrigin(unique2, &output2));
@@ -100,7 +100,7 @@
   EXPECT_TRUE(proxy->BounceOrigin(normalized, &output));
   EXPECT_EQ(normalized, output);
   EXPECT_EQ(non_unique, output);
-  EXPECT_FALSE(output.unique());
+  EXPECT_FALSE(output.opaque());
 }
 
 }  // namespace url
diff --git a/url/origin.cc b/url/origin.cc
index fa334de..1c78bc9 100644
--- a/url/origin.cc
+++ b/url/origin.cc
@@ -54,7 +54,7 @@
   if (url.IsAboutBlank())
     return base_origin;
   Origin result = Origin::Create(url);
-  if (!result.unique())
+  if (!result.opaque())
     return result;
   return base_origin.DeriveNewOpaqueOrigin();
 }
@@ -122,7 +122,7 @@
 }
 
 std::string Origin::Serialize() const {
-  if (unique())
+  if (opaque())
     return "null";
 
   if (scheme() == kFileScheme)
@@ -132,7 +132,7 @@
 }
 
 GURL Origin::GetURL() const {
-  if (unique())
+  if (opaque())
     return GURL();
 
   if (scheme() == kFileScheme)
@@ -155,7 +155,7 @@
 }
 
 bool Origin::DomainIs(base::StringPiece canonical_domain) const {
-  return !unique() && url::DomainIs(tuple_.host(), canonical_domain);
+  return !opaque() && url::DomainIs(tuple_.host(), canonical_domain);
 }
 
 bool Origin::operator<(const Origin& other) const {
@@ -167,14 +167,14 @@
 }
 
 Origin::Origin(SchemeHostPort tuple) : tuple_(std::move(tuple)) {
-  DCHECK(!unique());
+  DCHECK(!opaque());
   DCHECK(!tuple_.IsInvalid());
 }
 
 // Constructs an opaque origin derived from |precursor|.
 Origin::Origin(const Nonce& nonce, SchemeHostPort precursor)
     : tuple_(std::move(precursor)), nonce_(std::move(nonce)) {
-  DCHECK(unique());
+  DCHECK(opaque());
   // |precursor| is retained, but not accessible via scheme()/host()/port().
   DCHECK_EQ("", scheme());
   DCHECK_EQ("", host());
@@ -184,7 +184,7 @@
 std::ostream& operator<<(std::ostream& out, const url::Origin& origin) {
   out << origin.Serialize();
 
-  if (origin.unique()) {
+  if (origin.opaque()) {
     // For opaque origins, log the nonce and precursor as well. Without this,
     // EXPECT_EQ failures between opaque origins are nearly impossible to
     // understand.
diff --git a/url/origin.h b/url/origin.h
index 4e1d349..c34779f 100644
--- a/url/origin.h
+++ b/url/origin.h
@@ -104,7 +104,7 @@
 //     origin.scheme(); // "https"
 //     origin.host(); // "example.com"
 //     origin.port(); // 443
-//     origin.unique(); // false
+//     origin.opaque(); // false
 //
 // * To answer the question "Are |this| and |that| "same-origin" with each
 //   other?", use |Origin::IsSameOriginWith|:
@@ -171,15 +171,14 @@
 
   // For opaque origins, these return ("", "", 0).
   const std::string& scheme() const {
-    return !unique() ? tuple_.scheme() : base::EmptyString();
+    return !opaque() ? tuple_.scheme() : base::EmptyString();
   }
   const std::string& host() const {
-    return !unique() ? tuple_.host() : base::EmptyString();
+    return !opaque() ? tuple_.host() : base::EmptyString();
   }
-  uint16_t port() const { return !unique() ? tuple_.port() : 0; }
+  uint16_t port() const { return !opaque() ? tuple_.port() : 0; }
 
-  // TODO(dcheng): Rename this to opaque().
-  bool unique() const { return nonce_.has_value(); }
+  bool opaque() const { return nonce_.has_value(); }
 
   // An ASCII serialization of the Origin as per Section 6.2 of RFC 6454, with
   // the addition that all Origins with a 'file' scheme serialize to "file://".
@@ -228,7 +227,7 @@
   // URL (e.g. with a path component).
   GURL GetURL() const;
 
-  // Same as GURL::DomainIs. If |this| origin is unique, then returns false.
+  // Same as GURL::DomainIs. If |this| origin is opaque, then returns false.
   bool DomainIs(base::StringPiece canonical_domain) const;
 
   // Allows Origin to be used as a key in STL (for example, a std::set or
@@ -343,7 +342,7 @@
   // given |nonce|.
   Origin(const Nonce& nonce, SchemeHostPort precursor);
 
-  // Get the nonce associated with this origin, if it is unique. This should be
+  // Get the nonce associated with this origin, if it is opaque. This should be
   // used only when trying to send an Origin across an IPC pipe.
   base::Optional<base::UnguessableToken> GetNonceForSerialization() const;
 
diff --git a/url/origin_unittest.cc b/url/origin_unittest.cc
index b377d8e..86554e4 100644
--- a/url/origin_unittest.cc
+++ b/url/origin_unittest.cc
@@ -80,7 +80,7 @@
   }
 
   bool HasNonceTokenBeenInitialized(const url::Origin& origin) {
-    EXPECT_TRUE(origin.unique());
+    EXPECT_TRUE(origin.opaque());
     // Avoid calling nonce_.token() here, to not trigger lazy initialization.
     return !origin.nonce_->token_.is_empty();
   }
@@ -110,14 +110,14 @@
   // A default-constructed Origin should should be cross origin to everything
   // but itself.
   url::Origin opaque_a, opaque_b;
-  EXPECT_TRUE(opaque_a.unique());
+  EXPECT_TRUE(opaque_a.opaque());
   EXPECT_EQ("", opaque_a.scheme());
   EXPECT_EQ("", opaque_a.host());
   EXPECT_EQ(0, opaque_a.port());
   EXPECT_EQ(SchemeHostPort(), opaque_a.GetTupleOrPrecursorTupleIfOpaque());
   EXPECT_TRUE(opaque_a.GetTupleOrPrecursorTupleIfOpaque().IsInvalid());
 
-  EXPECT_TRUE(opaque_b.unique());
+  EXPECT_TRUE(opaque_b.opaque());
   EXPECT_EQ("", opaque_b.scheme());
   EXPECT_EQ("", opaque_b.host());
   EXPECT_EQ(0, opaque_b.port());
@@ -222,7 +222,7 @@
       EXPECT_EQ("", origin.scheme());
       EXPECT_EQ("", origin.host());
       EXPECT_EQ(0, origin.port());
-      EXPECT_TRUE(origin.unique());
+      EXPECT_TRUE(origin.opaque());
       // An origin is always same-origin with itself.
       EXPECT_EQ(origin, origin);
       EXPECT_NE(origin, url::Origin());
@@ -232,7 +232,7 @@
       EXPECT_EQ("", origin_copy.scheme());
       EXPECT_EQ("", origin_copy.host());
       EXPECT_EQ(0, origin_copy.port());
-      EXPECT_TRUE(origin_copy.unique());
+      EXPECT_TRUE(origin_copy.opaque());
       EXPECT_EQ(origin, origin_copy);
       // And it should always be cross-origin to another opaque Origin.
       EXPECT_NE(origin, opaque_origin);
@@ -362,7 +362,7 @@
     EXPECT_EQ(test_case.expected_scheme, origin.scheme());
     EXPECT_EQ(test_case.expected_host, origin.host());
     EXPECT_EQ(test_case.expected_port, origin.port());
-    EXPECT_FALSE(origin.unique());
+    EXPECT_FALSE(origin.opaque());
     EXPECT_EQ(origin, origin);
     EXPECT_NE(different_origin, origin);
     EXPECT_NE(origin, different_origin);
@@ -374,7 +374,7 @@
     url::Origin derived_opaque =
         Origin::Resolve(GURL("about:blank?bar#foo"), origin)
             .DeriveNewOpaqueOrigin();
-    EXPECT_TRUE(derived_opaque.unique());
+    EXPECT_TRUE(derived_opaque.opaque());
     EXPECT_NE(origin, derived_opaque);
     EXPECT_FALSE(derived_opaque.GetTupleOrPrecursorTupleIfOpaque().IsInvalid());
     EXPECT_EQ(origin.GetTupleOrPrecursorTupleIfOpaque(),
@@ -383,7 +383,7 @@
 
     url::Origin derived_opaque_via_data_url =
         Origin::Resolve(GURL("data:text/html,baz"), origin);
-    EXPECT_TRUE(derived_opaque_via_data_url.unique());
+    EXPECT_TRUE(derived_opaque_via_data_url.opaque());
     EXPECT_NE(origin, derived_opaque_via_data_url);
     EXPECT_FALSE(derived_opaque_via_data_url.GetTupleOrPrecursorTupleIfOpaque()
                      .IsInvalid());
@@ -485,7 +485,7 @@
     EXPECT_EQ(test.scheme, origin->scheme());
     EXPECT_EQ(test.host, origin->host());
     EXPECT_EQ(test.port, origin->port());
-    EXPECT_FALSE(origin->unique());
+    EXPECT_FALSE(origin->opaque());
     EXPECT_TRUE(origin->IsSameOriginWith(*origin));
 
     ExpectParsedUrlsEqual(GURL(origin->Serialize()), origin->GetURL());
@@ -495,7 +495,7 @@
         UnsafelyCreateOpaqueOriginWithoutNormalization(
             test.scheme, test.host, test.port, CreateNonce(nonce));
     ASSERT_TRUE(opaque_origin);
-    EXPECT_TRUE(opaque_origin->unique());
+    EXPECT_TRUE(opaque_origin->opaque());
     EXPECT_FALSE(*opaque_origin == origin);
     EXPECT_EQ(opaque_origin->GetTupleOrPrecursorTupleIfOpaque(),
               origin->GetTupleOrPrecursorTupleIfOpaque());
@@ -556,7 +556,7 @@
       << "An invalid tuple is a valid input to "
       << "UnsafelyCreateOpaqueOriginWithoutNormalization, so long as it is "
       << "the canonical form of the invalid tuple.";
-  EXPECT_TRUE(anonymous_opaque->unique());
+  EXPECT_TRUE(anonymous_opaque->opaque());
   EXPECT_EQ(GetNonce(anonymous_opaque.value()), token);
   EXPECT_EQ(anonymous_opaque->GetTupleOrPrecursorTupleIfOpaque(),
             url::SchemeHostPort());