diff --git a/DEPS b/DEPS
index 2b194c6..bbc0c3a2 100644
--- a/DEPS
+++ b/DEPS
@@ -105,11 +105,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '5953a476d9f74baa9e61ab14f71b2d211fca9721',
+  'skia_revision': '9db44ed0ef7f4f1e548fdc3f3b9bb4674f9ee4ef',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '0c05bf73b422ca9c849cec08fa23cf4589b0b508',
+  'v8_revision': '132145aaee8c9e4c7d089763a3dd40646e686516',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -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': 'd95dde6e066fe1b0ef88d3e0e5ccb5cae48b05a9',
+  'catapult_revision': 'a7fb87b3a3d1dde21cc2cb1e0fd10e6c3bf3496c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -181,7 +181,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.
-  'feed_revision': 'a4e91c7238e329ad11e48b068fe3b1e935c0de9b',
+  'feed_revision': '831b51c0ac199fea3278ceb9de361c22486da935',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_build-tools_version
   # and whatever else without interference from each other.
@@ -604,7 +604,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0ec9d15571fb274b817e3f0336a78bfd35b75e50',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '81db1d50324a9f2df87c05ff7cc6d082b27db242',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -954,7 +954,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '46ef92275f435ab46cfa6e848e844d50a9067da9',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'de2476bcaacf85f60bb6d8f13fadbe871dd1e3ce',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 1e026c1..e5c9d537 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -5,6 +5,7 @@
 #include "android_webview/browser/aw_content_browser_client.h"
 
 #include <utility>
+#include <vector>
 
 #include "android_webview/browser/aw_browser_context.h"
 #include "android_webview/browser/aw_browser_main_parts.h"
@@ -354,7 +355,7 @@
 void AwContentBrowserClient::AllowWorkerFileSystem(
     const GURL& url,
     content::ResourceContext* context,
-    const std::vector<std::pair<int, int> >& render_frames,
+    const std::vector<content::GlobalFrameRoutingId>& render_frames,
     base::Callback<void(bool)> callback) {
   callback.Run(true);
 }
@@ -363,7 +364,7 @@
     const GURL& url,
     const base::string16& name,
     content::ResourceContext* context,
-    const std::vector<std::pair<int, int> >& render_frames) {
+    const std::vector<content::GlobalFrameRoutingId>& render_frames) {
   return true;
 }
 
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index 17725d9..7f01296 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -79,13 +79,13 @@
   void AllowWorkerFileSystem(
       const GURL& url,
       content::ResourceContext* context,
-      const std::vector<std::pair<int, int>>& render_frames,
+      const std::vector<content::GlobalFrameRoutingId>& render_frames,
       base::Callback<void(bool)> callback) override;
   bool AllowWorkerIndexedDB(
       const GURL& url,
       const base::string16& name,
       content::ResourceContext* context,
-      const std::vector<std::pair<int, int>>& render_frames) override;
+      const std::vector<content::GlobalFrameRoutingId>& render_frames) override;
   content::QuotaPermissionContext* CreateQuotaPermissionContext() override;
   void GetQuotaSettings(
       content::BrowserContext* context,
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
index bbe8c8ca..522110b9 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "android_webview/browser/aw_browser_context.h"
 #include "android_webview/browser/aw_contents_client_bridge.h"
@@ -249,7 +250,7 @@
         request_, net::LOAD_ONLY_FROM_CACHE | net::LOAD_SKIP_CACHE_VALIDATION);
   } else {
     AwContentsIoThreadClient::CacheMode cache_mode = io_client->GetCacheMode();
-    switch(cache_mode) {
+    switch (cache_mode) {
       case AwContentsIoThreadClient::LOAD_CACHE_ELSE_NETWORK:
         SetCacheControlFlag(request_, net::LOAD_SKIP_CACHE_VALIDATION);
         break;
@@ -428,9 +429,9 @@
 void AwResourceDispatcherHostDelegate::RemovePendingThrottleOnIoThread(
     IoThreadClientThrottle* throttle) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  PendingThrottleMap::iterator it = pending_throttles_.find(
-      FrameRouteIDPair(throttle->render_process_id(),
-                       throttle->render_frame_id()));
+  PendingThrottleMap::iterator it =
+      pending_throttles_.find(content::GlobalFrameRoutingId(
+          throttle->render_process_id(), throttle->render_frame_id()));
   if (it != pending_throttles_.end()) {
     pending_throttles_.erase(it);
   }
@@ -469,8 +470,8 @@
     IoThreadClientThrottle* pending_throttle) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   pending_throttles_.insert(
-      std::pair<FrameRouteIDPair, IoThreadClientThrottle*>(
-          FrameRouteIDPair(render_process_id, render_frame_id_id),
+      std::pair<content::GlobalFrameRoutingId, IoThreadClientThrottle*>(
+          content::GlobalFrameRoutingId(render_process_id, render_frame_id_id),
           pending_throttle));
 }
 
@@ -478,8 +479,9 @@
     int new_render_process_id,
     int new_render_frame_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  PendingThrottleMap::iterator it = pending_throttles_.find(
-      FrameRouteIDPair(new_render_process_id, new_render_frame_id));
+  PendingThrottleMap::iterator it =
+      pending_throttles_.find(content::GlobalFrameRoutingId(
+          new_render_process_id, new_render_frame_id));
 
   if (it != pending_throttles_.end()) {
     IoThreadClientThrottle* throttle = it->second;
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
index 790c0dd..5ab886e 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
@@ -11,6 +11,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/macros.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 
@@ -76,8 +77,7 @@
                                content::ResourceContext* resource_context);
 
   // Pair of render_process_id and render_frame_id.
-  typedef std::pair<int, int> FrameRouteIDPair;
-  typedef std::map<FrameRouteIDPair, IoThreadClientThrottle*>
+  typedef std::map<content::GlobalFrameRoutingId, IoThreadClientThrottle*>
       PendingThrottleMap;
 
   // Only accessed on the IO thread.
diff --git a/base/test/android/junit/src/org/chromium/base/test/asynctask/BackgroundShadowAsyncTask.java b/base/test/android/junit/src/org/chromium/base/test/asynctask/BackgroundShadowAsyncTask.java
index 83e0ce8..f8ba988e 100644
--- a/base/test/android/junit/src/org/chromium/base/test/asynctask/BackgroundShadowAsyncTask.java
+++ b/base/test/android/junit/src/org/chromium/base/test/asynctask/BackgroundShadowAsyncTask.java
@@ -29,13 +29,13 @@
 
     @Override
     @Implementation
-    public final AsyncTask<Result> execute() {
+    public final AsyncTask<Result> executeOnExecutor(Executor e) {
         try {
             return sExecutorService
                     .submit(new Callable<AsyncTask<Result>>() {
                         @Override
                         public AsyncTask<Result> call() throws Exception {
-                            return BackgroundShadowAsyncTask.super.execute();
+                            return BackgroundShadowAsyncTask.super.executeInRobolectric();
                         }
                     })
                     .get();
@@ -47,12 +47,6 @@
 
     @Override
     @Implementation
-    public final AsyncTask<Result> executeOnExecutor(Executor e) {
-        return execute();
-    }
-
-    @Override
-    @Implementation
     public final Result get() {
         try {
             runBackgroundTasks();
diff --git a/base/test/android/junit/src/org/chromium/base/test/asynctask/CustomShadowAsyncTask.java b/base/test/android/junit/src/org/chromium/base/test/asynctask/CustomShadowAsyncTask.java
index 069e298..e84c84b 100644
--- a/base/test/android/junit/src/org/chromium/base/test/asynctask/CustomShadowAsyncTask.java
+++ b/base/test/android/junit/src/org/chromium/base/test/asynctask/CustomShadowAsyncTask.java
@@ -22,6 +22,6 @@
     @Override
     @Implementation
     public final AsyncTask<Result> executeOnExecutor(Executor executor) {
-        return super.execute();
+        return super.executeInRobolectric();
     }
 }
diff --git a/chrome/android/java/res/drawable-hdpi/btn_new_tab_incognito_normal.png b/chrome/android/java/res/drawable-hdpi/btn_new_tab_incognito_normal.png
deleted file mode 100644
index 576c6d7..0000000
--- a/chrome/android/java/res/drawable-hdpi/btn_new_tab_incognito_normal.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/btn_new_tab_incognito_pressed.png b/chrome/android/java/res/drawable-hdpi/btn_new_tab_incognito_pressed.png
deleted file mode 100644
index 6b092685..0000000
--- a/chrome/android/java/res/drawable-hdpi/btn_new_tab_incognito_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-hdpi/ic_omnibox_incognito_badge.png
deleted file mode 100644
index 23bf4cb..0000000
--- a/chrome/android/java/res/drawable-hdpi/ic_omnibox_incognito_badge.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_omnibox_incognito_badge.png
deleted file mode 100644
index 005cf9bd..0000000
--- a/chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_omnibox_incognito_badge.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_omnibox_incognito_badge.png
deleted file mode 100644
index b40745e..0000000
--- a/chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_omnibox_incognito_badge.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_omnibox_incognito_badge.png
deleted file mode 100644
index 2645aee..0000000
--- a/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_omnibox_incognito_badge.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_omnibox_incognito_badge.png
deleted file mode 100644
index cb033ef8..0000000
--- a/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_omnibox_incognito_badge.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_omnibox_incognito_badge.png
deleted file mode 100644
index 7517752..0000000
--- a/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_omnibox_incognito_badge.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/btn_new_tab_incognito_normal.png b/chrome/android/java/res/drawable-mdpi/btn_new_tab_incognito_normal.png
deleted file mode 100644
index ef804ae..0000000
--- a/chrome/android/java/res/drawable-mdpi/btn_new_tab_incognito_normal.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/btn_new_tab_incognito_pressed.png b/chrome/android/java/res/drawable-mdpi/btn_new_tab_incognito_pressed.png
deleted file mode 100644
index befee8e..0000000
--- a/chrome/android/java/res/drawable-mdpi/btn_new_tab_incognito_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-mdpi/ic_omnibox_incognito_badge.png
deleted file mode 100644
index 39768de50..0000000
--- a/chrome/android/java/res/drawable-mdpi/ic_omnibox_incognito_badge.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/btn_new_tab_incognito_normal.png b/chrome/android/java/res/drawable-xhdpi/btn_new_tab_incognito_normal.png
deleted file mode 100644
index c2190cd..0000000
--- a/chrome/android/java/res/drawable-xhdpi/btn_new_tab_incognito_normal.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/btn_new_tab_incognito_pressed.png b/chrome/android/java/res/drawable-xhdpi/btn_new_tab_incognito_pressed.png
deleted file mode 100644
index 44e3289..0000000
--- a/chrome/android/java/res/drawable-xhdpi/btn_new_tab_incognito_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-xhdpi/ic_omnibox_incognito_badge.png
deleted file mode 100644
index 42b591c..0000000
--- a/chrome/android/java/res/drawable-xhdpi/ic_omnibox_incognito_badge.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/btn_new_tab_incognito_normal.png b/chrome/android/java/res/drawable-xxhdpi/btn_new_tab_incognito_normal.png
deleted file mode 100644
index 03003443..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/btn_new_tab_incognito_normal.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/btn_new_tab_incognito_pressed.png b/chrome/android/java/res/drawable-xxhdpi/btn_new_tab_incognito_pressed.png
deleted file mode 100644
index 4d5b881..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/btn_new_tab_incognito_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-xxhdpi/ic_omnibox_incognito_badge.png
deleted file mode 100644
index 8e5e7967..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/ic_omnibox_incognito_badge.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_incognito_normal.png b/chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_incognito_normal.png
deleted file mode 100644
index 258d7f0..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_incognito_normal.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_incognito_pressed.png b/chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_incognito_pressed.png
deleted file mode 100644
index ff86c7b..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_incognito_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-xxxhdpi/ic_omnibox_incognito_badge.png
deleted file mode 100644
index 5e5b21b..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/ic_omnibox_incognito_badge.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable/btn_new_tab_incognito.xml b/chrome/android/java/res/drawable/btn_new_tab_incognito.xml
deleted file mode 100644
index b2ec0147..0000000
--- a/chrome/android/java/res/drawable/btn_new_tab_incognito.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:drawable="@drawable/btn_new_tab_incognito_pressed" />
-    <item android:state_selected="true" android:drawable="@drawable/btn_new_tab_incognito_pressed" />
-    <item android:state_focused="true" android:drawable="@drawable/btn_new_tab_incognito_pressed" />
-    <item android:drawable="@drawable/btn_new_tab_incognito_normal" />
-</selector>
diff --git a/chrome/android/java/res/layout/control_container.xml b/chrome/android/java/res/layout/control_container.xml
index 8470dd5..0484e201 100644
--- a/chrome/android/java/res/layout/control_container.xml
+++ b/chrome/android/java/res/layout/control_container.xml
@@ -21,9 +21,9 @@
             android:layout_height="@dimen/toolbar_height_no_shadow" />
         <ImageView
             android:id="@+id/toolbar_shadow"
-            android:src="@drawable/toolbar_shadow"
+            android:src="@drawable/modern_toolbar_shadow"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
+            android:layout_height="@dimen/toolbar_shadow_height"
             android:layout_marginTop="@dimen/tab_strip_and_toolbar_height"
             android:scaleType="fitXY"
             tools:ignore="ContentDescription" />
diff --git a/chrome/android/java/res/layout/keyboard_accessory.xml b/chrome/android/java/res/layout/keyboard_accessory.xml
index d0c9528..4a73188 100644
--- a/chrome/android/java/res/layout/keyboard_accessory.xml
+++ b/chrome/android/java/res/layout/keyboard_accessory.xml
@@ -17,7 +17,6 @@
     android:layout_height="@dimen/keyboard_accessory_height"
     android:layout_width="match_parent"
     android:paddingEnd="0dp"
-    android:paddingStart="@dimen/keyboard_accessory_padding"
     android:clickable="true"
     android:focusable="true">
 
@@ -25,11 +24,13 @@
         android:id="@+id/tabs"
         app:tabIndicatorHeight="0dp"
         android:layout_width="wrap_content"
-        android:layout_height="match_parent" />
+        android:layout_height="match_parent"/>
+
+    <View style="@style/VerticalDivider" />
 
     <android.support.v7.widget.RecyclerView
         android:id="@+id/actions_view"
         android:layout_width="wrap_content"
-        android:layout_height="match_parent" />
+        android:layout_height="match_parent"/>
 
 </org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryView>
diff --git a/chrome/android/java/res/layout/keyboard_accessory_action.xml b/chrome/android/java/res/layout/keyboard_accessory_action.xml
index 2de4c8c..3635972a 100644
--- a/chrome/android/java/res/layout/keyboard_accessory_action.xml
+++ b/chrome/android/java/res/layout/keyboard_accessory_action.xml
@@ -12,8 +12,8 @@
     android:minHeight="0dp"
     android:minWidth="0dp"
     android:paddingBottom="0dp"
-    android:paddingEnd="@dimen/keyboard_accessory_half_padding"
-    android:paddingStart="@dimen/keyboard_accessory_half_padding"
+    android:paddingEnd="@dimen/keyboard_accessory_action_padding"
+    android:paddingStart="@dimen/keyboard_accessory_action_padding"
     android:paddingTop="0dp"
     android:layout_marginBottom="@dimen/keyboard_accessory_half_padding"
     android:layout_marginTop="@dimen/keyboard_accessory_half_padding"
diff --git a/chrome/android/java/res/layout/location_bar_base.xml b/chrome/android/java/res/layout/location_bar_base.xml
index d678d61..6d9c528 100644
--- a/chrome/android/java/res/layout/location_bar_base.xml
+++ b/chrome/android/java/res/layout/location_bar_base.xml
@@ -8,17 +8,7 @@
 -->
 <merge
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools">
-
-    <ImageView android:id="@+id/incognito_badge"
-        style="@style/LocationBarButton"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:scaleType="center"
-        android:src="@drawable/ic_omnibox_incognito_badge"
-        tools:ignore="ContentDescription"
-        android:visibility="gone" />
+    xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <FrameLayout android:id="@+id/location_bar_icon"
         android:layout_width="@dimen/location_bar_icon_width"
diff --git a/chrome/android/java/res/layout/password_accessory_sheet_label.xml b/chrome/android/java/res/layout/password_accessory_sheet_label.xml
index 4e85e90..e922c3df 100644
--- a/chrome/android/java/res/layout/password_accessory_sheet_label.xml
+++ b/chrome/android/java/res/layout/password_accessory_sheet_label.xml
@@ -11,5 +11,6 @@
     android:paddingEnd="16dp"
     android:fillViewport="true"
     android:layout_height="48dp"
+    android:gravity="center_vertical"
     android:textAppearance="@style/BlackHint1"
-    android:layout_width="match_parent"/>
\ No newline at end of file
+    android:layout_width="match_parent"/>
diff --git a/chrome/android/java/res/layout/password_accessory_sheet_option.xml b/chrome/android/java/res/layout/password_accessory_sheet_option.xml
index 81934f0b..06bfd64 100644
--- a/chrome/android/java/res/layout/password_accessory_sheet_option.xml
+++ b/chrome/android/java/res/layout/password_accessory_sheet_option.xml
@@ -12,4 +12,5 @@
     android:fillViewport="true"
     android:layout_height="48dp"
     android:textAppearance="@style/BlackTitle1"
-    android:layout_width="match_parent"/>
\ No newline at end of file
+    android:layout_width="match_parent"
+    android:background="?android:attr/selectableItemBackground"/>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml b/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml
index d7cbb66..8d0eb919 100644
--- a/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml
+++ b/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml
@@ -6,10 +6,8 @@
 <TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/suggestion_text"
-    android:layout_marginStart="@dimen/keyboard_accessory_suggestion_margin"
-    android:paddingEnd="@dimen/keyboard_accessory_suggestion_margin"
     android:gravity="center_vertical|start"
     android:fillViewport="true"
     android:layout_height="@dimen/keyboard_accessory_suggestion_height"
-    android:textAppearance="@style/BlackTitle1"
-    android:layout_width="match_parent"/>
\ No newline at end of file
+    android:layout_width="match_parent"
+    android:textAppearance="@style/BlackTitle1"/>
\ No newline at end of file
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index fccda2d1..07aee30 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -220,12 +220,21 @@
         <item name="android:layout_marginTop">2dp</item>
         <item name="android:background">@color/google_grey_600</item>
     </style>
+
+    <!-- Dividers -->
     <style name="Divider">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">@dimen/divider_height</item>
         <item name="android:background">@color/google_grey_300</item>
         <item name="android:importantForAccessibility">no</item>
     </style>
+    <style name="VerticalDivider">
+        <item name="android:layout_width">@dimen/divider_height</item>
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:background">@color/google_grey_300</item>
+        <item name="android:importantForAccessibility">no</item>
+    </style>
+
 
     <style name="ThemeWithActionBarBase" parent="Theme.AppCompat.Light">
         <item name="android:windowBackground">@drawable/action_bar_activity_bg</item>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 836c9b3..dc7b16b 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -125,11 +125,12 @@
 
     <!-- Autofill keyboard accessory dimensions -->
     <dimen name="keyboard_accessory_action_height">36dp</dimen>
+    <dimen name="keyboard_accessory_action_padding">16dp</dimen>
     <dimen name="keyboard_accessory_half_padding">6dp</dimen>
     <dimen name="keyboard_accessory_height">48dp</dimen>
     <dimen name="keyboard_accessory_padding">6dp</dimen>
     <dimen name="keyboard_accessory_sheet_height">330dp</dimen>
-    <dimen name="keyboard_accessory_suggestion_margin">16dp</dimen>
+    <dimen name="keyboard_accessory_suggestion_padding">16dp</dimen>
     <dimen name="keyboard_accessory_suggestion_height">48dp</dimen>
     <dimen name="keyboard_accessory_suggestion_icon_size">20dp</dimen>
 
@@ -272,9 +273,7 @@
     <dimen name="location_bar_google_g_container_width">40dp</dimen>
     <dimen name="location_bar_vertical_margin">8dp</dimen>
     <dimen name="location_bar_url_text_size">16sp</dimen>
-    <dimen name="location_bar_incognito_badge_padding">7dp</dimen>
     <dimen name="location_bar_icon_width">32dp</dimen>
-    <dimen name="location_bar_corner_radius">1dp</dimen>
 
     <dimen name="tablet_toolbar_start_padding">4dp</dimen>
     <dimen name="tablet_toolbar_start_padding_no_buttons">6dp</dimen>
diff --git a/chrome/android/java/res/xml/account_management_preferences.xml b/chrome/android/java/res/xml/account_management_preferences.xml
index 5c5581d..2f38746 100644
--- a/chrome/android/java/res/xml/account_management_preferences.xml
+++ b/chrome/android/java/res/xml/account_management_preferences.xml
@@ -38,8 +38,7 @@
                 <TextView android:id="@android:id/summary"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:textAppearance="?android:attr/textAppearanceSmall"
-                    android:textColor="?android:attr/textColorSecondary"/>
+                    android:textAppearance="@style/BlackBody"/>
 
                 <LinearLayout android:id="@android:id/widget_frame"
                     android:layout_width="wrap_content"
@@ -62,6 +61,7 @@
         android:title="@string/sign_in_sync"/>
 
     <Preference
+        android:key="sync_settings_divider"
         android:layout="@layout/divider_preference"/>
 
     <Preference
@@ -71,6 +71,7 @@
         android:summary="@string/sign_in_google_activity_controls_message"/>
 
     <Preference
+        android:key="google_activity_controls_divider"
         android:layout="@layout/divider_preference"/>
 
     <Preference
diff --git a/chrome/android/java/res/xml/sync_and_services_preferences.xml b/chrome/android/java/res/xml/sync_and_services_preferences.xml
index e39171d..702a825 100644
--- a/chrome/android/java/res/xml/sync_and_services_preferences.xml
+++ b/chrome/android/java/res/xml/sync_and_services_preferences.xml
@@ -32,11 +32,11 @@
             android:title="@string/sync_bookmarks"/>
         <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference
             android:persistent="false"
-            android:key="payments_integration"
-            android:title="@string/payments_integration"/>
+            android:key="sync_payments_integration"
+            android:title="@string/sync_payments_integration"/>
         <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference
             android:persistent="false"
-            android:key="sync_omnibox"
+            android:key="sync_history"
             android:title="@string/sync_history"/>
         <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference
             android:persistent="false"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
index fa52318..d0be972 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
@@ -7,11 +7,10 @@
 import static org.chromium.ui.base.LocalizationUtils.isLayoutRtl;
 
 import android.content.Context;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.support.design.widget.TabLayout;
+import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.view.ViewPager;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -94,6 +93,7 @@
         if (mTabLayout == null) return; // Inflation not done yet. Will be invoked again afterwards.
         TabLayout.Tab tab = mTabLayout.newTab();
         tab.setIcon(icon.mutate()); // mutate() needed to change the active tint.
+        DrawableCompat.setTint(tab.getIcon(), getResources().getColor(R.color.default_icon_color));
         tab.setContentDescription(contentDescription);
         mTabLayout.addTab(tab, position, false);
     }
@@ -129,11 +129,10 @@
         for (int i = mTabLayout.getTabCount() - 1; i >= 0; i--) {
             TabLayout.Tab t = mTabLayout.getTabAt(i);
             if (t == null || t.getIcon() == null) continue;
-            if (activeTab == null || i != activeTab) {
-                t.getIcon().clearColorFilter();
-            } else {
-                t.getIcon().setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_ATOP);
-            }
+            int activeStateColor = (activeTab == null || i != activeTab)
+                    ? R.color.default_icon_color
+                    : R.color.default_icon_color_blue;
+            DrawableCompat.setTint(t.getIcon(), getResources().getColor(activeStateColor));
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
index a86d5880..614a397 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
@@ -72,10 +72,10 @@
     }
 
     /**
-     * Tries to reopen the keyboard which will implicitly show the keyboard accessory bar again.
+     * Opens the keyboard which implicitly dismisses the sheet. Without open sheet, this is a NoOp.
      */
-    public void openKeyboard() {
-        mMediator.onOpenKeyboard();
+    public void swapSheetWithKeyboard() {
+        mMediator.swapSheetWithKeyboard();
     }
 
     void registerActionProvider(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
index a1f8184..47435db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
@@ -155,8 +155,13 @@
             }
 
             @Override
-            public void willCloseTab(Tab tab, boolean animate) {
+            public void tabClosureCommitted(Tab tab) {
                 mModel.remove(tab);
+            }
+
+            @Override
+            public void willCloseTab(Tab tab, boolean animate) {
+                if (mActiveBrowserTab == tab) mActiveBrowserTab = null;
                 restoreCachedState(mActiveBrowserTab);
             }
         };
@@ -257,6 +262,13 @@
         mAccessorySheet.hide();
     }
 
+    /**
+     * Opens the keyboard which implicitly dismisses the sheet. Without open sheet, this is a NoOp.
+     */
+    void swapSheetWithKeyboard() {
+        if (mAccessorySheet.isShown()) onOpenKeyboard();
+    }
+
     @Override
     public void onOpenKeyboard() {
         assert mActivity != null : "ManualFillingMediator needs initialization.";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java
index c93217a..6e1be89 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java
@@ -75,8 +75,8 @@
     }
 
     @CalledByNative
-    private void openKeyboard() {
-        mManualFillingCoordinator.openKeyboard();
+    private void swapSheetWithKeyboard() {
+        mManualFillingCoordinator.swapSheetWithKeyboard();
     }
 
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java
index 70d6b1d..49f2ab6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java
@@ -4,11 +4,11 @@
 
 package org.chromium.chrome.browser.autofill.keyboard_accessory;
 
+import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.Nullable;
-import android.support.v4.view.MarginLayoutParamsCompat;
 import android.support.v7.content.res.AppCompatResources;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -111,14 +111,14 @@
      */
     static class IconTextViewHolder extends TextViewHolder {
         private final TextView mSuggestionText;
-        private final int mMargin;
+        private final int mPadding;
         private final int mIconSize;
 
         IconTextViewHolder(View itemView) {
             super(itemView);
             mSuggestionText = itemView.findViewById(R.id.suggestion_text);
-            mMargin = itemView.getContext().getResources().getDimensionPixelSize(
-                    R.dimen.keyboard_accessory_suggestion_margin);
+            mPadding = itemView.getContext().getResources().getDimensionPixelSize(
+                    R.dimen.keyboard_accessory_suggestion_padding);
             mIconSize = itemView.getContext().getResources().getDimensionPixelSize(
                     R.dimen.keyboard_accessory_suggestion_icon_size);
         }
@@ -131,19 +131,27 @@
         @Override
         protected void bind(Item item) {
             super.bind(item);
-            ViewGroup.MarginLayoutParams params =
-                    new ViewGroup.MarginLayoutParams(mSuggestionText.getLayoutParams());
-            MarginLayoutParamsCompat.setMarginEnd(params, mMargin);
             if (!item.isPassword()) {
                 setIconForBitmap(null); // Set the default icon, then try to get a better one.
                 item.fetchFavicon(this::setIconForBitmap);
-                MarginLayoutParamsCompat.setMarginStart(params, mMargin);
+                mSuggestionText.setPadding(mPadding, 0, mPadding, 0);
             } else {
                 ApiCompatibilityUtils.setCompoundDrawablesRelative(
                         mSuggestionText, null, null, null, null);
-                MarginLayoutParamsCompat.setMarginStart(params, 2 * mMargin + mIconSize);
+                mSuggestionText.setPadding(2 * mPadding + mIconSize, 0, mPadding, 0);
             }
-            mSuggestionText.setLayoutParams(params);
+
+            if (item.getItemSelectedCallback() == null) {
+                mSuggestionText.setEnabled(false);
+                mSuggestionText.setBackground(null);
+            } else {
+                mSuggestionText.setEnabled(true);
+                TypedArray a = mSuggestionText.getContext().obtainStyledAttributes(
+                        new int[] {R.attr.selectableItemBackground});
+                Drawable suggestionBackground = a.getDrawable(0);
+                a.recycle();
+                mSuggestionText.setBackground(suggestionBackground);
+            }
         }
 
         private void setIconForBitmap(@Nullable Bitmap favicon) {
@@ -157,7 +165,7 @@
             if (icon != null) { // AppCompatResources.getDrawable is @Nullable.
                 icon.setBounds(0, 0, mIconSize, mIconSize);
             }
-            mSuggestionText.setCompoundDrawablePadding(mMargin);
+            mSuggestionText.setCompoundDrawablePadding(mPadding);
             ApiCompatibilityUtils.setCompoundDrawablesRelative(
                     mSuggestionText, icon, null, null, null);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index fc7045ef..944fc2a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -2037,9 +2037,7 @@
 
         if (visible && (!locationBarShownInNTP || ignoreNtpChecks)) {
             mScrimParams.backgroundColor =
-                    useModernDesign() && !mIsTablet && !mToolbarDataProvider.isIncognito()
-                    ? mLightScrimColor
-                    : null;
+                    !mIsTablet && !mToolbarDataProvider.isIncognito() ? mLightScrimColor : null;
 
             // If the location bar is shown in the NTP, the toolbar will eventually trigger a
             // fade in.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
index 610891a..e66a2f7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
@@ -8,9 +8,7 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.support.annotation.Nullable;
 import android.support.v4.view.MarginLayoutParamsCompat;
-import android.support.v4.view.ViewCompat;
 import android.support.v4.view.animation.FastOutLinearInInterpolator;
 import android.util.AttributeSet;
 import android.view.TouchDelegate;
@@ -42,10 +40,8 @@
             new FastOutLinearInInterpolator();
 
     private View mFirstVisibleFocusedView;
-    private @Nullable View mIncognitoBadge;
     private View mGoogleGContainer;
     private View mGoogleG;
-    private int mIncognitoBadgePadding;
     private int mGoogleGWidth;
     private int mGoogleGMargin;
 
@@ -64,9 +60,6 @@
         super.onFinishInflate();
 
         mFirstVisibleFocusedView = findViewById(R.id.url_bar);
-        mIncognitoBadge = findViewById(R.id.incognito_badge);
-        mIncognitoBadgePadding =
-                getResources().getDimensionPixelSize(R.dimen.location_bar_incognito_badge_padding);
 
         mGoogleGContainer = findViewById(R.id.google_g_container);
         mGoogleG = findViewById(R.id.google_g);
@@ -242,53 +235,10 @@
     }
 
     @Override
-    protected void updateLocationBarIconContainerVisibility() {
-        super.updateLocationBarIconContainerVisibility();
-        updateIncognitoBadgePadding();
-    }
-
-    private void updateIncognitoBadgePadding() {
-        // This can be triggered in the super.onFinishInflate, so we need to null check in this
-        // place only.
-        if (mIncognitoBadge == null) return;
-
-        if (findViewById(R.id.location_bar_icon).getVisibility() == GONE) {
-            ViewCompat.setPaddingRelative(mIncognitoBadge, 0, 0, mIncognitoBadgePadding, 0);
-        } else {
-            ViewCompat.setPaddingRelative(mIncognitoBadge, 0, 0, 0, 0);
-        }
-    }
-
-    @Override
-    public void updateVisualsForState() {
-        super.updateVisualsForState();
-
-        if (mIncognitoBadge == null) return;
-
-        boolean showIncognitoBadge =
-                getToolbarDataProvider() != null && getToolbarDataProvider().isIncognito();
-        mIncognitoBadge.setVisibility(showIncognitoBadge ? VISIBLE : GONE);
-        updateIncognitoBadgePadding();
-    }
-
-    @Override
     protected boolean shouldAnimateIconChanges() {
         return super.shouldAnimateIconChanges() || isUrlFocusChangeInProgress();
     }
 
-    @Override
-    public void setLayoutDirection(int layoutDirection) {
-        super.setLayoutDirection(layoutDirection);
-        updateIncognitoBadgePadding();
-    }
-
-    /**
-     * @return Whether the incognito badge is currently visible.
-     */
-    public boolean isIncognitoBadgeVisible() {
-        return mIncognitoBadge != null && mIncognitoBadge.getVisibility() == View.VISIBLE;
-    }
-
     /**
      * @param softInputMode The software input resize mode.
      * @param delay Delay the change in input mode.
@@ -348,24 +298,7 @@
             }
         });
 
-        // Chrome Home does not use the incognito badge. Remove the View to save memory.
-        removeView(mIncognitoBadge);
-        mIncognitoBadge = null;
-
         // TODO(twellington): remove and null out mGoogleG and mGoogleGContainer if we remove
         //                    support for the Google 'G' to save memory.
     }
-
-    @Override
-    public void onNativeLibraryReady() {
-        super.onNativeLibraryReady();
-
-        // TODO(twellington): Move this to constructor when isModernUiEnabled() is available before
-        // native is loaded.
-        if (useModernDesign()) {
-            // Modern does not use the incognito badge. Remove the View to save memory.
-            removeView(mIncognitoBadge);
-            mIncognitoBadge = null;
-        }
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
index 0a4e93f1..c022c46 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
@@ -69,47 +69,39 @@
 public class SyncAndServicesPreferences extends PreferenceFragment
         implements PassphraseDialogFragment.Listener, PassphraseCreationDialogFragment.Listener,
                    PassphraseTypeDialogFragment.Listener, Preference.OnPreferenceChangeListener,
-                   Preference.OnPreferenceClickListener,
                    ProfileSyncService.SyncStateChangedListener {
-    private static final String USE_SYNC_AND_ALL_SERVICES = "use_sync_and_all_services";
-    private static final String SYNC_AND_PERSONALIZATION = "sync_and_personalization";
-    private static final String NONPERSONALIZED_SERVICES = "nonpersonalized_services";
-    private static final String PREF_NAVIGATION_ERROR = "navigation_error";
-    private static final String PREF_SEARCH_SUGGESTIONS = "search_suggestions";
-    private static final String PREF_SAFE_BROWSING_EXTENDED_REPORTING =
-            "safe_browsing_extended_reporting";
-    private static final String PREF_SAFE_BROWSING_SCOUT_REPORTING =
-            "safe_browsing_scout_reporting";
-    private static final String PREF_SAFE_BROWSING = "safe_browsing";
-    private static final String PREF_CONTEXTUAL_SEARCH = "contextual_search";
-    private static final String PREF_NETWORK_PREDICTIONS = "network_predictions";
-    private static final String PREF_USAGE_AND_CRASH_REPORTING = "usage_and_crash_reports";
-
     @VisibleForTesting
     public static final String FRAGMENT_ENTER_PASSPHRASE = "enter_password";
     @VisibleForTesting
     public static final String FRAGMENT_CUSTOM_PASSPHRASE = "custom_password";
     @VisibleForTesting
     public static final String FRAGMENT_PASSPHRASE_TYPE = "password_type";
-    @VisibleForTesting
-    public static final String PREFERENCE_SYNC_AUTOFILL = "sync_autofill";
-    @VisibleForTesting
-    public static final String PREFERENCE_SYNC_BOOKMARKS = "sync_bookmarks";
-    @VisibleForTesting
-    public static final String PREFERENCE_SYNC_OMNIBOX = "sync_omnibox";
-    @VisibleForTesting
-    public static final String PREFERENCE_SYNC_PASSWORDS = "sync_passwords";
-    @VisibleForTesting
-    public static final String PREFERENCE_SYNC_RECENT_TABS = "sync_recent_tabs";
-    @VisibleForTesting
-    public static final String PREFERENCE_SYNC_SETTINGS = "sync_settings";
-    @VisibleForTesting
-    public static final String PREFERENCE_PAYMENTS_INTEGRATION = "payments_integration";
-    @VisibleForTesting
-    public static final String PREFERENCE_ENCRYPTION = "encryption";
-    @VisibleForTesting
-    public static final String PREFERENCE_SYNC_MANAGE_DATA = "sync_manage_data";
-    public static final String PREFERENCE_SYNC_ERROR_CARD = "sync_error_card";
+
+    private static final String PREF_USE_SYNC_AND_ALL_SERVICES = "use_sync_and_all_services";
+
+    private static final String PREF_SYNC_AND_PERSONALIZATION = "sync_and_personalization";
+    private static final String PREF_SYNC_AUTOFILL = "sync_autofill";
+    private static final String PREF_SYNC_BOOKMARKS = "sync_bookmarks";
+    private static final String PREF_SYNC_PAYMENTS_INTEGRATION = "sync_payments_integration";
+    private static final String PREF_SYNC_HISTORY = "sync_history";
+    private static final String PREF_SYNC_PASSWORDS = "sync_passwords";
+    private static final String PREF_SYNC_RECENT_TABS = "sync_recent_tabs";
+    private static final String PREF_SYNC_SETTINGS = "sync_settings";
+    private static final String PREF_ENCRYPTION = "encryption";
+    private static final String PREF_SYNC_MANAGE_DATA = "sync_manage_data";
+    private static final String PREF_SYNC_ERROR_CARD = "sync_error_card";
+
+    private static final String PREF_NONPERSONALIZED_SERVICES = "nonpersonalized_services";
+    private static final String PREF_SEARCH_SUGGESTIONS = "search_suggestions";
+    private static final String PREF_NETWORK_PREDICTIONS = "network_predictions";
+    private static final String PREF_NAVIGATION_ERROR = "navigation_error";
+    private static final String PREF_SAFE_BROWSING = "safe_browsing";
+    private static final String PREF_SAFE_BROWSING_EXTENDED_REPORTING =
+            "safe_browsing_extended_reporting";
+    private static final String PREF_SAFE_BROWSING_SCOUT_REPORTING =
+            "safe_browsing_scout_reporting";
+    private static final String PREF_USAGE_AND_CRASH_REPORTING = "usage_and_crash_reports";
+    private static final String PREF_CONTEXTUAL_SEARCH = "contextual_search";
 
     @IntDef({SyncError.NO_ERROR, SyncError.ANDROID_SYNC_DISABLED, SyncError.AUTH_ERROR,
             SyncError.PASSPHRASE_REQUIRED, SyncError.CLIENT_OUT_OF_DATE, SyncError.OTHER_ERRORS})
@@ -137,26 +129,26 @@
     private SigninExpandablePreferenceGroup mSyncGroup;
     private CheckBoxPreference mSyncAutofill;
     private CheckBoxPreference mSyncBookmarks;
-    private CheckBoxPreference mSyncOmnibox;
+    private CheckBoxPreference mSyncPaymentsIntegration;
+    private CheckBoxPreference mSyncHistory;
     private CheckBoxPreference mSyncPasswords;
     private CheckBoxPreference mSyncRecentTabs;
     private CheckBoxPreference mSyncSettings;
-    private CheckBoxPreference mPaymentsIntegration;
     // Contains preferences for all sync data types.
-    private CheckBoxPreference[] mAllTypes;
+    private CheckBoxPreference[] mSyncAllTypes;
 
     private Preference mSyncEncryption;
     private Preference mManageSyncData;
     private Preference mSyncErrorCard;
 
     private SigninExpandablePreferenceGroup mNonpersonalizedServices;
-    private ChromeBaseCheckBoxPreference mNavigationError;
-    private ChromeBaseCheckBoxPreference mNetworkPredictions;
     private ChromeBaseCheckBoxPreference mSearchSuggestions;
-    private Preference mContextualSearch;
-    private ChromeBaseCheckBoxPreference mSafeBrowsingReporting;
+    private ChromeBaseCheckBoxPreference mNetworkPredictions;
+    private ChromeBaseCheckBoxPreference mNavigationError;
     private ChromeBaseCheckBoxPreference mSafeBrowsing;
+    private ChromeBaseCheckBoxPreference mSafeBrowsingReporting;
     private Preference mUsageAndCrashReporting;
+    private Preference mContextualSearch;
 
     private boolean mIsEngineInitialized;
     private boolean mIsPassphraseRequired;
@@ -178,33 +170,44 @@
 
         PreferenceUtils.addPreferencesFromResource(this, R.xml.sync_and_services_preferences);
 
-        mUseSyncAndAllServices = (ChromeSwitchPreference) findPreference(USE_SYNC_AND_ALL_SERVICES);
+        mUseSyncAndAllServices =
+                (ChromeSwitchPreference) findPreference(PREF_USE_SYNC_AND_ALL_SERVICES);
         mUseSyncAndAllServices.setOnPreferenceChangeListener(this);
-        mSyncGroup = (SigninExpandablePreferenceGroup) findPreference(SYNC_AND_PERSONALIZATION);
+        mSyncGroup =
+                (SigninExpandablePreferenceGroup) findPreference(PREF_SYNC_AND_PERSONALIZATION);
         mNonpersonalizedServices =
-                (SigninExpandablePreferenceGroup) findPreference(NONPERSONALIZED_SERVICES);
+                (SigninExpandablePreferenceGroup) findPreference(PREF_NONPERSONALIZED_SERVICES);
 
-        mSyncAutofill = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_AUTOFILL);
-        mSyncBookmarks = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_BOOKMARKS);
-        mSyncOmnibox = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_OMNIBOX);
-        mSyncPasswords = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_PASSWORDS);
-        mSyncRecentTabs = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_RECENT_TABS);
-        mSyncSettings = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_SETTINGS);
-        mPaymentsIntegration = (CheckBoxPreference) findPreference(PREFERENCE_PAYMENTS_INTEGRATION);
+        mSyncAutofill = (CheckBoxPreference) findPreference(PREF_SYNC_AUTOFILL);
+        mSyncBookmarks = (CheckBoxPreference) findPreference(PREF_SYNC_BOOKMARKS);
+        mSyncPaymentsIntegration =
+                (CheckBoxPreference) findPreference(PREF_SYNC_PAYMENTS_INTEGRATION);
+        mSyncHistory = (CheckBoxPreference) findPreference(PREF_SYNC_HISTORY);
+        mSyncPasswords = (CheckBoxPreference) findPreference(PREF_SYNC_PASSWORDS);
+        mSyncRecentTabs = (CheckBoxPreference) findPreference(PREF_SYNC_RECENT_TABS);
+        mSyncSettings = (CheckBoxPreference) findPreference(PREF_SYNC_SETTINGS);
 
-        mSyncEncryption = findPreference(PREFERENCE_ENCRYPTION);
-        mSyncEncryption.setOnPreferenceClickListener(this);
-        mManageSyncData = findPreference(PREFERENCE_SYNC_MANAGE_DATA);
-        mManageSyncData.setOnPreferenceClickListener(this);
-        mSyncErrorCard = findPreference(PREFERENCE_SYNC_ERROR_CARD);
-        mSyncErrorCard.setOnPreferenceClickListener(this);
+        mSyncEncryption = findPreference(PREF_ENCRYPTION);
+        mSyncEncryption.setOnPreferenceClickListener(
+                toOnClickListener(this::onSyncEncryptionClicked));
+        mManageSyncData = findPreference(PREF_SYNC_MANAGE_DATA);
+        mManageSyncData.setOnPreferenceClickListener(
+                toOnClickListener(this::openDashboardTabInNewActivityStack));
+        mSyncErrorCard = findPreference(PREF_SYNC_ERROR_CARD);
+        mSyncErrorCard.setOnPreferenceClickListener(
+                toOnClickListener(this::onSyncErrorCardClicked));
 
-        mAllTypes = new CheckBoxPreference[] {mSyncAutofill, mSyncBookmarks, mSyncOmnibox,
-                mSyncPasswords, mSyncRecentTabs, mSyncSettings, mPaymentsIntegration};
-        for (CheckBoxPreference type : mAllTypes) {
+        mSyncAllTypes =
+                new CheckBoxPreference[] {mSyncAutofill, mSyncBookmarks, mSyncPaymentsIntegration,
+                        mSyncHistory, mSyncPasswords, mSyncRecentTabs, mSyncSettings};
+        for (CheckBoxPreference type : mSyncAllTypes) {
             type.setOnPreferenceChangeListener(this);
         }
 
+        mSearchSuggestions = (ChromeBaseCheckBoxPreference) findPreference(PREF_SEARCH_SUGGESTIONS);
+        mSearchSuggestions.setOnPreferenceChangeListener(this);
+        mSearchSuggestions.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
+
         mNetworkPredictions =
                 (ChromeBaseCheckBoxPreference) findPreference(PREF_NETWORK_PREDICTIONS);
         mNetworkPredictions.setOnPreferenceChangeListener(this);
@@ -214,15 +217,9 @@
         mNavigationError.setOnPreferenceChangeListener(this);
         mNavigationError.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
-        mSearchSuggestions = (ChromeBaseCheckBoxPreference) findPreference(PREF_SEARCH_SUGGESTIONS);
-        mSearchSuggestions.setOnPreferenceChangeListener(this);
-        mSearchSuggestions.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
-
-        mContextualSearch = findPreference(PREF_CONTEXTUAL_SEARCH);
-        if (!ContextualSearchFieldTrial.isEnabled()) {
-            removePreference(mNonpersonalizedServices, mContextualSearch);
-            mContextualSearch = null;
-        }
+        mSafeBrowsing = (ChromeBaseCheckBoxPreference) findPreference(PREF_SAFE_BROWSING);
+        mSafeBrowsing.setOnPreferenceChangeListener(this);
+        mSafeBrowsing.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
         Preference extendedReporting = findPreference(PREF_SAFE_BROWSING_EXTENDED_REPORTING);
         Preference scoutReporting = findPreference(PREF_SAFE_BROWSING_SCOUT_REPORTING);
@@ -237,15 +234,29 @@
         mSafeBrowsingReporting.setOnPreferenceChangeListener(this);
         mSafeBrowsingReporting.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
-        mSafeBrowsing = (ChromeBaseCheckBoxPreference) findPreference(PREF_SAFE_BROWSING);
-        mSafeBrowsing.setOnPreferenceChangeListener(this);
-        mSafeBrowsing.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
-
         mUsageAndCrashReporting = findPreference(PREF_USAGE_AND_CRASH_REPORTING);
 
+        mContextualSearch = findPreference(PREF_CONTEXTUAL_SEARCH);
+        if (!ContextualSearchFieldTrial.isEnabled()) {
+            removePreference(mNonpersonalizedServices, mContextualSearch);
+            mContextualSearch = null;
+        }
+
         updatePreferences();
     }
 
+    private Preference.OnPreferenceClickListener toOnClickListener(Runnable runnable) {
+        return preference -> {
+            if (!isResumed()) {
+                // This event could come in after onPause if the user clicks back and the preference
+                // at roughly the same time. See http://b/5983282.
+                return false;
+            }
+            runnable.run();
+            return false;
+        };
+    }
+
     @Override
     public void onActivityCreated(@Nullable Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
@@ -301,7 +312,7 @@
             // Inform sync that the user has finished setting up sync at least once.
             mProfileSyncService.setFirstSetupComplete();
         }
-        PersonalDataManager.setPaymentsIntegrationEnabled(mPaymentsIntegration.isChecked());
+        PersonalDataManager.setPaymentsIntegrationEnabled(mSyncPaymentsIntegration.isChecked());
         // Setup is done. This was preventing sync from turning on even if it was enabled.
         // TODO(crbug/557784): This needs to be set only when we think the user is done with
         // setting up. This means: 1) If the user leaves the Sync Settings screen (via back)
@@ -318,7 +329,7 @@
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         String key = preference.getKey();
-        if (USE_SYNC_AND_ALL_SERVICES.equals(key)) {
+        if (PREF_USE_SYNC_AND_ALL_SERVICES.equals(key)) {
             boolean enabled = (boolean) newValue;
             if (enabled) {
                 mSyncGroup.setExpanded(true);
@@ -350,8 +361,8 @@
                     //
                     // If the user unchecks the autofill sync checkbox, then disable and uncheck
                     // the payments integration checkbox.
-                    mPaymentsIntegration.setEnabled(preferenceChecked);
-                    mPaymentsIntegration.setChecked(preferenceChecked);
+                    mSyncPaymentsIntegration.setEnabled(preferenceChecked);
+                    mSyncPaymentsIntegration.setChecked(preferenceChecked);
                 }
                 updateSyncStateFromSelectedModelTypes();
             });
@@ -359,31 +370,6 @@
         return true;
     }
 
-    /** Callback for OnPreferenceClickListener */
-    @Override
-    public boolean onPreferenceClick(Preference preference) {
-        if (!isResumed()) {
-            // This event could come in after onPause if the user clicks back and the preference at
-            // roughly the same time. See http://b/5983282
-            return false;
-        }
-        if (preference == mSyncEncryption && mProfileSyncService.isEngineInitialized()) {
-            if (mProfileSyncService.isPassphraseRequiredForDecryption()) {
-                displayPassphraseDialog();
-            } else {
-                displayPassphraseTypeDialog();
-                return true;
-            }
-        } else if (preference == mManageSyncData) {
-            openDashboardTabInNewActivityStack();
-            return true;
-        } else if (preference == mSyncErrorCard) {
-            onSyncErrorCardClicked();
-            return true;
-        }
-        return false;
-    }
-
     /**
      * ProfileSyncService.SyncStateChangedListener implementation, listens to sync state changes.
      *
@@ -412,7 +398,7 @@
     }
 
     private boolean isSyncTypePreference(Preference preference) {
-        for (Preference pref : mAllTypes) {
+        for (Preference pref : mSyncAllTypes) {
             if (pref == preference) return true;
         }
         return false;
@@ -502,7 +488,7 @@
         Set<Integer> types = new HashSet<>();
         if (mSyncAutofill.isChecked()) types.add(ModelType.AUTOFILL);
         if (mSyncBookmarks.isChecked()) types.add(ModelType.BOOKMARKS);
-        if (mSyncOmnibox.isChecked()) types.add(ModelType.TYPED_URLS);
+        if (mSyncHistory.isChecked()) types.add(ModelType.TYPED_URLS);
         if (mSyncPasswords.isChecked()) types.add(ModelType.PASSWORDS);
         if (mSyncRecentTabs.isChecked()) types.add(ModelType.PROXY_TABS);
         if (mSyncSettings.isChecked()) types.add(ModelType.PREFERENCES);
@@ -607,6 +593,16 @@
         displayCustomPassphraseDialog();
     }
 
+    private void onSyncEncryptionClicked() {
+        if (!mProfileSyncService.isEngineInitialized()) return;
+
+        if (mProfileSyncService.isPassphraseRequiredForDecryption()) {
+            displayPassphraseDialog();
+        } else {
+            displayPassphraseTypeDialog();
+        }
+    }
+
     /** Opens the Google Dashboard where the user can control the data stored for the account. */
     private void openDashboardTabInNewActivityStack() {
         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(DASHBOARD_URL));
@@ -628,11 +624,11 @@
                 && mProfileSyncService.isCryptographerReady();
         Set<Integer> syncTypes = mProfileSyncService.getPreferredDataTypes();
         boolean syncAutofill = syncTypes.contains(ModelType.AUTOFILL);
-        for (CheckBoxPreference pref : mAllTypes) {
+        for (CheckBoxPreference pref : mSyncAllTypes) {
             // Set the default state of each data type checkbox.
             boolean canSyncType = true;
             if (pref == mSyncPasswords) canSyncType = passwordSyncConfigurable;
-            if (pref == mPaymentsIntegration) {
+            if (pref == mSyncPaymentsIntegration) {
                 canSyncType = syncAutofill || syncEverything;
             }
 
@@ -647,13 +643,13 @@
             // to match the prefs.
             mSyncAutofill.setChecked(syncAutofill);
             mSyncBookmarks.setChecked(syncTypes.contains(ModelType.BOOKMARKS));
-            mSyncOmnibox.setChecked(syncTypes.contains(ModelType.TYPED_URLS));
+            mSyncPaymentsIntegration.setChecked(
+                    syncAutofill && PersonalDataManager.isPaymentsIntegrationEnabled());
+            mSyncHistory.setChecked(syncTypes.contains(ModelType.TYPED_URLS));
             mSyncPasswords.setChecked(
                     passwordSyncConfigurable && syncTypes.contains(ModelType.PASSWORDS));
             mSyncRecentTabs.setChecked(syncTypes.contains(ModelType.PROXY_TABS));
             mSyncSettings.setChecked(syncTypes.contains(ModelType.PREFERENCES));
-            mPaymentsIntegration.setChecked(
-                    syncAutofill && PersonalDataManager.isPaymentsIntegrationEnabled());
         }
     }
 
@@ -783,21 +779,21 @@
     private void updatePreferences() {
         mUseSyncAndAllServices.setChecked(UnifiedConsentServiceBridge.isUnifiedConsentGiven());
 
-        mNavigationError.setChecked(mPrefServiceBridge.isResolveNavigationErrorEnabled());
-        mNetworkPredictions.setChecked(mPrefServiceBridge.getNetworkPredictionEnabled());
         mSearchSuggestions.setChecked(mPrefServiceBridge.isSearchSuggestEnabled());
+        mNetworkPredictions.setChecked(mPrefServiceBridge.getNetworkPredictionEnabled());
+        mNavigationError.setChecked(mPrefServiceBridge.isResolveNavigationErrorEnabled());
         mSafeBrowsing.setChecked(mPrefServiceBridge.isSafeBrowsingEnabled());
         mSafeBrowsingReporting.setChecked(
                 mPrefServiceBridge.isSafeBrowsingExtendedReportingEnabled());
 
         CharSequence textOn = getActivity().getResources().getText(R.string.text_on);
         CharSequence textOff = getActivity().getResources().getText(R.string.text_off);
+        mUsageAndCrashReporting.setSummary(
+                mPrivacyPrefManager.isUsageAndCrashReportingPermittedByUser() ? textOn : textOff);
         if (mContextualSearch != null) {
             boolean isContextualSearchEnabled = !mPrefServiceBridge.isContextualSearchDisabled();
             mContextualSearch.setSummary(isContextualSearchEnabled ? textOn : textOff);
         }
-        mUsageAndCrashReporting.setSummary(
-                mPrivacyPrefManager.isUsageAndCrashReportingPermittedByUser() ? textOn : textOff);
     }
 
     private ManagedPreferenceDelegate createManagedPreferenceDelegate() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
index a07af7d..589bccf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
@@ -34,6 +34,7 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.AppHooks;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.ChromeBasePreference;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.Preferences;
@@ -87,7 +88,10 @@
     public static final String PREF_CHILD_CONTENT = "child_content";
     public static final String PREF_CHILD_CONTENT_DIVIDER = "child_content_divider";
     public static final String PREF_GOOGLE_ACTIVITY_CONTROLS = "google_activity_controls";
+    public static final String PREF_GOOGLE_ACTIVITY_CONTROLS_DIVIDER =
+            "google_activity_controls_divider";
     public static final String PREF_SYNC_SETTINGS = "sync_settings";
+    public static final String PREF_SYNC_SETTINGS_DIVIDER = "sync_settings_divider";
     public static final String PREF_SIGN_OUT = "sign_out";
     public static final String PREF_SIGN_OUT_DIVIDER = "sign_out_divider";
 
@@ -221,6 +225,10 @@
             getPreferenceScreen().removePreference(signOutSwitch);
             getPreferenceScreen().removePreference(findPreference(PREF_SIGN_OUT_DIVIDER));
         } else {
+            signOutSwitch.setTitle(ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_CONSENT)
+                            ? R.string.sign_out_and_turn_off_sync
+                            : R.string.account_management_sign_out);
+
             signOutSwitch.setEnabled(getSignOutAllowedPreferenceValue());
             signOutSwitch.setOnPreferenceClickListener(preference -> {
                 if (!isVisible() || !isResumed()) return false;
@@ -260,8 +268,14 @@
     }
 
     private void configureSyncSettings() {
+        Preference syncSettings = findPreference(PREF_SYNC_SETTINGS);
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_CONSENT)) {
+            getPreferenceScreen().removePreference(syncSettings);
+            getPreferenceScreen().removePreference(findPreference(PREF_SYNC_SETTINGS_DIVIDER));
+            return;
+        }
         final Preferences preferences = (Preferences) getActivity();
-        findPreference(PREF_SYNC_SETTINGS).setOnPreferenceClickListener(preference -> {
+        syncSettings.setOnPreferenceClickListener(preference -> {
             if (!isVisible() || !isResumed()) return false;
 
             if (ProfileSyncService.get() == null) return true;
@@ -273,6 +287,12 @@
 
     private void configureGoogleActivityControls() {
         Preference pref = findPreference(PREF_GOOGLE_ACTIVITY_CONTROLS);
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_CONSENT)) {
+            getPreferenceScreen().removePreference(pref);
+            getPreferenceScreen().removePreference(
+                    findPreference(PREF_GOOGLE_ACTIVITY_CONTROLS_DIVIDER));
+            return;
+        }
         if (mProfile.isChild()) {
             pref.setSummary(R.string.sign_in_google_activity_controls_message_child_account);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
index de3ac47..2a6366b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
@@ -827,7 +827,7 @@
 
     @Override
     public boolean useModernDesign() {
-        return false;
+        return true;
     }
 
     @Override
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 3d98256..ba89f9e 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
@@ -22,7 +22,6 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.TransitionDrawable;
 import android.os.Build;
 import android.os.SystemClock;
 import android.support.annotation.IntDef;
@@ -261,8 +260,6 @@
 
     protected final int mToolbarSidePadding;
     private final int mModernLocationBarLateralInset;
-    protected int mLocationBarBackgroundCornerRadius;
-    protected int mLocationBarVerticalMargin;
 
     private ValueAnimator mBrandColorTransitionAnimation;
     private boolean mBrandColorTransitionActive;
@@ -415,33 +412,19 @@
      * Initializes the background, padding, margins, etc. for the location bar background.
      */
     protected void initLocationBarBackground() {
-        if (mLocationBar.useModernDesign()) {
-            Resources res = getResources();
-            mModernLocationBarBackgroundHeight =
-                    res.getDimensionPixelSize(R.dimen.modern_toolbar_background_size);
-            mLocationBarBackground = createModernLocationBarBackground(getResources());
-            mLocationBarBackground.getPadding(mLocationBarBackgroundPadding);
-            mLocationBarBackground.mutate();
-            mLocationBar.setPadding(mLocationBarBackgroundPadding.left,
-                    mLocationBarBackgroundPadding.top, mLocationBarBackgroundPadding.right,
-                    mLocationBarBackgroundPadding.bottom);
+        Resources res = getResources();
+        mModernLocationBarBackgroundHeight =
+                res.getDimensionPixelSize(R.dimen.modern_toolbar_background_size);
+        mLocationBarBackground = createModernLocationBarBackground(getResources());
+        mLocationBarBackground.getPadding(mLocationBarBackgroundPadding);
+        mLocationBarBackground.mutate();
+        mLocationBar.setPadding(mLocationBarBackgroundPadding.left,
+                mLocationBarBackgroundPadding.top, mLocationBarBackgroundPadding.right,
+                mLocationBarBackgroundPadding.bottom);
 
-            mModernLocationBarExtraFocusedStartMargin = getResources().getDimensionPixelSize(
-                    R.dimen.modern_toolbar_background_focused_left_margin);
-            mLocationBarBackgroundCornerRadius = 0;
-        } else {
-            mLocationBarVerticalMargin =
-                    getResources().getDimensionPixelOffset(R.dimen.location_bar_vertical_margin);
-            mLocationBarBackgroundCornerRadius =
-                    getResources().getDimensionPixelOffset(R.dimen.location_bar_corner_radius);
+        mModernLocationBarExtraFocusedStartMargin = getResources().getDimensionPixelSize(
+                R.dimen.modern_toolbar_background_focused_left_margin);
 
-            mLocationBarBackground =
-                    ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.card_single);
-            mLocationBarBackground.getPadding(mLocationBarBackgroundPadding);
-            mLocationBar.setPadding(mLocationBarBackgroundPadding.left,
-                    mLocationBarBackgroundPadding.top, mLocationBarBackgroundPadding.right,
-                    mLocationBarBackgroundPadding.bottom);
-        }
         mActiveLocationBarBackground = mLocationBarBackground;
     }
 
@@ -474,7 +457,7 @@
      */
     private int getLocationBarColorForToolbarColor(int toolbarColor) {
         return ColorUtils.getTextBoxColorForToolbarBackground(
-                getResources(), false, toolbarColor, mLocationBar.useModernDesign());
+                getResources(), false, toolbarColor, true);
     }
 
     private void inflateTabSwitchingResources() {
@@ -560,7 +543,7 @@
             });
         onHomeButtonUpdate(HomepageManager.isHomepageEnabled());
 
-        if (mNewTabButton != null && mLocationBar.useModernDesign()) mNewTabButton.setIsModern();
+        if (mNewTabButton != null) mNewTabButton.postNativeInitialization();
 
         setTabSwitcherAnimationMenuDrawable();
         updateVisualsForToolbarState();
@@ -771,12 +754,9 @@
      * @return The width of the location bar when it has focus.
      */
     protected int getFocusedLocationBarWidth(int containerWidth, int priorVisibleWidth) {
-        int width = containerWidth - (2 * mToolbarSidePadding) + priorVisibleWidth;
-
-        if (mLocationBar.useModernDesign()) {
-            width = width - mModernLocationBarExtraFocusedStartMargin
-                    - mLocationBarBackgroundPadding.left - mLocationBarBackgroundPadding.right;
-        }
+        int width = containerWidth - (2 * mToolbarSidePadding) + priorVisibleWidth
+                - mModernLocationBarExtraFocusedStartMargin - mLocationBarBackgroundPadding.left
+                - mLocationBarBackgroundPadding.right;
 
         return width;
     }
@@ -786,19 +766,11 @@
      * @return The left margin of the location bar when it has focus.
      */
     protected int getFocusedLocationBarLeftMargin(int priorVisibleWidth) {
-        if (mLocationBar.useModernDesign()) {
-            int baseMargin = mToolbarSidePadding + mLocationBarBackgroundPadding.left;
-            if (ApiCompatibilityUtils.isLayoutRtl(mLocationBar)) {
-                return baseMargin;
-            } else {
-                return baseMargin - priorVisibleWidth + mModernLocationBarExtraFocusedStartMargin;
-            }
-        }
-
+        int baseMargin = mToolbarSidePadding + mLocationBarBackgroundPadding.left;
         if (ApiCompatibilityUtils.isLayoutRtl(mLocationBar)) {
-            return mToolbarSidePadding;
+            return baseMargin;
         } else {
-            return -priorVisibleWidth + mToolbarSidePadding;
+            return baseMargin - priorVisibleWidth + mModernLocationBarExtraFocusedStartMargin;
         }
     }
 
@@ -811,7 +783,7 @@
         // Uses getMeasuredWidth()s instead of getLeft() because this is called in onMeasure
         // and the layout values have not yet been set.
         if (visualState == VisualState.NEW_TAB_NORMAL) {
-            return mLocationBar.useModernDesign() ? mToolbarSidePadding : 0;
+            return mToolbarSidePadding;
         } else if (ApiCompatibilityUtils.isLayoutRtl(this)) {
             return getBoundsAfterAccountingForRightButtons();
         } else {
@@ -839,7 +811,7 @@
         // Uses getMeasuredWidth()s instead of getRight() because this is called in onMeasure
         // and the layout values have not yet been set.
         if (visualState == VisualState.NEW_TAB_NORMAL) {
-            return getMeasuredWidth() - (mLocationBar.useModernDesign() ? mToolbarSidePadding : 0);
+            return getMeasuredWidth() - mToolbarSidePadding;
         } else if (ApiCompatibilityUtils.isLayoutRtl(this)) {
             return getMeasuredWidth() - getBoundsAfterAccountingForLeftButton();
         } else {
@@ -888,34 +860,29 @@
         Resources res = getResources();
         switch (visualState) {
             case VisualState.NEW_TAB_NORMAL:
-                if (mLocationBar.useModernDesign() && mUrlExpansionPercent == 1.f) {
+                if (mUrlExpansionPercent == 1.f) {
                     // When the location bar reaches the top of the screen, the background needs
                     // to change back to the default, solid color so that the NTP content is
                     // not visible beneath the toolbar.
-                    return ColorUtils.getDefaultThemeColor(
-                            getResources(), mLocationBar.useModernDesign(), false);
+                    return ColorUtils.getDefaultThemeColor(getResources(), true, false);
                 }
                 return Color.TRANSPARENT;
             case VisualState.NORMAL:
-                return ColorUtils.getDefaultThemeColor(
-                        getResources(), mLocationBar.useModernDesign(), false);
+                return ColorUtils.getDefaultThemeColor(getResources(), true, false);
             case VisualState.INCOGNITO:
-                return ColorUtils.getDefaultThemeColor(
-                        getResources(), mLocationBar.useModernDesign(), true);
+                return ColorUtils.getDefaultThemeColor(getResources(), true, true);
             case VisualState.BRAND_COLOR:
                 return getToolbarDataProvider().getPrimaryColor();
             case VisualState.TAB_SWITCHER_NORMAL:
             case VisualState.TAB_SWITCHER_INCOGNITO:
-                if (usingHorizontalTabSwitcher()) return Color.TRANSPARENT;
-
-                if (mLocationBar.useModernDesign()) {
-                    if (!DeviceClassManager.enableAccessibilityLayout()) return Color.TRANSPARENT;
+                if (DeviceClassManager.enableAccessibilityLayout()) {
                     int colorId = visualState == VisualState.TAB_SWITCHER_NORMAL
                             ? R.color.modern_primary_color
                             : R.color.incognito_modern_primary_color;
                     return ApiCompatibilityUtils.getColor(res, colorId);
                 }
-                return ApiCompatibilityUtils.getColor(res, R.color.tab_switcher_background);
+
+                return Color.TRANSPARENT;
             default:
                 assert false;
                 return ApiCompatibilityUtils.getColor(res, R.color.default_primary_color);
@@ -1001,7 +968,7 @@
         // - The right most visible location bar child view.
         // - The bottom of the viewport is aligned with the bottom of the location bar.
         // Additional padding can be applied for use during animations.
-        int verticalMargin = getLocationBarBackgroundVerticalMargin(expansion);
+        int verticalMargin = getLocationBarBackgroundVerticalMargin();
         out.set(leftViewPosition,
                 mLocationBar.getTop() + verticalMargin,
                 rightViewPosition,
@@ -1009,16 +976,11 @@
     }
 
     /**
-     * @param expansion The current url expansion percent.
      * @return The vertical margin to apply to the location bar background. The margin is used to
      *         clip the background.
      */
-    protected int getLocationBarBackgroundVerticalMargin(float expansion) {
-        if (mLocationBar.useModernDesign()) {
-            return (int) ((mLocationBar.getHeight() - mModernLocationBarBackgroundHeight) / 2);
-        }
-
-        return (int) MathUtils.interpolate(mLocationBarVerticalMargin, 0, expansion);
+    protected int getLocationBarBackgroundVerticalMargin() {
+        return (int) ((mLocationBar.getHeight() - mModernLocationBarBackgroundHeight) / 2);
     }
 
     /**
@@ -1038,8 +1000,7 @@
      *         has focus.
      */
     protected int getFocusedLeftPositionOfLocationBarBackground() {
-        if (mLocationBar.useModernDesign()) return mToolbarSidePadding;
-        return -mLocationBarBackgroundCornerRadius;
+        return mToolbarSidePadding;
     }
 
     /**
@@ -1060,8 +1021,7 @@
      *         has focus.
      */
     protected int getFocusedRightPositionOfLocationBarBackground() {
-        if (mLocationBar.useModernDesign()) return getWidth() - mToolbarSidePadding;
-        return getWidth() + mLocationBarBackgroundCornerRadius;
+        return getWidth() - mToolbarSidePadding;
     }
 
     private float getExpansionPercentForVisualState(@VisualState int visualState) {
@@ -1165,8 +1125,7 @@
 
         // 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 (mLocationBar.useModernDesign() && !isLocationBarShownInNTP()
-                && mTabSwitcherState == STATIC_TAB) {
+        if (!isLocationBarShownInNTP() && mTabSwitcherState == STATIC_TAB) {
             int defaultColor = ColorUtils.getDefaultThemeColor(getResources(), true, isIncognito());
             int defaultLocationBarColor = getLocationBarColorForToolbarColor(defaultColor);
             int primaryColor = getToolbarDataProvider().getPrimaryColor();
@@ -1227,9 +1186,8 @@
             if (mHomeButton != null) mHomeButton.setTranslationY(0);
         }
 
-        if (!(mLocationBar.useModernDesign() && mUrlFocusChangeInProgress)) {
-            mToolbarShadow.setAlpha(
-                    mLocationBar.useModernDesign() && mUrlBar.hasFocus() ? 0.f : 1.f);
+        if (!mUrlFocusChangeInProgress) {
+            mToolbarShadow.setAlpha(mUrlBar.hasFocus() ? 0.f : 1.f);
         }
 
         mLocationBar.setAlpha(1);
@@ -1255,11 +1213,10 @@
         if (mTabSwitcherState == TAB_SWITCHER || mTabSwitcherState == ENTERING_TAB_SWITCHER) return;
 
         boolean isExpanded = mUrlExpansionPercent > 0f;
-        boolean useModern = mLocationBar.useModernDesign();
         setAncestorsShouldClipChildren(!isExpanded);
-        if (!(useModern && mUrlFocusChangeInProgress)) {
+        if (!mUrlFocusChangeInProgress) {
             float alpha = 0.f;
-            if (useModern && !mUrlBar.hasFocus() && mNtpSearchBoxScrollPercent == 1.f) {
+            if (!mUrlBar.hasFocus() && mNtpSearchBoxScrollPercent == 1.f) {
                 alpha = 1.f;
             }
             mToolbarShadow.setAlpha(alpha);
@@ -1281,12 +1238,9 @@
 
         int leftBoundDifference = mNtpSearchBoxBounds.left - mLocationBarBackgroundBounds.left;
         int rightBoundDifference = mNtpSearchBoxBounds.right - mLocationBarBackgroundBounds.right;
-        int verticalInset = 0;
-        if (useModern) {
-            verticalInset = (int) (getResources().getDimensionPixelSize(
+        int verticalInset = (int) (getResources().getDimensionPixelSize(
                                            R.dimen.ntp_search_box_bounds_vertical_inset_modern)
-                    * (1.f - mUrlExpansionPercent));
-        }
+                * (1.f - mUrlExpansionPercent));
         mLocationBarBackgroundNtpOffset.set(
                 Math.round(leftBoundDifference * shrinkage),
                 locationBarTranslationY,
@@ -1294,13 +1248,8 @@
                 locationBarTranslationY);
         mLocationBarBackgroundNtpOffset.inset(0, verticalInset);
 
-        // The omnibox background bounds are outset by |mLocationBarBackgroundCornerRadius| in the
-        // fully expanded state (and only there!) to hide the rounded corners, so undo that before
-        // applying the shrinkage factor.
-        mLocationBarNtpOffsetLeft =
-                (leftBoundDifference - mLocationBarBackgroundCornerRadius) * shrinkage;
-        mLocationBarNtpOffsetRight =
-                (rightBoundDifference + mLocationBarBackgroundCornerRadius) * shrinkage;
+        mLocationBarNtpOffsetLeft = leftBoundDifference * shrinkage;
+        mLocationBarNtpOffsetRight = rightBoundDifference * shrinkage;
 
         mLocationBarBackgroundAlpha = isExpanded ? 255 : 0;
         mForceDrawLocationBarBackground = mLocationBarBackgroundAlpha > 0;
@@ -1549,28 +1498,6 @@
         boolean clipped = false;
         if (shouldDrawLocationBar()) {
             canvas.save();
-            int backgroundAlpha;
-            if (mTabSwitcherModeAnimation != null) {
-                // Fade out/in the location bar towards the beginning of the animations to avoid
-                // large jumps of stark white.
-                backgroundAlpha =
-                        (int) (Math.pow(mLocationBar.getAlpha(), 3) * mLocationBarBackgroundAlpha);
-            } else if (getToolbarDataProvider().isUsingBrandColor()
-                    && !mBrandColorTransitionActive) {
-                backgroundAlpha = mUnfocusedLocationBarUsesTransparentBg
-                        ? (int) (MathUtils.interpolate(LOCATION_BAR_TRANSPARENT_BACKGROUND_ALPHA,
-                                255, mUrlExpansionPercent))
-                        : 255;
-            } else {
-                backgroundAlpha = mLocationBarBackgroundAlpha;
-            }
-
-            // If modern is enabled the location bar background is opaque.
-            // TODO(mdjones): The location bar background should always be opaque. We have the
-            // capability to determine the foreground color without alpha and it reduces the amount
-            // of state that this class tracks.
-            if (mLocationBar.useModernDesign()) backgroundAlpha = 255;
-            mLocationBarBackground.setAlpha(backgroundAlpha);
 
             if (shouldDrawLocationBarBackground()) {
                 if (mActiveLocationBarBackground instanceof NtpSearchBoxDrawable) {
@@ -1649,26 +1576,10 @@
 
         // This is a workaround for http://crbug.com/574928. Since Jelly Bean is the lowest version
         // we support now and the next deprecation target, we decided to simply workaround.
-        // The drawable also has to be set here when using modern design.
-        // TODO(twellington): Update XML for modern and remove || check after modern launches.
-        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN
-                || mLocationBar.useModernDesign()) {
-            mToolbarShadow.setImageDrawable(getToolbarShadowDrawable());
+        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
+            mToolbarShadow.setImageDrawable(ApiCompatibilityUtils.getDrawable(
+                    getResources(), R.drawable.modern_toolbar_shadow));
         }
-        if (mLocationBar.useModernDesign()) {
-            mToolbarShadow.getLayoutParams().height =
-                    getResources().getDimensionPixelSize(R.dimen.toolbar_shadow_height);
-            mToolbarShadow.setScaleType(ImageView.ScaleType.FIT_XY);
-        }
-    }
-
-    /**
-     * @return The {@link Drawable} to use for the toolbar shadow.
-     */
-    private Drawable getToolbarShadowDrawable() {
-        return ApiCompatibilityUtils.getDrawable(getResources(),
-                mLocationBar.useModernDesign() ? R.drawable.modern_toolbar_shadow
-                                               : R.drawable.toolbar_shadow);
     }
 
     @Override
@@ -1749,17 +1660,15 @@
     @Override
     public void getLocationBarContentRect(Rect outRect) {
         updateLocationBarBackgroundBounds(outRect, VisualState.NORMAL);
-        if (mLocationBar.useModernDesign()) {
-            // Remove the insets for the composited version.
-            // TODO(mdjones): The image asset used to render the location bar in java is different
-            // from the one used in the compositor. The java asset has padding applied to both sides
-            // while the compositor one does not. The value manipulation here is to account for that
-            // difference. Instead we should just remove the padding from the toolbar asset, but
-            // there is much more overhead in updating the animations. Fix this once modern is the
-            // new default.
-            outRect.left -= mModernLocationBarLateralInset;
-            outRect.right += mModernLocationBarLateralInset;
-        }
+        // Remove the insets for the composited version.
+        // TODO(mdjones): The image asset used to render the location bar in java is different
+        // from the one used in the compositor. The java asset has padding applied to both sides
+        // while the compositor one does not. The value manipulation here is to account for that
+        // difference. Instead we should just remove the padding from the toolbar asset, but
+        // there is much more overhead in updating the animations. Fix this once modern is the
+        // new default.
+        outRect.left -= mModernLocationBarLateralInset;
+        outRect.right += mModernLocationBarLateralInset;
     }
 
     @Override
@@ -2154,12 +2063,10 @@
             animators.add(animator);
         }
 
-        if (mLocationBar.useModernDesign()) {
-            animator = ObjectAnimator.ofFloat(mToolbarShadow, ALPHA, 0);
-            animator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
-            animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
-            animators.add(animator);
-        }
+        animator = ObjectAnimator.ofFloat(mToolbarShadow, ALPHA, 0);
+        animator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
+        animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+        animators.add(animator);
     }
 
     private void populateUrlClearFocusingAnimatorSet(List<Animator> animators) {
@@ -2236,12 +2143,10 @@
             }
         }
 
-        if (mLocationBar.useModernDesign()) {
-            animator = ObjectAnimator.ofFloat(mToolbarShadow, ALPHA, 1);
-            animator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
-            animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
-            animators.add(animator);
-        }
+        animator = ObjectAnimator.ofFloat(mToolbarShadow, ALPHA, 1);
+        animator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
+        animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+        animators.add(animator);
     }
 
     @Override
@@ -2251,8 +2156,6 @@
         triggerUrlFocusAnimation(hasFocus);
 
         if (hasFocus) dismissTabSwitcherCallout();
-
-        transitionShadowDrawable(hasFocus);
     }
 
     protected void triggerUrlFocusAnimation(final boolean hasFocus) {
@@ -2417,10 +2320,8 @@
                 }
                 updateToolbarBackground(
                         ColorUtils.getColorWithOverlay(initialColor, finalColor, fraction));
-                if (mLocationBar.useModernDesign()) {
-                    updateModernLocationBarColor(ColorUtils.getColorWithOverlay(
-                            initialLocationBarColor, finalLocationBarColor, fraction));
-                }
+                updateModernLocationBarColor(ColorUtils.getColorWithOverlay(
+                        initialLocationBarColor, finalLocationBarColor, fraction));
             }
         });
         mBrandColorTransitionAnimation.addListener(new AnimatorListenerAdapter() {
@@ -2447,11 +2348,11 @@
         mVisibleNewTabPage = getToolbarDataProvider().getNewTabPageForCurrentTab();
         if (mVisibleNewTabPage != null && mVisibleNewTabPage.isLocationBarShownInNTP()) {
             mVisibleNewTabPage.setSearchBoxScrollListener(this);
-            if (mLocationBar.useModernDesign()) {
-                NtpSearchBoxDrawable ntpSearchBox = new NtpSearchBoxDrawable(getContext(), this);
-                mVisibleNewTabPage.setSearchBoxBackground(ntpSearchBox);
-                mActiveLocationBarBackground = ntpSearchBox;
-            }
+
+            NtpSearchBoxDrawable ntpSearchBox = new NtpSearchBoxDrawable(getContext(), this);
+            mVisibleNewTabPage.setSearchBoxBackground(ntpSearchBox);
+            mActiveLocationBarBackground = ntpSearchBox;
+
             requestLayout();
         } else if (wasShowingNtp) {
             // Convert the previous NTP scroll percentage to URL focus percentage because that
@@ -2487,27 +2388,6 @@
     @Override
     protected void handleFindToolbarStateChange(boolean showing) {
         setVisibility(showing ? View.GONE : View.VISIBLE);
-
-        transitionShadowDrawable(showing);
-    }
-
-    /**
-     * Transition the shadow drawable, if a transition drawable is being used.
-     * @param startTransition Whether the transition, showing the second layer on top of the first,
-     *                        should begin. See {@link TransitionDrawable#startTransition(int)}.
-     *                        If false, the transition will be reversed.
-     *                        See {@link TransitionDrawable#reverseTransition(int)}.
-     */
-    private void transitionShadowDrawable(boolean startTransition) {
-        // Modern does not use a transition drawable for the shadow.
-        if (mLocationBar.useModernDesign()) return;
-
-        TransitionDrawable shadowDrawable = (TransitionDrawable) mToolbarShadow.getDrawable();
-        if (startTransition) {
-            shadowDrawable.startTransition(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
-        } else {
-            shadowDrawable.reverseTransition(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
-        }
     }
 
     private boolean isLocationBarShownInNTP() {
@@ -2538,13 +2418,11 @@
     }
 
     private boolean hideShadowForIncognitoNtp() {
-        return mLocationBar.useModernDesign() && isIncognito()
-                && NewTabPage.isNTPUrl(getToolbarDataProvider().getCurrentUrl());
+        return isIncognito() && NewTabPage.isNTPUrl(getToolbarDataProvider().getCurrentUrl());
     }
 
     private boolean hideShadowForInterstitial() {
-        return mLocationBar.useModernDesign() && getToolbarDataProvider() != null
-                && getToolbarDataProvider().getTab() != null
+        return getToolbarDataProvider() != null && getToolbarDataProvider().getTab() != null
                 && (getToolbarDataProvider().getTab().isShowingInterstitialPage()
                            || getToolbarDataProvider().getTab().isShowingErrorPage());
     }
@@ -2688,9 +2566,7 @@
             getMenuButton().setTint(mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
         }
 
-        if (mLocationBar.useModernDesign()) {
-            updateModernLocationBarColor(getLocationBarColorForToolbarColor(currentPrimaryColor));
-        }
+        updateModernLocationBarColor(getLocationBarColorForToolbarColor(currentPrimaryColor));
         if (mExperimentalButton != null) {
             mExperimentalButton.setTint(mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
         }
@@ -2703,16 +2579,6 @@
         if (mIsHomeButtonEnabled && mHomeButton != null) mHomeButton.setTint(tint);
 
         mLocationBar.updateVisualsForState();
-        // Remove the side padding for incognito to ensure the badge icon aligns correctly with the
-        // background of the location bar.
-        if (mLocationBar.isIncognitoBadgeVisible()) {
-            mLocationBar.setPadding(
-                    0, mLocationBarBackgroundPadding.top, 0, mLocationBarBackgroundPadding.bottom);
-        } else {
-            mLocationBar.setPadding(
-                    mLocationBarBackgroundPadding.left, mLocationBarBackgroundPadding.top,
-                    mLocationBarBackgroundPadding.right, mLocationBarBackgroundPadding.bottom);
-        }
 
         // We update the alpha before comparing the visual state as we need to change
         // its value when entering and exiting TabSwitcher mode.
@@ -2742,12 +2608,10 @@
             getMenuButtonWrapper().setVisibility(View.VISIBLE);
         }
 
-        if (mLocationBar.useModernDesign()) {
-            DrawableCompat.setTint(mLocationBarBackground,
-                    isIncognito() ? Color.WHITE
-                                  : ApiCompatibilityUtils.getColor(
-                                            getResources(), R.color.modern_light_grey));
-        }
+        DrawableCompat.setTint(mLocationBarBackground,
+                isIncognito() ? Color.WHITE
+                              : ApiCompatibilityUtils.getColor(
+                                        getResources(), R.color.modern_light_grey));
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VR_JAVA_OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/vr/VR_JAVA_OWNERS
index 88f07e7..c356d956 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VR_JAVA_OWNERS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VR_JAVA_OWNERS
@@ -1,4 +1,3 @@
-asimjour@chromium.org
 mthiesse@chromium.org
 
 # TEAM: xr-dev@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/newtab/NewTabButton.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/newtab/NewTabButton.java
index ca8f0ae6..8897d03 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/newtab/NewTabButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/newtab/NewTabButton.java
@@ -4,9 +4,6 @@
 
 package org.chromium.chrome.browser.widget.newtab;
 
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
@@ -21,10 +18,6 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.device.DeviceClassManager;
-import org.chromium.chrome.browser.widget.animation.AnimatorProperties;
-
-import java.util.ArrayList;
-import java.util.List;
 
 /**
  * Button for creating new tabs.
@@ -33,43 +26,39 @@
 
     private final ColorStateList mLightModeTint;
     private final ColorStateList mDarkModeTint;
-    private Drawable mNormalDrawable;
-    private Drawable mIncognitoDrawable;
     private VectorDrawableCompat mModernDrawable;
     private boolean mIsIncognito;
-    private AnimatorSet mTransitionAnimation;
+    private boolean mIsNativeReady;
 
     /**
      * Constructor for inflating from XML.
      */
     public NewTabButton(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mNormalDrawable = ApiCompatibilityUtils.getDrawable(
-                getResources(), R.drawable.btn_new_tab_white);
-        mNormalDrawable.setBounds(
-                0, 0, mNormalDrawable.getIntrinsicWidth(), mNormalDrawable.getIntrinsicHeight());
-        mNormalDrawable.setCallback(this);
-        mIncognitoDrawable = ApiCompatibilityUtils.getDrawable(
-                getResources(), R.drawable.btn_new_tab_incognito);
-        mIncognitoDrawable.setBounds(
-                0, 0,
-                mIncognitoDrawable.getIntrinsicWidth(), mIncognitoDrawable.getIntrinsicHeight());
-        mIncognitoDrawable.setCallback(this);
+
         mIsIncognito = false;
         mLightModeTint =
                 AppCompatResources.getColorStateList(getContext(), R.color.light_mode_tint);
         mDarkModeTint = AppCompatResources.getColorStateList(getContext(), R.color.dark_mode_tint);
+        mModernDrawable = VectorDrawableCompat.create(
+                getContext().getResources(), R.drawable.new_tab_icon, getContext().getTheme());
+        mModernDrawable.setBounds(
+                0, 0, mModernDrawable.getIntrinsicWidth(), mModernDrawable.getIntrinsicHeight());
+        mModernDrawable.setCallback(this);
+    }
+
+    /**
+     * Called to finish initializing the NewTabButton. Must be called after native initialization
+     * is finished.
+     */
+    public void postNativeInitialization() {
+        mIsNativeReady = true;
+        updateDrawableTint();
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int desiredWidth;
-        if (mModernDrawable != null) {
-            desiredWidth = mModernDrawable.getIntrinsicWidth();
-        } else {
-            desiredWidth = Math.max(
-                    mIncognitoDrawable.getIntrinsicWidth(), mNormalDrawable.getIntrinsicWidth());
-        }
+        int desiredWidth = mModernDrawable.getIntrinsicWidth();
         desiredWidth += getPaddingLeft() + getPaddingRight();
         widthMeasureSpec = MeasureSpec.makeMeasureSpec(desiredWidth, MeasureSpec.EXACTLY);
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -86,15 +75,7 @@
         canvas.save();
         if (!isRtl) canvas.translate(paddingStart, 0);
 
-        if (mModernDrawable != null) {
-            drawIcon(canvas, mModernDrawable, isRtl, widthWithoutPadding);
-        } else {
-            drawIcon(canvas, mNormalDrawable, isRtl, widthWithoutPadding);
-            if (mIsIncognito
-                    || (mTransitionAnimation != null && mTransitionAnimation.isRunning())) {
-                drawIcon(canvas, mIncognitoDrawable, isRtl, widthWithoutPadding);
-            }
-        }
+        drawIcon(canvas, mModernDrawable, isRtl, widthWithoutPadding);
 
         canvas.restore();
     }
@@ -111,7 +92,7 @@
 
     @Override
     public void invalidateDrawable(Drawable dr) {
-        if (dr == mIncognitoDrawable || dr == mNormalDrawable || dr == mModernDrawable) {
+        if (dr == mModernDrawable) {
             invalidate();
         } else {
             super.invalidateDrawable(dr);
@@ -119,22 +100,6 @@
     }
 
     /**
-     * Set the icon to use the drawable for Chrome Modern.
-     */
-    public void setIsModern() {
-        mModernDrawable = VectorDrawableCompat.create(
-                getContext().getResources(), R.drawable.new_tab_icon, getContext().getTheme());
-        mModernDrawable.setState(getDrawableState());
-        updateDrawableTint();
-        mModernDrawable.setBounds(
-                0, 0, mModernDrawable.getIntrinsicWidth(), mModernDrawable.getIntrinsicHeight());
-        mModernDrawable.setCallback(this);
-
-        mNormalDrawable = null;
-        mIncognitoDrawable = null;
-    }
-
-    /**
      * Updates the visual state based on whether incognito or normal tabs are being created.
      * @param incognito Whether the button is now used for creating incognito tabs.
      */
@@ -142,41 +107,8 @@
         if (mIsIncognito == incognito) return;
         mIsIncognito = incognito;
 
-        if (mModernDrawable != null) {
-            updateDrawableTint();
-            invalidateDrawable(mModernDrawable);
-            return;
-        }
-
-        if (mTransitionAnimation != null) {
-            mTransitionAnimation.cancel();
-            mTransitionAnimation = null;
-        }
-
-        Drawable fadeOutDrawable = incognito ? mNormalDrawable : mIncognitoDrawable;
-        Drawable fadeInDrawable = incognito ? mIncognitoDrawable : mNormalDrawable;
-
-        if (getVisibility() != VISIBLE) {
-            fadeOutDrawable.setAlpha(0);
-            fadeInDrawable.setAlpha(255);
-            return;
-        }
-
-        List<Animator> animations = new ArrayList<Animator>();
-        Animator animation = ObjectAnimator.ofInt(
-                fadeOutDrawable, AnimatorProperties.DRAWABLE_ALPHA_PROPERTY, 255, 0);
-        animation.setDuration(100);
-        animations.add(animation);
-
-        animation = ObjectAnimator.ofInt(
-                fadeInDrawable, AnimatorProperties.DRAWABLE_ALPHA_PROPERTY, 0, 255);
-        animation.setStartDelay(150);
-        animation.setDuration(100);
-        animations.add(animation);
-
-        mTransitionAnimation = new AnimatorSet();
-        mTransitionAnimation.playTogether(animations);
-        mTransitionAnimation.start();
+        updateDrawableTint();
+        invalidateDrawable(mModernDrawable);
     }
 
     /** Called when accessibility status is changed. */
@@ -188,20 +120,15 @@
     protected void drawableStateChanged() {
         super.drawableStateChanged();
 
-        if (mModernDrawable != null) {
-            mModernDrawable.setState(getDrawableState());
-        } else {
-            mNormalDrawable.setState(getDrawableState());
-            mIncognitoDrawable.setState(getDrawableState());
-        }
+        mModernDrawable.setState(getDrawableState());
     }
 
     /** Update the tint for the icon drawable for Chrome Modern. */
     private void updateDrawableTint() {
-        final boolean shouldUseLightMode =
-                (DeviceClassManager.enableAccessibilityLayout()
-                        || ChromeFeatureList.isEnabled(
-                                   ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID))
+        final boolean shouldUseLightMode = mIsNativeReady
+                && (DeviceClassManager.enableAccessibilityLayout()
+                           || ChromeFeatureList.isEnabled(
+                                      ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID))
                 && mIsIncognito;
         mModernDrawable.setTintList(shouldUseLightMode ? mLightModeTint : mDarkModeTint);
     }
diff --git a/chrome/android/java/strings/OWNERS b/chrome/android/java/strings/OWNERS
new file mode 100644
index 0000000..8cb2f0b
--- /dev/null
+++ b/chrome/android/java/strings/OWNERS
@@ -0,0 +1,6 @@
+# Please ensure you check for duplicate strings before adding new ones.
+#
+# Prefer generalizing feature specific existing strings instead of creating
+# a new version of the same (or an extremely similiar string).
+
+*
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index ce32e6ab..d1c134c 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -313,6 +313,9 @@
         Sync error occurred, tap to get details.
       </message>
       <!-- Unified consent preferences -->
+      <message name="IDS_SIGN_OUT_AND_TURN_OFF_SYNC" desc="The text for a preferences row that for signs out the user and turns off sync.">
+        Sign out and turn off sync
+      </message>
       <message name="IDS_USE_SYNC_AND_ALL_SERVICES" desc="Title for switch preference which enables sync'ing of all data types and turns on all Chrome services that communicate with Google.">
         Use sync and all services
       </message>
@@ -1589,7 +1592,7 @@
       <message name="IDS_PAYMENTS_INTEGRATION_LEGACY" desc="Title for preference which enables import of Google Pay data for Autofill. 'Google Pay' should not be translated as it is the product name.">
         Cards and addresses using Google Pay
       </message>
-      <message name="IDS_PAYMENTS_INTEGRATION" desc="Title for preference which enables import of Google Pay data for Autofill. 'Google Pay' should not be translated as it is the product name.">
+      <message name="IDS_SYNC_PAYMENTS_INTEGRATION" desc="Title for preference which enables import of Google Pay data for Autofill. 'Google Pay' should not be translated as it is the product name.">
         Credit cards and addresses using Google Pay
       </message>
       <message name="IDS_SYNC_ACTIVITY_AND_INTERACTIONS_TITLE" desc="Title for preference which enables sync'ing of activity and interactions.">
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
index 51787c3..6ee61d26 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
@@ -262,6 +262,36 @@
     }
 
     @Test
+    public void testPasswordTabRestoredWhenClosingTabIsUndone() {
+        ManualFillingMediator mediator = mController.getMediatorForTesting();
+        KeyboardAccessoryModel keyboardAccessoryModel =
+                mediator.getKeyboardAccessory().getMediatorForTesting().getModelForTesting();
+        assertThat(keyboardAccessoryModel.getTabList().size(), is(0));
+
+        // Create a new tab with a passwords tab:
+        Tab tab = addTab(mediator, 1111, null);
+        mController.registerPasswordProvider(new PropertyProvider<>());
+        assertThat(keyboardAccessoryModel.getTabList().size(), is(1));
+
+        // Simulate closing the tab:
+        mediator.getTabModelObserverForTesting().willCloseTab(tab, false);
+        mediator.getTabObserverForTesting().onHidden(tab);
+        // Temporary removes the tab, but keeps it in memory so it can be brought back on undo:
+        assertThat(keyboardAccessoryModel.getTabList().size(), is(0));
+
+        // Simulate undo closing the tab and selecting it:
+        mediator.getTabModelObserverForTesting().tabClosureUndone(tab);
+        switchTab(mediator, null, tab);
+        // There should still be a tab in the accessory:
+        assertThat(keyboardAccessoryModel.getTabList().size(), is(1));
+
+        // Simulate closing the tab and committing to it (i.e. wait out undo message):
+        closeTab(mediator, tab, null);
+        mediator.getTabModelObserverForTesting().tabClosureCommitted(tab);
+        assertThat(keyboardAccessoryModel.getTabList().size(), is(0));
+    }
+
+    @Test
     public void testRecoversFromInvalidState() {
         ManualFillingMediator mediator = mController.getMediatorForTesting();
 
diff --git a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java
index e060f056..7f0cf03 100644
--- a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java
+++ b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java
@@ -31,5 +31,7 @@
             "org.chromium.webapk.shell_apk.iconUrlsAndIconMurmur2Hashes";
     public static final String WEB_MANIFEST_URL = "org.chromium.webapk.shell_apk.webManifestUrl";
     public static final String BADGE_ICON_ID = "org.chromium.webapk.shell_apk.badgeIconId";
-    public static final String SHARE_TEMPLATE = "org.chromium.webapk.shell_apk.shareTemplate";
+    public static final String SHARE_ACTION = "org.chromium.webapk.shell_apk.shareAction";
+    public static final String SHARE_PARAM_TITLE = "org.chromium.webapk.shell_apk.shareParamTitle";
+    public static final String SHARE_PARAM_TEXT = "org.chromium.webapk.shell_apk.shareParamText";
 }
diff --git a/chrome/android/webapk/shell_apk/AndroidManifest.xml b/chrome/android/webapk/shell_apk/AndroidManifest.xml
index 4d9094a..c38a779 100644
--- a/chrome/android/webapk/shell_apk/AndroidManifest.xml
+++ b/chrome/android/webapk/shell_apk/AndroidManifest.xml
@@ -43,7 +43,10 @@
                   android:label="{{{title}}}"
                   android:theme="@android:style/Theme.Translucent.NoTitleBar"
                   android:excludeFromRecents="true">
-          <meta-data android:name="org.chromium.webapk.shell_apk.shareTemplate" android:value="{{{url_template}}}" />
+          <meta-data android:name="org.chromium.webapk.shell_apk.shareAction" android:value="{{{action}}}" />
+          <meta-data android:name="org.chromium.webapk.shell_apk.shareParamTitle" android:value="{{{param_title}}}" />
+          <meta-data android:name="org.chromium.webapk.shell_apk.shareParamText" android:value="{{{param_text}}}" />
+          <meta-data android:name="org.chromium.webapk.shell_apk.shareParamUrl" android:value="{{{param_url}}}" />
           <intent-filter>
             <action android:name="android.intent.action.SEND" />
             <category android:name="android.intent.category.DEFAULT" />
diff --git a/chrome/android/webapk/shell_apk/BUILD.gn b/chrome/android/webapk/shell_apk/BUILD.gn
index 019d3ac..820c183 100644
--- a/chrome/android/webapk/shell_apk/BUILD.gn
+++ b/chrome/android/webapk/shell_apk/BUILD.gn
@@ -221,6 +221,7 @@
   java_files = [
     "junit/src/org/chromium/webapk/shell_apk/HostBrowserClassLoaderTest.java",
     "junit/src/org/chromium/webapk/shell_apk/MainActivityTest.java",
+    "junit/src/org/chromium/webapk/shell_apk/ShareActivityTest.java",
     "junit/src/org/chromium/webapk/shell_apk/WebApkServiceImplWrapperTest.java",
     "junit/src/org/chromium/webapk/shell_apk/WebApkUtilsTest.java",
   ]
diff --git a/chrome/android/webapk/shell_apk/bound_manifest_config.json b/chrome/android/webapk/shell_apk/bound_manifest_config.json
index 51be5688..1f07f4b 100644
--- a/chrome/android/webapk/shell_apk/bound_manifest_config.json
+++ b/chrome/android/webapk/shell_apk/bound_manifest_config.json
@@ -24,11 +24,18 @@
   "share_template": [{
 	  "index": "0",
 	  "title": "Share All",
-	  "url_template": "https://pwa.rocks/share_public?title={title}&amp;text={text}&amp;url={url}"
+	  "action": "https://pwa.rocks/share.html",
+	  "param_title": "title",
+	  "param_text": "text",
+	  "param_url": "url"
   },
   {
 	  "index": "1",
 	  "title": "Share Title",
-	  "url_template": "https://pwa.rocks/share_private?title={title}"
+	  "action": "https://pwa.rocks/share_title.html",
+	  "param_title": "title",
+	  "param_text": "text",
+	  "param_url": "url"
   }]
+
 }
diff --git a/chrome/android/webapk/shell_apk/http_manifest_config.json b/chrome/android/webapk/shell_apk/http_manifest_config.json
index 044c4cd..064d5952 100644
--- a/chrome/android/webapk/shell_apk/http_manifest_config.json
+++ b/chrome/android/webapk/shell_apk/http_manifest_config.json
@@ -24,11 +24,17 @@
   "share_template": [{
 	  "index": "0",
 	  "title": "Share All",
-	  "url_template": "http://pwa.rocks/share_public?title={title}&amp;text={text}&amp;url={url}"
+	  "action": "http://pwa.rocks/share.html",
+	  "param_title": "title",
+	  "param_text": "text",
+	  "param_url": "url"
   },
   {
 	  "index": "1",
 	  "title": "Share Title",
-	  "url_template": "http://pwa.rocks/share_private?title={title}"
+	  "action": "http://pwa.rocks/share_title.html",
+	  "param_title": "title",
+	  "param_text": "text",
+	  "param_url": "url"
   }]
 }
diff --git a/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/ShareActivityTest.java b/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/ShareActivityTest.java
new file mode 100644
index 0000000..751b37c8
--- /dev/null
+++ b/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/ShareActivityTest.java
@@ -0,0 +1,96 @@
+// 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.webapk.shell_apk;
+
+import android.util.Pair;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for ShareActivity's WebShareTarget parsing.
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class ShareActivityTest {
+    /*
+     * Test that {@link ShareActivity#createWebShareTargetUriString()} handles adding query
+     * parameters to an action url with different path formats.
+     */
+    @Test
+    public void testCreateWebShareTargetUriStringBasic() {
+        ArrayList<Pair<String, String>> params = new ArrayList<>();
+        params.add(new Pair<>("title", "mytitle"));
+        params.add(new Pair<>("foo", "bar"));
+
+        String uri =
+                ShareActivity.createWebShareTargetUriString("https://www.chromium.org/wst", params);
+        Assert.assertEquals("https://www.chromium.org/wst?title=mytitle&foo=bar", uri);
+
+        uri = ShareActivity.createWebShareTargetUriString("https://www.chromium.org/wst/", params);
+        Assert.assertEquals("https://www.chromium.org/wst/?title=mytitle&foo=bar", uri);
+
+        uri = ShareActivity.createWebShareTargetUriString(
+                "https://www.chromium.org/base/wst.html", params);
+        Assert.assertEquals("https://www.chromium.org/base/wst.html?title=mytitle&foo=bar", uri);
+
+        uri = ShareActivity.createWebShareTargetUriString(
+                "https://www.chromium.org/base/wst.html/", params);
+        Assert.assertEquals("https://www.chromium.org/base/wst.html/?title=mytitle&foo=bar", uri);
+    }
+
+    /*
+     * Test that {@link ShareActivity#createWebShareTargetUriString()} skips null names or values.
+     */
+    @Test
+    public void testCreateWebShareTargetUriStringNull() {
+        ArrayList<Pair<String, String>> params = new ArrayList<>();
+        params.add(new Pair<>(null, "mytitle"));
+        params.add(new Pair<>("foo", null));
+        params.add(new Pair<>("hello", "world"));
+        params.add(new Pair<>(null, null));
+        // The baseUrl, shareAction and params are checked to be non-null in
+        // ShareActivity#extractShareTarget.
+        String uri =
+                ShareActivity.createWebShareTargetUriString("https://www.chromium.org/wst", params);
+        Assert.assertEquals("https://www.chromium.org/wst?hello=world", uri);
+    }
+
+    /*
+     * Test that {@link ShareActivity#createWebShareTargetUriString()} handles replacing the query
+     * string of an action url with an existing query.
+     */
+    @Test
+    public void testCreateWebShareTargetClearQuery() {
+        ArrayList<Pair<String, String>> params = new ArrayList<>();
+        params.add(new Pair<>("hello", "world"));
+        params.add(new Pair<>("foobar", "baz"));
+        String uri = ShareActivity.createWebShareTargetUriString(
+                "https://www.chromium.org/wst?a=b&c=d", params);
+        Assert.assertEquals("https://www.chromium.org/wst?hello=world&foobar=baz", uri);
+    }
+
+    /*
+     * Test that {@link ShareActivity#createWebShareTargetUriString()} escapes characters.
+     */
+    @Test
+    public void testCreateWebShareTargetEscaping() {
+        ArrayList<Pair<String, String>> params = new ArrayList<>();
+        params.add(new Pair<>("hello", "world !\"#$%&'()*+,-./0?@[\\]^_a`{}~"));
+        params.add(new Pair<>("foo bar", "baz"));
+        params.add(new Pair<>("a!\"#$%&'()*+,-./0?@[\\]^_a`{}~", "b"));
+        String uri = ShareActivity.createWebShareTargetUriString(
+                "https://www.chromium.org/wst%25%20space", params);
+        Assert.assertEquals(
+                "https://www.chromium.org/wst%25%20space?hello=world+!%22%23%24%25%26'()*%2B%2C-.%2F0%3F%40%5B%5C%5D%5E_a%60%7B%7D~&foo+bar=baz&a!%22%23%24%25%26'()*%2B%2C-.%2F0%3F%40%5B%5C%5D%5E_a%60%7B%7D~=b",
+                uri);
+    }
+}
diff --git a/chrome/android/webapk/shell_apk/shell_apk_version.gni b/chrome/android/webapk/shell_apk/shell_apk_version.gni
index ccbdc1d..db6bfe1 100644
--- a/chrome/android/webapk/shell_apk/shell_apk_version.gni
+++ b/chrome/android/webapk/shell_apk/shell_apk_version.gni
@@ -6,7 +6,7 @@
 # (including AndroidManifest.xml) is updated. This version should be incremented
 # prior to uploading a new ShellAPK to the WebAPK Minting Server.
 # Does not affect Chrome.apk
-template_shell_apk_version = 48
+template_shell_apk_version = 49
 
 # The ShellAPK version expected by Chrome. Chrome will try to update the WebAPK
 # if the WebAPK's ShellAPK version is less than |expected_shell_apk_version|.
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ShareActivity.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ShareActivity.java
index 2aa7e6f..3d76f7d3c 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ShareActivity.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ShareActivity.java
@@ -12,14 +12,12 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.text.TextUtils;
+import android.util.Pair;
 
 import org.chromium.webapk.lib.common.WebApkConstants;
 import org.chromium.webapk.lib.common.WebApkMetaDataKeys;
 
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.ArrayList;
 
 /**
  * WebAPK's share handler Activity.
@@ -43,65 +41,60 @@
     }
 
     private String extractShareTarget() {
-        ActivityInfo ai;
+        ActivityInfo shareActivityInfo;
         try {
-            ai = getPackageManager().getActivityInfo(
+            shareActivityInfo = getPackageManager().getActivityInfo(
                     getComponentName(), PackageManager.GET_META_DATA);
         } catch (PackageManager.NameNotFoundException e) {
             return null;
         }
-        if (ai == null || ai.metaData == null) {
+        if (shareActivityInfo == null || shareActivityInfo.metaData == null) {
+            return null;
+        }
+        Bundle metaData = shareActivityInfo.metaData;
+
+        String shareAction = metaData.getString(WebApkMetaDataKeys.SHARE_ACTION);
+        if (TextUtils.isEmpty(shareAction)) {
             return null;
         }
 
-        String shareTemplate = ai.metaData.getString(WebApkMetaDataKeys.SHARE_TEMPLATE);
-        if (TextUtils.isEmpty(shareTemplate)) {
-            return null;
-        }
+        // These can be null, they are checked downstream.
+        ArrayList<Pair<String, String>> entryList = new ArrayList<>();
+        entryList.add(new Pair<>(metaData.getString(WebApkMetaDataKeys.SHARE_PARAM_TITLE),
+                getIntent().getStringExtra(Intent.EXTRA_SUBJECT)));
+        entryList.add(new Pair<>(metaData.getString(WebApkMetaDataKeys.SHARE_PARAM_TEXT),
+                getIntent().getStringExtra(Intent.EXTRA_TEXT)));
 
-        String text = getIntent().getStringExtra(Intent.EXTRA_TEXT);
-        String shareUrl = getIntent().getStringExtra(Intent.EXTRA_SUBJECT);
-        Uri shareTemplateUri = Uri.parse(shareTemplate);
-        return shareTemplateUri.buildUpon()
-                .encodedQuery(
-                        replacePlaceholders(shareTemplateUri.getEncodedQuery(), text, shareUrl))
-                .encodedFragment(
-                        replacePlaceholders(shareTemplateUri.getEncodedFragment(), text, shareUrl))
-                .build()
-                .toString();
+        return createWebShareTargetUriString(shareAction, entryList);
     }
 
     /**
-     * Replace {} placeholders in {@link toFill}. "{text}" and "{title}" are replaced with the
-     * supplied strings. All other placeholders are deleted.
+     * Converts the action url and parameters of a webshare target into a URI.
+     * Example:
+     * - action = "https://example.org/includinator/share.html"
+     * - params
+     *     title param: "title"
+     *     title intent: "news"
+     *     text param: "description"
+     *     text intent: "story"
+     * Becomes:
+     *   https://example.org/includinator/share.html?title=news&description=story
+     * TODO(ckitagawa): The escaping behavior isn't entirely correct. The exact encoding is still
+     * being discussed at https://github.com/WICG/web-share-target/issues/59.
      */
-    private String replacePlaceholders(String toFill, String text, String title) {
-        if (toFill == null) {
-            return null;
-        }
-
-        Pattern placeholder = Pattern.compile("\\{.*?\\}");
-        Matcher matcher = placeholder.matcher(toFill);
-        StringBuffer buffer = new StringBuffer();
-        while (matcher.find()) {
-            String replacement = "";
-            if (matcher.group().equals("{text}")) {
-                replacement = text;
-            } else if (matcher.group().equals("{title}")) {
-                replacement = title;
+    protected static String createWebShareTargetUriString(
+            String action, ArrayList<Pair<String, String>> entryList) {
+        Uri.Builder queryBuilder = new Uri.Builder();
+        for (Pair<String, String> nameValue : entryList) {
+            if (!TextUtils.isEmpty(nameValue.first) && !TextUtils.isEmpty(nameValue.second)) {
+                // Uri.Builder does URL escaping.
+                queryBuilder.appendQueryParameter(nameValue.first, nameValue.second);
             }
-
-            String encodedReplacement = "";
-            if (replacement != null) {
-                try {
-                    encodedReplacement = URLEncoder.encode(replacement, "UTF-8");
-                } catch (UnsupportedEncodingException e) {
-                    // Should not be reached.
-                }
-            }
-            matcher.appendReplacement(buffer, encodedReplacement);
         }
-        matcher.appendTail(buffer);
-        return buffer.toString();
+        Uri shareUri = Uri.parse(action);
+        Uri.Builder builder = shareUri.buildUpon();
+        // Uri.Builder uses %20 rather than + for spaces, the spec requires +.
+        builder.encodedQuery(queryBuilder.build().toString().replace("%20", "+").substring(1));
+        return builder.build().toString();
     }
 }
diff --git a/chrome/browser/android/autofill_assistant/assistant_ui_controller_android.cc b/chrome/browser/android/autofill_assistant/assistant_ui_controller_android.cc
index d715b55..f6de6db6 100644
--- a/chrome/browser/android/autofill_assistant/assistant_ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/assistant_ui_controller_android.cc
@@ -55,6 +55,18 @@
                                            java_assistant_ui_controller_);
 }
 
+void AssistantUiControllerAndroid::ChooseAddress(
+    base::OnceCallback<void(const std::string&)> callback) {
+  // TODO(crbug.com/806868): Implement ChooseAddress.
+  std::move(callback).Run("");
+}
+
+void AssistantUiControllerAndroid::ChooseCard(
+    base::OnceCallback<void(const std::string&)> callback) {
+  // TODO(crbug.com/806868): Implement ChooseCard.
+  std::move(callback).Run("");
+}
+
 void AssistantUiControllerAndroid::Destroy(JNIEnv* env,
                                            const JavaParamRef<jobject>& obj) {
   ui_delegate_->OnDestroy();
diff --git a/chrome/browser/android/autofill_assistant/assistant_ui_controller_android.h b/chrome/browser/android/autofill_assistant/assistant_ui_controller_android.h
index f943ce1..97bf928e 100644
--- a/chrome/browser/android/autofill_assistant/assistant_ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/assistant_ui_controller_android.h
@@ -27,6 +27,10 @@
   void ShowStatusMessage(const std::string& message) override;
   void ShowOverlay() override;
   void HideOverlay() override;
+  void ChooseAddress(
+      base::OnceCallback<void(const std::string&)> callback) override;
+  void ChooseCard(
+      base::OnceCallback<void(const std::string&)> callback) override;
 
   // Called by Java.
   void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
@@ -41,4 +45,4 @@
 };
 
 }  // namespace autofill_assistant.
-#endif  // CHROME_BROWSER_ANDROID_AUTOFILL_ASSISTANT_ASSISTANT_UI_CONTROLLER_ANDROID_H_
\ No newline at end of file
+#endif  // CHROME_BROWSER_ANDROID_AUTOFILL_ASSISTANT_ASSISTANT_UI_CONTROLLER_ANDROID_H_
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index ee168e3..f6f3a49 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -221,7 +221,7 @@
                                            base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kCCTResourcePrefetch{"CCTResourcePrefetch",
-                                         base::FEATURE_DISABLED_BY_DEFAULT};
+                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kChromeDuetFeature{"ChromeDuet",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/password_manager/password_accessory_view_android.cc b/chrome/browser/android/password_manager/password_accessory_view_android.cc
index 37acb1c..424a322 100644
--- a/chrome/browser/android/password_manager/password_accessory_view_android.cc
+++ b/chrome/browser/android/password_manager/password_accessory_view_android.cc
@@ -69,8 +69,8 @@
       base::android::AttachCurrentThread(), java_object_);
 }
 
-void PasswordAccessoryViewAndroid::OpenKeyboard() {
-  Java_PasswordAccessoryBridge_openKeyboard(
+void PasswordAccessoryViewAndroid::SwapSheetWithKeyboard() {
+  Java_PasswordAccessoryBridge_swapSheetWithKeyboard(
       base::android::AttachCurrentThread(), java_object_);
 }
 
diff --git a/chrome/browser/android/password_manager/password_accessory_view_android.h b/chrome/browser/android/password_manager/password_accessory_view_android.h
index 413b9f1..3d0d2f9 100644
--- a/chrome/browser/android/password_manager/password_accessory_view_android.h
+++ b/chrome/browser/android/password_manager/password_accessory_view_android.h
@@ -30,7 +30,7 @@
   void OnItemsAvailable(const std::vector<AccessoryItem>& items) override;
   void OnAutomaticGenerationStatusChanged(bool available) override;
   void CloseAccessorySheet() override;
-  void OpenKeyboard() override;
+  void SwapSheetWithKeyboard() override;
 
   // Called from Java via JNI:
   void OnFaviconRequested(
diff --git a/chrome/browser/android/shortcut_info.cc b/chrome/browser/android/shortcut_info.cc
index 864d9926..ca946dc 100644
--- a/chrome/browser/android/shortcut_info.cc
+++ b/chrome/browser/android/shortcut_info.cc
@@ -71,8 +71,16 @@
   for (const auto& icon : manifest.icons)
     icon_urls.push_back(icon.src.spec());
 
-  if (manifest.share_target)
-    share_target_url_template = manifest.share_target->url_template;
+  if (manifest.share_target) {
+    share_target = ShareTarget();
+    share_target->action = manifest.share_target->action;
+    if (!manifest.share_target->params.text.is_null())
+      share_target->params.text = manifest.share_target->params.text.string();
+    if (!manifest.share_target->params.title.is_null())
+      share_target->params.title = manifest.share_target->params.title.string();
+    if (!manifest.share_target->params.url.is_null())
+      share_target->params.url = manifest.share_target->params.url.string();
+  }
 }
 
 void ShortcutInfo::UpdateSource(const Source new_source) {
diff --git a/chrome/browser/android/shortcut_info.h b/chrome/browser/android/shortcut_info.h
index 809b37b..b594bd88 100644
--- a/chrome/browser/android/shortcut_info.h
+++ b/chrome/browser/android/shortcut_info.h
@@ -16,6 +16,19 @@
 #include "third_party/skia/include/core/SkColor.h"
 #include "url/gurl.h"
 
+// https://wicg.github.io/web-share-target/#dom-sharetargetparams
+struct ShareTargetParams {
+  base::string16 title;
+  base::string16 text;
+  base::string16 url;
+};
+
+// https://wicg.github.io/web-share-target/#dom-sharetarget
+struct ShareTarget {
+  GURL action;
+  ShareTargetParams params;
+};
+
 // Information needed to create a shortcut via ShortcutHelper.
 struct ShortcutInfo {
 
@@ -96,7 +109,7 @@
   GURL best_primary_icon_url;
   GURL best_badge_icon_url;
   std::vector<std::string> icon_urls;
-  GURL share_target_url_template;
+  base::Optional<ShareTarget> share_target;
 };
 
 #endif  // CHROME_BROWSER_ANDROID_SHORTCUT_INFO_H_
diff --git a/chrome/browser/android/vr/OWNERS b/chrome/browser/android/vr/OWNERS
index 26161de..7b73e4ba45 100644
--- a/chrome/browser/android/vr/OWNERS
+++ b/chrome/browser/android/vr/OWNERS
@@ -1,4 +1,3 @@
-asimjour@chromium.org
 cjgrant@chromium.org
 mthiesse@chromium.org
 tiborg@chromium.org
diff --git a/chrome/browser/android/webapk/webapk.proto b/chrome/browser/android/webapk/webapk.proto
index d889523..183c5b8 100644
--- a/chrome/browser/android/webapk/webapk.proto
+++ b/chrome/browser/android/webapk/webapk.proto
@@ -95,7 +95,6 @@
 }
 
 message Image {
-
   enum Usage {
     PRIMARY_ICON = 1;
     BADGE_ICON = 2;
@@ -118,8 +117,25 @@
   reserved 2, 3, 4, 7;
 }
 
+// A proto representing ShareTargetParams
+// https://wicg.github.io/web-share-target/#dom-sharetargetparams
+// Each field corresponds to key in ShareData. These are the query parameter
+// keys to be used for the data supplied in a ShareData instance.
+// ShareData: https://wicg.github.io/web-share#dom-sharedata
+message ShareTargetParams {
+  optional string title = 1;
+  optional string text = 2;
+  optional string url = 3;
+}
+
+// A proto representing a ShareTarget.
+// https://wicg.github.io/web-share-target/#dom-sharetarget
 message ShareTarget {
-  // The URL template that contains placeholders to be replaced with shared
-  // data.
-  optional string url_template = 1;
+  // The URL to be resolved when sharing.
+  optional string action = 2;
+  optional ShareTargetParams params = 3;
+  // TODO(ckitagawa):
+  // Add method and enctype for POST (GET by default).
+
+  reserved 1;
 }
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc
index 510af09..67651b0 100644
--- a/chrome/browser/android/webapk/webapk_installer.cc
+++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -214,10 +214,17 @@
   std::string* scope = web_app_manifest->add_scopes();
   scope->assign(GetScope(shortcut_info).spec());
 
-  if (!shortcut_info.share_target_url_template.is_empty()) {
+  if (shortcut_info.share_target) {
     webapk::ShareTarget* share_target = web_app_manifest->add_share_targets();
-    share_target->set_url_template(
-        shortcut_info.share_target_url_template.spec());
+    share_target->set_action(shortcut_info.share_target->action.spec());
+    webapk::ShareTargetParams* share_target_params =
+        share_target->mutable_params();
+    share_target_params->set_title(
+        base::UTF16ToUTF8(shortcut_info.share_target->params.title));
+    share_target_params->set_text(
+        base::UTF16ToUTF8(shortcut_info.share_target->params.text));
+    share_target_params->set_url(
+        base::UTF16ToUTF8(shortcut_info.share_target->params.url));
   }
 
   if (shortcut_info.best_primary_icon_url.is_empty()) {
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 1ab4de97b..6d53e3d 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -4430,3 +4430,26 @@
       embedder->GetRenderWidgetHostView()->GetRenderWidgetHost()->GetProcess(),
       guest->GetRenderWidgetHostView()->GetRenderWidgetHost()));
 }
+
+// Test that a guest sees the synthetic wheel events of a touchpad pinch.
+IN_PROC_BROWSER_TEST_F(WebViewTest, TouchpadPinchSyntheticWheelEvents) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  LoadAppWithGuest("web_view/touchpad_pinch");
+  content::WebContents* guest_contents = GetGuestWebContents();
+
+  // Ensure the compositor thread is aware of the wheel listener.
+  content::MainThreadFrameObserver synchronize_threads(
+      guest_contents->GetRenderWidgetHostView()->GetRenderWidgetHost());
+  synchronize_threads.Wait();
+
+  ExtensionTestMessageListener synthetic_wheel_listener("Seen wheel event",
+                                                        false);
+
+  const gfx::Rect contents_rect = guest_contents->GetContainerBounds();
+  const gfx::Point pinch_position(contents_rect.width() / 2,
+                                  contents_rect.height() / 2);
+  content::SimulateGesturePinchSequence(guest_contents, pinch_position, 1.23,
+                                        blink::kWebGestureDeviceTouchpad);
+
+  ASSERT_TRUE(synthetic_wheel_listener.WaitUntilSatisfied());
+}
diff --git a/chrome/browser/apps/platform_apps/app_browsertest.cc b/chrome/browser/apps/platform_apps/app_browsertest.cc
index bc99655..079e017b3 100644
--- a/chrome/browser/apps/platform_apps/app_browsertest.cc
+++ b/chrome/browser/apps/platform_apps/app_browsertest.cc
@@ -1400,4 +1400,32 @@
   ASSERT_TRUE(RunPlatformAppTest("platform_apps/new_window_about_blank"));
 }
 
+// Test that an app window sees the synthetic wheel events of a touchpad pinch.
+// While the app window itself does not scale in response to a pinch, we
+// still offer the synthetic wheels for pages that want to implement custom
+// pinch zoom behaviour.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       TouchpadPinchSyntheticWheelEvents) {
+  LoadAndLaunchPlatformApp("touchpad_pinch", "Launched");
+
+  WebContents* web_contents = GetFirstAppWindowWebContents();
+  ASSERT_TRUE(web_contents);
+
+  // Ensure the compositor thread is aware of the wheel listener.
+  content::MainThreadFrameObserver synchronize_threads(
+      web_contents->GetRenderWidgetHostView()->GetRenderWidgetHost());
+  synchronize_threads.Wait();
+
+  ExtensionTestMessageListener synthetic_wheel_listener("Seen wheel event",
+                                                        false);
+
+  const gfx::Rect contents_rect = web_contents->GetContainerBounds();
+  const gfx::Point pinch_position(contents_rect.width() / 2,
+                                  contents_rect.height() / 2);
+  content::SimulateGesturePinchSequence(web_contents, pinch_position, 1.23,
+                                        blink::kWebGestureDeviceTouchpad);
+
+  ASSERT_TRUE(synthetic_wheel_listener.WaitUntilSatisfied());
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/background_fetch/background_fetch_browsertest.cc b/chrome/browser/background_fetch/background_fetch_browsertest.cc
index 653f9b97..971f9c6a 100644
--- a/chrome/browser/background_fetch/background_fetch_browsertest.cc
+++ b/chrome/browser/background_fetch/background_fetch_browsertest.cc
@@ -12,6 +12,9 @@
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "chrome/browser/background_fetch/background_fetch_delegate_impl.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/download/download_request_limiter.h"
 #include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -19,6 +22,8 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings_types.h"
 #include "components/download/public/background_service/download_service.h"
 #include "components/download/public/background_service/logger.h"
 #include "components/offline_items_collection/core/offline_content_aggregator.h"
@@ -149,6 +154,8 @@
   DISALLOW_COPY_AND_ASSIGN(OfflineContentProviderObserver);
 };
 
+}  // namespace
+
 class BackgroundFetchBrowserTest : public InProcessBrowserTest {
  public:
   BackgroundFetchBrowserTest()
@@ -223,13 +230,13 @@
     run_loop.Run();
   }
 
-  // Runs the |script| and waits for a background fetch event.
+  // Runs the |script| and waits for a message.
   // Wrap in ASSERT_NO_FATAL_FAILURE().
-  void RunScriptAndCheckResultingEvent(const std::string& script,
-                                       const std::string& expected_event) {
+  void RunScriptAndCheckResultingMessage(const std::string& script,
+                                         const std::string& expected_message) {
     std::string result;
     ASSERT_NO_FATAL_FAILURE(RunScript(script, &result));
-    ASSERT_EQ(expected_event, result);
+    ASSERT_EQ(expected_message, result);
   }
 
   void GetVisualsForOfflineItemSync(
@@ -292,6 +299,30 @@
     std::move(quit_closure).Run();
   }
 
+  void RevokeDownloadPermission() {
+    content::WebContents* web_contents =
+        browser()->tab_strip_model()->GetActiveWebContents();
+    DownloadRequestLimiter::TabDownloadState* tab_download_state =
+        g_browser_process->download_request_limiter()->GetDownloadState(
+            web_contents, web_contents, true /* create */);
+    tab_download_state->set_download_seen();
+    tab_download_state->SetDownloadStatusAndNotify(
+        DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED);
+  }
+
+  void SetPermission(ContentSettingsType content_type, ContentSetting setting) {
+    auto* settings_map =
+        HostContentSettingsMapFactory::GetForProfile(browser()->profile());
+    DCHECK(settings_map);
+
+    ContentSettingsPattern host_pattern =
+        ContentSettingsPattern::FromURL(https_server_->base_url());
+
+    settings_map->SetContentSettingCustomScope(
+        host_pattern, host_pattern, content_type,
+        std::string() /* resource_identifier */, setting);
+  }
+
  protected:
   download::DownloadService* download_service_{nullptr};
 
@@ -492,7 +523,7 @@
 
 IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest,
                        FetchesRunToCompletionAndUpdateTitle_Fetched) {
-  ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingEvent(
+  ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingMessage(
       "RunFetchTillCompletion()", "backgroundfetchsuccess"));
   base::RunLoop().RunUntilIdle();  // Give `updateUI` a chance to propagate.
   EXPECT_TRUE(
@@ -502,7 +533,7 @@
 
 IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest,
                        FetchesRunToCompletionAndUpdateTitle_Failed) {
-  ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingEvent(
+  ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingMessage(
       "RunFetchTillCompletionWithMissingResource()", "backgroundfetchfail"));
   base::RunLoop().RunUntilIdle();  // Give `updateUI` a chance to propagate.
   EXPECT_TRUE(
@@ -510,4 +541,62 @@
                        "New Failed Title!", base::CompareCase::SENSITIVE));
 }
 
-}  // namespace
+IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest,
+                       FetchRejectedWithoutPermission) {
+  RevokeDownloadPermission();
+  ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingMessage(
+      "RunFetchAnExpectAnException()",
+      "This origin does not have permission to start a fetch."));
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest, FetchFromServiceWorker) {
+  auto* settings_map =
+      HostContentSettingsMapFactory::GetForProfile(browser()->profile());
+  DCHECK(settings_map);
+
+  // Give the needed permissions.
+  SetPermission(CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+                CONTENT_SETTING_ALLOW);
+  SetPermission(CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC, CONTENT_SETTING_ALLOW);
+
+  // The fetch should succeed.
+  ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingMessage(
+      "StartFetchFromServiceWorker()", "backgroundfetchsuccess"));
+
+  // Revoke Automatic Downloads permission.
+  SetPermission(CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+                CONTENT_SETTING_BLOCK);
+
+  // This should fail without the Automatic Downloads permission.
+  ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingMessage(
+      "StartFetchFromServiceWorker()", "permissionerror"));
+
+  // Reset Automatic Downloads permission and remove Background Sync permission
+  SetPermission(CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+                CONTENT_SETTING_ALLOW);
+  SetPermission(CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC, CONTENT_SETTING_BLOCK);
+
+  // This should also fail now.
+  ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingMessage(
+      "StartFetchFromServiceWorker()", "permissionerror"));
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest,
+                       FetchFromChildFrameWithPermissions) {
+  // Give the needed permissions.
+  SetPermission(CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+                CONTENT_SETTING_ALLOW);
+  SetPermission(CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC, CONTENT_SETTING_ALLOW);
+  ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingMessage(
+      "StartFetchFromIframe()", "backgroundfetchsuccess"));
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest,
+                       FetchFromChildFrameWithMissingPermissions) {
+  SetPermission(CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+                CONTENT_SETTING_ALLOW);
+  // Revoke Background Sync permission.
+  SetPermission(CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC, CONTENT_SETTING_BLOCK);
+  ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingMessage(
+      "StartFetchFromIframe()", "permissionerror"));
+}
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_factory.cc b/chrome/browser/background_fetch/background_fetch_delegate_factory.cc
index 6d6eea8..6c05e1e7 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_factory.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_factory.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/background_fetch/background_fetch_delegate_impl.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
@@ -33,6 +34,7 @@
           "BackgroundFetchService",
           BrowserContextDependencyManager::GetInstance()) {
   DependsOn(DownloadServiceFactory::GetInstance());
+  DependsOn(HostContentSettingsMapFactory::GetInstance());
 }
 
 BackgroundFetchDelegateFactory::~BackgroundFetchDelegateFactory() {}
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
index 6f33c52..5c628adc 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -12,9 +12,14 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/download/download_request_limiter.h"
 #include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings_types.h"
 #include "components/download/public/background_service/download_params.h"
 #include "components/download/public/background_service/download_service.h"
 #include "components/offline_items_collection/core/offline_content_aggregator.h"
@@ -25,16 +30,19 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/image/image_skia.h"
+#include "url/origin.h"
 
 BackgroundFetchDelegateImpl::BackgroundFetchDelegateImpl(
     Profile* profile,
     const std::string& provider_namespace)
     : profile_(profile),
+      provider_namespace_(provider_namespace),
       offline_content_aggregator_(
           OfflineContentAggregatorFactory::GetForBrowserContext(profile)),
       weak_ptr_factory_(this) {
   DCHECK(profile_);
-  offline_content_aggregator_->RegisterProvider(provider_namespace, this);
+  DCHECK(!provider_namespace_.empty());
+  offline_content_aggregator_->RegisterProvider(provider_namespace_, this);
 }
 
 BackgroundFetchDelegateImpl::~BackgroundFetchDelegateImpl() = default;
@@ -59,10 +67,11 @@
 BackgroundFetchDelegateImpl::JobDetails::JobDetails(JobDetails&&) = default;
 
 BackgroundFetchDelegateImpl::JobDetails::JobDetails(
-    std::unique_ptr<content::BackgroundFetchDescription> fetch_description)
+    std::unique_ptr<content::BackgroundFetchDescription> fetch_description,
+    const std::string& provider_namespace)
     : cancelled(false),
       offline_item(offline_items_collection::ContentId(
-          "background_fetch",
+          provider_namespace,
           fetch_description->job_unique_id)),
       fetch_description(std::move(fetch_description)) {
   UpdateOfflineItem();
@@ -148,6 +157,52 @@
   std::move(callback).Run(display_size);
 }
 
+void BackgroundFetchDelegateImpl::GetPermissionForOrigin(
+    const url::Origin& origin,
+    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    GetPermissionForOriginCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (wc_getter) {
+    // There is an associated frame so we might need to expose some permission
+    // UI using the DownloadRequestLimiter.
+    DownloadRequestLimiter* limiter =
+        g_browser_process->download_request_limiter();
+    DCHECK(limiter);
+
+    // The fetch should be thought of as one download. So the origin will be
+    // used as the URL, and the |request_method| is set to GET.
+    limiter->CanDownload(wc_getter, origin.GetURL(), "GET",
+                         base::AdaptCallbackForRepeating(std::move(callback)));
+    return;
+  }
+
+  auto* host_content_settings_map =
+      HostContentSettingsMapFactory::GetForProfile(profile_);
+  DCHECK(host_content_settings_map);
+
+  // This is running from a worker context, use the Automatic Downloads
+  // permission.
+  ContentSetting content_setting = host_content_settings_map->GetContentSetting(
+      origin.GetURL(), origin.GetURL(),
+      CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+      std::string() /* resource_identifier */);
+
+  if (content_setting != CONTENT_SETTING_ALLOW) {
+    std::move(callback).Run(/* has_permission= */ false);
+    return;
+  }
+
+  // Also make sure that Background Sync has permission.
+  // TODO(crbug.com/616321): Remove this check after Automatic Downloads
+  // permissions can be modified from Android.
+  content_setting = host_content_settings_map->GetContentSetting(
+      origin.GetURL(), origin.GetURL(), CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC,
+      std::string() /* resource_identifier */);
+
+  std::move(callback).Run(content_setting == CONTENT_SETTING_ALLOW);
+}
+
 void BackgroundFetchDelegateImpl::CreateDownloadJob(
     std::unique_ptr<content::BackgroundFetchDescription> fetch_description) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -155,7 +210,8 @@
   std::string job_unique_id = fetch_description->job_unique_id;
   DCHECK(!job_details_map_.count(job_unique_id));
   auto emplace_result = job_details_map_.emplace(
-      job_unique_id, JobDetails(std::move(fetch_description)));
+      job_unique_id,
+      JobDetails(std::move(fetch_description), provider_namespace_));
 
   const JobDetails& details = emplace_result.first->second;
   for (const auto& download_guid : details.fetch_description->current_guids) {
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.h b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
index 81200ea..c1356e1 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.h
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
@@ -52,6 +52,10 @@
 
   // BackgroundFetchDelegate implementation:
   void GetIconDisplaySize(GetIconDisplaySizeCallback callback) override;
+  void GetPermissionForOrigin(
+      const url::Origin& origin,
+      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      GetPermissionForOriginCallback callback) override;
   void CreateDownloadJob(std::unique_ptr<content::BackgroundFetchDescription>
                              fetch_description) override;
   void DownloadUrl(const std::string& job_unique_id,
@@ -110,8 +114,9 @@
  private:
   struct JobDetails {
     JobDetails(JobDetails&&);
-    explicit JobDetails(
-        std::unique_ptr<content::BackgroundFetchDescription> fetch_description);
+    JobDetails(
+        std::unique_ptr<content::BackgroundFetchDescription> fetch_description,
+        const std::string& provider_namespace);
     ~JobDetails();
 
     void UpdateOfflineItem();
@@ -146,6 +151,10 @@
   // The profile this service is being created for.
   Profile* profile_;
 
+  // The namespace provided to the |offline_content_aggregator_| and used when
+  // creating Content IDs.
+  std::string provider_namespace_;
+
   // The BackgroundFetchDelegateImplFactory depends on the
   // DownloadServiceFactory, so |download_service_| should outlive |this|.
   download::DownloadService* download_service_ = nullptr;
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 860c373..fe903f3 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -80,7 +80,7 @@
         <include name="IDR_WEBAUTHN_ILLUSTRATION_BLE_TAP_1X" file="resources\webauthn\ble_tap.png" type="BINDATA" />
         <include name="IDR_WEBAUTHN_ILLUSTRATION_BLE_PIN_1X" file="resources\webauthn\ble_pin.png" type="BINDATA" />
         <include name="IDR_WEBAUTHN_ILLUSTRATION_ERROR_BLUETOOTH_1X" file="resources\webauthn\error_bt.png" type="BINDATA" />
-        <include name="IDR_WEBAUTHN_ILLUSTRATION_ERROR_TIMEOUT_1X" file="resources\webauthn\error_timeout.png" type="BINDATA" />
+        <include name="IDR_WEBAUTHN_ILLUSTRATION_ERROR_1X" file="resources\webauthn\error.png" type="BINDATA" />
         <include name="IDR_WEBAUTHN_ILLUSTRATION_PHONE_1X" file="resources\webauthn\phone.png" type="BINDATA" />
         <include name="IDR_WEBAUTHN_ILLUSTRATION_USB_1X" file="resources\webauthn\usb.png" type="BINDATA" />
         <include name="IDR_WEBAUTHN_ILLUSTRATION_WELCOME_1X" file="resources\webauthn\welcome.png" type="BINDATA" />
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
index ce279a0..4fac677f 100644
--- a/chrome/browser/certificate_manager_model.cc
+++ b/chrome/browser/certificate_manager_model.cc
@@ -7,8 +7,11 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/callback_helpers.h"
 #include "base/i18n/time_formatting.h"
 #include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -25,14 +28,14 @@
 #include "net/cert/x509_util_nss.h"
 #include "ui/base/l10n/l10n_util.h"
 
-// TODO(wychen): ChromeOS headers should only be included when building
-//               ChromeOS, and the following headers should be guarded by
-//               #if defined(OS_CHROMEOS). However, the types are actually
-//               used, and it takes another CL to clean them up.
-//               Reference: crbug.com/720159
+#if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
+#include "chrome/browser/chromeos/policy/policy_certificate_provider.h"
+#include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
+#include "chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h"
+#endif
 
 using content::BrowserThread;
 
@@ -71,8 +74,403 @@
   return org;
 }
 
+#if defined(OS_CHROMEOS)
+// Log message for an operation that can not be performed on a certificate of a
+// given source.
+constexpr char kOperationNotPermitted[] =
+    "Operation not permitted on a certificate. Source: ";
+#endif  // OS_CHROMEOS
+
 }  // namespace
 
+// A source of certificates that should be displayed on the certificate manager
+// UI. Currently, a CertsSource yields CertInfo objects. Each CertInfo contains
+// a NSS ScopedCERTCertificate.
+class CertificateManagerModel::CertsSource {
+ public:
+  // |certs_source_updated_callback| will be invoked when the list of
+  // certificates provided by this CertsSource changes.
+  explicit CertsSource(base::RepeatingClosure certs_source_updated_callback)
+      : certs_source_updated_callback_(certs_source_updated_callback) {}
+  virtual ~CertsSource() = default;
+
+  // Returns the CertInfos provided by this CertsSource.
+  const std::vector<std::unique_ptr<CertificateManagerModel::CertInfo>>&
+  cert_infos() const {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    return cert_infos_;
+  }
+
+  // Returns true if |cert| is in this CertsSource's certificate list.
+  bool HasCert(CERTCertificate* cert) const {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    for (const auto& cert_info : cert_infos_) {
+      if (cert_info->cert() == cert)
+        return true;
+    }
+    return false;
+  }
+
+  // Triggers a refresh of this CertsSource. When done, the
+  // |certs_source_updated_callback| passed to the constructor will be invoked.
+  virtual void Refresh() = 0;
+
+  // If any CertsSource's |IsHoldBackUpdates| is returning true, the
+  // CertificateManagerModel will not notify its Observer about updates.
+  bool IsHoldBackUpdates() const { return hold_back_updates_; }
+
+  // Set trust values for certificate.
+  // |trust_bits| should be a bit field of TRUST* values from NSSCertDatabase.
+  // Returns true on success or false on failure.
+  virtual bool SetCertTrust(CERTCertificate* cert,
+                            net::CertType type,
+                            net::NSSCertDatabase::TrustBits trust_bits) = 0;
+
+  // Delete the cert. Returns true on success. |cert| is still valid when this
+  // function returns.
+  virtual bool Delete(CERTCertificate* cert) = 0;
+
+ protected:
+  // To be called by subclasses to set the CertInfo list provided by this
+  // CertsSource. If this CertsSource is signalling that updates should be held
+  // back (|SetHoldBackUpdates(true)|, this will be set to false. The
+  // |certs_source_updated_callback| passed to the constructor will be invoked.
+  void SetCertInfos(
+      std::vector<std::unique_ptr<CertificateManagerModel::CertInfo>>
+          cert_infos) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    cert_infos_.swap(cert_infos);
+    SetHoldBackUpdates(false);
+    certs_source_updated_callback_.Run();
+  }
+
+  // Signal to |CertificateManagerModel| that updates to its Observer should be
+  // held back. This will be automatically taken back on |SetCertInfos|.
+  // This should only be used by |CertsSource|s that provide their list of
+  // certificates asynchronously but expect their certificate listing to be
+  // fast.
+  void SetHoldBackUpdates(bool hold_back_updates) {
+    hold_back_updates_ = hold_back_updates;
+  }
+
+  // Used to verify that the constructor, and accessing |cert_infos_| are
+  // performed on the same sequence. Offered to subclasses so they can also
+  // check that they're being called on a valid sequence.
+  SEQUENCE_CHECKER(sequence_checker_);
+
+ private:
+  // Cached CertInfos provided by this CertsSource.
+  std::vector<std::unique_ptr<CertificateManagerModel::CertInfo>> cert_infos_;
+
+  // Invoked when the list of certificates provided by this CertsSource has
+  // changed.
+  base::RepeatingClosure certs_source_updated_callback_;
+
+  // If true, the CertificateManagerModel should be holding back update
+  // notifications.
+  bool hold_back_updates_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(CertsSource);
+};
+
+namespace {
+// Provides certificates enumerable from a NSSCertDatabase.
+class CertsSourcePlatformNSS : public CertificateManagerModel::CertsSource {
+ public:
+  CertsSourcePlatformNSS(base::RepeatingClosure certs_source_updated_callback,
+                         net::NSSCertDatabase* nss_cert_database)
+      : CertsSource(certs_source_updated_callback),
+        cert_db_(nss_cert_database),
+        weak_ptr_factory_(this) {}
+  ~CertsSourcePlatformNSS() override = default;
+
+  void Refresh() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    SetHoldBackUpdates(true);
+    DVLOG(1) << "refresh started";
+    std::vector<crypto::ScopedPK11Slot> modules;
+    cert_db_->ListModules(&modules, false);
+    DVLOG(1) << "refresh waiting for unlocking...";
+    chrome::UnlockSlotsIfNecessary(
+        std::move(modules), kCryptoModulePasswordListCerts,
+        net::HostPortPair(),  // unused.
+        nullptr,              // TODO(mattm): supply parent window.
+        base::AdaptCallbackForRepeating(
+            base::BindOnce(&CertsSourcePlatformNSS::RefreshSlotsUnlocked,
+                           weak_ptr_factory_.GetWeakPtr())));
+  }
+
+  bool SetCertTrust(CERTCertificate* cert,
+                    net::CertType type,
+                    net::NSSCertDatabase::TrustBits trust_bits) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    return cert_db_->SetCertTrust(cert, type, trust_bits);
+  }
+
+  bool Delete(CERTCertificate* cert) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    bool result = cert_db_->DeleteCertAndKey(cert);
+    if (result)
+      Refresh();
+    return result;
+  }
+
+ private:
+  void RefreshSlotsUnlocked() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    DVLOG(1) << "refresh listing certs...";
+    cert_db_->ListCerts(base::AdaptCallbackForRepeating(base::BindOnce(
+        &CertsSourcePlatformNSS::DidGetCerts, weak_ptr_factory_.GetWeakPtr())));
+  }
+
+  void DidGetCerts(net::ScopedCERTCertificateList certs) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    DVLOG(1) << "refresh finished for platform provided certificates";
+    std::vector<std::unique_ptr<CertificateManagerModel::CertInfo>> cert_infos;
+
+    cert_infos.reserve(certs.size());
+    for (auto& cert : certs) {
+      net::CertType type = x509_certificate_model::GetType(cert.get());
+      bool read_only = cert_db_->IsReadOnly(cert.get());
+      bool untrusted = cert_db_->IsUntrusted(cert.get());
+      bool hardware_backed = cert_db_->IsHardwareBacked(cert.get());
+      bool web_trust_anchor = cert_db_->IsWebTrustAnchor(cert.get());
+      base::string16 name = GetName(cert.get(), hardware_backed);
+      cert_infos.push_back(std::make_unique<CertificateManagerModel::CertInfo>(
+          std::move(cert), type, name, read_only, untrusted,
+          CertificateManagerModel::CertInfo::Source::kPlatform,
+          web_trust_anchor, hardware_backed));
+    }
+
+    SetCertInfos(std::move(cert_infos));
+  }
+
+  static base::string16 GetName(CERTCertificate* cert,
+                                bool is_hardware_backed) {
+    base::string16 name =
+        base::UTF8ToUTF16(x509_certificate_model::GetCertNameOrNickname(cert));
+    if (is_hardware_backed) {
+      name = l10n_util::GetStringFUTF16(
+          IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT, name,
+          l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED));
+    }
+    return name;
+  }
+
+  // The source NSSCertDatabase used for listing certificates.
+  net::NSSCertDatabase* cert_db_;
+
+  base::WeakPtrFactory<CertsSourcePlatformNSS> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CertsSourcePlatformNSS);
+};
+
+#if defined(OS_CHROMEOS)
+// Provides certificates installed through enterprise policy.
+class CertsSourcePolicy : public CertificateManagerModel::CertsSource,
+                          policy::PolicyCertificateProvider::Observer {
+ public:
+  // Defines which policy-provided certificates this CertsSourcePolicy instance
+  // should yield.
+  enum class Mode {
+    // Only certificates which are installed by enterprise policy, but not Web
+    // trusted.
+    kPolicyCertsWithoutWebTrust,
+    // Only certificates which are installed by enterprise policy and Web
+    // trusted.
+    kPolicyCertsWithWebTrust
+  };
+
+  CertsSourcePolicy(base::RepeatingClosure certs_source_updated_callback,
+                    policy::PolicyCertificateProvider* policy_certs_provider,
+                    Mode mode)
+      : CertsSource(certs_source_updated_callback),
+        policy_certs_provider_(policy_certs_provider),
+        mode_(mode) {
+    policy_certs_provider_->AddPolicyProvidedCertsObserver(this);
+  }
+
+  ~CertsSourcePolicy() override {
+    policy_certs_provider_->RemovePolicyProvidedCertsObserver(this);
+  }
+
+  // policy::PolicyCertificateProvider::Observer
+  void OnPolicyProvidedCertsChanged(
+      const net::CertificateList& all_server_and_authority_certs,
+      const net::CertificateList& web_trusted_certs) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    Refresh();
+  }
+
+  void Refresh() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    switch (mode_) {
+      case Mode::kPolicyCertsWithoutWebTrust:
+        RefreshImpl(policy_certs_provider_->GetCertificatesWithoutWebTrust(),
+                    false /* policy_web_trusted */);
+        break;
+      case Mode::kPolicyCertsWithWebTrust:
+        RefreshImpl(policy_certs_provider_->GetWebTrustedCertificates(),
+                    true /* policy_web_trusted */);
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+
+  bool SetCertTrust(CERTCertificate* cert,
+                    net::CertType type,
+                    net::NSSCertDatabase::TrustBits trust_bits) override {
+    // Trust of policy-provided certificates can not be changed.
+    LOG(WARNING) << kOperationNotPermitted << "Policy";
+    return false;
+  }
+
+  bool Delete(CERTCertificate* cert) override {
+    // Policy-provided certificates can not be deleted.
+    LOG(WARNING) << kOperationNotPermitted << "Policy";
+    return false;
+  }
+
+ private:
+  void RefreshImpl(const net::CertificateList& certificates,
+                   bool policy_web_trusted) {
+    std::vector<std::unique_ptr<CertificateManagerModel::CertInfo>> cert_infos;
+    cert_infos.reserve(certificates.size());
+
+    for (const auto& policy_cert : certificates) {
+      net::ScopedCERTCertificate nss_cert(
+          net::x509_util::CreateCERTCertificateFromX509Certificate(
+              policy_cert.get()));
+      if (!nss_cert)
+        continue;
+
+      net::CertType type = x509_certificate_model::GetType(nss_cert.get());
+      base::string16 cert_name = base::UTF8ToUTF16(
+          x509_certificate_model::GetCertNameOrNickname(nss_cert.get()));
+      cert_infos.push_back(std::make_unique<CertificateManagerModel::CertInfo>(
+          std::move(nss_cert), type, std::move(cert_name), true /* read_only */,
+          false /* untrusted */,
+          CertificateManagerModel::CertInfo::Source::kPolicy,
+          policy_web_trusted /* web_trust_anchor */,
+          false /* hardware_backed */));
+    }
+
+    SetCertInfos(std::move(cert_infos));
+  }
+
+  policy::PolicyCertificateProvider* policy_certs_provider_;
+  Mode mode_;
+
+  DISALLOW_COPY_AND_ASSIGN(CertsSourcePolicy);
+};
+
+// Provides certificates made available by extensions through the
+// chrome.certificateProvider API.
+class CertsSourceExtensions : public CertificateManagerModel::CertsSource {
+ public:
+  CertsSourceExtensions(base::RepeatingClosure certs_source_updated_callback,
+                        std::unique_ptr<chromeos::CertificateProvider>
+                            certificate_provider_service)
+      : CertsSource(certs_source_updated_callback),
+        certificate_provider_service_(std::move(certificate_provider_service)),
+        weak_ptr_factory_(this) {}
+
+  void Refresh() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    certificate_provider_service_->GetCertificates(
+        base::AdaptCallbackForRepeating(
+            base::BindOnce(&CertsSourceExtensions::DidGetCerts,
+                           weak_ptr_factory_.GetWeakPtr())));
+  }
+
+  bool SetCertTrust(CERTCertificate* cert,
+                    net::CertType type,
+                    net::NSSCertDatabase::TrustBits trust_bits) override {
+    // Extension-provided certificates are user certificates; changing trust
+    // does not make sense here.
+    LOG(WARNING) << kOperationNotPermitted << "Extension";
+    return false;
+  }
+
+  bool Delete(CERTCertificate* cert) override {
+    // Extension-provided certificates can not be deleted.
+    LOG(WARNING) << kOperationNotPermitted << "Extension";
+    return false;
+  }
+
+ private:
+  void DidGetCerts(net::ClientCertIdentityList cert_identities) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    std::vector<std::unique_ptr<CertificateManagerModel::CertInfo>> cert_infos;
+
+    cert_infos.reserve(cert_identities.size());
+    for (const auto& identity : cert_identities) {
+      net::ScopedCERTCertificate nss_cert(
+          net::x509_util::CreateCERTCertificateFromX509Certificate(
+              identity->certificate()));
+      if (!nss_cert)
+        continue;
+
+      base::string16 cert_name = base::UTF8ToUTF16(
+          x509_certificate_model::GetCertNameOrNickname(nss_cert.get()));
+      base::string16 display_name = l10n_util::GetStringFUTF16(
+          IDS_CERT_MANAGER_EXTENSION_PROVIDED_FORMAT, std::move(cert_name));
+
+      cert_infos.push_back(std::make_unique<CertificateManagerModel::CertInfo>(
+          std::move(nss_cert), net::CertType::USER_CERT /* type */,
+          display_name, true /* read_only */, false /* untrusted */,
+          CertificateManagerModel::CertInfo::Source::kExtension,
+          false /* web_trust_anchor */, false /* hardware_backed */));
+    }
+
+    SetCertInfos(std::move(cert_infos));
+  }
+
+  std::unique_ptr<chromeos::CertificateProvider> certificate_provider_service_;
+
+  base::WeakPtrFactory<CertsSourceExtensions> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CertsSourceExtensions);
+};
+
+#endif  // OS_CHROMEOS
+
+}  // namespace
+
+CertificateManagerModel::CertInfo::CertInfo(net::ScopedCERTCertificate cert,
+                                            net::CertType type,
+                                            base::string16 name,
+                                            bool read_only,
+                                            bool untrusted,
+                                            Source source,
+                                            bool web_trust_anchor,
+                                            bool hardware_backed)
+    : cert_(std::move(cert)),
+      type_(type),
+      name_(std::move(name)),
+      read_only_(read_only),
+      untrusted_(untrusted),
+      source_(source),
+      web_trust_anchor_(web_trust_anchor),
+      hardware_backed_(hardware_backed) {}
+
+CertificateManagerModel::CertInfo::~CertInfo() {}
+
+// static
+std::unique_ptr<CertificateManagerModel::CertInfo>
+CertificateManagerModel::CertInfo::Clone(const CertInfo* cert_info) {
+  return std::make_unique<CertInfo>(
+      net::x509_util::DupCERTCertificate(cert_info->cert()), cert_info->type(),
+      cert_info->name(), cert_info->read_only(), cert_info->untrusted(),
+      cert_info->source(), cert_info->web_trust_anchor(),
+      cert_info->hardware_backed());
+}
+
+CertificateManagerModel::Params::Params() = default;
+CertificateManagerModel::Params::~Params() = default;
+CertificateManagerModel::Params::Params(Params&& other) = default;
+
 // static
 void CertificateManagerModel::Create(
     content::BrowserContext* browser_context,
@@ -80,145 +478,132 @@
     const CreationCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  std::unique_ptr<chromeos::CertificateProvider> extension_certificate_provider;
+  std::unique_ptr<Params> params = std::make_unique<Params>();
 #if defined(OS_CHROMEOS)
-  chromeos::CertificateProviderService* service =
+  policy::UserNetworkConfigurationUpdater* user_network_configuration_updater =
+      policy::UserNetworkConfigurationUpdaterFactory::GetForBrowserContext(
+          browser_context);
+  params->policy_certs_provider = user_network_configuration_updater;
+
+  chromeos::CertificateProviderService* certificate_provider_service =
       chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
           browser_context);
-  extension_certificate_provider = service->CreateCertificateProvider();
+  params->extension_certificate_provider =
+      certificate_provider_service->CreateCertificateProvider();
 #endif
 
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
       base::BindOnce(&CertificateManagerModel::GetCertDBOnIOThread,
-                     browser_context->GetResourceContext(), observer,
-                     std::move(extension_certificate_provider), callback));
+                     std::move(params), browser_context->GetResourceContext(),
+                     observer, callback));
 }
 
 CertificateManagerModel::CertificateManagerModel(
+    std::unique_ptr<Params> params,
+    Observer* observer,
     net::NSSCertDatabase* nss_cert_database,
     bool is_user_db_available,
-    bool is_tpm_available,
-    Observer* observer,
-    std::unique_ptr<chromeos::CertificateProvider>
-        extension_certificate_provider)
+    bool is_tpm_available)
     : cert_db_(nss_cert_database),
       is_user_db_available_(is_user_db_available),
       is_tpm_available_(is_tpm_available),
-      observer_(observer),
-      extension_certificate_provider_(std::move(
-                                          extension_certificate_provider)),
-      weak_ptr_factory_(this) {
+      observer_(observer) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
 
-CertificateManagerModel::~CertificateManagerModel() {
-}
+  // Fill |certs_sources_|. Note that the order matters. Higher priority
+  // CertsSources must come first.
 
-void CertificateManagerModel::Refresh() {
-  DVLOG(1) << "refresh started";
-  std::vector<crypto::ScopedPK11Slot> modules;
-  cert_db_->ListModules(&modules, false);
-  DVLOG(1) << "refresh waiting for unlocking...";
-  chrome::UnlockSlotsIfNecessary(
-      std::move(modules), kCryptoModulePasswordListCerts,
-      net::HostPortPair(),  // unused.
-      NULL,                 // TODO(mattm): supply parent window.
-      base::Bind(&CertificateManagerModel::RefreshSlotsUnlocked,
-                 base::Unretained(this)));
+  base::RepeatingClosure certs_source_updated_callback = base::BindRepeating(
+      &CertificateManagerModel::OnCertsSourceUpdated, base::Unretained(this));
 
 #if defined(OS_CHROMEOS)
-  extension_certificate_provider_->GetCertificates(base::Bind(
-      &CertificateManagerModel::RefreshExtensionCertificates,
-      weak_ptr_factory_.GetWeakPtr()));
+  // Certificates installed and web trusted by enterprise policy is the highest
+  // priority CertsSource.
+  // UserNetworkConfigurationUpdater is only available for the primary user's
+  // profile.
+  if (params->policy_certs_provider) {
+    certs_sources_.push_back(std::make_unique<CertsSourcePolicy>(
+        certs_source_updated_callback, params->policy_certs_provider,
+        CertsSourcePolicy::Mode::kPolicyCertsWithWebTrust));
+  }
+#endif
+
+  // Add the main NSS DB based CertsSource.
+  certs_sources_.push_back(std::make_unique<CertsSourcePlatformNSS>(
+      certs_source_updated_callback, nss_cert_database));
+
+#if defined(OS_CHROMEOS)
+  // Certificates installed by enterprise policy without web trust are lower
+  // priority than the main NSS DB based CertsSource.
+  // Rationale: The user should be able to add trust to policy-provided
+  // certificates by re-importing them and modifying their trust settings.
+  if (params->policy_certs_provider) {
+    certs_sources_.push_back(std::make_unique<CertsSourcePolicy>(
+        certs_source_updated_callback, params->policy_certs_provider,
+        CertsSourcePolicy::Mode::kPolicyCertsWithoutWebTrust));
+  }
+
+  // Extensions is the lowest priority CertsSource.
+  if (params->extension_certificate_provider) {
+    certs_sources_.push_back(std::make_unique<CertsSourceExtensions>(
+        certs_source_updated_callback,
+        std::move(params->extension_certificate_provider)));
+  }
 #endif
 }
 
-void CertificateManagerModel::RefreshSlotsUnlocked() {
-  DVLOG(1) << "refresh listing certs...";
-  // TODO(tbarzic): Use async |ListCerts|.
-  cert_list_ = cert_db_->ListCertsSync();
+CertificateManagerModel::~CertificateManagerModel() {}
+
+void CertificateManagerModel::OnCertsSourceUpdated() {
+  if (hold_back_updates_)
+    return;
+  for (const auto& certs_source : certs_sources_) {
+    if (certs_source->IsHoldBackUpdates()) {
+      return;
+    }
+  }
+
   observer_->CertificatesRefreshed();
-  DVLOG(1) << "refresh finished for platform provided certificates";
 }
 
-void CertificateManagerModel::RefreshExtensionCertificates(
-    net::ClientCertIdentityList new_cert_identities) {
-  extension_cert_list_.clear();
-  extension_cert_list_.reserve(new_cert_identities.size());
-  for (const auto& identity : new_cert_identities) {
-    net::ScopedCERTCertificate nss_cert(
-        net::x509_util::CreateCERTCertificateFromX509Certificate(
-            identity->certificate()));
-    if (nss_cert)
-      extension_cert_list_.push_back(std::move(nss_cert));
+CertificateManagerModel::CertsSource*
+CertificateManagerModel::FindCertsSourceForCert(CERTCertificate* cert) {
+  for (auto& certs_source : certs_sources_) {
+    if (certs_source->HasCert(cert))
+      return certs_source.get();
   }
-  observer_->CertificatesRefreshed();
-  DVLOG(1) << "refresh finished for extension provided certificates";
+  return nullptr;
+}
+
+void CertificateManagerModel::Refresh() {
+  hold_back_updates_ = true;
+
+  for (auto& certs_source : certs_sources_)
+    certs_source->Refresh();
+
+  hold_back_updates_ = false;
+  OnCertsSourceUpdated();
 }
 
 void CertificateManagerModel::FilterAndBuildOrgGroupingMap(
     net::CertType filter_type,
-    CertificateManagerModel::OrgGroupingMap* map) const {
-  for (const net::ScopedCERTCertificate& cert : cert_list_) {
-    net::CertType type = x509_certificate_model::GetType(cert.get());
-    if (type != filter_type)
-      continue;
+    CertificateManagerModel::OrgGroupingMap* out_org_grouping_map) const {
+  std::map<CERTCertificate*, std::unique_ptr<CertInfo>> cert_info_map;
+  for (const auto& certs_source : certs_sources_) {
+    for (const auto& cert_info : certs_source->cert_infos()) {
+      if (cert_info->type() != filter_type)
+        continue;
 
-    std::string org = GetCertificateOrg(cert.get());
-    (*map)[org].push_back(net::x509_util::DupCERTCertificate(cert.get()));
-  }
-
-  // Display extension provided certificates under the "Your Certificates" tab.
-  if (filter_type == net::USER_CERT) {
-    for (const auto& cert : extension_cert_list_) {
-      std::string org = GetCertificateOrg(cert.get());
-      (*map)[org].push_back(net::x509_util::DupCERTCertificate(cert.get()));
+      if (cert_info_map.find(cert_info->cert()) == cert_info_map.end())
+        cert_info_map[cert_info->cert()] = CertInfo::Clone(cert_info.get());
     }
   }
-}
 
-base::string16 CertificateManagerModel::GetColumnText(CERTCertificate* cert,
-                                                      Column column) const {
-  base::string16 rv;
-  switch (column) {
-    case COL_SUBJECT_NAME:
-      rv = base::UTF8ToUTF16(
-          x509_certificate_model::GetCertNameOrNickname(cert));
-
-      // Mark extension provided certificates.
-      if (std::find_if(extension_cert_list_.begin(), extension_cert_list_.end(),
-                       [cert](const net::ScopedCERTCertificate& element) {
-                         return element.get() == cert;
-                       }) != extension_cert_list_.end()) {
-        rv = l10n_util::GetStringFUTF16(
-            IDS_CERT_MANAGER_EXTENSION_PROVIDED_FORMAT,
-            rv);
-      } else if (IsHardwareBacked(cert)) {
-        // TODO(xiyuan): Put this into a column when we have js tree-table.
-        rv = l10n_util::GetStringFUTF16(
-            IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT,
-            rv,
-            l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED));
-      }
-      break;
-    case COL_CERTIFICATE_STORE:
-      rv = base::UTF8ToUTF16(x509_certificate_model::GetTokenName(cert));
-      break;
-    case COL_SERIAL_NUMBER:
-      rv = base::ASCIIToUTF16(
-          x509_certificate_model::GetSerialNumberHexified(cert, std::string()));
-      break;
-    case COL_EXPIRES_ON: {
-      base::Time not_after;
-      if (net::x509_util::GetValidityTimes(cert, nullptr, &not_after))
-        rv = base::TimeFormatShortDateNumeric(not_after);
-      break;
-    }
-    default:
-      NOTREACHED();
+  for (auto& cert_info_kv : cert_info_map) {
+    std::string org = GetCertificateOrg(cert_info_kv.second->cert());
+    (*out_org_grouping_map)[org].push_back(std::move(cert_info_kv.second));
   }
-  return rv;
 }
 
 int CertificateManagerModel::ImportFromPKCS12(PK11SlotInfo* slot_info,
@@ -266,42 +651,40 @@
     CERTCertificate* cert,
     net::CertType type,
     net::NSSCertDatabase::TrustBits trust_bits) {
-  return cert_db_->SetCertTrust(cert, type, trust_bits);
+  CertsSource* certs_source = FindCertsSourceForCert(cert);
+  if (!certs_source)
+    return false;
+  return certs_source->SetCertTrust(cert, type, trust_bits);
 }
 
 bool CertificateManagerModel::Delete(CERTCertificate* cert) {
-  bool result = cert_db_->DeleteCertAndKey(cert);
-  if (result)
-    Refresh();
-  return result;
-}
-
-bool CertificateManagerModel::IsHardwareBacked(CERTCertificate* cert) const {
-  return cert_db_->IsHardwareBacked(cert);
+  CertsSource* certs_source = FindCertsSourceForCert(cert);
+  if (!certs_source)
+    return false;
+  return certs_source->Delete(cert);
 }
 
 // static
 void CertificateManagerModel::DidGetCertDBOnUIThread(
+    std::unique_ptr<Params> params,
+    CertificateManagerModel::Observer* observer,
+    const CreationCallback& callback,
     net::NSSCertDatabase* cert_db,
     bool is_user_db_available,
-    bool is_tpm_available,
-    CertificateManagerModel::Observer* observer,
-    std::unique_ptr<chromeos::CertificateProvider>
-        extension_certificate_provider,
-    const CreationCallback& callback) {
+    bool is_tpm_available) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  std::unique_ptr<CertificateManagerModel> model(new CertificateManagerModel(
-      cert_db, is_user_db_available, is_tpm_available, observer,
-      std::move(extension_certificate_provider)));
+  std::unique_ptr<CertificateManagerModel> model =
+      std::make_unique<CertificateManagerModel>(std::move(params), observer,
+                                                cert_db, is_user_db_available,
+                                                is_tpm_available);
   callback.Run(std::move(model));
 }
 
 // static
 void CertificateManagerModel::DidGetCertDBOnIOThread(
+    std::unique_ptr<Params> params,
     CertificateManagerModel::Observer* observer,
-    std::unique_ptr<chromeos::CertificateProvider>
-        extension_certificate_provider,
     const CreationCallback& callback,
     net::NSSCertDatabase* cert_db) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -313,31 +696,27 @@
 #endif
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&CertificateManagerModel::DidGetCertDBOnUIThread, cert_db,
-                     is_user_db_available, is_tpm_available, observer,
-                     std::move(extension_certificate_provider), callback));
+      base::BindOnce(&CertificateManagerModel::DidGetCertDBOnUIThread,
+                     std::move(params), observer, callback, cert_db,
+                     is_user_db_available, is_tpm_available));
 }
 
 // static
 void CertificateManagerModel::GetCertDBOnIOThread(
-    content::ResourceContext* context,
+    std::unique_ptr<Params> params,
+    content::ResourceContext* resource_context,
     CertificateManagerModel::Observer* observer,
-    std::unique_ptr<chromeos::CertificateProvider>
-        extension_certificate_provider,
     const CreationCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  auto did_get_cert_db_callback = base::Bind(
-      &CertificateManagerModel::DidGetCertDBOnIOThread, observer,
-      base::Passed(&extension_certificate_provider), callback);
+  auto did_get_cert_db_callback = base::AdaptCallbackForRepeating(
+      base::BindOnce(&CertificateManagerModel::DidGetCertDBOnIOThread,
+                     std::move(params), observer, callback));
 
   net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext(
-      context, did_get_cert_db_callback);
-
-  // The callback is run here instead of the actual function call because of
-  // extension_certificate_provider ownership semantics, ie. ownership can only
-  // be released once. The callback will only be run once (either inside the
-  // function above or here).
+      resource_context, did_get_cert_db_callback);
+  // If the NSS database was already available, |cert_db| is non-null and
+  // |did_get_cert_db_callback| has not been called. Call it explicitly.
   if (cert_db)
     did_get_cert_db_callback.Run(cert_db);
 }
diff --git a/chrome/browser/certificate_manager_model.h b/chrome/browser/certificate_manager_model.h
index 10c216bf..119a46c6 100644
--- a/chrome/browser/certificate_manager_model.h
+++ b/chrome/browser/certificate_manager_model.h
@@ -12,47 +12,134 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "net/cert/nss_cert_database.h"
 #include "net/cert/scoped_nss_types.h"
 #include "net/ssl/client_cert_identity.h"
 
-namespace chromeos {
-class CertificateProvider;
-}  // namespace chromeos
-
 namespace content {
 class BrowserContext;
 class ResourceContext;
 }  // namespace content
 
+#if defined(OS_CHROMEOS)
+namespace chromeos {
+class CertificateProvider;
+}
+
+namespace policy {
+class PolicyCertificateProvider;
+}
+#endif
+
 // CertificateManagerModel provides the data to be displayed in the certificate
 // manager dialog, and processes changes from the view.
 class CertificateManagerModel {
  public:
+  // Holds information about a certificate, along with the certificate itself.
+  class CertInfo {
+   public:
+    enum class Source {
+      // This certificate is installed in the platform certificate database.
+      kPlatform,
+      // This certificate is provided by enterprise policy.
+      kPolicy,
+      // This certificate is provided by an extension.
+      kExtension
+    };
+
+    CertInfo(net::ScopedCERTCertificate cert,
+             net::CertType type,
+             base::string16 name,
+             bool read_only,
+             bool untrusted,
+             Source source,
+             bool web_trust_anchor,
+             bool hardware_backed);
+    ~CertInfo();
+
+    CERTCertificate* cert() const { return cert_.get(); }
+    net::CertType type() const { return type_; }
+    const base::string16& name() const { return name_; }
+    bool read_only() const { return read_only_; }
+    bool untrusted() const { return untrusted_; }
+    Source source() const { return source_; }
+    bool web_trust_anchor() const { return web_trust_anchor_; }
+    bool hardware_backed() const { return hardware_backed_; }
+
+    // Clones a CertInfo, duplicating the contained NSS certificate.
+    static std::unique_ptr<CertInfo> Clone(const CertInfo* cert_info);
+
+   private:
+    // The certificate itself.
+    net::ScopedCERTCertificate cert_;
+
+    // The type of the certificate. Used to filter certificates to be displayed
+    // on the tabs of the certificate manager UI.
+    net::CertType type_;
+
+    // A user readable certificate name.
+    base::string16 name_;
+
+    // true if the certificate is stored on a read-only slot or provided by
+    // enterprise policy or an extension.
+    bool read_only_;
+
+    // true if the certificate is untrusted.
+    bool untrusted_;
+
+    // Describes where this certificate originates from.
+    Source source_;
+
+    // true if the certificate is given web trust (either by its platform trust
+    // settings, or by enterprise policy).
+    bool web_trust_anchor_;
+
+    // true if the certificate is hardware-backed. Note that extension-provided
+    // certificates are not regarded as hardware-backed.
+    bool hardware_backed_;
+
+    DISALLOW_COPY_AND_ASSIGN(CertInfo);
+  };
+
+  class CertsSource;
+
+  // Holds parameters during construction.
+  struct Params {
+#if defined(OS_CHROMEOS)
+    // May be nullptr.
+    policy::PolicyCertificateProvider* policy_certs_provider = nullptr;
+    // May be nullptr.
+    std::unique_ptr<chromeos::CertificateProvider>
+        extension_certificate_provider;
+#endif
+
+    Params();
+    Params(Params&& other);
+    ~Params();
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Params);
+  };
+
   // Map from the subject organization name to the list of certs from that
   // organization.  If a cert does not have an organization name, the
   // subject's CertPrincipal::GetDisplayName() value is used instead.
-  typedef std::map<std::string, net::ScopedCERTCertificateList> OrgGroupingMap;
+  typedef std::map<std::string, std::vector<std::unique_ptr<CertInfo>>>
+      OrgGroupingMap;
 
   typedef base::Callback<void(std::unique_ptr<CertificateManagerModel>)>
       CreationCallback;
 
-  // Enumeration of the possible columns in the certificate manager tree view.
-  enum Column {
-    COL_SUBJECT_NAME,
-    COL_CERTIFICATE_STORE,
-    COL_SERIAL_NUMBER,
-    COL_EXPIRES_ON,
-  };
-
   class Observer {
    public:
     // Called to notify the view that the certificate list has been refreshed.
     // TODO(mattm): do a more granular updating strategy?  Maybe retrieve new
     // list of certs, diff against past list, and then notify of the changes?
     virtual void CertificatesRefreshed() = 0;
+
+   protected:
+    virtual ~Observer() = default;
   };
 
   // Creates a CertificateManagerModel. The model will be passed to the callback
@@ -62,6 +149,13 @@
                      Observer* observer,
                      const CreationCallback& callback);
 
+  // Use |Create| instead to create a |CertificateManagerModel| for a
+  // |BrowserContext|.
+  CertificateManagerModel(std::unique_ptr<Params> params,
+                          Observer* observer,
+                          net::NSSCertDatabase* nss_cert_database,
+                          bool is_user_db_available,
+                          bool is_tpm_available);
   ~CertificateManagerModel();
 
   bool is_user_db_available() const { return is_user_db_available_; }
@@ -76,12 +170,9 @@
   // refresh its tree views.
   void Refresh();
 
-  // Fill |map| with the certificates matching |filter_type|.
+  // Fill |*out_org_grouping_map| with the certificates matching |filter_type|.
   void FilterAndBuildOrgGroupingMap(net::CertType filter_type,
-                                    OrgGroupingMap* map) const;
-
-  // Get the data to be displayed in |column| for the given |cert|.
-  base::string16 GetColumnText(CERTCertificate* cert, Column column) const;
+                                    OrgGroupingMap* out_org_grouping_map) const;
 
   // Import private keys and certificates from PKCS #12 encoded
   // |data|, using the given |password|. If |is_extractable| is false,
@@ -132,52 +223,43 @@
   // function returns.
   bool Delete(CERTCertificate* cert);
 
-  // IsHardwareBacked returns true if |cert| is hardware backed.
-  bool IsHardwareBacked(CERTCertificate* cert) const;
-
  private:
-  CertificateManagerModel(
-      net::NSSCertDatabase* nss_cert_database,
-      bool is_user_db_available,
-      bool is_tpm_available,
-      Observer* observer,
-      std::unique_ptr<chromeos::CertificateProvider>
-          extension_certificate_provider);
+  // Called when one of the |certs_sources_| has been updated. Will notify the
+  // |observer_| that the certificate list has been refreshed.
+  void OnCertsSourceUpdated();
+
+  // Finds the |CertsSource| which provided |cert|. Can return nullptr (e.g. if
+  // the cert has been deleted in the meantime).
+  CertsSource* FindCertsSourceForCert(CERTCertificate* cert);
 
   // Methods used during initialization, see the comment at the top of the .cc
   // file for details.
   static void DidGetCertDBOnUIThread(
+      std::unique_ptr<Params> params,
+      CertificateManagerModel::Observer* observer,
+      const CreationCallback& callback,
       net::NSSCertDatabase* cert_db,
       bool is_user_db_available,
-      bool is_tpm_available,
-      CertificateManagerModel::Observer* observer,
-      std::unique_ptr<chromeos::CertificateProvider>
-          extension_certificate_provider,
-      const CreationCallback& callback);
+      bool is_tpm_available);
   static void DidGetCertDBOnIOThread(
+      std::unique_ptr<Params> params,
       CertificateManagerModel::Observer* observer,
-      std::unique_ptr<chromeos::CertificateProvider>
-          extension_certificate_provider,
       const CreationCallback& callback,
       net::NSSCertDatabase* cert_db);
-  static void GetCertDBOnIOThread(
-      content::ResourceContext* context,
-      CertificateManagerModel::Observer* observer,
-      std::unique_ptr<chromeos::CertificateProvider>
-          extension_certificate_provider,
-      const CreationCallback& callback);
-
-  // Callback used by Refresh() for when the cert slots have been unlocked.
-  // This method does the actual refreshing.
-  void RefreshSlotsUnlocked();
-
-  // Callback used to refresh extension provided certificates. Refreshes UI.
-  void RefreshExtensionCertificates(
-      net::ClientCertIdentityList new_cert_identities);
+  static void GetCertDBOnIOThread(std::unique_ptr<Params> params,
+                                  content::ResourceContext* resource_context,
+                                  CertificateManagerModel::Observer* observer,
+                                  const CreationCallback& callback);
 
   net::NSSCertDatabase* cert_db_;
-  net::ScopedCERTCertificateList cert_list_;
-  net::ScopedCERTCertificateList extension_cert_list_;
+
+  // CertsSource instances providing certificates. The order matters - if a
+  // certificate is provided by more than one CertsSource, only the first one is
+  // accepted.
+  std::vector<std::unique_ptr<CertsSource>> certs_sources_;
+
+  bool hold_back_updates_ = false;
+
   // Whether the certificate database has a public slot associated with the
   // profile. If not set, importing certificates is not allowed with this model.
   bool is_user_db_available_;
@@ -186,12 +268,6 @@
   // The observer to notify when certificate list is refreshed.
   Observer* observer_;
 
-  // Certificate provider used to fetch extension provided certificates.
-  std::unique_ptr<chromeos::CertificateProvider>
-      extension_certificate_provider_;
-
-  base::WeakPtrFactory<CertificateManagerModel> weak_ptr_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(CertificateManagerModel);
 };
 
diff --git a/chrome/browser/certificate_manager_model_unittest.cc b/chrome/browser/certificate_manager_model_unittest.cc
new file mode 100644
index 0000000..59ca003
--- /dev/null
+++ b/chrome/browser/certificate_manager_model_unittest.cc
@@ -0,0 +1,639 @@
+// 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/certificate_manager_model.h"
+#include "base/observer_list.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "crypto/scoped_test_nss_db.h"
+#include "net/cert/nss_cert_database.h"
+#include "net/cert/scoped_nss_types.h"
+#include "net/cert/x509_util_nss.h"
+#include "net/ssl/client_cert_identity_test_util.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
+#include "chrome/browser/chromeos/policy/policy_certificate_provider.h"
+#endif
+
+namespace {
+
+// A fake CertificateManagerModel::Observer that has the ability to execute a
+// OnceClosure passed to it when |CertificatesRefreshed| is called.
+class FakeObserver : public CertificateManagerModel::Observer {
+ public:
+  void CertificatesRefreshed() override {
+    if (!run_on_refresh_.is_null())
+      std::move(run_on_refresh_).Run();
+  }
+
+  // Execute |closure| on the next |CertificatesRefreshed| invocation.
+  void RunOnNextRefresh(base::OnceClosure closure) {
+    run_on_refresh_ = std::move(closure);
+  }
+
+ private:
+  base::OnceClosure run_on_refresh_;
+};
+
+// Looks up a |CertInfo| in |org_grouping_map| corresponding to |cert|. Returns
+// nullptr if no such |CertInfo| was found.
+CertificateManagerModel::CertInfo* GetCertInfoFromOrgGroupingMap(
+    const CertificateManagerModel::OrgGroupingMap& org_grouping_map,
+    CERTCertificate* cert) {
+  for (const auto& org_and_cert_info_list : org_grouping_map) {
+    for (const auto& cert_info : org_and_cert_info_list.second) {
+      if (net::x509_util::IsSameCertificate(cert_info->cert(), cert))
+        return cert_info.get();
+    }
+  }
+  return nullptr;
+}
+
+}  // namespace
+
+class CertificateManagerModelTest : public testing::Test {
+ public:
+  CertificateManagerModelTest() {}
+
+ protected:
+  void SetUp() override {
+    ASSERT_TRUE(test_nssdb_.is_open());
+
+    nss_cert_db_ = std::make_unique<net::NSSCertDatabase>(
+        crypto::ScopedPK11Slot(
+            PK11_ReferenceSlot(test_nssdb_.slot())) /* public slot */,
+        crypto::ScopedPK11Slot(
+            PK11_ReferenceSlot(test_nssdb_.slot())) /* private slot */);
+
+    fake_observer_ = std::make_unique<FakeObserver>();
+    certificate_manager_model_ = std::make_unique<CertificateManagerModel>(
+        GetCertificateManagerModelParams(), fake_observer_.get(),
+        nss_cert_db_.get(), true /* is_user_db_available */,
+        true /* bool is_tpm_available */);
+  }
+
+  void TearDown() override {
+    certificate_manager_model_.reset();
+    nss_cert_db_.reset();
+  }
+
+  // Provides the platform-specific |Params| (containing policy/extension
+  // certificate provides on Chrome OS).
+  virtual std::unique_ptr<CertificateManagerModel::Params>
+  GetCertificateManagerModelParams() {
+    return std::make_unique<CertificateManagerModel::Params>();
+  }
+
+ protected:
+  // Invoke an explicit Refresh and wait until the observer has been notified.
+  void RefreshAndWait() {
+    base::RunLoop run_loop;
+    fake_observer_->RunOnNextRefresh(run_loop.QuitClosure());
+    certificate_manager_model_->Refresh();
+    run_loop.Run();
+  }
+
+  content::TestBrowserThreadBundle thread_bundle_;
+  crypto::ScopedTestNSSDB test_nssdb_;
+  std::unique_ptr<net::NSSCertDatabase> nss_cert_db_;
+  std::unique_ptr<FakeObserver> fake_observer_;
+  std::unique_ptr<CertificateManagerModel> certificate_manager_model_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CertificateManagerModelTest);
+};
+
+// CertificateManagerModel correctly lists CA certificates from the platform NSS
+// Database.
+// TODO(https://crbug.com/787602): Re-enable this test when it is identified why
+// it was flaky.
+TEST_F(CertificateManagerModelTest, DISABLED_ListsCertsFromPlatform) {
+  net::ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
+      net::GetTestCertsDirectory(), "websocket_cacert.pem",
+      net::X509Certificate::FORMAT_AUTO);
+  ASSERT_EQ(1U, certs.size());
+  CERTCertificate* cert = certs[0].get();
+
+  ASSERT_EQ(SECSuccess,
+            PK11_ImportCert(test_nssdb_.slot(), cert, CK_INVALID_HANDLE, "cert",
+                            PR_FALSE /* includeTrust (unused) */));
+  RefreshAndWait();
+
+  {
+    CertificateManagerModel::OrgGroupingMap org_grouping_map;
+    certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+        net::CertType::CA_CERT, &org_grouping_map);
+    CertificateManagerModel::CertInfo* cert_info =
+        GetCertInfoFromOrgGroupingMap(org_grouping_map, cert);
+    ASSERT_TRUE(cert_info);
+
+    EXPECT_EQ(net::CertType::CA_CERT, cert_info->type());
+    EXPECT_EQ(base::UTF8ToUTF16("pywebsocket"), cert_info->name());
+    EXPECT_FALSE(cert_info->read_only());
+    // This platform cert is untrusted because it is self-signed and has no
+    // trust bits.
+    EXPECT_TRUE(cert_info->untrusted());
+    EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPlatform,
+              cert_info->source());
+    EXPECT_FALSE(cert_info->web_trust_anchor());
+    EXPECT_FALSE(cert_info->hardware_backed());
+  }
+
+  certificate_manager_model_->SetCertTrust(cert, net::CertType::CA_CERT,
+                                           net::NSSCertDatabase::TRUSTED_SSL);
+  RefreshAndWait();
+  {
+    CertificateManagerModel::OrgGroupingMap org_grouping_map;
+    certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+        net::CertType::CA_CERT, &org_grouping_map);
+    CertificateManagerModel::CertInfo* cert_info =
+        GetCertInfoFromOrgGroupingMap(org_grouping_map, cert);
+    ASSERT_TRUE(cert_info);
+
+    EXPECT_FALSE(cert_info->untrusted());
+    EXPECT_TRUE(cert_info->web_trust_anchor());
+  }
+}
+
+// CertificateManagerModel correctly lists client certificates from the platform
+// NSS Database.
+TEST_F(CertificateManagerModelTest, ListsClientCertsFromPlatform) {
+  net::ScopedCERTCertificate platform_client_cert;
+  net::ImportClientCertAndKeyFromFile(
+      net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8",
+      test_nssdb_.slot(), &platform_client_cert);
+
+  RefreshAndWait();
+
+  CertificateManagerModel::OrgGroupingMap org_grouping_map;
+  certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+      net::CertType::USER_CERT, &org_grouping_map);
+  CertificateManagerModel::CertInfo* platform_cert_info =
+      GetCertInfoFromOrgGroupingMap(org_grouping_map,
+                                    platform_client_cert.get());
+  ASSERT_TRUE(platform_cert_info);
+
+  EXPECT_EQ(net::CertType::USER_CERT, platform_cert_info->type());
+  EXPECT_EQ(base::UTF8ToUTF16("Client Cert A"), platform_cert_info->name());
+  EXPECT_FALSE(platform_cert_info->read_only());
+  EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPlatform,
+            platform_cert_info->source());
+  EXPECT_FALSE(platform_cert_info->web_trust_anchor());
+  EXPECT_FALSE(platform_cert_info->hardware_backed());
+}
+
+#if defined(OS_CHROMEOS)
+namespace {
+
+class FakePolicyCertificateProvider : public policy::PolicyCertificateProvider {
+ public:
+  void AddPolicyProvidedCertsObserver(Observer* observer) override {
+    observer_list_.AddObserver(observer);
+  }
+
+  void RemovePolicyProvidedCertsObserver(Observer* observer) override {
+    observer_list_.RemoveObserver(observer);
+  }
+
+  net::CertificateList GetAllServerAndAuthorityCertificates() const override {
+    net::CertificateList merged;
+    merged.insert(merged.end(), web_trusted_certs_.begin(),
+                  web_trusted_certs_.end());
+    merged.insert(merged.end(), not_web_trusted_certs_.begin(),
+                  not_web_trusted_certs_.end());
+    return merged;
+  }
+
+  net::CertificateList GetWebTrustedCertificates() const override {
+    return web_trusted_certs_;
+  }
+
+  net::CertificateList GetCertificatesWithoutWebTrust() const override {
+    return not_web_trusted_certs_;
+  }
+
+  void SetPolicyProvidedCertificates(
+      const net::CertificateList& web_trusted_certs,
+      const net::CertificateList& not_web_trusted_certs) {
+    web_trusted_certs_ = web_trusted_certs;
+    not_web_trusted_certs_ = not_web_trusted_certs;
+  }
+
+  void NotifyObservers() {
+    net::CertificateList all_server_and_authority_certs =
+        GetAllServerAndAuthorityCertificates();
+    net::CertificateList trust_anchors = GetWebTrustedCertificates();
+
+    for (auto& observer : observer_list_) {
+      observer.OnPolicyProvidedCertsChanged(all_server_and_authority_certs,
+                                            trust_anchors);
+    }
+  }
+
+ private:
+  base::ObserverList<PolicyCertificateProvider::Observer,
+                     true /* check_empty */>::Unchecked observer_list_;
+  net::CertificateList web_trusted_certs_;
+  net::CertificateList not_web_trusted_certs_;
+};
+
+class FakeExtensionCertificateProvider : public chromeos::CertificateProvider {
+ public:
+  FakeExtensionCertificateProvider(
+      const net::CertificateList* extension_client_certificates,
+      const bool* extensions_hang)
+      : extension_client_certificates_(extension_client_certificates),
+        extensions_hang_(extensions_hang) {}
+
+  void GetCertificates(
+      const base::RepeatingCallback<void(net::ClientCertIdentityList)>&
+          callback) override {
+    if (*extensions_hang_)
+      return;
+
+    callback.Run(FakeClientCertIdentityListFromCertificateList(
+        *extension_client_certificates_));
+  }
+
+  std::unique_ptr<CertificateProvider> Copy() override {
+    NOTREACHED();
+    return nullptr;
+  }
+
+ private:
+  const net::CertificateList* extension_client_certificates_;
+
+  // If *|extensions_hang| is true, the |FakeExtensionCertificateProvider| hangs
+  // - it never calls the callbacks passed to |GetCertificates|.
+  const bool* extensions_hang_;
+};
+
+// Looks up a |CertInfo| in |org_grouping_map| corresponding to |cert|. Returns
+// nullptr if no such |CertInfo| was found.
+CertificateManagerModel::CertInfo* GetCertInfoFromOrgGroupingMap(
+    const CertificateManagerModel::OrgGroupingMap& org_grouping_map,
+    const net::X509Certificate* cert) {
+  for (const auto& org_and_cert_info_list : org_grouping_map) {
+    for (const auto& cert_info : org_and_cert_info_list.second) {
+      if (net::x509_util::IsSameCertificate(cert_info->cert(), cert))
+        return cert_info.get();
+    }
+  }
+  return nullptr;
+}
+
+}  // namespace
+
+class CertificateManagerModelChromeOSTest : public CertificateManagerModelTest {
+ protected:
+  std::unique_ptr<CertificateManagerModel::Params>
+  GetCertificateManagerModelParams() override {
+    auto params = std::make_unique<CertificateManagerModel::Params>();
+    params->policy_certs_provider = &policy_certs_provider_;
+    params->extension_certificate_provider =
+        std::make_unique<FakeExtensionCertificateProvider>(
+            &extension_client_certs_, &extensions_hang_);
+    return params;
+  }
+
+  void NotifyPolicyObserversAndWaitForRefresh() {
+    base::RunLoop run_loop;
+    fake_observer_->RunOnNextRefresh(run_loop.QuitClosure());
+    policy_certs_provider_.NotifyObservers();
+    run_loop.Run();
+  }
+
+  // Provider for policy certificates. In a non-test environment, this would
+  // usually be the UserNetworkConfigurationUpdater.
+  FakePolicyCertificateProvider policy_certs_provider_;
+
+  // List of certificates that will be returned from the
+  // FakeExtensionCertificateProvider.
+  net::CertificateList extension_client_certs_;
+  // If true, the FakeExtensionCertificateProvider hangs.
+  bool extensions_hang_ = false;
+};
+
+// CertificateManagerModel correctly lists policy-provided certificates with web
+// trust.
+TEST_F(CertificateManagerModelChromeOSTest, ListsWebTrustedCertsFromPolicy) {
+  scoped_refptr<net::X509Certificate> cert = net::ImportCertFromFile(
+      net::GetTestCertsDirectory(), "websocket_cacert.pem");
+  ASSERT_TRUE(cert.get());
+  policy_certs_provider_.SetPolicyProvidedCertificates({cert}, {});
+
+  NotifyPolicyObserversAndWaitForRefresh();
+
+  CertificateManagerModel::OrgGroupingMap org_grouping_map;
+  certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+      net::CertType::CA_CERT, &org_grouping_map);
+  CertificateManagerModel::CertInfo* cert_info =
+      GetCertInfoFromOrgGroupingMap(org_grouping_map, cert.get());
+  ASSERT_TRUE(cert_info);
+
+  EXPECT_EQ(net::CertType::CA_CERT, cert_info->type());
+  EXPECT_EQ(base::UTF8ToUTF16("pywebsocket"), cert_info->name());
+  EXPECT_TRUE(cert_info->read_only());
+  EXPECT_FALSE(cert_info->untrusted());
+  EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPolicy,
+            cert_info->source());
+  EXPECT_TRUE(cert_info->web_trust_anchor());
+  EXPECT_FALSE(cert_info->hardware_backed());
+}
+
+// CertificateManagerModel correctly lists policy-provided certificates without
+// web trust.
+TEST_F(CertificateManagerModelChromeOSTest, ListsNotWebTrustedCertsFromPolicy) {
+  scoped_refptr<net::X509Certificate> cert = net::ImportCertFromFile(
+      net::GetTestCertsDirectory(), "websocket_cacert.pem");
+  ASSERT_TRUE(cert.get());
+  policy_certs_provider_.SetPolicyProvidedCertificates({}, {cert});
+
+  NotifyPolicyObserversAndWaitForRefresh();
+
+  CertificateManagerModel::OrgGroupingMap org_grouping_map;
+  certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+      net::CertType::CA_CERT, &org_grouping_map);
+  CertificateManagerModel::CertInfo* cert_info =
+      GetCertInfoFromOrgGroupingMap(org_grouping_map, cert.get());
+  ASSERT_TRUE(cert_info);
+
+  EXPECT_EQ(net::CertType::CA_CERT, cert_info->type());
+  EXPECT_EQ(base::UTF8ToUTF16("pywebsocket"), cert_info->name());
+  EXPECT_TRUE(cert_info->read_only());
+  EXPECT_FALSE(cert_info->untrusted());
+  EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPolicy,
+            cert_info->source());
+  EXPECT_FALSE(cert_info->web_trust_anchor());
+  EXPECT_FALSE(cert_info->hardware_backed());
+}
+
+// CertificateManagerModel correctly lists CA certificates that are in the
+// platform NSS database and provided by policy with web trust. The
+// policy-provided certificate hides the platform certificate in this case.
+TEST_F(CertificateManagerModelChromeOSTest,
+       WebTrustedPolicyCertsWinOverPlatformCerts) {
+  net::ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
+      net::GetTestCertsDirectory(), "websocket_cacert.pem",
+      net::X509Certificate::FORMAT_AUTO);
+  ASSERT_EQ(1U, certs.size());
+  CERTCertificate* platform_cert = certs[0].get();
+  ASSERT_EQ(SECSuccess, PK11_ImportCert(test_nssdb_.slot(), platform_cert,
+                                        CK_INVALID_HANDLE, "cert",
+                                        PR_FALSE /* includeTrust (unused) */));
+
+  scoped_refptr<net::X509Certificate> policy_cert = net::ImportCertFromFile(
+      net::GetTestCertsDirectory(), "websocket_cacert.pem");
+  ASSERT_TRUE(policy_cert.get());
+  policy_certs_provider_.SetPolicyProvidedCertificates({policy_cert}, {});
+
+  RefreshAndWait();
+
+  {
+    CertificateManagerModel::OrgGroupingMap org_grouping_map;
+    certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+        net::CertType::CA_CERT, &org_grouping_map);
+    CertificateManagerModel::CertInfo* platform_cert_info =
+        GetCertInfoFromOrgGroupingMap(org_grouping_map, platform_cert);
+    ASSERT_TRUE(platform_cert_info);
+    CertificateManagerModel::CertInfo* policy_cert_info =
+        GetCertInfoFromOrgGroupingMap(org_grouping_map, policy_cert.get());
+    ASSERT_TRUE(policy_cert_info);
+
+    EXPECT_EQ(platform_cert_info, policy_cert_info);
+
+    EXPECT_EQ(net::CertType::CA_CERT, policy_cert_info->type());
+    EXPECT_EQ(base::UTF8ToUTF16("pywebsocket"), policy_cert_info->name());
+    EXPECT_TRUE(policy_cert_info->read_only());
+    EXPECT_FALSE(policy_cert_info->untrusted());
+    EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPolicy,
+              policy_cert_info->source());
+    EXPECT_TRUE(policy_cert_info->web_trust_anchor());
+    EXPECT_FALSE(policy_cert_info->hardware_backed());
+  }
+
+  // Remove the cert from policy-provided certs again. The platform certificate
+  // should be visible afterwards.
+  policy_certs_provider_.SetPolicyProvidedCertificates({}, {});
+  NotifyPolicyObserversAndWaitForRefresh();
+
+  {
+    CertificateManagerModel::OrgGroupingMap org_grouping_map;
+    certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+        net::CertType::CA_CERT, &org_grouping_map);
+    CertificateManagerModel::CertInfo* platform_cert_info =
+        GetCertInfoFromOrgGroupingMap(org_grouping_map, platform_cert);
+    ASSERT_TRUE(platform_cert_info);
+
+    EXPECT_EQ(net::CertType::CA_CERT, platform_cert_info->type());
+    EXPECT_EQ(base::UTF8ToUTF16("pywebsocket"), platform_cert_info->name());
+    EXPECT_FALSE(platform_cert_info->read_only());
+    EXPECT_TRUE(platform_cert_info->untrusted());
+    EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPlatform,
+              platform_cert_info->source());
+    EXPECT_FALSE(platform_cert_info->web_trust_anchor());
+    EXPECT_FALSE(platform_cert_info->hardware_backed());
+  }
+}
+
+// CertificateManagerModel correctly lists CA certificates that are in the
+// platform NSS database and provided by policy without web trust. The platform
+// certificate hides the policy-provided certificate in this case.
+TEST_F(CertificateManagerModelChromeOSTest,
+       PlatformCertsWinOverNotWebTrustedCerts) {
+  net::ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
+      net::GetTestCertsDirectory(), "websocket_cacert.pem",
+      net::X509Certificate::FORMAT_AUTO);
+  ASSERT_EQ(1U, certs.size());
+  CERTCertificate* platform_cert = certs[0].get();
+  ASSERT_EQ(SECSuccess, PK11_ImportCert(test_nssdb_.slot(), platform_cert,
+                                        CK_INVALID_HANDLE, "cert",
+                                        PR_FALSE /* includeTrust (unused) */));
+
+  scoped_refptr<net::X509Certificate> policy_cert = net::ImportCertFromFile(
+      net::GetTestCertsDirectory(), "websocket_cacert.pem");
+  ASSERT_TRUE(policy_cert.get());
+  policy_certs_provider_.SetPolicyProvidedCertificates({}, {policy_cert});
+
+  RefreshAndWait();
+
+  {
+    CertificateManagerModel::OrgGroupingMap org_grouping_map;
+    certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+        net::CertType::CA_CERT, &org_grouping_map);
+    CertificateManagerModel::CertInfo* platform_cert_info =
+        GetCertInfoFromOrgGroupingMap(org_grouping_map, platform_cert);
+    ASSERT_TRUE(platform_cert_info);
+    CertificateManagerModel::CertInfo* policy_cert_info =
+        GetCertInfoFromOrgGroupingMap(org_grouping_map, policy_cert.get());
+    ASSERT_TRUE(policy_cert_info);
+
+    EXPECT_EQ(platform_cert_info, policy_cert_info);
+
+    EXPECT_EQ(net::CertType::CA_CERT, platform_cert_info->type());
+    EXPECT_EQ(base::UTF8ToUTF16("pywebsocket"), platform_cert_info->name());
+    EXPECT_FALSE(platform_cert_info->read_only());
+    EXPECT_TRUE(platform_cert_info->untrusted());
+    EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPlatform,
+              platform_cert_info->source());
+    EXPECT_FALSE(platform_cert_info->web_trust_anchor());
+    EXPECT_FALSE(platform_cert_info->hardware_backed());
+  }
+
+  // Remove the certificate from the platform NSS database. The policy-provided
+  // certificate should be visible afterwards.
+  base::RunLoop run_loop;
+  fake_observer_->RunOnNextRefresh(run_loop.QuitClosure());
+  certificate_manager_model_->Delete(platform_cert);
+  run_loop.Run();
+
+  {
+    CertificateManagerModel::OrgGroupingMap org_grouping_map;
+    certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+        net::CertType::CA_CERT, &org_grouping_map);
+    CertificateManagerModel::CertInfo* policy_cert_info =
+        GetCertInfoFromOrgGroupingMap(org_grouping_map, policy_cert.get());
+    ASSERT_TRUE(policy_cert_info);
+
+    EXPECT_EQ(net::CertType::CA_CERT, policy_cert_info->type());
+    EXPECT_EQ(base::UTF8ToUTF16("pywebsocket"), policy_cert_info->name());
+    EXPECT_TRUE(policy_cert_info->read_only());
+    EXPECT_FALSE(policy_cert_info->untrusted());
+    EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPolicy,
+              policy_cert_info->source());
+    EXPECT_FALSE(policy_cert_info->web_trust_anchor());
+    EXPECT_FALSE(policy_cert_info->hardware_backed());
+  }
+}
+
+// When the Extension CertificateProvider hangs (e.g. because an extension is
+// not responding), policy and platform certificates are still listed.
+TEST_F(CertificateManagerModelChromeOSTest,
+       PlatformAndPolicyCertsListedWhenExtensionsHang) {
+  extensions_hang_ = true;
+
+  net::ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
+      net::GetTestCertsDirectory(), "websocket_cacert.pem",
+      net::X509Certificate::FORMAT_AUTO);
+  ASSERT_EQ(1U, certs.size());
+  CERTCertificate* platform_cert = certs[0].get();
+  ASSERT_EQ(SECSuccess, PK11_ImportCert(test_nssdb_.slot(), platform_cert,
+                                        CK_INVALID_HANDLE, "cert",
+                                        PR_FALSE /* includeTrust (unused) */));
+
+  scoped_refptr<net::X509Certificate> policy_cert =
+      net::ImportCertFromFile(net::GetTestCertsDirectory(), "root_ca_cert.pem");
+  ASSERT_TRUE(policy_cert.get());
+  policy_certs_provider_.SetPolicyProvidedCertificates({policy_cert}, {});
+
+  RefreshAndWait();
+
+  CertificateManagerModel::OrgGroupingMap org_grouping_map;
+  certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+      net::CertType::CA_CERT, &org_grouping_map);
+  CertificateManagerModel::CertInfo* platform_cert_info =
+      GetCertInfoFromOrgGroupingMap(org_grouping_map, platform_cert);
+  ASSERT_TRUE(platform_cert_info);
+  CertificateManagerModel::CertInfo* policy_cert_info =
+      GetCertInfoFromOrgGroupingMap(org_grouping_map, policy_cert.get());
+  ASSERT_TRUE(policy_cert_info);
+
+  EXPECT_NE(platform_cert_info, policy_cert_info);
+}
+
+// CertificateManagerModel lists client certificates provided by extensions.
+TEST_F(CertificateManagerModelChromeOSTest, ListsExtensionCerts) {
+  scoped_refptr<net::X509Certificate> extension_cert =
+      net::ImportCertFromFile(net::GetTestCertsDirectory(), "client_1.pem");
+  ASSERT_TRUE(extension_cert.get());
+  extension_client_certs_.push_back(extension_cert);
+
+  RefreshAndWait();
+
+  CertificateManagerModel::OrgGroupingMap org_grouping_map;
+  certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+      net::CertType::USER_CERT, &org_grouping_map);
+  CertificateManagerModel::CertInfo* extension_cert_info =
+      GetCertInfoFromOrgGroupingMap(org_grouping_map, extension_cert.get());
+  ASSERT_TRUE(extension_cert_info);
+
+  EXPECT_EQ(net::CertType::USER_CERT, extension_cert_info->type());
+  EXPECT_EQ(base::UTF8ToUTF16("Client Cert A (extension provided)"),
+            extension_cert_info->name());
+  EXPECT_TRUE(extension_cert_info->read_only());
+  EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kExtension,
+            extension_cert_info->source());
+  EXPECT_FALSE(extension_cert_info->web_trust_anchor());
+  EXPECT_FALSE(extension_cert_info->hardware_backed());
+}
+
+TEST_F(CertificateManagerModelChromeOSTest,
+       PlatformCertsWinOverExtensionCerts) {
+  net::ScopedCERTCertificate platform_client_cert;
+  net::ImportClientCertAndKeyFromFile(
+      net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8",
+      test_nssdb_.slot(), &platform_client_cert);
+
+  scoped_refptr<net::X509Certificate> extension_cert =
+      net::ImportCertFromFile(net::GetTestCertsDirectory(), "client_1.pem");
+  ASSERT_TRUE(extension_cert.get());
+  extension_client_certs_.push_back(extension_cert);
+
+  RefreshAndWait();
+
+  {
+    CertificateManagerModel::OrgGroupingMap org_grouping_map;
+    certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+        net::CertType::USER_CERT, &org_grouping_map);
+    CertificateManagerModel::CertInfo* platform_cert_info =
+        GetCertInfoFromOrgGroupingMap(org_grouping_map,
+                                      platform_client_cert.get());
+    ASSERT_TRUE(platform_cert_info);
+    CertificateManagerModel::CertInfo* extension_cert_info =
+        GetCertInfoFromOrgGroupingMap(org_grouping_map, extension_cert.get());
+    ASSERT_TRUE(extension_cert_info);
+
+    EXPECT_EQ(platform_cert_info, extension_cert_info);
+
+    EXPECT_EQ(net::CertType::USER_CERT, platform_cert_info->type());
+    EXPECT_EQ(base::UTF8ToUTF16("Client Cert A"), platform_cert_info->name());
+    EXPECT_FALSE(platform_cert_info->read_only());
+    EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPlatform,
+              platform_cert_info->source());
+    EXPECT_FALSE(platform_cert_info->web_trust_anchor());
+    EXPECT_FALSE(platform_cert_info->hardware_backed());
+  }
+
+  // Remove the platform client certificate. The extension-provided client
+  // certificate should be visible afterwards.
+  base::RunLoop run_loop;
+  fake_observer_->RunOnNextRefresh(run_loop.QuitClosure());
+  certificate_manager_model_->Delete(platform_client_cert.get());
+  run_loop.Run();
+
+  {
+    CertificateManagerModel::OrgGroupingMap org_grouping_map;
+    certificate_manager_model_->FilterAndBuildOrgGroupingMap(
+        net::CertType::USER_CERT, &org_grouping_map);
+    CertificateManagerModel::CertInfo* extension_cert_info =
+        GetCertInfoFromOrgGroupingMap(org_grouping_map, extension_cert.get());
+    ASSERT_TRUE(extension_cert_info);
+
+    EXPECT_EQ(net::CertType::USER_CERT, extension_cert_info->type());
+    EXPECT_EQ(base::UTF8ToUTF16("Client Cert A (extension provided)"),
+              extension_cert_info->name());
+    EXPECT_TRUE(extension_cert_info->read_only());
+    EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kExtension,
+              extension_cert_info->source());
+    EXPECT_FALSE(extension_cert_info->web_trust_anchor());
+    EXPECT_FALSE(extension_cert_info->hardware_backed());
+  }
+}
+
+#endif  // defined(OS_CHROMEOS)
diff --git a/chrome/browser/chrome_browser_main_browsertest.cc b/chrome/browser/chrome_browser_main_browsertest.cc
index fe2676a..84eb5064 100644
--- a/chrome/browser/chrome_browser_main_browsertest.cc
+++ b/chrome/browser/chrome_browser_main_browsertest.cc
@@ -14,15 +14,8 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/variations/service/variations_service.h"
 #include "components/variations/variations_switches.h"
-#include "content/public/browser/network_service_instance.h"
-#include "content/public/common/service_manager_connection.h"
-#include "content/public/common/service_names.mojom.h"
-#include "content/public/test/browser_test_utils.h"
 #include "net/base/mock_network_change_notifier.h"
 #include "net/base/network_change_notifier_factory.h"
-#include "services/network/public/cpp/features.h"
-#include "services/network/public/mojom/network_service_test.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
 
 // Friend of ChromeBrowserMainPartsTestApi to poke at internal state.
 class ChromeBrowserMainPartsTestApi {
@@ -43,50 +36,44 @@
 
 namespace {
 
-// Simulates a network connection change.
-void SimulateNetworkChange(network::mojom::ConnectionType type) {
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
-      !content::IsNetworkServiceRunningInProcess()) {
-    network::mojom::NetworkServiceTestPtr network_service_test;
-    content::ServiceManagerConnection::GetForProcess()
-        ->GetConnector()
-        ->BindInterface(content::mojom::kNetworkServiceName,
-                        &network_service_test);
-    base::RunLoop run_loop;
-    network_service_test->SimulateNetworkChange(type, run_loop.QuitClosure());
-    run_loop.Run();
-    return;
-  }
-  net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
-      net::NetworkChangeNotifier::ConnectionType(type));
-}
-
 // ChromeBrowserMainExtraParts used to install a MockNetworkChangeNotifier.
 class ChromeBrowserMainExtraPartsNetFactoryInstaller
     : public ChromeBrowserMainExtraParts {
  public:
   ChromeBrowserMainExtraPartsNetFactoryInstaller() = default;
+  ~ChromeBrowserMainExtraPartsNetFactoryInstaller() override {
+    // |network_change_notifier_| needs to be destroyed before |net_installer_|.
+    network_change_notifier_.reset();
+  }
+
+  net::test::MockNetworkChangeNotifier* network_change_notifier() {
+    return network_change_notifier_.get();
+  }
 
   // ChromeBrowserMainExtraParts:
   void PreEarlyInitialization() override {}
-  void ServiceManagerConnectionStarted(
-      content::ServiceManagerConnection* connection) override {
-    SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_NONE);
+  void PostMainMessageLoopStart() override {
+    ASSERT_TRUE(net::NetworkChangeNotifier::HasNetworkChangeNotifier());
+    net_installer_ =
+        std::make_unique<net::NetworkChangeNotifier::DisableForTest>();
+    network_change_notifier_ =
+        std::make_unique<net::test::MockNetworkChangeNotifier>();
+    network_change_notifier_->SetConnectionType(
+        net::NetworkChangeNotifier::CONNECTION_NONE);
   }
 
  private:
+  std::unique_ptr<net::test::MockNetworkChangeNotifier>
+      network_change_notifier_;
+  std::unique_ptr<net::NetworkChangeNotifier::DisableForTest> net_installer_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsNetFactoryInstaller);
 };
 
-class ChromeBrowserMainBrowserTest
-    : public InProcessBrowserTest,
-      network::NetworkConnectionTracker::NetworkConnectionObserver {
+class ChromeBrowserMainBrowserTest : public InProcessBrowserTest {
  public:
   ChromeBrowserMainBrowserTest() = default;
-  ~ChromeBrowserMainBrowserTest() override {
-    content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(
-        this);
-  }
+  ~ChromeBrowserMainBrowserTest() override = default;
 
  protected:
   // InProcessBrowserTest:
@@ -108,33 +95,8 @@
     chrome_browser_main_parts->AddParts(extra_parts_);
   }
 
-  void SetUpOnMainThread() override {
-    content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
-  }
-
-  void WaitForConnectionType(network::mojom::ConnectionType type) {
-    if (connection_type_ == type)
-      return;
-
-    expected_connection_type_ = type;
-    run_loop_ = std::make_unique<base::RunLoop>();
-    run_loop_->Run();
-  }
-
   ChromeBrowserMainExtraPartsNetFactoryInstaller* extra_parts_ = nullptr;
 
- private:
-  // network::NetworkConnectionTracker::NetworkConnectionObserver:
-  void OnConnectionChanged(network::mojom::ConnectionType type) override {
-    connection_type_ = type;
-    if (expected_connection_type_ == connection_type_ && run_loop_)
-      run_loop_->Quit();
-  }
-
-  network::mojom::ConnectionType expected_connection_type_;
-  network::mojom::ConnectionType connection_type_;
-  std::unique_ptr<base::RunLoop> run_loop_;
-
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainBrowserTest);
 };
 
@@ -145,11 +107,14 @@
   const int initial_request_count =
       g_browser_process->variations_service()->request_count();
   ASSERT_TRUE(extra_parts_);
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_WIFI);
-  WaitForConnectionType(network::mojom::ConnectionType::CONNECTION_WIFI);
+  extra_parts_->network_change_notifier()->SetConnectionType(
+      net::NetworkChangeNotifier::CONNECTION_WIFI);
+  net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
+      net::NetworkChangeNotifier::CONNECTION_WIFI);
   // NotifyObserversOfNetworkChangeForTests uses PostTask, so run the loop until
   // idle to ensure VariationsService processes the network change.
-  base::RunLoop().RunUntilIdle();
+  base::RunLoop run_loop;
+  run_loop.RunUntilIdle();
   const int final_request_count =
       g_browser_process->variations_service()->request_count();
   EXPECT_EQ(initial_request_count + 1, final_request_count);
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 7be05e7d..7da42548 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2408,7 +2408,7 @@
 void ChromeContentBrowserClient::AllowWorkerFileSystem(
     const GURL& url,
     content::ResourceContext* context,
-    const std::vector<std::pair<int, int> >& render_frames,
+    const std::vector<content::GlobalFrameRoutingId>& render_frames,
     base::Callback<void(bool)> callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
@@ -2426,22 +2426,21 @@
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 void ChromeContentBrowserClient::GuestPermissionRequestHelper(
     const GURL& url,
-    const std::vector<std::pair<int, int> >& render_frames,
+    const std::vector<content::GlobalFrameRoutingId>& render_frames,
     base::Callback<void(bool)> callback,
     bool allow) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  std::vector<std::pair<int, int> >::const_iterator i;
   std::map<int, int> process_map;
   std::map<int, int>::const_iterator it;
   bool has_web_view_guest = false;
   // Record access to file system for potential display in UI.
-  for (i = render_frames.begin(); i != render_frames.end(); ++i) {
-    if (process_map.find(i->first) != process_map.end())
+  for (const auto& it : render_frames) {
+    if (process_map.find(it.child_id) != process_map.end())
       continue;
 
-    process_map.insert(std::pair<int, int>(i->first, i->second));
+    process_map.insert(std::pair<int, int>(it.child_id, it.frame_routing_id));
 
-    if (extensions::WebViewRendererState::GetInstance()->IsGuest(i->first))
+    if (extensions::WebViewRendererState::GetInstance()->IsGuest(it.child_id))
       has_web_view_guest = true;
   }
   if (!has_web_view_guest) {
@@ -2480,16 +2479,15 @@
 
 void ChromeContentBrowserClient::FileSystemAccessed(
     const GURL& url,
-    const std::vector<std::pair<int, int> >& render_frames,
+    const std::vector<content::GlobalFrameRoutingId>& render_frames,
     base::Callback<void(bool)> callback,
     bool allow) {
   // Record access to file system for potential display in UI.
-  std::vector<std::pair<int, int> >::const_iterator i;
-  for (i = render_frames.begin(); i != render_frames.end(); ++i) {
+  for (const auto& it : render_frames) {
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
         base::BindOnce(&TabSpecificContentSettings::FileSystemAccessed,
-                       i->first, i->second, url, !allow));
+                       it.child_id, it.frame_routing_id, url, !allow));
   }
   callback.Run(allow);
 }
@@ -2498,7 +2496,7 @@
     const GURL& url,
     const base::string16& name,
     content::ResourceContext* context,
-    const std::vector<std::pair<int, int> >& render_frames) {
+    const std::vector<content::GlobalFrameRoutingId>& render_frames) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
   content_settings::CookieSettings* cookie_settings =
@@ -2506,12 +2504,11 @@
   bool allow = cookie_settings->IsCookieAccessAllowed(url, url);
 
   // Record access to IndexedDB for potential display in UI.
-  std::vector<std::pair<int, int> >::const_iterator i;
-  for (i = render_frames.begin(); i != render_frames.end(); ++i) {
+  for (const auto& it : render_frames) {
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
-        base::BindOnce(&TabSpecificContentSettings::IndexedDBAccessed, i->first,
-                       i->second, url, name, !allow));
+        base::BindOnce(&TabSpecificContentSettings::IndexedDBAccessed,
+                       it.child_id, it.frame_routing_id, url, name, !allow));
   }
 
   return allow;
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index d41a2a79..58cd542ac 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -232,13 +232,13 @@
   void AllowWorkerFileSystem(
       const GURL& url,
       content::ResourceContext* context,
-      const std::vector<std::pair<int, int>>& render_frames,
+      const std::vector<content::GlobalFrameRoutingId>& render_frames,
       base::Callback<void(bool)> callback) override;
   bool AllowWorkerIndexedDB(
       const GURL& url,
       const base::string16& name,
       content::ResourceContext* context,
-      const std::vector<std::pair<int, int>>& render_frames) override;
+      const std::vector<content::GlobalFrameRoutingId>& render_frames) override;
   AllowWebBluetoothResult AllowWebBluetooth(
       content::BrowserContext* browser_context,
       const url::Origin& requesting_origin,
@@ -516,14 +516,14 @@
 
   void FileSystemAccessed(
       const GURL& url,
-      const std::vector<std::pair<int, int> >& render_frames,
+      const std::vector<content::GlobalFrameRoutingId>& render_frames,
       base::Callback<void(bool)> callback,
       bool allow);
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   void GuestPermissionRequestHelper(
       const GURL& url,
-      const std::vector<std::pair<int, int> >& render_frames,
+      const std::vector<content::GlobalFrameRoutingId>& render_frames,
       base::Callback<void(bool)> callback,
       bool allow);
 
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index ea1d515a..dd643d7 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -597,8 +597,6 @@
     "dbus/chrome_features_service_provider.h",
     "dbus/chrome_proxy_resolution_service_provider_delegate.cc",
     "dbus/chrome_proxy_resolution_service_provider_delegate.h",
-    "dbus/chrome_virtual_file_request_service_provider_delegate.cc",
-    "dbus/chrome_virtual_file_request_service_provider_delegate.h",
     "dbus/component_updater_service_provider.cc",
     "dbus/component_updater_service_provider.h",
     "dbus/drive_file_stream_service_provider.cc",
@@ -1485,6 +1483,7 @@
     "policy/policy_cert_service_factory.h",
     "policy/policy_cert_verifier.cc",
     "policy/policy_cert_verifier.h",
+    "policy/policy_certificate_provider.h",
     "policy/policy_oauth2_token_fetcher.cc",
     "policy/policy_oauth2_token_fetcher.h",
     "policy/pre_signin_policy_fetcher.cc",
@@ -2202,6 +2201,7 @@
     "policy/device_cloud_policy_manager_chromeos_unittest.cc",
     "policy/device_cloud_policy_store_chromeos_unittest.cc",
     "policy/device_local_account_policy_service_unittest.cc",
+    "policy/device_policy_decoder_chromeos_unittest.cc",
     "policy/dm_token_storage_unittest.cc",
     "policy/extension_cache_unittest.cc",
     "policy/fake_affiliated_invalidation_service_provider.cc",
diff --git a/chrome/browser/chromeos/account_mapper_util.cc b/chrome/browser/chromeos/account_mapper_util.cc
index 69aa2e7..f067280 100644
--- a/chrome/browser/chromeos/account_mapper_util.cc
+++ b/chrome/browser/chromeos/account_mapper_util.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/chromeos/account_mapper_util.h"
 
+#include "components/account_id/account_id.h"
+#include "components/signin/core/browser/account_info.h"
 #include "components/signin/core/browser/account_tracker_service.h"
 
 namespace chromeos {
@@ -22,12 +24,9 @@
       account_manager::AccountType::ACCOUNT_TYPE_GAIA) {
     return std::string();
   }
-
-  const std::string& account_id =
-      account_tracker_service_->FindAccountInfoByGaiaId(account_key.id)
-          .account_id;
-  DCHECK(!account_id.empty()) << "Can't find account id";
-  return account_id;
+  const AccountInfo& account_info = AccountKeyToGaiaAccountInfo(account_key);
+  DCHECK(!account_info.account_id.empty()) << "Can't find account id";
+  return account_info.account_id;
 }
 
 AccountManager::AccountKey AccountMapperUtil::OAuthAccountIdToAccountKey(
@@ -42,4 +41,35 @@
       account_info.gaia, account_manager::AccountType::ACCOUNT_TYPE_GAIA};
 }
 
+AccountInfo AccountMapperUtil::AccountKeyToGaiaAccountInfo(
+    const AccountManager::AccountKey& account_key) const {
+  AccountInfo account_info;
+
+  DCHECK(account_key.IsValid());
+  if (account_key.account_type !=
+      account_manager::AccountType::ACCOUNT_TYPE_GAIA) {
+    return account_info;
+  }
+  account_info =
+      account_tracker_service_->FindAccountInfoByGaiaId(account_key.id);
+  DCHECK(!account_info.IsEmpty()) << "Can't find account info";
+
+  return account_info;
+}
+
+// static
+bool AccountMapperUtil::IsEqual(const AccountManager::AccountKey& account_key,
+                                const AccountId& account_id) {
+  switch (account_key.account_type) {
+    case chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA:
+      return (account_id.GetAccountType() == AccountType::GOOGLE) &&
+             (account_id.GetGaiaId() == account_key.id);
+    case chromeos::account_manager::AccountType::ACCOUNT_TYPE_ACTIVE_DIRECTORY:
+      return (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY) &&
+             (account_id.GetObjGuid() == account_key.id);
+    case chromeos::account_manager::AccountType::ACCOUNT_TYPE_UNSPECIFIED:
+      return false;
+  }
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/account_mapper_util.h b/chrome/browser/chromeos/account_mapper_util.h
index 14e5b82..d8f1989 100644
--- a/chrome/browser/chromeos/account_mapper_util.h
+++ b/chrome/browser/chromeos/account_mapper_util.h
@@ -10,6 +10,8 @@
 #include "base/macros.h"
 #include "chromeos/account_manager/account_manager.h"
 
+class AccountId;
+struct AccountInfo;
 class AccountTrackerService;
 
 namespace chromeos {
@@ -30,6 +32,16 @@
   AccountManager::AccountKey OAuthAccountIdToAccountKey(
       const std::string& account_id) const;
 
+  // A utility method to map an |account_key| representing a GAIA account to
+  // |AccountInfo|. Returns an empty |AccountInfo| for non-GAIA accounts.
+  AccountInfo AccountKeyToGaiaAccountInfo(
+      const AccountManager::AccountKey& account_key) const;
+
+  // A utility method to check whether |account_key| and |account_id| represent
+  // the same account.
+  static bool IsEqual(const AccountManager::AccountKey& account_key,
+                      const AccountId& account_id);
+
  private:
   // A non-owning pointer to |AccountTrackerService|, which itself is a
   // |KeyedService|.
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc
index 6b258d1..fa59819c 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
 
+#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -18,7 +19,6 @@
 #include "chrome/browser/chromeos/arc/arc_optin_uma.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
-#include "chrome/browser/chromeos/arc/auth/arc_auth_context.h"
 #include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
 #include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator.h"
 #include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_oobe_negotiator.h"
@@ -456,8 +456,6 @@
       cryptohome::Identification(
           multi_user_util::GetAccountIdFromProfile(profile_)));
 
-  context_ = std::make_unique<ArcAuthContext>(profile_);
-
   if (g_enable_check_android_management_in_tests.value_or(g_ui_enabled))
     ArcAndroidManagementChecker::StartClient();
 
@@ -488,7 +486,6 @@
     support_host_->Close();
     support_host_.reset();
   }
-  context_.reset();
   pai_starter_.reset();
   fast_app_reinstall_starter_.reset();
   profile_ = nullptr;
@@ -876,8 +873,7 @@
     return;
 
   android_management_checker_ = std::make_unique<ArcAndroidManagementChecker>(
-      profile_, context_->token_service(), context_->account_id(),
-      false /* retry_on_error */);
+      profile_, false /* retry_on_error */);
   android_management_checker_->StartCheck(
       base::Bind(&ArcSessionManager::OnAndroidManagementChecked,
                  weak_ptr_factory_.GetWeakPtr()));
@@ -931,8 +927,7 @@
   }
 
   android_management_checker_ = std::make_unique<ArcAndroidManagementChecker>(
-      profile_, context_->token_service(), context_->account_id(),
-      true /* retry_on_error */);
+      profile_, true /* retry_on_error */);
   android_management_checker_->StartCheck(
       base::Bind(&ArcSessionManager::OnBackgroundAndroidManagementChecked,
                  weak_ptr_factory_.GetWeakPtr()));
@@ -975,8 +970,8 @@
   provisioning_reported_ = false;
 
   std::string locale;
-  std::string preferred_lanaguages;
-  GetLocaleAndPreferredLanguages(profile_, &locale, &preferred_lanaguages);
+  std::string preferred_languages;
+  GetLocaleAndPreferredLanguages(profile_, &locale, &preferred_languages);
 
   ArcSession::UpgradeParams params;
 
@@ -991,9 +986,9 @@
   params.is_child = profile_->IsChild();
   params.supervision_transition = GetSupervisionTransition(profile_);
   params.locale = locale;
-  // Empty |preferred_lanaguages| is converted to empty array.
+  // Empty |preferred_languages| is converted to empty array.
   params.preferred_languages = base::SplitString(
-      preferred_lanaguages, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+      preferred_languages, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
 
   arc_session_runner_->RequestUpgrade(std::move(params));
 }
@@ -1056,7 +1051,7 @@
   DCHECK_EQ(state_, State::STOPPED);
 
   if (!reenable_arc_) {
-    // Reenabling is not triggered. Do nothing.
+    // Re-enabling is not triggered. Do nothing.
     return;
   }
   DCHECK(enable_requested_);
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.h b/chrome/browser/chromeos/arc/arc_session_manager.h
index 328f60090..24f2167 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.h
+++ b/chrome/browser/chromeos/arc/arc_session_manager.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 #include <ostream>
-#include <string>
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -25,7 +24,6 @@
 namespace arc {
 
 class ArcAndroidManagementChecker;
-class ArcAuthContext;
 class ArcDataRemover;
 class ArcFastAppReinstallStarter;
 class ArcPaiStarter;
@@ -219,10 +217,6 @@
 
   ArcSupportHost* support_host() { return support_host_.get(); }
 
-  // TODO(hidehiko): Get rid of the getter by migration between ArcAuthContext
-  // and ArcAuthCodeFetcher.
-  ArcAuthContext* auth_context() { return context_.get(); }
-
   // On provisioning completion (regardless of whether successfully done or
   // not), this is called with its status. On success, called with
   // ProvisioningResult::SUCCESS, otherwise |result| is the error reason.
@@ -386,7 +380,6 @@
 
   std::unique_ptr<ArcTermsOfServiceNegotiator> terms_of_service_negotiator_;
 
-  std::unique_ptr<ArcAuthContext> context_;
   std::unique_ptr<ArcAndroidManagementChecker> android_management_checker_;
 
   std::unique_ptr<ScopedOptInFlowTracker> scoped_opt_in_tracker_;
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_context.cc b/chrome/browser/chromeos/arc/auth/arc_auth_context.cc
index 97470a7..bc76882 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_context.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_context.cc
@@ -6,16 +6,13 @@
 
 #include <utility>
 
+#include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager_base.h"
 #include "content/public/common/url_constants.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 #include "google_apis/gaia/gaia_constants.h"
@@ -58,17 +55,12 @@
 
 }  // namespace
 
-ArcAuthContext::ArcAuthContext(Profile* profile)
-    : profile_(profile), retry_backoff_(&kRetryBackoffPolicy) {
-  // Get token service and account ID to fetch auth tokens.
-  token_service_ = ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
-  const SigninManagerBase* const signin_manager =
-      SigninManagerFactory::GetForProfile(profile);
-  CHECK(token_service_ && signin_manager);
-  account_id_ = signin_manager->GetAuthenticatedAccountId();
-
-  full_account_id_ = base::UTF16ToUTF8(
-      signin_ui_util::GetAuthenticatedUsername(signin_manager));
+ArcAuthContext::ArcAuthContext(Profile* profile, const std::string& account_id)
+    : profile_(profile),
+      account_id_(account_id),
+      token_service_(ProfileOAuth2TokenServiceFactory::GetForProfile(profile)),
+      retry_backoff_(&kRetryBackoffPolicy) {
+  DCHECK(base::ContainsValue(token_service_->GetAccounts(), account_id_));
 }
 
 ArcAuthContext::~ArcAuthContext() {
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_context.h b/chrome/browser/chromeos/arc/auth/arc_auth_context.h
index a9d5731..f4a9fbcb 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_context.h
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_context.h
@@ -27,15 +27,17 @@
                        public GaiaAuthConsumer,
                        public OAuth2TokenService::Observer {
  public:
-  explicit ArcAuthContext(Profile* profile);
+  // Creates an |ArcAuthContext| for the given |account_id|. This |account_id|
+  // must be the |account_id| used by the OAuth Token Service chain.
+  // Note: |account_id| can be the Device Account or a Secondary Account stored
+  // in Chrome OS Account Manager.
+  ArcAuthContext(Profile* profile, const std::string& account_id);
   ~ArcAuthContext() override;
 
   ProfileOAuth2TokenService* token_service() { return token_service_; }
-  const std::string& account_id() const { return account_id_; }
 
-  // Returns full account id, including dots that are removed in CrOS for
-  // the default account id.
-  const std::string& full_account_id() const { return full_account_id_; }
+  // TODO(sinhak): Check usages of |account_id()| and see if we can remove it.
+  const std::string& account_id() const { return account_id_; }
 
   // Prepares the context. Calling while an inflight operation exists will
   // cancel the inflight operation.
@@ -70,10 +72,8 @@
 
   // Unowned pointer.
   Profile* const profile_;
-  ProfileOAuth2TokenService* token_service_;
-
-  std::string account_id_;
-  std::string full_account_id_;
+  const std::string account_id_;
+  ProfileOAuth2TokenService* const token_service_;
 
   // Whether the merge session should be skipped. Set to true only in testing.
   bool skip_merge_session_for_testing_ = false;
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
index 7c6f7c9..72c072c 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
@@ -6,9 +6,12 @@
 
 #include <utility>
 
+#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/singleton.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/arc/arc_optin_uma.h"
 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
@@ -16,9 +19,14 @@
 #include "chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h"
 #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/account_tracker_service_factory.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/ui/app_list/arc/arc_data_removal_dialog.h"
+#include "chromeos/account_manager/account_manager_factory.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
@@ -28,6 +36,8 @@
 #include "components/arc/arc_supervision_transition.h"
 #include "components/arc/arc_util.h"
 #include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/signin_manager_base.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -121,7 +131,8 @@
                                         const std::string& auth_info,
                                         const std::string& account_name,
                                         mojom::ChromeAccountType account_type,
-                                        bool is_managed) {
+                                        bool is_managed,
+                                        bool is_secondary_account) {
   mojom::AccountInfoPtr account_info = mojom::AccountInfo::New();
   account_info->account_name = account_name;
   if (account_type == mojom::ChromeAccountType::ACTIVE_DIRECTORY_ACCOUNT) {
@@ -134,6 +145,7 @@
   }
   account_info->account_type = account_type;
   account_info->is_managed = is_managed;
+  account_info->is_secondary_account = is_secondary_account;
   return account_info;
 }
 
@@ -151,22 +163,51 @@
 ArcAuthService::ArcAuthService(content::BrowserContext* browser_context,
                                ArcBridgeService* arc_bridge_service)
     : profile_(Profile::FromBrowserContext(browser_context)),
+      account_tracker_service_(
+          AccountTrackerServiceFactory::GetInstance()->GetForProfile(profile_)),
       arc_bridge_service_(arc_bridge_service),
+      account_mapper_util_(account_tracker_service_),
       url_loader_factory_(
           content::BrowserContext::GetDefaultStoragePartition(profile_)
               ->GetURLLoaderFactoryForBrowserProcess()),
       weak_ptr_factory_(this) {
   arc_bridge_service_->auth()->SetHost(this);
   arc_bridge_service_->auth()->AddObserver(this);
+
+  if (chromeos::switches::IsAccountManagerEnabled()) {
+    // TODO(sinhak): This will need to be independent of Profile, when
+    // Multi-Profile on Chrome OS is launched.
+    chromeos::AccountManagerFactory* factory =
+        g_browser_process->platform_part()->GetAccountManagerFactory();
+    account_manager_ = factory->GetAccountManager(profile_->GetPath().value());
+    account_manager_->AddObserver(this);
+  }
 }
 
 ArcAuthService::~ArcAuthService() {
+  if (chromeos::switches::IsAccountManagerEnabled()) {
+    account_manager_->RemoveObserver(this);
+  }
   arc_bridge_service_->auth()->RemoveObserver(this);
   arc_bridge_service_->auth()->SetHost(nullptr);
 }
 
+void ArcAuthService::OnConnectionReady() {
+  if (chromeos::switches::IsAccountManagerEnabled()) {
+    // The Mojo |OnSecondaryAccountUpserted| API is guaranteed to be called at
+    // least once for every account at startup. We need to get the list of
+    // accounts from |AccountManager|, just to be safe, since we may have missed
+    // the initial |AccountManager::Observer| notifications. We can safely call
+    // the Mojo |OnSecondaryAccountUpserted| API twice for every account since
+    // it is guaranteed to be idempotent.
+    account_manager_->GetAccounts(base::BindOnce(
+        &ArcAuthService::GetAccountsCallback, weak_ptr_factory_.GetWeakPtr()));
+  }
+}
+
 void ArcAuthService::OnConnectionClosed() {
-  fetcher_.reset();
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  pending_token_requests_.clear();
 }
 
 void ArcAuthService::OnAuthorizationComplete(mojom::ArcSignInStatus status,
@@ -260,11 +301,32 @@
   instance->OnAccountInfoReady(std::move(account_info), status);
 }
 
-void ArcAuthService::RequestAccountInfo(bool initial_signin) {
+void ArcAuthService::RequestAccountInfo(
+    bool initial_signin,
+    const base::Optional<std::string>& account_name) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  // No other auth code-related operation may be in progress.
-  DCHECK(!fetcher_);
 
+  // Check if |account_name| points to a Secondary Account.
+  if (account_name.has_value()) {
+    DCHECK(!account_name.value().empty());
+
+    const std::string& gaia_id =
+        account_tracker_service_->FindAccountInfoByEmail(account_name.value())
+            .gaia;
+    DCHECK(!gaia_id.empty());
+
+    if (!IsDeviceAccount(chromeos::AccountManager::AccountKey{
+            gaia_id,
+            chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA})) {
+      FetchSecondaryAccountInfo(account_name.value());
+      return;
+    }
+  }
+
+  FetchDeviceAccountInfo(initial_signin);
+}
+
+void ArcAuthService::FetchDeviceAccountInfo(bool initial_signin) {
   const mojom::ChromeAccountType account_type = GetAccountType(profile_);
 
   if (IsArcOptInVerificationDisabled()) {
@@ -272,7 +334,8 @@
         CreateAccountInfo(false /* is_enforced */,
                           std::string() /* auth_info */,
                           std::string() /* auth_name */, account_type,
-                          policy_util::IsAccountManaged(profile_)),
+                          policy_util::IsAccountManaged(profile_),
+                          false /* is_secondary_account */),
         mojom::ArcSignInStatus::SUCCESS);
     return;
   }
@@ -283,10 +346,10 @@
     auto enrollment_token_fetcher =
         std::make_unique<ArcActiveDirectoryEnrollmentTokenFetcher>(
             ArcSessionManager::Get()->support_host());
-    enrollment_token_fetcher->Fetch(
-        base::BindOnce(&ArcAuthService::OnEnrollmentTokenFetched,
-                       weak_ptr_factory_.GetWeakPtr()));
-    fetcher_ = std::move(enrollment_token_fetcher);
+    enrollment_token_fetcher->Fetch(base::BindOnce(
+        &ArcAuthService::OnActiveDirectoryEnrollmentTokenFetched,
+        weak_ptr_factory_.GetWeakPtr(), enrollment_token_fetcher.get()));
+    pending_token_requests_.emplace_back(std::move(enrollment_token_fetcher));
     return;
   }
 
@@ -295,7 +358,8 @@
     OnAccountInfoReady(
         CreateAccountInfo(true /* is_enforced */, std::string() /* auth_info */,
                           std::string() /* auth_name */, account_type,
-                          true /* is_managed */),
+                          true /* is_managed */,
+                          false /* is_secondary_account */),
         mojom::ArcSignInStatus::SUCCESS);
     return;
   }
@@ -308,21 +372,67 @@
     auth_code_fetcher = std::make_unique<ArcRobotAuthCodeFetcher>();
   } else {
     // Optionally retrieve auth code in silent mode.
-    auth_code_fetcher = std::make_unique<ArcBackgroundAuthCodeFetcher>(
-        url_loader_factory_, profile_, ArcSessionManager::Get()->auth_context(),
-        initial_signin);
+    const SigninManagerBase* const signin_manager =
+        SigninManagerFactory::GetForProfile(profile_);
+    auth_code_fetcher = CreateArcBackgroundAuthCodeFetcher(
+        signin_manager->GetAuthenticatedAccountId(), initial_signin);
   }
-  auth_code_fetcher->Fetch(base::Bind(&ArcAuthService::OnAuthCodeFetched,
-                                      weak_ptr_factory_.GetWeakPtr()));
-  fetcher_ = std::move(auth_code_fetcher);
+  auth_code_fetcher->Fetch(
+      base::Bind(&ArcAuthService::OnDeviceAccountAuthCodeFetched,
+                 weak_ptr_factory_.GetWeakPtr(), auth_code_fetcher.get()));
+  pending_token_requests_.emplace_back(std::move(auth_code_fetcher));
 }
 
-void ArcAuthService::OnEnrollmentTokenFetched(
+void ArcAuthService::OnTokenUpserted(
+    const chromeos::AccountManager::AccountKey& account_key) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  // We send only Secondary Account update notifications to ARC++. ARC++ has a
+  // polling mechanism for the Device Account (See the Mojo APIs
+  // |RequestAccountInfo| and |OnAccountInfoReady|).
+  if (IsDeviceAccount(account_key)) {
+    return;
+  }
+
+  auto* instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->auth(),
+                                               OnSecondaryAccountUpserted);
+  if (!instance) {
+    LOG(ERROR) << "Auth instance is not available.";
+    return;
+  }
+
+  const std::string& account_name =
+      account_mapper_util_.AccountKeyToGaiaAccountInfo(account_key).email;
+  DCHECK(!account_name.empty());
+  instance->OnSecondaryAccountUpserted(account_name);
+}
+
+void ArcAuthService::OnAccountRemoved(
+    const chromeos::AccountManager::AccountKey& account_key) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(!IsDeviceAccount(account_key));
+
+  auto* instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->auth(),
+                                               OnSecondaryAccountRemoved);
+  if (!instance) {
+    LOG(ERROR) << "Auth instance is not available.";
+    return;
+  }
+
+  const std::string& account_name =
+      account_mapper_util_.AccountKeyToGaiaAccountInfo(account_key).email;
+  DCHECK(!account_name.empty());
+  instance->OnSecondaryAccountRemoved(account_name);
+}
+
+void ArcAuthService::OnActiveDirectoryEnrollmentTokenFetched(
+    ArcActiveDirectoryEnrollmentTokenFetcher* fetcher,
     ArcActiveDirectoryEnrollmentTokenFetcher::Status status,
     const std::string& enrollment_token,
     const std::string& user_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  fetcher_.reset();
+  DeletePendingTokenRequest(fetcher);
+  fetcher = nullptr;
 
   switch (status) {
     case ArcActiveDirectoryEnrollmentTokenFetcher::Status::SUCCESS: {
@@ -335,7 +445,8 @@
           CreateAccountInfo(true /* is_enforced */, enrollment_token,
                             std::string() /* account_name */,
                             mojom::ChromeAccountType::ACTIVE_DIRECTORY_ACCOUNT,
-                            true),
+                            true /* is_managed */,
+                            false /* is_secondary_account */),
           mojom::ArcSignInStatus::SUCCESS);
       break;
     }
@@ -353,17 +464,24 @@
   }
 }
 
-void ArcAuthService::OnAuthCodeFetched(bool success,
-                                       const std::string& auth_code) {
+void ArcAuthService::OnDeviceAccountAuthCodeFetched(
+    ArcAuthCodeFetcher* fetcher,
+    bool success,
+    const std::string& auth_code) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  fetcher_.reset();
+  DeletePendingTokenRequest(fetcher);
+  fetcher = nullptr;
 
   if (success) {
+    const SigninManagerBase* const signin_manager =
+        SigninManagerFactory::GetForProfile(profile_);
+    const std::string& full_account_id = base::UTF16ToUTF8(
+        signin_ui_util::GetAuthenticatedUsername(signin_manager));
     OnAccountInfoReady(
-        CreateAccountInfo(
-            !IsArcOptInVerificationDisabled(), auth_code,
-            ArcSessionManager::Get()->auth_context()->full_account_id(),
-            GetAccountType(profile_), policy_util::IsAccountManaged(profile_)),
+        CreateAccountInfo(!IsArcOptInVerificationDisabled(), auth_code,
+                          full_account_id, GetAccountType(profile_),
+                          policy_util::IsAccountManaged(profile_),
+                          false /* is_secondary_account */),
         mojom::ArcSignInStatus::SUCCESS);
   } else if (chromeos::DemoSession::Get() &&
              chromeos::DemoSession::Get()->started()) {
@@ -373,7 +491,8 @@
         CreateAccountInfo(true /* is_enforced */, std::string() /* auth_info */,
                           std::string() /* auth_name */,
                           mojom::ChromeAccountType::OFFLINE_DEMO_ACCOUNT,
-                          true /* is_managed */),
+                          true /* is_managed */,
+                          false /* is_secondary_account */),
         mojom::ArcSignInStatus::SUCCESS);
   } else {
     // Send error to ARC.
@@ -382,6 +501,60 @@
   }
 }
 
+void ArcAuthService::FetchSecondaryAccountInfo(
+    const std::string& account_name) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  const std::string& account_id =
+      account_tracker_service_->FindAccountInfoByEmail(account_name).account_id;
+  DCHECK(!account_id.empty());
+
+  std::unique_ptr<ArcBackgroundAuthCodeFetcher> fetcher =
+      CreateArcBackgroundAuthCodeFetcher(account_id,
+                                         false /* initial_signin */);
+  fetcher->Fetch(base::BindRepeating(
+      &ArcAuthService::OnSecondaryAccountAuthCodeFetched,
+      weak_ptr_factory_.GetWeakPtr(), account_name, fetcher.get()));
+  pending_token_requests_.emplace_back(std::move(fetcher));
+}
+
+void ArcAuthService::OnSecondaryAccountAuthCodeFetched(
+    const std::string& account_name,
+    ArcBackgroundAuthCodeFetcher* fetcher,
+    bool success,
+    const std::string& auth_code) {
+  DeletePendingTokenRequest(fetcher);
+  fetcher = nullptr;
+
+  if (success) {
+    OnAccountInfoReady(
+        CreateAccountInfo(true /* is_enforced */, auth_code, account_name,
+                          mojom::ChromeAccountType::USER_ACCOUNT,
+                          false /* is_managed */,
+                          true /* is_secondary_account */),
+        mojom::ArcSignInStatus::SUCCESS);
+  } else {
+    OnAccountInfoReady(
+        nullptr, mojom::ArcSignInStatus::CHROME_SERVER_COMMUNICATION_ERROR);
+  }
+}
+
+void ArcAuthService::DeletePendingTokenRequest(ArcFetcherBase* fetcher) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  for (auto it = pending_token_requests_.begin();
+       it != pending_token_requests_.end(); ++it) {
+    if (it->get() == fetcher) {
+      pending_token_requests_.erase(it);
+      return;
+    }
+  }
+
+  // We should not have received a call to delete a |fetcher| that was not in
+  // |pending_token_requests_|.
+  NOTREACHED();
+}
+
 void ArcAuthService::SetURLLoaderFactoryForTesting(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
   url_loader_factory_ = std::move(url_loader_factory);
@@ -398,4 +571,36 @@
   ArcSessionManager::Get()->StopAndEnableArc();
 }
 
+void ArcAuthService::GetAccountsCallback(
+    std::vector<chromeos::AccountManager::AccountKey> accounts) {
+  for (const auto& account_key : accounts) {
+    OnTokenUpserted(account_key);
+  }
+}
+
+bool ArcAuthService::IsDeviceAccount(
+    const chromeos::AccountManager::AccountKey& account_key) const {
+  const AccountId& device_account_id = chromeos::ProfileHelper::Get()
+                                           ->GetUserByProfile(profile_)
+                                           ->GetAccountId();
+
+  return account_mapper_util_.IsEqual(account_key, device_account_id);
+}
+
+std::unique_ptr<ArcBackgroundAuthCodeFetcher>
+ArcAuthService::CreateArcBackgroundAuthCodeFetcher(
+    const std::string& account_id,
+    bool initial_signin) {
+  auto fetcher = std::make_unique<ArcBackgroundAuthCodeFetcher>(
+      url_loader_factory_, profile_, account_id, initial_signin);
+  if (skip_merge_session_for_testing_)
+    fetcher->SkipMergeSessionForTesting();
+
+  return fetcher;
+}
+
+void ArcAuthService::SkipMergeSessionForTesting() {
+  skip_merge_session_for_testing_ = true;
+}
+
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service.h b/chrome/browser/chromeos/arc/auth/arc_auth_service.h
index ef73872..e59e814 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service.h
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service.h
@@ -7,15 +7,20 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "chrome/browser/chromeos/account_mapper_util.h"
 #include "chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h"
+#include "chromeos/account_manager/account_manager.h"
 #include "components/arc/common/auth.mojom.h"
 #include "components/arc/connection_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
 
+class AccountTrackerService;
 class Profile;
 
 namespace content {
@@ -28,13 +33,16 @@
 
 namespace arc {
 
-class ArcFetcherBase;
+class ArcAuthCodeFetcher;
+class ArcBackgroundAuthCodeFetcher;
 class ArcBridgeService;
+class ArcFetcherBase;
 
 // Implementation of ARC authorization.
 class ArcAuthService : public KeyedService,
                        public mojom::AuthHost,
-                       public ConnectionObserver<mojom::AuthInstance> {
+                       public ConnectionObserver<mojom::AuthInstance>,
+                       public chromeos::AccountManager::Observer {
  public:
   // Returns singleton instance for the given BrowserContext,
   // or nullptr if the browser |context| is not allowed to use ARC.
@@ -48,6 +56,7 @@
   static const char kArcServiceName[];
 
   // ConnectionObserver<mojom::AuthInstance>:
+  void OnConnectionReady() override;
   void OnConnectionClosed() override;
 
   // mojom::AuthHost:
@@ -55,7 +64,9 @@
                                bool initial_signin) override;
   void OnSignInCompleteDeprecated() override;
   void OnSignInFailedDeprecated(mojom::ArcSignInStatus reason) override;
-  void RequestAccountInfo(bool initial_signin) override;
+  void RequestAccountInfo(
+      bool initial_signin,
+      const base::Optional<std::string>& account_name) override;
   void ReportMetrics(mojom::MetricsType metrics_type, int32_t value) override;
   void ReportAccountCheckStatus(mojom::AccountCheckStatus status) override;
   void ReportSupervisionChangeStatus(
@@ -64,13 +75,51 @@
   void SetURLLoaderFactoryForTesting(
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
 
+  // chromeos::AccountManager::Observer:
+  void OnTokenUpserted(
+      const chromeos::AccountManager::AccountKey& account_key) override;
+  void OnAccountRemoved(
+      const chromeos::AccountManager::AccountKey& account_key) override;
+
+  void SkipMergeSessionForTesting();
+
  private:
-  // Callbacks when auth info is fetched.
-  void OnEnrollmentTokenFetched(
+  // Callback when Active Directory Enrollment Token is fetched.
+  void OnActiveDirectoryEnrollmentTokenFetched(
+      ArcActiveDirectoryEnrollmentTokenFetcher* fetcher,
       ArcActiveDirectoryEnrollmentTokenFetcher::Status status,
       const std::string& enrollment_token,
       const std::string& user_id);
-  void OnAuthCodeFetched(bool success, const std::string& auth_code);
+
+  // Issues a request for fetching AccountInfo for the Device Account.
+  // |initial_signin| denotes whether this is the initial ARC++ provisioning
+  // flow or a subsequent sign-in.
+  void FetchDeviceAccountInfo(bool initial_signin);
+
+  // Callback for |FetchDeviceAccountInfo|.
+  // |fetcher| is a pointer to the object that issues this callback. Used for
+  // deleting pending requests from |pending_token_requests_|.
+  // |success| and |auth_code| are the callback parameters passed by
+  // |ArcBackgroundAuthCodeFetcher::Fetch|.
+  void OnDeviceAccountAuthCodeFetched(ArcAuthCodeFetcher* fetcher,
+                                      bool success,
+                                      const std::string& auth_code);
+
+  // Issues a request for fetching AccountInfo for a Secondary Account
+  // represented by |account_name|. |account_name| is the account identifier
+  // used by ARC++/Android.
+  void FetchSecondaryAccountInfo(const std::string& account_name);
+
+  // Callback for |FetchSecondaryAccountInfo|, issued by
+  // |ArcBackgroundAuthCodeFetcher::Fetch|. |account_name| is the account
+  // identifier used by ARC++/Android. |fetcher| is used to identify the
+  // |ArcBackgroundAuthCodeFetcher| instance that completed the request.
+  // |success| and |auth_code| are arguments passed by
+  // |ArcBackgroundAuthCodeFetcher::Fetch| callback.
+  void OnSecondaryAccountAuthCodeFetched(const std::string& account_name,
+                                         ArcBackgroundAuthCodeFetcher* fetcher,
+                                         bool success,
+                                         const std::string& auth_code);
 
   // Called to let ARC container know the account info.
   void OnAccountInfoReady(mojom::AccountInfoPtr account_info,
@@ -79,11 +128,40 @@
   // Callback for data removal confirmation.
   void OnDataRemovalAccepted(bool accepted);
 
+  // |AccountManager::GetAccounts| callback.
+  void GetAccountsCallback(
+      std::vector<chromeos::AccountManager::AccountKey> accounts);
+
+  // Checks whether |account_key| points to the Device Account.
+  bool IsDeviceAccount(
+      const chromeos::AccountManager::AccountKey& account_key) const;
+
+  // Creates an |ArcBackgroundAuthCodeFetcher| for |account_id|. Can be used for
+  // Device Account and Secondary Accounts. |initial_signin| denotes whether the
+  // fetcher is being created for the initial ARC++ provisioning flow or for a
+  // subsequent sign-in.
+  std::unique_ptr<ArcBackgroundAuthCodeFetcher>
+  CreateArcBackgroundAuthCodeFetcher(const std::string& account_id,
+                                     bool initial_signin);
+
+  // Deletes a completed enrollment token / auth code fetch request from
+  // |pending_token_requests_|.
+  void DeletePendingTokenRequest(ArcFetcherBase* fetcher);
+
+  // Non-owning pointers.
   Profile* const profile_;
+  chromeos::AccountManager* account_manager_ = nullptr;
+  AccountTrackerService* const account_tracker_service_;
   ArcBridgeService* const arc_bridge_service_;
+
+  chromeos::AccountMapperUtil account_mapper_util_;
+
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
-  std::unique_ptr<ArcFetcherBase> fetcher_;
+  // A list of pending enrollment token / auth code requests.
+  std::vector<std::unique_ptr<ArcFetcherBase>> pending_token_requests_;
+
+  bool skip_merge_session_for_testing_ = false;
 
   base::WeakPtrFactory<ArcAuthService> weak_ptr_factory_;
 
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
index 96c5c2dc..560e10c 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
+#include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/browser_process.h"
@@ -26,6 +27,7 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/policy/cloud/test_request_interceptor.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/chrome_device_id_helper.h"
 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
 #include "chrome/browser/signin/fake_signin_manager_builder.h"
@@ -36,6 +38,8 @@
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
+#include "chromeos/account_manager/account_manager.h"
+#include "chromeos/account_manager/account_manager_factory.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "components/account_id/account_id.h"
 #include "components/arc/arc_bridge_service.h"
@@ -52,6 +56,7 @@
 #include "components/policy/core/common/policy_switches.h"
 #include "components/prefs/pref_member.h"
 #include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "components/user_manager/user_manager.h"
@@ -92,17 +97,38 @@
     std::move(done_closure_).Run();
   }
 
-  void RequestAccountInfo(base::Closure done_closure) {
-    done_closure_ = done_closure;
-    host_->RequestAccountInfo(true);
+  void RequestAccountInfo(base::OnceClosure done_closure) {
+    done_closure_ = std::move(done_closure);
+    host_->RequestAccountInfo(true /* initial_signin */, base::nullopt);
+  }
+
+  void RequestSecondaryAccountInfo(base::OnceClosure done_closure,
+                                   const std::string& account_name) {
+    done_closure_ = std::move(done_closure);
+    host_->RequestAccountInfo(false /* initial_signin */, account_name);
+  }
+
+  void OnSecondaryAccountUpserted(const std::string& account_name) override {
+    ++num_account_upserted_calls_;
+    upserted_account_name_ = account_name;
+  }
+
+  void OnSecondaryAccountRemoved(const std::string& account_name) override {
+    ++num_account_removed_calls_;
+    removed_account_name_ = account_name;
   }
 
   mojom::AccountInfo* account_info() { return account_info_.get(); }
 
+  int num_account_upserted_calls_ = 0;
+  std::string upserted_account_name_;
+  int num_account_removed_calls_ = 0;
+  std::string removed_account_name_;
+
  private:
   mojom::AuthHostPtr host_;
   mojom::AccountInfoPtr account_info_;
-  base::Closure done_closure_;
+  base::OnceClosure done_closure_;
 };
 
 class ArcAuthServiceTest : public InProcessBrowserTest {
@@ -195,6 +221,16 @@
 
     profile_ = profile_builder.Build();
 
+    chromeos::AccountManagerFactory* factory =
+        g_browser_process->platform_part()->GetAccountManagerFactory();
+    chromeos::AccountManager* account_manager =
+        factory->GetAccountManager(profile_->GetPath().value());
+    account_manager->Initialize(
+        temp_dir_.GetPath(), test_shared_loader_factory_,
+        base::BindRepeating([](const base::RepeatingClosure& closure) -> void {
+          closure.Run();
+        }));
+
     FakeProfileOAuth2TokenService* token_service =
         static_cast<FakeProfileOAuth2TokenService*>(
             ProfileOAuth2TokenServiceFactory::GetForProfile(profile()));
@@ -211,11 +247,6 @@
 
     ArcServiceLauncher::Get()->OnPrimaryUserProfilePrepared(profile());
 
-    // It is non-trivial to navigate through the merge session in a testing
-    // context; currently we just skip it.
-    // TODO(blundell): Figure out how to enable this flow.
-    ArcSessionManager::Get()->auth_context()->SkipMergeSessionForTesting();
-
     auth_service_ = ArcAuthService::GetForBrowserContext(profile());
     DCHECK(auth_service_);
 
@@ -223,6 +254,10 @@
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_);
     auth_service_->SetURLLoaderFactoryForTesting(test_shared_loader_factory_);
+    // It is non-trivial to navigate through the merge session in a testing
+    // context; currently we just skip it.
+    // TODO(blundell): Figure out how to enable this flow.
+    auth_service_->SkipMergeSessionForTesting();
 
     arc_bridge_service_ = ArcServiceManager::Get()->arc_bridge_service();
     DCHECK(arc_bridge_service_);
@@ -230,6 +265,31 @@
     WaitForInstanceReady(arc_bridge_service_->auth());
   }
 
+  void SeedAccountInfo(const std::string& gaia_id, const std::string& email) {
+    AccountTrackerService* account_tracker_service =
+        AccountTrackerServiceFactory::GetInstance()->GetForProfile(profile());
+
+    AccountInfo account_info;
+    account_info.gaia = gaia_id;
+    account_info.email = email;
+    account_info.full_name = "name";
+    account_info.given_name = "name";
+    account_info.hosted_domain = "example.com";
+    account_info.locale = "en";
+    account_info.picture_url = "https://example.com";
+    account_info.is_child_account = false;
+    account_info.account_id = account_tracker_service->PickAccountIdForAccount(
+        account_info.gaia, account_info.email);
+
+    ASSERT_TRUE(account_info.IsValid());
+    account_tracker_service->SeedAccountInfo(account_info);
+
+    FakeProfileOAuth2TokenService* token_service =
+        static_cast<FakeProfileOAuth2TokenService*>(
+            ProfileOAuth2TokenServiceFactory::GetForProfile(profile()));
+    token_service->UpdateCredentials(account_info.account_id, kRefreshToken);
+  }
+
   Profile* profile() { return profile_.get(); }
 
   void set_profile_name(const std::string& username) {
@@ -262,7 +322,7 @@
   SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
   test_url_loader_factory().AddResponse(
       arc::kAuthTokenExchangeEndPoint,
-      "{ \"token\" : \"" + std::string(kFakeAuthCode) + "\" }");
+      R"({ "token" : ")" + std::string(kFakeAuthCode) + R"(" })");
 
   base::RunLoop run_loop;
   auth_instance().RequestAccountInfo(run_loop.QuitClosure());
@@ -276,6 +336,83 @@
             auth_instance().account_info()->account_type);
   EXPECT_FALSE(auth_instance().account_info()->enrollment_token);
   EXPECT_FALSE(auth_instance().account_info()->is_managed);
+  EXPECT_FALSE(auth_instance().account_info()->is_secondary_account);
+}
+
+IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
+                       SecondaryAccountUpsertsArePropagated) {
+  const std::string gaia_id = "123999";
+  const std::string email = "email.111@gmail.com";
+
+  SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
+  SeedAccountInfo(gaia_id, email);
+
+  EXPECT_EQ(0, auth_instance().num_account_upserted_calls_);
+
+  chromeos::AccountManager::AccountKey account_key{
+      gaia_id, chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA};
+  auth_service().OnTokenUpserted(account_key);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(1, auth_instance().num_account_upserted_calls_);
+  EXPECT_EQ(email, auth_instance().upserted_account_name_);
+}
+
+IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
+                       SecondaryAccountRemovalsArePropagated) {
+  const std::string gaia_id = "123999";
+  const std::string email = "email.111@gmail.com";
+
+  SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
+  SeedAccountInfo(gaia_id, email);
+
+  EXPECT_EQ(0, auth_instance().num_account_removed_calls_);
+
+  chromeos::AccountManager::AccountKey account_key{
+      gaia_id, chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA};
+  auth_service().OnAccountRemoved(account_key);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(1, auth_instance().num_account_removed_calls_);
+  EXPECT_EQ(email, auth_instance().removed_account_name_);
+}
+
+IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
+                       DeviceAccountUpsertsAreNotPropagated) {
+  SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
+
+  EXPECT_EQ(0, auth_instance().num_account_upserted_calls_);
+
+  chromeos::AccountManager::AccountKey account_key{
+      kFakeGaiaId, chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA};
+  auth_service().OnTokenUpserted(account_key);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(0, auth_instance().num_account_upserted_calls_);
+}
+
+IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, FetchSecondaryAccountInfoSucceeds) {
+  const std::string gaia_id = "123999";
+  const std::string email = "email.111@gmail.com";
+
+  SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
+  SeedAccountInfo(gaia_id, email);
+  test_url_loader_factory().AddResponse(
+      arc::kAuthTokenExchangeEndPoint,
+      R"({ "token" : ")" + std::string(kFakeAuthCode) + R"(" })");
+
+  base::RunLoop run_loop;
+  auth_instance().RequestSecondaryAccountInfo(run_loop.QuitClosure(), email);
+  run_loop.Run();
+
+  ASSERT_TRUE(auth_instance().account_info());
+  EXPECT_EQ(email, auth_instance().account_info()->account_name.value());
+  EXPECT_EQ(kFakeAuthCode, auth_instance().account_info()->auth_code.value());
+  EXPECT_EQ(mojom::ChromeAccountType::USER_ACCOUNT,
+            auth_instance().account_info()->account_type);
+  EXPECT_FALSE(auth_instance().account_info()->enrollment_token);
+  EXPECT_FALSE(auth_instance().account_info()->is_managed);
+  EXPECT_TRUE(auth_instance().account_info()->is_secondary_account);
 }
 
 class ArcRobotAccountAuthServiceTest : public ArcAuthServiceTest {
@@ -441,7 +578,7 @@
   EXPECT_TRUE(profile()->IsChild());
   test_url_loader_factory().AddResponse(
       arc::kAuthTokenExchangeEndPoint,
-      "{ \"token\" : \"" + std::string(kFakeAuthCode) + "\" }");
+      R"({ "token" : ")" + std::string(kFakeAuthCode) + R"(" })");
 
   base::RunLoop run_loop;
   auth_instance().RequestAccountInfo(run_loop.QuitClosure());
diff --git a/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.cc b/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.cc
index 8ba6be43..0d9ea4b 100644
--- a/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.cc
@@ -51,12 +51,12 @@
 ArcBackgroundAuthCodeFetcher::ArcBackgroundAuthCodeFetcher(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     Profile* profile,
-    ArcAuthContext* context,
+    const std::string& account_id,
     bool initial_signin)
     : OAuth2TokenService::Consumer(kConsumerName),
       url_loader_factory_(std::move(url_loader_factory)),
       profile_(profile),
-      context_(context),
+      context_(profile_, account_id),
       initial_signin_(initial_signin),
       weak_ptr_factory_(this) {}
 
@@ -65,8 +65,8 @@
 void ArcBackgroundAuthCodeFetcher::Fetch(const FetchCallback& callback) {
   DCHECK(callback_.is_null());
   callback_ = callback;
-  context_->Prepare(base::Bind(&ArcBackgroundAuthCodeFetcher::OnPrepared,
-                               weak_ptr_factory_.GetWeakPtr()));
+  context_.Prepare(base::Bind(&ArcBackgroundAuthCodeFetcher::OnPrepared,
+                              weak_ptr_factory_.GetWeakPtr()));
 }
 
 void ArcBackgroundAuthCodeFetcher::OnPrepared(
@@ -77,13 +77,13 @@
   }
 
   // Get token service and account ID to fetch auth tokens.
-  ProfileOAuth2TokenService* const token_service = context_->token_service();
-  const std::string& account_id = context_->account_id();
-  DCHECK(token_service->RefreshTokenIsAvailable(account_id));
+  ProfileOAuth2TokenService* const token_service = context_.token_service();
+  DCHECK(token_service->RefreshTokenIsAvailable(context_.account_id()));
 
   OAuth2TokenService::ScopeSet scopes;
   scopes.insert(GaiaConstants::kOAuth1LoginScope);
-  login_token_request_ = token_service->StartRequest(account_id, scopes, this);
+  login_token_request_ =
+      token_service->StartRequest(context_.account_id(), scopes, this);
 }
 
 void ArcBackgroundAuthCodeFetcher::OnGetTokenSuccess(
@@ -230,11 +230,17 @@
 void ArcBackgroundAuthCodeFetcher::ReportResult(
     const std::string& auth_code,
     OptInSilentAuthCode uma_status) {
-  if (initial_signin_)
+  if (initial_signin_) {
     UpdateSilentAuthCodeUMA(uma_status);
-  else
+  } else {
+    // TODO(sinhak): Check if we need to migrate this / create a new metric.
     UpdateReauthorizationSilentAuthCodeUMA(uma_status);
+  }
   std::move(callback_).Run(!auth_code.empty(), auth_code);
 }
 
+void ArcBackgroundAuthCodeFetcher::SkipMergeSessionForTesting() {
+  context_.SkipMergeSessionForTesting();
+}
+
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h b/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h
index 8622bcc..9ad9c09 100644
--- a/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h
+++ b/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h
@@ -38,16 +38,19 @@
 class ArcBackgroundAuthCodeFetcher : public ArcAuthCodeFetcher,
                                      public OAuth2TokenService::Consumer {
  public:
+  // |account_id| is the id used by the OAuth Token Service chain.
   ArcBackgroundAuthCodeFetcher(
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       Profile* profile,
-      ArcAuthContext* context,
+      const std::string& account_id,
       bool initial_signin);
   ~ArcBackgroundAuthCodeFetcher() override;
 
   // ArcAuthCodeFetcher:
   void Fetch(const FetchCallback& callback) override;
 
+  void SkipMergeSessionForTesting();
+
  private:
   void ResetFetchers();
   void OnPrepared(net::URLRequestContextGetter* request_context_getter);
@@ -65,9 +68,9 @@
                     OptInSilentAuthCode uma_status);
 
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
-  // Unowned pointers.
+  // Unowned pointer.
   Profile* const profile_;
-  ArcAuthContext* const context_;
+  ArcAuthContext context_;
   FetchCallback callback_;
 
   std::unique_ptr<OAuth2TokenService::Request> login_token_request_;
diff --git a/chrome/browser/chromeos/arc/policy/arc_android_management_checker.cc b/chrome/browser/chromeos/arc/policy/arc_android_management_checker.cc
index a369091..4ead23e7 100644
--- a/chrome/browser/chromeos/arc/policy/arc_android_management_checker.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_android_management_checker.cc
@@ -15,9 +15,12 @@
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/common/cloud/device_management_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_manager_base.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace arc {
@@ -33,24 +36,30 @@
   return connector->device_management_service();
 }
 
+// Returns the Device Account Id. Assumes that |profile| is the only Profile
+// on Chrome OS.
+std::string GetDeviceAccountId(Profile* profile) {
+  const SigninManagerBase* const signin_manager =
+      SigninManagerFactory::GetForProfile(profile);
+
+  return signin_manager->GetAuthenticatedAccountId();
+}
+
 }  // namespace
 
-ArcAndroidManagementChecker::ArcAndroidManagementChecker(
-    Profile* profile,
-    ProfileOAuth2TokenService* token_service,
-    const std::string& account_id,
-    bool retry_on_error)
+ArcAndroidManagementChecker::ArcAndroidManagementChecker(Profile* profile,
+                                                         bool retry_on_error)
     : profile_(profile),
-      token_service_(token_service),
-      account_id_(account_id),
+      token_service_(ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)),
+      device_account_id_(GetDeviceAccountId(profile_)),
       retry_on_error_(retry_on_error),
       retry_delay_(kRetryDelayMin),
       android_management_client_(
           GetDeviceManagementService(),
           g_browser_process->system_network_context_manager()
               ->GetSharedURLLoaderFactory(),
-          account_id,
-          token_service),
+          device_account_id_,
+          token_service_),
       weak_ptr_factory_(this) {}
 
 ArcAndroidManagementChecker::~ArcAndroidManagementChecker() {
@@ -79,7 +88,7 @@
 }
 
 void ArcAndroidManagementChecker::EnsureRefreshTokenLoaded() {
-  if (token_service_->RefreshTokenIsAvailable(account_id_)) {
+  if (token_service_->RefreshTokenIsAvailable(device_account_id_)) {
     // If the refresh token is already available, just start the management
     // check immediately.
     StartCheckInternal();
@@ -93,7 +102,7 @@
 
 void ArcAndroidManagementChecker::OnRefreshTokenAvailable(
     const std::string& account_id) {
-  if (account_id != account_id_)
+  if (account_id != device_account_id_)
     return;
   OnRefreshTokensLoaded();
 }
@@ -106,7 +115,7 @@
 void ArcAndroidManagementChecker::StartCheckInternal() {
   DCHECK(!callback_.is_null());
 
-  if (!token_service_->RefreshTokenIsAvailable(account_id_)) {
+  if (!token_service_->RefreshTokenIsAvailable(device_account_id_)) {
     VLOG(2) << "No refresh token is available for android management check.";
     std::move(callback_).Run(policy::AndroidManagementClient::Result::ERROR);
     return;
diff --git a/chrome/browser/chromeos/arc/policy/arc_android_management_checker.h b/chrome/browser/chromeos/arc/policy/arc_android_management_checker.h
index 54b0de6..e1abc36 100644
--- a/chrome/browser/chromeos/arc/policy/arc_android_management_checker.h
+++ b/chrome/browser/chromeos/arc/policy/arc_android_management_checker.h
@@ -21,10 +21,7 @@
 
 class ArcAndroidManagementChecker : public OAuth2TokenService::Observer {
  public:
-  ArcAndroidManagementChecker(Profile* profile,
-                              ProfileOAuth2TokenService* token_service,
-                              const std::string& account_id,
-                              bool retry_on_error);
+  ArcAndroidManagementChecker(Profile* profile, bool retry_on_error);
   ~ArcAndroidManagementChecker() override;
 
   static void StartClient();
@@ -54,7 +51,7 @@
   Profile* profile_;
   ProfileOAuth2TokenService* const token_service_;
 
-  const std::string account_id_;
+  const std::string device_account_id_;
 
   // If true, on error, instead of reporting the error to the caller, schedule
   // the retry with delay.
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 93698f8b..c04f681 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -47,7 +47,6 @@
 #include "chrome/browser/chromeos/boot_times_recorder.h"
 #include "chrome/browser/chromeos/dbus/chrome_features_service_provider.h"
 #include "chrome/browser/chromeos/dbus/chrome_proxy_resolution_service_provider_delegate.h"
-#include "chrome/browser/chromeos/dbus/chrome_virtual_file_request_service_provider_delegate.h"
 #include "chrome/browser/chromeos/dbus/component_updater_service_provider.h"
 #include "chrome/browser/chromeos/dbus/drive_file_stream_service_provider.h"
 #include "chrome/browser/chromeos/dbus/kiosk_info_service_provider.h"
@@ -347,9 +346,7 @@
         kVirtualFileRequestServiceName,
         dbus::ObjectPath(kVirtualFileRequestServicePath),
         CrosDBusService::CreateServiceProviderList(
-            std::make_unique<VirtualFileRequestServiceProvider>(
-                std::make_unique<
-                    ChromeVirtualFileRequestServiceProviderDelegate>())));
+            std::make_unique<VirtualFileRequestServiceProvider>()));
 
     component_updater_service_ = CrosDBusService::Create(
         kComponentUpdaterServiceName,
diff --git a/chrome/browser/chromeos/dbus/chrome_virtual_file_request_service_provider_delegate.cc b/chrome/browser/chromeos/dbus/chrome_virtual_file_request_service_provider_delegate.cc
deleted file mode 100644
index 352e22fb..0000000
--- a/chrome/browser/chromeos/dbus/chrome_virtual_file_request_service_provider_delegate.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/dbus/chrome_virtual_file_request_service_provider_delegate.h"
-
-#include "chrome/browser/chromeos/arc/arc_session_manager.h"
-#include "chrome/browser/chromeos/arc/fileapi/arc_file_system_bridge.h"
-#include "chrome/browser/profiles/profile.h"
-
-namespace chromeos {
-
-namespace {
-
-arc::ArcFileSystemBridge* GetArcFileSystemBridge() {
-  arc::ArcSessionManager* session_manager = arc::ArcSessionManager::Get();
-  if (!session_manager)
-    return nullptr;
-  Profile* profile = session_manager->profile();
-  if (!profile)
-    return nullptr;
-  return arc::ArcFileSystemBridge::GetForBrowserContext(profile);
-}
-
-}  // namespace
-
-ChromeVirtualFileRequestServiceProviderDelegate::
-    ChromeVirtualFileRequestServiceProviderDelegate() = default;
-
-ChromeVirtualFileRequestServiceProviderDelegate::
-    ~ChromeVirtualFileRequestServiceProviderDelegate() = default;
-
-bool ChromeVirtualFileRequestServiceProviderDelegate::HandleReadRequest(
-    const std::string& id,
-    int64_t offset,
-    int64_t size,
-    base::ScopedFD pipe_write_end) {
-  arc::ArcFileSystemBridge* bridge = GetArcFileSystemBridge();
-  if (!bridge)
-    return false;
-  return bridge->HandleReadRequest(id, offset, size, std::move(pipe_write_end));
-}
-
-bool ChromeVirtualFileRequestServiceProviderDelegate::HandleIdReleased(
-    const std::string& id) {
-  arc::ArcFileSystemBridge* bridge = GetArcFileSystemBridge();
-  if (!bridge)
-    return false;
-  return bridge->HandleIdReleased(id);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/chrome_virtual_file_request_service_provider_delegate.h b/chrome/browser/chromeos/dbus/chrome_virtual_file_request_service_provider_delegate.h
deleted file mode 100644
index d00f428..0000000
--- a/chrome/browser/chromeos/dbus/chrome_virtual_file_request_service_provider_delegate.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_DBUS_CHROME_VIRTUAL_FILE_REQUEST_SERVICE_PROVIDER_DELEGATE_H_
-#define CHROME_BROWSER_CHROMEOS_DBUS_CHROME_VIRTUAL_FILE_REQUEST_SERVICE_PROVIDER_DELEGATE_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/chromeos/dbus/virtual_file_request_service_provider.h"
-
-namespace chromeos {
-
-// Chrome's VirtualFileRequestServiceProvider::Delegate implementation.
-class ChromeVirtualFileRequestServiceProviderDelegate
-    : public VirtualFileRequestServiceProvider::Delegate {
- public:
-  ChromeVirtualFileRequestServiceProviderDelegate();
-  ~ChromeVirtualFileRequestServiceProviderDelegate() override;
-
-  // VirtualFileRequestServiceProvider::Delegate overrides:
-  bool HandleReadRequest(const std::string& id,
-                         int64_t offset,
-                         int64_t size,
-                         base::ScopedFD pipe_write_end) override;
-  bool HandleIdReleased(const std::string& id) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ChromeVirtualFileRequestServiceProviderDelegate);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_DBUS_CHROME_VIRTUAL_FILE_REQUEST_SERVICE_PROVIDER_DELEGATE_H_
diff --git a/chrome/browser/chromeos/dbus/virtual_file_request_service_provider.cc b/chrome/browser/chromeos/dbus/virtual_file_request_service_provider.cc
index 39b76e0..05fc138 100644
--- a/chrome/browser/chromeos/dbus/virtual_file_request_service_provider.cc
+++ b/chrome/browser/chromeos/dbus/virtual_file_request_service_provider.cc
@@ -4,17 +4,37 @@
 
 #include "chrome/browser/chromeos/dbus/virtual_file_request_service_provider.h"
 
+#include <stdint.h>
+
+#include <memory>
+#include <string>
 #include <utility>
 
 #include "base/bind.h"
+#include "base/files/scoped_file.h"
+#include "chrome/browser/chromeos/arc/arc_session_manager.h"
+#include "chrome/browser/chromeos/arc/fileapi/arc_file_system_bridge.h"
+#include "chrome/browser/profiles/profile.h"
 #include "dbus/message.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace chromeos {
+namespace {
 
-VirtualFileRequestServiceProvider::VirtualFileRequestServiceProvider(
-    std::unique_ptr<Delegate> delegate)
-    : delegate_(std::move(delegate)), weak_ptr_factory_(this) {}
+arc::ArcFileSystemBridge* GetArcFileSystemBridge() {
+  arc::ArcSessionManager* session_manager = arc::ArcSessionManager::Get();
+  if (!session_manager)
+    return nullptr;
+  Profile* profile = session_manager->profile();
+  if (!profile)
+    return nullptr;
+  return arc::ArcFileSystemBridge::GetForBrowserContext(profile);
+}
+
+}  // namespace
+
+VirtualFileRequestServiceProvider::VirtualFileRequestServiceProvider()
+    : weak_ptr_factory_(this) {}
 
 VirtualFileRequestServiceProvider::~VirtualFileRequestServiceProvider() =
     default;
@@ -57,13 +77,15 @@
         method_call, DBUS_ERROR_INVALID_ARGS, std::string()));
     return;
   }
-  if (!delegate_->HandleReadRequest(id, offset, size,
-                                    std::move(pipe_write_end))) {
+
+  arc::ArcFileSystemBridge* bridge = GetArcFileSystemBridge();
+  if (bridge &&
+      bridge->HandleReadRequest(id, offset, size, std::move(pipe_write_end))) {
+    response_sender.Run(dbus::Response::FromMethodCall(method_call));
+  } else {
     response_sender.Run(dbus::ErrorResponse::FromMethodCall(
         method_call, DBUS_ERROR_FAILED, std::string()));
-    return;
   }
-  response_sender.Run(dbus::Response::FromMethodCall(method_call));
 }
 
 void VirtualFileRequestServiceProvider::HandleIdReleased(
@@ -76,12 +98,14 @@
         method_call, DBUS_ERROR_INVALID_ARGS, std::string()));
     return;
   }
-  if (!delegate_->HandleIdReleased(id)) {
+
+  arc::ArcFileSystemBridge* bridge = GetArcFileSystemBridge();
+  if (bridge && bridge->HandleIdReleased(id)) {
+    response_sender.Run(dbus::Response::FromMethodCall(method_call));
+  } else {
     response_sender.Run(dbus::ErrorResponse::FromMethodCall(
         method_call, DBUS_ERROR_FAILED, std::string()));
-    return;
   }
-  response_sender.Run(dbus::Response::FromMethodCall(method_call));
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/virtual_file_request_service_provider.h b/chrome/browser/chromeos/dbus/virtual_file_request_service_provider.h
index b589fc05..244740ad 100644
--- a/chrome/browser/chromeos/dbus/virtual_file_request_service_provider.h
+++ b/chrome/browser/chromeos/dbus/virtual_file_request_service_provider.h
@@ -5,13 +5,6 @@
 #ifndef CHROME_BROWSER_CHROMEOS_DBUS_VIRTUAL_FILE_REQUEST_SERVICE_PROVIDER_H_
 #define CHROME_BROWSER_CHROMEOS_DBUS_VIRTUAL_FILE_REQUEST_SERVICE_PROVIDER_H_
 
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -29,23 +22,7 @@
 class VirtualFileRequestServiceProvider
     : public CrosDBusService::ServiceProviderInterface {
  public:
-  // TODO(derat): Move the delegate into this class.
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-
-    // Writes the requested data to the given pipe write end.
-    virtual bool HandleReadRequest(const std::string& id,
-                                   int64_t offset,
-                                   int64_t size,
-                                   base::ScopedFD pipe_write_end) = 0;
-
-    // Releases resources associated with the ID.
-    virtual bool HandleIdReleased(const std::string& id) = 0;
-  };
-
-  explicit VirtualFileRequestServiceProvider(
-      std::unique_ptr<Delegate> delegate);
+  VirtualFileRequestServiceProvider();
   ~VirtualFileRequestServiceProvider() override;
 
   // CrosDBusService::ServiceProviderInterface overrides:
@@ -58,8 +35,6 @@
   void HandleIdReleased(dbus::MethodCall* method_call,
                         dbus::ExportedObject::ResponseSender response_sender);
 
-  std::unique_ptr<Delegate> delegate_;
-
   // Keep this last so that all weak pointers will be invalidated at the
   // beginning of destruction.
   base::WeakPtrFactory<VirtualFileRequestServiceProvider> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
index 6b3d9b38..c2e25b0 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -375,11 +375,19 @@
   // check that UnmountPath is really called with the same value.
   EXPECT_CALL(*disk_mount_manager_mock_, UnmountPath(_, _, _))
       .Times(0);
+  EXPECT_CALL(
+      *disk_mount_manager_mock_,
+      UnmountPath(chromeos::CrosDisksClient::GetRemovableDiskMountPoint()
+                      .AppendASCII("mount_path1")
+                      .AsUTF8Unsafe(),
+                  chromeos::UNMOUNT_OPTIONS_NONE, _))
+      .Times(1);
   EXPECT_CALL(*disk_mount_manager_mock_,
-              UnmountPath(
-                  chromeos::CrosDisksClient::GetArchiveMountPoint().AppendASCII(
-                      "archive_mount_path").AsUTF8Unsafe(),
-                  chromeos::UNMOUNT_OPTIONS_NONE, _)).Times(1);
+              UnmountPath(chromeos::CrosDisksClient::GetArchiveMountPoint()
+                              .AppendASCII("archive_mount_path")
+                              .AsUTF8Unsafe(),
+                          chromeos::UNMOUNT_OPTIONS_LAZY, _))
+      .Times(1);
 
   ASSERT_TRUE(RunComponentExtensionTest("file_browser/mount_test"))
       << message_;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
index 99d8f18..8a8ecdb 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
@@ -225,8 +225,12 @@
   switch (volume->type()) {
     case file_manager::VOLUME_TYPE_REMOVABLE_DISK_PARTITION:
     case file_manager::VOLUME_TYPE_MOUNTED_ARCHIVE_FILE: {
+      chromeos::UnmountOptions unmount_options = chromeos::UNMOUNT_OPTIONS_NONE;
+      if (volume->is_read_only())
+        unmount_options = chromeos::UNMOUNT_OPTIONS_LAZY;
+
       DiskMountManager::GetInstance()->UnmountPath(
-          volume->mount_path().value(), chromeos::UNMOUNT_OPTIONS_NONE,
+          volume->mount_path().value(), unmount_options,
           DiskMountManager::UnmountPathCallback());
       break;
     }
diff --git a/chrome/browser/chromeos/file_manager/filesystem_api_util.cc b/chrome/browser/chromeos/file_manager/filesystem_api_util.cc
index 61731e9..b6bbf7a3 100644
--- a/chrome/browser/chromeos/file_manager/filesystem_api_util.cc
+++ b/chrome/browser/chromeos/file_manager/filesystem_api_util.cc
@@ -129,6 +129,7 @@
   switch (type) {
     case storage::kFileSystemTypeNativeLocal:
     case storage::kFileSystemTypeRestrictedNativeLocal:
+    case storage::kFileSystemTypeDriveFs:
       return false;
     default:
       // The path indeed corresponds to a mount point not associated with a
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
index cc8aa16..7121a46 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -1389,7 +1389,8 @@
 InputMethodManagerImpl::GetInputMethodKeyboardController() {
   // Callers expect a nullptr when the keyboard is disabled. See
   // https://crbug.com/850020.
-  return keyboard::KeyboardController::Get()->enabled()
+  return keyboard::KeyboardController::HasInstance() &&
+                 keyboard::KeyboardController::Get()->enabled()
              ? keyboard::KeyboardController::Get()
              : nullptr;
 }
diff --git a/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc b/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc
index 3867f6d5..de5e676 100644
--- a/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc
+++ b/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc
@@ -4,37 +4,80 @@
 
 #include "chrome/browser/chromeos/login/screens/demo_preferences_screen.h"
 
-#include "base/logging.h"
 #include "chrome/browser/chromeos/login/screens/base_screen_delegate.h"
 #include "chrome/browser/chromeos/login/screens/demo_preferences_screen_view.h"
 #include "chrome/browser/chromeos/login/screens/screen_exit_code.h"
+#include "chrome/browser/chromeos/login/screens/welcome_screen.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "ui/base/ime/chromeos/input_method_descriptor.h"
 
 namespace chromeos {
 
+namespace {
+
 constexpr char kUserActionContinue[] = "continue-setup";
 constexpr char kUserActionClose[] = "close-setup";
 
+constexpr char kContextKeyLocale[] = "locale";
+constexpr char kContextKeyInputMethod[] = "input-method";
+
+WelcomeScreen* GetWelcomeScreen() {
+  const WizardController* wizard_controller =
+      WizardController::default_controller();
+  DCHECK(wizard_controller);
+  return WelcomeScreen::Get(wizard_controller->screen_manager());
+}
+
+// Sets locale and input method. If |locale| or |input_method| is empty then
+// they will not be changed.
+void SetApplicationLocaleAndInputMethod(const std::string& locale,
+                                        const std::string& input_method) {
+  WelcomeScreen* welcome_screen = GetWelcomeScreen();
+  DCHECK(welcome_screen);
+  welcome_screen->SetApplicationLocaleAndInputMethod(locale, input_method);
+}
+
+}  // namespace
+
 DemoPreferencesScreen::DemoPreferencesScreen(
     BaseScreenDelegate* base_screen_delegate,
     DemoPreferencesScreenView* view)
     : BaseScreen(base_screen_delegate,
                  OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES),
+      input_manager_observer_(this),
       view_(view) {
   DCHECK(view_);
   view_->Bind(this);
+
+  // TODO(agawronska): Add tests for locale and input changes.
+  input_method::InputMethodManager* input_manager =
+      input_method::InputMethodManager::Get();
+  UpdateInputMethod(input_manager);
+  input_manager_observer_.Add(input_manager);
 }
 
 DemoPreferencesScreen::~DemoPreferencesScreen() {
+  input_method::InputMethodManager::Get()->RemoveObserver(this);
+
   if (view_)
     view_->Bind(nullptr);
 }
 
 void DemoPreferencesScreen::Show() {
+  WelcomeScreen* welcome_screen = GetWelcomeScreen();
+  if (welcome_screen) {
+    initial_locale_ = welcome_screen->GetApplicationLocale();
+    initial_input_method_ = welcome_screen->GetInputMethod();
+  }
+
   if (view_)
     view_->Show();
 }
 
 void DemoPreferencesScreen::Hide() {
+  initial_locale_.clear();
+  initial_input_method_.clear();
+
   if (view_)
     view_->Hide();
 }
@@ -43,15 +86,44 @@
   if (action_id == kUserActionContinue) {
     Finish(ScreenExitCode::DEMO_MODE_PREFERENCES_CONTINUED);
   } else if (action_id == kUserActionClose) {
+    // Restore initial locale and input method if the user pressed back button.
+    SetApplicationLocaleAndInputMethod(initial_locale_, initial_input_method_);
     Finish(ScreenExitCode::DEMO_MODE_PREFERENCES_CANCELED);
   } else {
     BaseScreen::OnUserAction(action_id);
   }
 }
 
+void DemoPreferencesScreen::OnContextKeyUpdated(
+    const ::login::ScreenContext::KeyType& key) {
+  if (key == kContextKeyLocale) {
+    SetApplicationLocaleAndInputMethod(context_.GetString(kContextKeyLocale),
+                                       std::string());
+  } else if (key == kContextKeyInputMethod) {
+    SetApplicationLocaleAndInputMethod(
+        std::string(), context_.GetString(kContextKeyInputMethod));
+  } else {
+    BaseScreen::OnContextKeyUpdated(key);
+  }
+}
+
 void DemoPreferencesScreen::OnViewDestroyed(DemoPreferencesScreenView* view) {
   if (view_ == view)
     view_ = nullptr;
 }
 
+void DemoPreferencesScreen::InputMethodChanged(
+    input_method::InputMethodManager* manager,
+    Profile* profile,
+    bool show_message) {
+  UpdateInputMethod(manager);
+}
+
+void DemoPreferencesScreen::UpdateInputMethod(
+    input_method::InputMethodManager* input_manager) {
+  const input_method::InputMethodDescriptor input_method =
+      input_manager->GetActiveIMEState()->GetCurrentInputMethod();
+  GetContextEditor().SetString(kContextKeyInputMethod, input_method.id());
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/demo_preferences_screen.h b/chrome/browser/chromeos/login/screens/demo_preferences_screen.h
index e4826ea..4aab7a9 100644
--- a/chrome/browser/chromeos/login/screens/demo_preferences_screen.h
+++ b/chrome/browser/chromeos/login/screens/demo_preferences_screen.h
@@ -5,8 +5,13 @@
 #ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_DEMO_PREFERENCES_SCREEN_H_
 #define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_DEMO_PREFERENCES_SCREEN_H_
 
+#include <string>
+
 #include "base/macros.h"
+#include "base/scoped_observer.h"
 #include "chrome/browser/chromeos/login/screens/base_screen.h"
+#include "components/login/screens/screen_context.h"
+#include "ui/base/ime/chromeos/input_method_manager.h"
 
 namespace chromeos {
 
@@ -15,7 +20,9 @@
 
 // Controls demo mode preferences. The screen can be shown during OOBE. It
 // allows user to choose preferences for retail demo mode.
-class DemoPreferencesScreen : public BaseScreen {
+class DemoPreferencesScreen
+    : public BaseScreen,
+      public input_method::InputMethodManager::Observer {
  public:
   DemoPreferencesScreen(BaseScreenDelegate* base_screen_delegate,
                         DemoPreferencesScreenView* view);
@@ -25,12 +32,32 @@
   void Show() override;
   void Hide() override;
   void OnUserAction(const std::string& action_id) override;
+  void OnContextKeyUpdated(const ::login::ScreenContext::KeyType& key) override;
 
   // Called when view is being destroyed. If Screen is destroyed earlier
   // then it has to call Bind(nullptr).
   void OnViewDestroyed(DemoPreferencesScreenView* view);
 
  private:
+  // InputMethodManager::Observer:
+  void InputMethodChanged(input_method::InputMethodManager* manager,
+                          Profile* profile,
+                          bool show_message) override;
+
+  // Passes current input method to the context, so it can be shown in the UI.
+  void UpdateInputMethod(input_method::InputMethodManager* input_manager);
+
+  // Initial locale that was set when the screen was shown. It will be restored
+  // if user presses back button.
+  std::string initial_locale_;
+
+  // Initial input method that was set when the screen was shown. It will be
+  // restored if user presses back button.
+  std::string initial_input_method_;
+
+  ScopedObserver<input_method::InputMethodManager, DemoPreferencesScreen>
+      input_manager_observer_;
+
   DemoPreferencesScreenView* view_;
 
   DISALLOW_COPY_AND_ASSIGN(DemoPreferencesScreen);
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index cffe2e4..f734b34 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -148,7 +148,7 @@
   BaseScreen* GetScreen(OobeScreen screen);
 
   // Returns the current ScreenManager instance.
-  ScreenManager* screen_manager() { return screen_manager_.get(); }
+  ScreenManager* screen_manager() const { return screen_manager_.get(); }
 
   // Volume percent at which spoken feedback is still audible.
   static const int kMinAudibleOutputVolumePercent;
diff --git a/chrome/browser/chromeos/oauth2_token_service_delegate_unittest.cc b/chrome/browser/chromeos/oauth2_token_service_delegate_unittest.cc
index 62573c8..c02771c7 100644
--- a/chrome/browser/chromeos/oauth2_token_service_delegate_unittest.cc
+++ b/chrome/browser/chromeos/oauth2_token_service_delegate_unittest.cc
@@ -105,7 +105,7 @@
         AccountTrackerService::MIGRATION_NOT_STARTED);
     client_ = std::make_unique<TestSigninClient>(&pref_service_);
 
-    account_tracker_service_.Initialize(client_.get());
+    account_tracker_service_.Initialize(&pref_service_, base::FilePath());
 
     account_info_ = CreateAccountInfoTestFixture("111" /* gaia_id */,
                                                  "user@gmail.com" /* email */);
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
index 50a9d17..bc54873 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -15,7 +15,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/syslog_logging.h"
 #include "base/values.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser.h"
 #include "chrome/browser/chromeos/tpm_firmware_update.h"
@@ -23,6 +22,7 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/update_engine_client.h"
 #include "chromeos/settings/cros_settings_names.h"
+#include "components/policy/core/common/chrome_schema.h"
 #include "components/policy/core/common/external_data_fetcher.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/core/common/policy_types.h"
@@ -40,6 +40,26 @@
 
 namespace {
 
+// If the |json_string| can be decoded and validated against the schema
+// identified by |policy_name| in policy_templates.json, the policy
+// |policy_name| in |policies| will be set to the decoded base::Value.
+// Otherwise, the policy will be set to a base::Value of the original
+// |json_string|. This way, the faulty value can still be seen in
+// chrome://policy along with any errors/warnings.
+void SetJsonDevicePolicy(const std::string& policy_name,
+                         const std::string& json_string,
+                         PolicyMap* policies) {
+  std::string error;
+  std::unique_ptr<base::Value> decoded_json =
+      DecodeJsonStringAndNormalize(json_string, policy_name, &error);
+  auto value_to_set = decoded_json ? std::move(decoded_json)
+                                   : std::make_unique<base::Value>(json_string);
+  policies->Set(policy_name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+                POLICY_SOURCE_CLOUD, std::move(value_to_set), nullptr);
+  if (!error.empty())
+    policies->SetError(policy_name, error);
+}
+
 // Decodes a protobuf integer to an IntegerValue. Returns NULL in case the input
 // value is out of bounds.
 std::unique_ptr<base::Value> DecodeIntegerValue(google::protobuf::int64 value) {
@@ -53,50 +73,6 @@
   return std::unique_ptr<base::Value>(new base::Value(static_cast<int>(value)));
 }
 
-// Decodes a JSON string to a base::Value, and drops unknown properties
-// according to a policy schema. |policy_name| is the name of a policy schema
-// defined in policy_templates.json. Returns NULL in case the input is not a
-// valid JSON string.
-std::unique_ptr<base::Value> DecodeJsonStringAndDropUnknownBySchema(
-    const std::string& json_string,
-    const std::string& policy_name) {
-  std::string error;
-  std::unique_ptr<base::Value> root = base::JSONReader::ReadAndReturnError(
-      json_string, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error);
-
-  if (!root) {
-    LOG(WARNING) << "Invalid JSON string: " << error << ", ignoring.";
-    return std::unique_ptr<base::Value>();
-  }
-
-  const Schema& schema = g_browser_process->browser_policy_connector()
-                             ->GetChromeSchema()
-                             .GetKnownProperty(policy_name);
-
-  if (schema.valid()) {
-    std::string error_path;
-    bool changed = false;
-
-    if (!schema.Normalize(root.get(), SCHEMA_ALLOW_UNKNOWN, &error_path, &error,
-                          &changed)) {
-      LOG(WARNING) << "Invalid policy value for " << policy_name << ": "
-                   << error << " at " << error_path << ".";
-      return std::unique_ptr<base::Value>();
-    }
-
-    if (changed) {
-      LOG(WARNING) << "Some properties in " << policy_name
-                   << " were dropped: " << error << " at " << error_path << ".";
-    }
-  } else {
-    LOG(WARNING) << "Unknown or invalid policy schema for " << policy_name
-                 << ".";
-    return std::unique_ptr<base::Value>();
-  }
-
-  return root;
-}
-
 std::unique_ptr<base::Value> DecodeConnectionType(int value) {
   static const char* const kConnectionTypes[] = {
       shill::kTypeEthernet,  shill::kTypeWifi,     shill::kTypeWimax,
@@ -335,15 +311,8 @@
     const em::LoginScreenPowerManagementProto& container(
         policy.login_screen_power_management());
     if (container.has_login_screen_power_management()) {
-      std::unique_ptr<base::Value> decoded_json;
-      decoded_json = DecodeJsonStringAndDropUnknownBySchema(
-          container.login_screen_power_management(),
-          key::kDeviceLoginScreenPowerManagement);
-      if (decoded_json) {
-        policies->Set(key::kDeviceLoginScreenPowerManagement,
-                      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                      POLICY_SOURCE_CLOUD, std::move(decoded_json), nullptr);
-      }
+      SetJsonDevicePolicy(key::kDeviceLoginScreenPowerManagement,
+                          container.login_screen_power_management(), policies);
     }
   }
 
@@ -674,28 +643,13 @@
     }
 
     if (container.has_disallowed_time_intervals()) {
-      std::unique_ptr<base::Value> decoded_json =
-          DecodeJsonStringAndDropUnknownBySchema(
-              container.disallowed_time_intervals(),
-              key::kDeviceAutoUpdateTimeRestrictions);
-      if (decoded_json && !decoded_json->is_none()) {
-        policies->Set(key::kDeviceAutoUpdateTimeRestrictions,
-                      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                      POLICY_SOURCE_CLOUD, std::move(decoded_json), nullptr);
-      }
+      SetJsonDevicePolicy(key::kDeviceAutoUpdateTimeRestrictions,
+                          container.disallowed_time_intervals(), policies);
     }
 
     if (container.has_staging_schedule()) {
-      std::unique_ptr<base::Value> staging_percent_of_fleet_per_week_policy =
-          DecodeJsonStringAndDropUnknownBySchema(
-              container.staging_schedule(), key::kDeviceUpdateStagingSchedule);
-
-      if (staging_percent_of_fleet_per_week_policy) {
-        policies->Set(key::kDeviceUpdateStagingSchedule, POLICY_LEVEL_MANDATORY,
-                      POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
-                      std::move(staging_percent_of_fleet_per_week_policy),
-                      nullptr);
-      }
+      SetJsonDevicePolicy(key::kDeviceUpdateStagingSchedule,
+                          container.staging_schedule(), policies);
     }
   }
 
@@ -933,17 +887,8 @@
     const em::DeviceWallpaperImageProto& container(
         policy.device_wallpaper_image());
     if (container.has_device_wallpaper_image()) {
-      std::unique_ptr<base::DictionaryValue> dict_val =
-          base::DictionaryValue::From(
-              base::JSONReader::Read(container.device_wallpaper_image()));
-      if (dict_val) {
-        policies->Set(key::kDeviceWallpaperImage, POLICY_LEVEL_MANDATORY,
-                      POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
-                      std::move(dict_val), nullptr);
-      } else {
-        SYSLOG(ERROR) << "Value of wallpaper policy has invalid format: "
-                      << container.device_wallpaper_image();
-      }
+      SetJsonDevicePolicy(key::kDeviceWallpaperImage,
+                          container.device_wallpaper_image(), policies);
     }
   }
 
@@ -977,12 +922,8 @@
     const em::DeviceNativePrintersProto& container(
         policy.native_device_printers());
     if (container.has_external_policy()) {
-      std::unique_ptr<base::DictionaryValue> dict_val =
-          base::DictionaryValue::From(
-              base::JSONReader::Read(container.external_policy()));
-      policies->Set(key::kDeviceNativePrinters, POLICY_LEVEL_MANDATORY,
-                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
-                    std::move(dict_val), nullptr);
+      SetJsonDevicePolicy(key::kDeviceNativePrinters,
+                          container.external_policy(), policies);
     }
   }
 
@@ -1112,6 +1053,43 @@
 
 }  // namespace
 
+std::unique_ptr<base::Value> DecodeJsonStringAndNormalize(
+    const std::string& json_string,
+    const std::string& policy_name,
+    std::string* error) {
+  std::string json_error;
+  std::unique_ptr<base::Value> root = base::JSONReader::ReadAndReturnError(
+      json_string, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &json_error);
+  if (!root) {
+    *error = "Invalid JSON string: " + json_error;
+    return nullptr;
+  }
+
+  const Schema& schema =
+      policy::GetChromeSchema().GetKnownProperty(policy_name);
+  CHECK(schema.valid());
+
+  std::string schema_error;
+  std::string error_path;
+  bool changed = false;
+  if (!schema.Normalize(root.get(), SCHEMA_ALLOW_UNKNOWN, &error_path,
+                        &schema_error, &changed)) {
+    std::ostringstream msg;
+    msg << "Invalid policy value: " << schema_error << " (at "
+        << (error_path.empty() ? "toplevel" : error_path) << ")";
+    *error = msg.str();
+    return nullptr;
+  }
+  if (changed) {
+    std::ostringstream msg;
+    msg << "Dropped unknown properties: " << schema_error << " (at "
+        << (error_path.empty() ? "toplevel" : error_path) << ")";
+    *error = msg.str();
+  }
+
+  return root;
+}
+
 void DecodeDevicePolicy(const em::ChromeDeviceSettingsProto& policy,
                         PolicyMap* policies) {
   // Decode the various groups of policies.
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h
index bc9fc63..edc4f7f7 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h
@@ -5,14 +5,32 @@
 #ifndef CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_POLICY_DECODER_CHROMEOS_H_
 #define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_POLICY_DECODER_CHROMEOS_H_
 
+#include <memory>
+#include <string>
+
 namespace enterprise_management {
 class ChromeDeviceSettingsProto;
 }
 
+namespace base {
+class Value;
+}
+
 namespace policy {
 
 class PolicyMap;
 
+// Decodes a JSON string to a base::Value and validates it against the schema
+// defined in policy_templates.json for the policy named |policy_name|. Unknown
+// properties are dropped. Returns nullptr if the input cannot be parsed as
+// valid JSON string or doesn't comply with the declared schema (e.g. mismatched
+// type, missing required field, etc.). Any warning or error messages from the
+// decoding and schema validation process are stored in |error|.
+std::unique_ptr<base::Value> DecodeJsonStringAndNormalize(
+    const std::string& json_string,
+    const std::string& policy_name,
+    std::string* error);
+
 // Decodes device policy in ChromeDeviceSettingsProto representation into the a
 // PolicyMap.
 void DecodeDevicePolicy(
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos_unittest.cc
new file mode 100644
index 0000000..6482e49
--- /dev/null
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos_unittest.cc
@@ -0,0 +1,114 @@
+// 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/chromeos/policy/device_policy_decoder_chromeos.h"
+#include "components/policy/policy_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+namespace {
+
+constexpr char kInvalidJson[] = R"({"foo": "bar")";
+
+constexpr char kInvalidPolicyName[] = "invalid-policy-name";
+
+constexpr char kWallpaperJson[] = R"({
+      "url": "https://example.com/device_wallpaper.jpg",
+      "hash": "examplewallpaperhash"
+    })";
+
+constexpr char kWallpaperJsonInvalidValue[] = R"({
+      "url": 123,
+      "hash": "examplewallpaperhash"
+    })";
+
+constexpr char kWallpaperJsonUnknownProperty[] = R"({
+    "url": "https://example.com/device_wallpaper.jpg",
+    "hash": "examplewallpaperhash",
+    "unknown-field": "random-value"
+  })";
+
+constexpr char kWallpaperUrlPropertyName[] = "url";
+constexpr char kWallpaperUrlPropertyValue[] =
+    "https://example.com/device_wallpaper.jpg";
+constexpr char kWallpaperHashPropertyName[] = "hash";
+constexpr char kWallpaperHashPropertyValue[] = "examplewallpaperhash";
+
+}  // namespace
+
+class DevicePolicyDecoderChromeOSTest : public testing::Test {
+ public:
+  DevicePolicyDecoderChromeOSTest() = default;
+  ~DevicePolicyDecoderChromeOSTest() override = default;
+
+ protected:
+  std::unique_ptr<base::Value> GetWallpaperDict() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DevicePolicyDecoderChromeOSTest);
+};
+
+std::unique_ptr<base::Value> DevicePolicyDecoderChromeOSTest::GetWallpaperDict()
+    const {
+  auto dict = std::make_unique<base::DictionaryValue>();
+  dict->SetKey(kWallpaperUrlPropertyName,
+               base::Value(kWallpaperUrlPropertyValue));
+  dict->SetKey(kWallpaperHashPropertyName,
+               base::Value(kWallpaperHashPropertyValue));
+  return dict;
+}
+
+TEST_F(DevicePolicyDecoderChromeOSTest,
+       DecodeJsonStringAndNormalizeJSONParseError) {
+  std::string error;
+  std::unique_ptr<base::Value> decoded_json = DecodeJsonStringAndNormalize(
+      kInvalidJson, key::kDeviceWallpaperImage, &error);
+  EXPECT_FALSE(decoded_json);
+  EXPECT_EQ("Invalid JSON string: Line: 1, column: 13, Syntax error.", error);
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST_F(DevicePolicyDecoderChromeOSTest,
+       DecodeJsonStringAndNormalizeInvalidSchema) {
+  std::string error;
+  EXPECT_DEATH(
+      DecodeJsonStringAndNormalize(kWallpaperJson, kInvalidPolicyName, &error),
+      "");
+}
+#endif
+
+TEST_F(DevicePolicyDecoderChromeOSTest,
+       DecodeJsonStringAndNormalizeInvalidValue) {
+  std::string error;
+  std::unique_ptr<base::Value> decoded_json = DecodeJsonStringAndNormalize(
+      kWallpaperJsonInvalidValue, key::kDeviceWallpaperImage, &error);
+  EXPECT_FALSE(decoded_json);
+  EXPECT_EQ(
+      "Invalid policy value: The value type doesn't match the schema type. (at "
+      "url)",
+      error);
+}
+
+TEST_F(DevicePolicyDecoderChromeOSTest,
+       DecodeJsonStringAndNormalizeUnknownProperty) {
+  std::string error;
+  std::unique_ptr<base::Value> decoded_json = DecodeJsonStringAndNormalize(
+      kWallpaperJsonUnknownProperty, key::kDeviceWallpaperImage, &error);
+  EXPECT_EQ(*GetWallpaperDict(), *decoded_json);
+  EXPECT_EQ(
+      "Dropped unknown properties: Unknown property: unknown-field (at "
+      "toplevel)",
+      error);
+}
+
+TEST_F(DevicePolicyDecoderChromeOSTest, DecodeJsonStringAndNormalizeSuccess) {
+  std::string error;
+  std::unique_ptr<base::Value> decoded_json = DecodeJsonStringAndNormalize(
+      kWallpaperJson, key::kDeviceWallpaperImage, &error);
+  EXPECT_EQ(*GetWallpaperDict(), *decoded_json);
+  EXPECT_TRUE(error.empty());
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
index 8dcf37f..f2c0ddb0 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/run_loop.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h"
+#include "chrome/browser/chromeos/policy/policy_certificate_provider.h"
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
@@ -81,7 +82,7 @@
 };
 
 class FakePolicyProvidedCertsObserver
-    : public UserNetworkConfigurationUpdater::PolicyProvidedCertsObserver {
+    : public PolicyCertificateProvider::Observer {
  public:
   FakePolicyProvidedCertsObserver() {}
 
@@ -517,7 +518,8 @@
 TEST_F(NetworkConfigurationUpdaterTest,
        DoNotAllowTrustedCertificatesFromPolicy) {
   EXPECT_CALL(network_config_handler_,
-              SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, _, _));
+              SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, _, _))
+      .Times(AnyNumber());
 
   UserNetworkConfigurationUpdater* updater =
       CreateNetworkConfigurationUpdaterForUserPolicy(
@@ -529,10 +531,17 @@
   FakePolicyProvidedCertsObserver observer;
   updater->AddPolicyProvidedCertsObserver(&observer);
 
+  PolicyMap policy;
+  policy.Set(key::kOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY,
+             POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+             std::make_unique<base::Value>(kFakeONC), nullptr);
+  UpdateProviderPolicy(policy);
   MarkPolicyProviderInitialized();
   base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(updater->GetWebTrustedCertificates().empty());
+  EXPECT_EQ(2u, updater->GetCertificatesWithoutWebTrust().size());
+  EXPECT_EQ(2u, updater->GetAllServerAndAuthorityCertificates().size());
 
   EXPECT_TRUE(observer.trust_anchors_.empty());
   updater->RemovePolicyProvidedCertsObserver(&observer);
@@ -564,6 +573,8 @@
 
   // Certificates with the "Web" trust flag set will be returned.
   EXPECT_EQ(1u, updater->GetWebTrustedCertificates().size());
+  EXPECT_EQ(1u, updater->GetCertificatesWithoutWebTrust().size());
+  EXPECT_EQ(2u, updater->GetAllServerAndAuthorityCertificates().size());
 
   EXPECT_EQ(1u, observer.trust_anchors_.size());
   updater->RemovePolicyProvidedCertsObserver(&observer);
@@ -589,6 +600,8 @@
   // Verify that the returned certificate list is empty.
   EXPECT_TRUE(updater->GetWebTrustedCertificates().empty());
   EXPECT_TRUE(observer.trust_anchors_.empty());
+  EXPECT_TRUE(updater->GetCertificatesWithoutWebTrust().empty());
+  EXPECT_TRUE(updater->GetAllServerAndAuthorityCertificates().empty());
 
   // Change to ONC policy with web trust certs.
   PolicyMap policy;
@@ -602,6 +615,8 @@
   // to observers.
   EXPECT_EQ(1u, updater->GetWebTrustedCertificates().size());
   EXPECT_EQ(1u, observer.trust_anchors_.size());
+  EXPECT_EQ(1u, updater->GetCertificatesWithoutWebTrust().size());
+  EXPECT_EQ(2u, updater->GetAllServerAndAuthorityCertificates().size());
 
   updater->RemovePolicyProvidedCertsObserver(&observer);
 }
diff --git a/chrome/browser/chromeos/policy/policy_cert_service.h b/chrome/browser/chromeos/policy/policy_cert_service.h
index 1d436dd5..4ff69a0 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service.h
+++ b/chrome/browser/chromeos/policy/policy_cert_service.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/policy/policy_certificate_provider.h"
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
 #include "components/keyed_service/core/keyed_service.h"
 
@@ -34,9 +35,8 @@
 // and marking the profile's prefs if any of the trust anchors was used.
 // Except for unit tests, PolicyCertVerifier should only be created through this
 // class.
-class PolicyCertService
-    : public KeyedService,
-      public UserNetworkConfigurationUpdater::PolicyProvidedCertsObserver {
+class PolicyCertService : public KeyedService,
+                          public PolicyCertificateProvider::Observer {
  public:
   PolicyCertService(const std::string& user_id,
                     UserNetworkConfigurationUpdater* net_conf_updater,
diff --git a/chrome/browser/chromeos/policy/policy_cert_service_factory.cc b/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
index 8c86647f..a60b2ba00 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
+++ b/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
@@ -99,7 +99,7 @@
     return NULL;
 
   UserNetworkConfigurationUpdater* net_conf_updater =
-      UserNetworkConfigurationUpdaterFactory::GetForProfile(profile);
+      UserNetworkConfigurationUpdaterFactory::GetForBrowserContext(profile);
   if (!net_conf_updater)
     return NULL;
 
diff --git a/chrome/browser/chromeos/policy/policy_certificate_provider.h b/chrome/browser/chromeos/policy/policy_certificate_provider.h
new file mode 100644
index 0000000..ae1654ec
--- /dev/null
+++ b/chrome/browser/chromeos/policy/policy_certificate_provider.h
@@ -0,0 +1,60 @@
+// 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_CHROMEOS_POLICY_POLICY_CERTIFICATE_PROVIDER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_POLICY_CERTIFICATE_PROVIDER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+
+namespace net {
+class X509Certificate;
+using CertificateList = std::vector<scoped_refptr<X509Certificate>>;
+}  // namespace net
+
+namespace policy {
+
+class PolicyCertificateProvider {
+ public:
+  virtual ~PolicyCertificateProvider() {}
+
+  class Observer {
+   public:
+    virtual ~Observer() = default;
+
+    // Is called every time the list of policy-set server and authority
+    // certificates changes.
+    virtual void OnPolicyProvidedCertsChanged(
+        const net::CertificateList& all_server_and_authority_certs,
+        const net::CertificateList& trust_anchors) = 0;
+  };
+
+  virtual void AddPolicyProvidedCertsObserver(Observer* observer) = 0;
+  virtual void RemovePolicyProvidedCertsObserver(Observer* observer) = 0;
+
+  // Returns all server and authority certificates successfully parsed from ONC,
+  // independent of their trust bits.
+  virtual net::CertificateList GetAllServerAndAuthorityCertificates() const = 0;
+
+  // Returns the server and authority certificates which were successfully
+  // parsed from ONC and were granted web trust. This means that the
+  // certificates had the "Web" trust bit set, and this
+  // UserNetworkConfigurationUpdater instance was created with
+  // |allow_trusted_certs_from_policy| = true.
+  virtual net::CertificateList GetWebTrustedCertificates() const = 0;
+
+  // Returns the server and authority certificates which were successfully
+  // parsed from ONC and did not request or were not granted web trust.
+  // This is equivalent to calling |GetAllServerAndAuthorityCertificates| and
+  // then removing all certificates returned by |GetWebTrustedCertificates| from
+  // the result.
+  virtual net::CertificateList GetCertificatesWithoutWebTrust() const = 0;
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_POLICY_CERTIFICATE_PROVIDER_H_
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater.cc b/chrome/browser/chromeos/policy/user_network_configuration_updater.cc
index 2d4d7b7..b15c2f49 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater.cc
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater.cc
@@ -25,6 +25,8 @@
 #include "net/cert/x509_certificate.h"
 #include "net/cert/x509_util_nss.h"
 
+using chromeos::onc::OncParsedCertificates;
+
 namespace policy {
 
 UserNetworkConfigurationUpdater::~UserNetworkConfigurationUpdater() {}
@@ -52,13 +54,13 @@
 }
 
 void UserNetworkConfigurationUpdater::AddPolicyProvidedCertsObserver(
-    PolicyProvidedCertsObserver* observer) {
+    PolicyCertificateProvider::Observer* observer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   observer_list_.AddObserver(observer);
 }
 
 void UserNetworkConfigurationUpdater::RemovePolicyProvidedCertsObserver(
-    PolicyProvidedCertsObserver* observer) {
+    PolicyCertificateProvider::Observer* observer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   observer_list_.RemoveObserver(observer);
 }
@@ -75,7 +77,7 @@
                                   network_config_handler),
       allow_trusted_certificates_from_policy_(allow_trusted_certs_from_policy),
       user_(&user),
-      certs_(std::make_unique<chromeos::onc::OncParsedCertificates>()),
+      certs_(std::make_unique<OncParsedCertificates>()),
       weak_factory_(this) {
   // The updater is created with |client_certificate_importer_| unset and is
   // responsible for creating it. This requires |GetNSSCertDatabaseForProfile|
@@ -89,44 +91,40 @@
 
 net::CertificateList
 UserNetworkConfigurationUpdater::GetAllServerAndAuthorityCertificates() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  net::CertificateList all_server_and_authority_certs;
-
-  for (const chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate&
-           server_or_authority_cert :
-       certs_->server_or_authority_certificates()) {
-    all_server_and_authority_certs.push_back(
-        server_or_authority_cert.certificate());
-  }
-
-  return all_server_and_authority_certs;
+  return GetServerAndAuthorityCertificates(base::BindRepeating(
+      [](const OncParsedCertificates::ServerOrAuthorityCertificate& cert) {
+        return true;
+      }));
 }
 
 net::CertificateList
 UserNetworkConfigurationUpdater::GetWebTrustedCertificates() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
   if (!allow_trusted_certificates_from_policy_)
     return net::CertificateList();
 
-  net::CertificateList trust_anchors;
-  for (const chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate&
-           server_or_authority_cert :
-       certs_->server_or_authority_certificates()) {
-    if (server_or_authority_cert.web_trust_requested())
-      trust_anchors.push_back(server_or_authority_cert.certificate());
-  }
+  return GetServerAndAuthorityCertificates(base::BindRepeating(
+      [](const OncParsedCertificates::ServerOrAuthorityCertificate& cert) {
+        return cert.web_trust_requested();
+      }));
+}
 
-  return trust_anchors;
+net::CertificateList
+UserNetworkConfigurationUpdater::GetCertificatesWithoutWebTrust() const {
+  if (!allow_trusted_certificates_from_policy_)
+    return GetAllServerAndAuthorityCertificates();
+
+  return GetServerAndAuthorityCertificates(base::BindRepeating(
+      [](const OncParsedCertificates::ServerOrAuthorityCertificate& cert) {
+        return !cert.web_trust_requested();
+      }));
 }
 
 void UserNetworkConfigurationUpdater::ImportCertificates(
     const base::ListValue& certificates_onc) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::unique_ptr<chromeos::onc::OncParsedCertificates> incoming_certs =
-      std::make_unique<chromeos::onc::OncParsedCertificates>(certificates_onc);
+  std::unique_ptr<OncParsedCertificates> incoming_certs =
+      std::make_unique<OncParsedCertificates>(certificates_onc);
 
   bool server_or_authority_certs_changed =
       certs_->server_or_authority_certificates() !=
@@ -221,4 +219,20 @@
   }
 }
 
+net::CertificateList
+UserNetworkConfigurationUpdater::GetServerAndAuthorityCertificates(
+    ServerOrAuthorityCertPredicate predicate) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  net::CertificateList certificates;
+
+  for (const OncParsedCertificates::ServerOrAuthorityCertificate&
+           server_or_authority_cert :
+       certs_->server_or_authority_certificates()) {
+    if (predicate.Run(server_or_authority_cert))
+      certificates.push_back(server_or_authority_cert.certificate());
+  }
+
+  return certificates;
+}
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater.h b/chrome/browser/chromeos/policy/user_network_configuration_updater.h
index 07edd6f..d37e9f7 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater.h
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater.h
@@ -15,6 +15,7 @@
 #include "base/observer_list.h"
 #include "base/sequence_checker.h"
 #include "chrome/browser/chromeos/policy/network_configuration_updater.h"
+#include "chrome/browser/chromeos/policy/policy_certificate_provider.h"
 #include "chromeos/network/onc/onc_parsed_certificates.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "content/public/browser/notification_observer.h"
@@ -52,18 +53,10 @@
 // expansion with the user's name (or email address, etc.) and handling of "Web"
 // trust of certificates.
 class UserNetworkConfigurationUpdater : public NetworkConfigurationUpdater,
+                                        public PolicyCertificateProvider,
                                         public KeyedService,
                                         public content::NotificationObserver {
  public:
-  class PolicyProvidedCertsObserver {
-   public:
-    // Is called every time the list of policy-set server and authority
-    // certificates changes.
-    virtual void OnPolicyProvidedCertsChanged(
-        const net::CertificateList& all_server_and_authority_certs,
-        const net::CertificateList& trust_anchors) = 0;
-  };
-
   ~UserNetworkConfigurationUpdater() override;
 
   // Creates an updater that applies the ONC user policy from |policy_service|
@@ -79,19 +72,14 @@
       PolicyService* policy_service,
       chromeos::ManagedNetworkConfigurationHandler* network_config_handler);
 
-  void AddPolicyProvidedCertsObserver(PolicyProvidedCertsObserver* observer);
-  void RemovePolicyProvidedCertsObserver(PolicyProvidedCertsObserver* observer);
-
-  // Returns all server and authority certificates successfully parsed from ONC,
-  // independent of their trust bits.
-  net::CertificateList GetAllServerAndAuthorityCertificates() const;
-
-  // Returns the server and authority certificates which were successfully
-  // parsed from ONC and were granted web trust. This means that the
-  // certificates had the "Web" trust bit set, and this
-  // UserNetworkConfigurationUpdater instance was created with
-  // |allow_trusted_certs_from_policy| = true.
-  net::CertificateList GetWebTrustedCertificates() const;
+  // PolicyCertificateProvider:
+  void AddPolicyProvidedCertsObserver(
+      PolicyCertificateProvider::Observer* observer) override;
+  void RemovePolicyProvidedCertsObserver(
+      PolicyCertificateProvider::Observer* observer) override;
+  net::CertificateList GetAllServerAndAuthorityCertificates() const override;
+  net::CertificateList GetWebTrustedCertificates() const override;
+  net::CertificateList GetCertificatesWithoutWebTrust() const override;
 
   // Helper method to expose |SetClientCertificateImporter| for usage in tests.
   // Note that the CertificateImporter is only used for importing client
@@ -102,6 +90,11 @@
  private:
   class CrosTrustAnchorProvider;
 
+  // A predicate used for filtering server or authority certificates.
+  using ServerOrAuthorityCertPredicate = base::RepeatingCallback<bool(
+      const chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate&
+          cert)>;
+
   UserNetworkConfigurationUpdater(
       Profile* profile,
       bool allow_trusted_certs_from_policy,
@@ -132,13 +125,18 @@
 
   void NotifyPolicyProvidedCertsChanged();
 
+  // Returns all server and authority certificates successfully parsed from ONC
+  // for which |predicate| returns true.
+  net::CertificateList GetServerAndAuthorityCertificates(
+      ServerOrAuthorityCertPredicate predicate) const;
+
   // Whether Web trust is allowed or not.
   bool allow_trusted_certificates_from_policy_;
 
   // The user for whom the user policy will be applied.
   const user_manager::User* user_;
 
-  base::ObserverList<PolicyProvidedCertsObserver, true>::Unchecked
+  base::ObserverList<PolicyCertificateProvider::Observer, true>::Unchecked
       observer_list_;
 
   // Holds certificates from the last parsed ONC policy.
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc
index 680c8171..b503ed2 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc
@@ -21,9 +21,10 @@
 
 // static
 UserNetworkConfigurationUpdater*
-UserNetworkConfigurationUpdaterFactory::GetForProfile(Profile* profile) {
+UserNetworkConfigurationUpdaterFactory::GetForBrowserContext(
+    content::BrowserContext* browser_context) {
   return static_cast<UserNetworkConfigurationUpdater*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
+      GetInstance()->GetServiceForBrowserContext(browser_context, true));
 }
 
 // static
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h
index 946721c..e250989 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h
@@ -14,7 +14,9 @@
 struct DefaultSingletonTraits;
 }  // namespace base
 
-class Profile;
+namespace content {
+class BrowserContext;
+}
 
 namespace policy {
 
@@ -25,9 +27,11 @@
     : public BrowserContextKeyedServiceFactory {
  public:
   // Returns an existing or creates a new UserNetworkConfigurationUpdater for
-  // |profile|. Will return NULL if this service isn't allowed for |profile|,
-  // i.e. for all but the primary user's profile.
-  static UserNetworkConfigurationUpdater* GetForProfile(Profile* profile);
+  // |browser_context|. Will return nullptr if this service isn't allowed for
+  // |browser_context|, i.e. for all but the BrowserContext which refers to the
+  // primary user's profile.
+  static UserNetworkConfigurationUpdater* GetForBrowserContext(
+      content::BrowserContext* browser_context);
 
   static UserNetworkConfigurationUpdaterFactory* GetInstance();
 
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc
index 544a7ae..838d51e 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 #include "chrome/browser/chromeos/policy/login_policy_test_base.h"
+#include "chrome/browser/chromeos/policy/policy_certificate_provider.h"
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -74,11 +75,11 @@
 // Allows waiting until the list of policy-pushed web-trusted certificates
 // changes.
 class WebTrustedCertsChangedObserver
-    : public UserNetworkConfigurationUpdater::PolicyProvidedCertsObserver {
+    : public PolicyCertificateProvider::Observer {
  public:
   WebTrustedCertsChangedObserver() {}
 
-  // UserNetworkConfigurationUpdater:PolicyProvidedCertsObserver
+  // PolicyCertificateProvider::Observer
   void OnPolicyProvidedCertsChanged(
       const net::CertificateList& all_server_and_authority_certs,
       const net::CertificateList& trust_anchors) override {
@@ -255,7 +256,7 @@
   // |profile|'s UserNetworkConfigurationUpdater.
   void SetRootCertONCPolicy(Profile* profile) {
     UserNetworkConfigurationUpdater* user_network_configuration_updater =
-        UserNetworkConfigurationUpdaterFactory::GetForProfile(profile);
+        UserNetworkConfigurationUpdaterFactory::GetForBrowserContext(profile);
     WebTrustedCertsChangedObserver trust_roots_changed_observer;
     user_network_configuration_updater->AddPolicyProvidedCertsObserver(
         &trust_roots_changed_observer);
diff --git a/chrome/browser/chromeos/printing/synced_printers_manager.cc b/chrome/browser/chromeos/printing/synced_printers_manager.cc
index 73fcfd17..860f0f26 100644
--- a/chrome/browser/chromeos/printing/synced_printers_manager.cc
+++ b/chrome/browser/chromeos/printing/synced_printers_manager.cc
@@ -354,8 +354,6 @@
 // static
 void SyncedPrintersManager::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
-  registry->RegisterListPref(prefs::kPrintingDevices,
-                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterListPref(prefs::kRecommendedNativePrinters);
 
   ExternalPrintersPrefBridge::RegisterProfilePrefs(registry, UserPolicyNames());
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc
index 4904303..cc9a253 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
+#include "chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h"
 #include "chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/device_settings_cache.h"
@@ -35,6 +36,7 @@
 #include "components/policy/core/common/chrome_schema.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/schema.h"
+#include "components/policy/policy_constants.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "components/prefs/pref_service.h"
 
@@ -121,49 +123,23 @@
     kDeviceAutoUpdateTimeRestrictions,
 };
 
-// Decodes a JSON string to a base::Value, and drops unknown properties
-// according to a policy schema. |policy_name| is the name of a policy schema
-// defined in policy_templates.json. Returns null in case the input is not a
-// valid JSON string.
-std::unique_ptr<base::Value> DecodeJsonStringAndDropUnknownBySchema(
-    const std::string& json_string,
-    const std::string& policy_name) {
+// Re-use the DecodeJsonStringAndNormalize from device_policy_decoder_chromeos.h
+// here to decode the json string and validate it against |policy_name|'s
+// schema. If the json string is valid, the decoded base::Value will be stored
+// as |setting_name| in |pref_value_map|. The error can be ignored here since it
+// is already reported during decoding in device_policy_decoder_chromeos.cc.
+void SetJsonDeviceSetting(const std::string& setting_name,
+                          const std::string& policy_name,
+                          const std::string& json_string,
+                          PrefValueMap* pref_value_map) {
   std::string error;
-  std::unique_ptr<base::Value> root = base::JSONReader::ReadAndReturnError(
-      json_string, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
-
-  if (!root) {
-    LOG(WARNING) << "Invalid JSON string: " << error << ", ignoring.";
-    return nullptr;
-  }
-
-  const policy::Schema& schema =
-      policy::GetChromeSchema().GetKnownProperty(policy_name);
-
-  if (!schema.valid()) {
-    LOG(WARNING) << "Unknown or invalid policy schema for " << policy_name
-                 << ".";
-    return nullptr;
-  }
-
-  std::string error_path;
-  bool changed = false;
-  if (!schema.Normalize(root.get(), policy::SCHEMA_ALLOW_UNKNOWN, &error_path,
-                        &error, &changed)) {
-    LOG(WARNING) << "Invalid policy value for " << policy_name << ": " << error
-                 << " at " << error_path << ".";
-    return nullptr;
-  }
-  if (changed) {
-    LOG(WARNING) << "Some properties in " << policy_name
-                 << " were dropped: " << error << " at " << error_path << ".";
-  }
-
-  return root;
+  std::unique_ptr<base::Value> decoded_json =
+      policy::DecodeJsonStringAndNormalize(json_string, policy_name, &error);
+  if (decoded_json)
+    pref_value_map->SetValue(setting_name, std::move(decoded_json));
 }
 
 void DecodeLoginPolicies(const em::ChromeDeviceSettingsProto& policy,
-                         bool is_enterprise_managed,
                          PrefValueMap* new_values_cache) {
   // For all our boolean settings the following is applicable:
   // true is default permissive value and false is safe prohibitive value.
@@ -202,7 +178,7 @@
       policy.guest_mode_enabled().guest_mode_enabled());
 
   bool supervised_users_enabled = false;
-  if (is_enterprise_managed) {
+  if (InstallAttributes::Get()->IsEnterpriseManaged()) {
     supervised_users_enabled =
         policy.has_supervised_users_settings() &&
         policy.supervised_users_settings().has_supervised_users_enabled() &&
@@ -444,14 +420,10 @@
     }
 
     if (au_settings_proto.has_disallowed_time_intervals()) {
-      std::unique_ptr<base::Value> decoded_intervals =
-          DecodeJsonStringAndDropUnknownBySchema(
-              au_settings_proto.disallowed_time_intervals(),
-              "DeviceAutoUpdateTimeRestrictions");
-      if (decoded_intervals) {
-        new_values_cache->SetValue(kDeviceAutoUpdateTimeRestrictions,
-                                   std::move(decoded_intervals));
-      }
+      SetJsonDeviceSetting(kDeviceAutoUpdateTimeRestrictions,
+                           policy::key::kDeviceAutoUpdateTimeRestrictions,
+                           au_settings_proto.disallowed_time_intervals(),
+                           new_values_cache);
     }
   }
 }
@@ -534,7 +506,6 @@
 }
 
 void DecodeGenericPolicies(const em::ChromeDeviceSettingsProto& policy,
-                           bool is_enterprise_managed,
                            PrefValueMap* new_values_cache) {
   if (policy.has_metrics_enabled() &&
       policy.metrics_enabled().has_metrics_enabled()) {
@@ -543,7 +514,8 @@
   } else {
     // If the policy is missing, default to reporting enabled on enterprise-
     // enrolled devices, c.f. crbug/456186.
-    new_values_cache->SetBoolean(kStatsReportingPref, is_enterprise_managed);
+    new_values_cache->SetBoolean(
+        kStatsReportingPref, InstallAttributes::Get()->IsEnterpriseManaged());
   }
 
   if (!policy.has_release_channel() ||
@@ -637,16 +609,10 @@
 
   if (policy.has_device_wallpaper_image() &&
       policy.device_wallpaper_image().has_device_wallpaper_image()) {
-    const std::string& wallpaper_policy(
-        policy.device_wallpaper_image().device_wallpaper_image());
-    std::unique_ptr<base::DictionaryValue> dict_val =
-        base::DictionaryValue::From(base::JSONReader::Read(wallpaper_policy));
-    if (dict_val) {
-      new_values_cache->SetValue(kDeviceWallpaperImage, std::move(dict_val));
-    } else {
-      SYSLOG(ERROR) << "Value of wallpaper policy has invalid format: "
-                    << wallpaper_policy;
-    }
+    SetJsonDeviceSetting(
+        kDeviceWallpaperImage, policy::key::kDeviceWallpaperImage,
+        policy.device_wallpaper_image().device_wallpaper_image(),
+        new_values_cache);
   }
 
   if (policy.has_device_off_hours()) {
@@ -704,7 +670,7 @@
   } else {
     // If the policy is missing, default to false on enterprise-enrolled
     // devices.
-    if (is_enterprise_managed) {
+    if (InstallAttributes::Get()->IsEnterpriseManaged()) {
       new_values_cache->SetBoolean(kVirtualMachinesAllowed, false);
     }
   }
@@ -772,14 +738,12 @@
 void DeviceSettingsProvider::DecodePolicies(
     const em::ChromeDeviceSettingsProto& policy,
     PrefValueMap* new_values_cache) {
-  bool is_enterprise_managed = InstallAttributes::Get()->IsEnterpriseManaged();
-
-  DecodeLoginPolicies(policy, is_enterprise_managed, new_values_cache);
+  DecodeLoginPolicies(policy, new_values_cache);
   DecodeNetworkPolicies(policy, new_values_cache);
   DecodeAutoUpdatePolicies(policy, new_values_cache);
   DecodeReportingPolicies(policy, new_values_cache);
   DecodeHeartbeatPolicies(policy, new_values_cache);
-  DecodeGenericPolicies(policy, is_enterprise_managed, new_values_cache);
+  DecodeGenericPolicies(policy, new_values_cache);
   DecodeLogUploadPolicies(policy, new_values_cache);
 }
 
diff --git a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
index 535ecd3..098f9f1 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
@@ -604,7 +604,7 @@
   EXPECT_EQ(nullptr, provider_->Get(kDeviceWallpaperImage));
 
   // Set with valid json format.
-  const std::string valid_format("{\"type\":\"object\"}");
+  const std::string valid_format(R"({"url":"foo", "hash": "bar"})");
   SetWallpaperSettings(valid_format);
   std::unique_ptr<base::DictionaryValue> expected_value =
       base::DictionaryValue::From(base::JSONReader::Read(valid_format));
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc
index d5f209b..0ab7555 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.cc
+++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -320,7 +320,11 @@
 
 void SmbService::RegisterHostLocators() {
   SetUpMdnsHostLocator();
-  SetUpNetBiosHostLocator();
+  if (IsNetBiosDiscoveryEnabled()) {
+    SetUpNetBiosHostLocator();
+  } else {
+    LOG(WARNING) << "SmbService: NetBios discovery disabled.";
+  }
 }
 
 void SmbService::SetUpMdnsHostLocator() {
@@ -342,6 +346,10 @@
   return profile_->GetPrefs()->GetBoolean(prefs::kNetworkFileSharesAllowed);
 }
 
+bool SmbService::IsNetBiosDiscoveryEnabled() const {
+  return profile_->GetPrefs()->GetBoolean(prefs::kNetBiosShareDiscoveryEnabled);
+}
+
 void SmbService::RecordMountCount() const {
   const std::vector<ProvidedFileSystemInfo> file_systems =
       GetProviderService()->GetProvidedFileSystemInfoList(provider_id_);
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h
index 0691864..b671801 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.h
+++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -138,6 +138,9 @@
   // Whether Network File Shares are allowed to be used. Controlled via policy.
   bool IsAllowedByPolicy() const;
 
+  // Whether NetBios discovery should be used. Controlled via policy.
+  bool IsNetBiosDiscoveryEnabled() const;
+
   // Records metrics on the number of SMB mounts a user has.
   void RecordMountCount() const;
 
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
index e204cf6d..c145260 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
@@ -152,7 +152,7 @@
     // render frames don't have a record. However, this can also be caused by
     // URLRequests racing the frame create events.
     // TODO(kundaji): Add UMA.
-    RenderFrameHostID frame_key(render_process_id, render_frame_id);
+    content::GlobalFrameRoutingId frame_key(render_process_id, render_frame_id);
     const auto main_frame_key_iter = subframe_to_mainframe_map_.find(frame_key);
     if (main_frame_key_iter == subframe_to_mainframe_map_.end()) {
       return data_use_recorders_.end();
@@ -307,14 +307,14 @@
     return;
 
   const auto render_frame =
-      RenderFrameHostID(render_process_id, render_frame_id);
+      content::GlobalFrameRoutingId(render_process_id, render_frame_id);
 
   if (main_render_process_id != -1 && main_render_frame_id != -1) {
     // Create an entry in |subframe_to_mainframe_map_| for this frame mapped to
     // it's parent frame.
     subframe_to_mainframe_map_.insert(std::make_pair(
-        render_frame,
-        RenderFrameHostID(main_render_process_id, main_render_frame_id)));
+        render_frame, content::GlobalFrameRoutingId(main_render_process_id,
+                                                    main_render_frame_id)));
   } else {
     subframe_to_mainframe_map_.insert(
         std::make_pair(render_frame, render_frame));
@@ -338,7 +338,7 @@
   if (IsDisabled())
     return;
 
-  RenderFrameHostID key(render_process_id, render_frame_id);
+  content::GlobalFrameRoutingId key(render_process_id, render_frame_id);
 
   if (main_render_process_id == -1 && main_render_frame_id == -1) {
     auto main_frame_it = main_render_frame_entry_map_.find(key);
@@ -396,7 +396,7 @@
     return;
 
   main_render_frame_entry_map_
-      .find(RenderFrameHostID(render_process_id, render_frame_id))
+      .find(content::GlobalFrameRoutingId(render_process_id, render_frame_id))
       ->second.pending_navigation_global_request_id = global_request_id;
 }
 
@@ -411,7 +411,7 @@
   if (IsDisabled())
     return;
 
-  RenderFrameHostID main_frame(render_process_id, render_frame_id);
+  content::GlobalFrameRoutingId main_frame(render_process_id, render_frame_id);
 
   auto main_frame_it = main_render_frame_entry_map_.find(main_frame);
   if (main_frame_it == main_render_frame_entry_map_.end())
@@ -547,7 +547,7 @@
   if (!validated_url.SchemeIsHTTPOrHTTPS())
     return;
 
-  RenderFrameHostID main_frame(render_process_id, render_frame_id);
+  content::GlobalFrameRoutingId main_frame(render_process_id, render_frame_id);
 
   auto main_frame_it = main_render_frame_entry_map_.find(main_frame);
   if (main_frame_it == main_render_frame_entry_map_.end())
@@ -609,8 +609,9 @@
   if (IsDisabled())
     return;
 
-  auto main_frame_it = main_render_frame_entry_map_.find(
-      RenderFrameHostID(main_render_process_id, main_render_frame_id));
+  auto main_frame_it =
+      main_render_frame_entry_map_.find(content::GlobalFrameRoutingId(
+          main_render_process_id, main_render_frame_id));
   if (main_frame_it != main_render_frame_entry_map_.end()) {
     main_frame_it->second.is_visible = visible;
     if (main_frame_it->second.data_use_recorder != data_use_recorders_.end())
@@ -626,8 +627,9 @@
   if (IsDisabled())
     return;
 
-  auto old_frame_iter = main_render_frame_entry_map_.find(
-      RenderFrameHostID(old_render_process_id, old_render_frame_id));
+  auto old_frame_iter =
+      main_render_frame_entry_map_.find(content::GlobalFrameRoutingId(
+          old_render_process_id, old_render_frame_id));
 
   if (old_frame_iter != main_render_frame_entry_map_.end()) {
     WasShownOrHidden(new_render_process_id, new_render_frame_id, true);
@@ -636,7 +638,8 @@
       // Transfer the pending navigation global request ID from old to new main
       // frame.
       main_render_frame_entry_map_
-          .find(RenderFrameHostID(new_render_process_id, new_render_frame_id))
+          .find(content::GlobalFrameRoutingId(new_render_process_id,
+                                              new_render_frame_id))
           ->second.pending_navigation_global_request_id =
           old_frame_iter->second.pending_navigation_global_request_id;
       old_frame_iter->second.pending_navigation_global_request_id =
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
index f9ef712..23db643 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
@@ -21,6 +21,7 @@
 #include "chrome/browser/data_use_measurement/chrome_data_use_recorder.h"
 #include "components/data_use_measurement/core/data_use_ascriber.h"
 #include "content/public/browser/global_request_id.h"
+#include "content/public/browser/global_routing_id.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -205,13 +206,14 @@
   // Map from RenderFrameHost to the MainRenderFrameEntry which contains all
   // details of the main frame. New entry is added on main render frame creation
   // and removed on its deletion.
-  std::map<RenderFrameHostID, MainRenderFrameEntry>
+  std::map<content::GlobalFrameRoutingId, MainRenderFrameEntry>
       main_render_frame_entry_map_;
 
   // Maps subframe IDs to the mainframe ID, so the mainframe lifetime can have
   // ownership over the lifetime of entries in |data_use_recorders_|. Mainframes
   // are mapped to themselves.
-  std::map<RenderFrameHostID, RenderFrameHostID> subframe_to_mainframe_map_;
+  std::map<content::GlobalFrameRoutingId, content::GlobalFrameRoutingId>
+      subframe_to_mainframe_map_;
 
   // Map from pending navigations to the DataUseRecorderEntry in
   // |data_use_recorders_| that the navigation ascribes data use to.
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc
index cb793cb..fa2b530 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc
@@ -243,7 +243,7 @@
   // Navigation commit should merge the two data use recorder entries.
   EXPECT_EQ(1u, recorders().size());
   auto& recorder_entry = recorders().front();
-  EXPECT_EQ(RenderFrameHostID(kRenderProcessId, kRenderFrameId),
+  EXPECT_EQ(content::GlobalFrameRoutingId(kRenderProcessId, kRenderFrameId),
             recorder_entry.main_frame_id());
   EXPECT_EQ(content::GlobalRequestID(kRenderProcessId, 0),
             recorder_entry.main_frame_request_id());
@@ -305,7 +305,7 @@
 
   EXPECT_EQ(1u, recorders().size());
   auto& recorder_entry = recorders().front();
-  EXPECT_EQ(RenderFrameHostID(kRenderProcessId, kRenderFrameId),
+  EXPECT_EQ(content::GlobalFrameRoutingId(kRenderProcessId, kRenderFrameId),
             recorder_entry.main_frame_id());
   EXPECT_EQ(content::GlobalRequestID(kRenderProcessId, 0),
             recorder_entry.main_frame_request_id());
@@ -351,7 +351,7 @@
 
   EXPECT_EQ(1u, recorders().size());
   auto& page_load_a_recorder = recorders().front();
-  EXPECT_EQ(RenderFrameHostID(kRenderProcessId, kRenderFrameId),
+  EXPECT_EQ(content::GlobalFrameRoutingId(kRenderProcessId, kRenderFrameId),
             page_load_a_recorder.main_frame_id());
   EXPECT_EQ(content::GlobalRequestID(kRenderProcessId, 0),
             page_load_a_recorder.main_frame_request_id());
@@ -384,7 +384,7 @@
   // Previous page recorder is gone.
   EXPECT_EQ(1u, recorders().size());
   auto& page_load_b_recorder = recorders().back();
-  EXPECT_EQ(RenderFrameHostID(kRenderProcessId, kRenderFrameId),
+  EXPECT_EQ(content::GlobalFrameRoutingId(kRenderProcessId, kRenderFrameId),
             page_load_b_recorder.main_frame_id());
   EXPECT_EQ(content::GlobalRequestID(kRenderProcessId, 0),
             page_load_b_recorder.main_frame_request_id());
@@ -491,7 +491,7 @@
 
   EXPECT_EQ(1u, recorders().size());
   auto& recorder_entry = recorders().front();
-  EXPECT_EQ(RenderFrameHostID(kRenderProcessId, kRenderFrameId),
+  EXPECT_EQ(content::GlobalFrameRoutingId(kRenderProcessId, kRenderFrameId),
             recorder_entry.main_frame_id());
   EXPECT_EQ(content::GlobalRequestID(kRenderProcessId, 0),
             recorder_entry.main_frame_request_id());
@@ -548,7 +548,7 @@
 
   EXPECT_EQ(1u, recorders().size());
   auto& recorder_entry = recorders().front();
-  EXPECT_EQ(RenderFrameHostID(kRenderProcessId, kRenderFrameId),
+  EXPECT_EQ(content::GlobalFrameRoutingId(kRenderProcessId, kRenderFrameId),
             recorder_entry.main_frame_id());
   EXPECT_EQ(content::GlobalRequestID(kRenderProcessId, 0),
             recorder_entry.main_frame_request_id());
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_recorder.h b/chrome/browser/data_use_measurement/chrome_data_use_recorder.h
index 9ca8b49..88bce23 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_recorder.h
+++ b/chrome/browser/data_use_measurement/chrome_data_use_recorder.h
@@ -10,19 +10,18 @@
 #include "base/macros.h"
 #include "components/data_use_measurement/core/data_use_recorder.h"
 #include "content/public/browser/global_request_id.h"
+#include "content/public/browser/global_routing_id.h"
 
 namespace data_use_measurement {
 
-typedef std::pair<int, int> RenderFrameHostID;
-
 class ChromeDataUseRecorder : public DataUseRecorder {
  public:
   explicit ChromeDataUseRecorder(DataUse::TrafficType traffic_type);
   ~ChromeDataUseRecorder() override;
 
-  RenderFrameHostID main_frame_id() const { return main_frame_id_; }
+  content::GlobalFrameRoutingId main_frame_id() const { return main_frame_id_; }
 
-  void set_main_frame_id(RenderFrameHostID frame_id) {
+  void set_main_frame_id(content::GlobalFrameRoutingId frame_id) {
     main_frame_id_ = frame_id;
   }
 
@@ -37,7 +36,7 @@
  private:
   // Identifier for the main frame for the page load this recorder is tracking.
   // Only valid if the data use is associated with a page load.
-  RenderFrameHostID main_frame_id_;
+  content::GlobalFrameRoutingId main_frame_id_;
 
   // Identifier for the MAIN_FRAME request for this page load. Only valid if
   // the data use is associated with a page load.
diff --git a/chrome/browser/download/download_request_limiter.h b/chrome/browser/download/download_request_limiter.h
index 1ac98258..577b77ee 100644
--- a/chrome/browser/download/download_request_limiter.h
+++ b/chrome/browser/download/download_request_limiter.h
@@ -239,6 +239,7 @@
   FRIEND_TEST_ALL_PREFIXES(ContentSettingImageModelBrowserTest,
                            CreateBubbleModel);
   friend class base::RefCountedThreadSafe<DownloadRequestLimiter>;
+  friend class BackgroundFetchBrowserTest;
   friend class ContentSettingBubbleDialogTest;
   friend class DownloadRequestLimiterTest;
   friend class TabDownloadState;
diff --git a/chrome/browser/download/download_target_determiner_unittest.cc b/chrome/browser/download/download_target_determiner_unittest.cc
index 4ca3d5e9..e169701 100644
--- a/chrome/browser/download/download_target_determiner_unittest.cc
+++ b/chrome/browser/download/download_target_determiner_unittest.cc
@@ -592,7 +592,14 @@
   callback.Run(new_path, DownloadPathReservationTracker::UNIQUIFY);
 }
 
-TEST_F(DownloadTargetDeterminerTest, Basic) {
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_Basic DISABLED_Basic
+#else
+#define MAYBE_Basic Basic
+#endif
+
+TEST_F(DownloadTargetDeterminerTest, MAYBE_Basic) {
   const DownloadTestCase kBasicTestCases[] = {
       {// Automatic Safe
        AUTOMATIC, download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
@@ -728,9 +735,16 @@
                              arraysize(kSafeBrowsingTestCases));
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_MaybeDangerousContent DISABLED_MaybeDangerousContent
+#else
+#define MAYBE_MaybeDangerousContent MaybeDangerousContent
+#endif
+
 // The SafeBrowsing check is performed early. Make sure that a download item
 // that has been marked as MAYBE_DANGEROUS_CONTENT behaves correctly.
-TEST_F(DownloadTargetDeterminerTest, MaybeDangerousContent) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_MaybeDangerousContent) {
   const DownloadTestCase kSafeBrowsingTestCases[] = {
       {// 0: Automatic Maybe dangerous content
        AUTOMATIC, download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT,
@@ -784,8 +798,15 @@
                              arraysize(kSafeBrowsingTestCases));
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_LastSavePath DISABLED_LastSavePath
+#else
+#define MAYBE_LastSavePath LastSavePath
+#endif
+
 // Test whether the last saved directory is used for 'Save As' downloads.
-TEST_F(DownloadTargetDeterminerTest, LastSavePath) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_LastSavePath) {
   const DownloadTestCase kLastSavePathTestCasesPre[] = {
       {// 0: If the last save path is empty, then the default download directory
        //    should be used.
@@ -972,6 +993,13 @@
   }
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_InactiveDownload DISABLED_InactiveDownload
+#else
+#define MAYBE_InactiveDownload InactiveDownload
+#endif
+
 // Test that an inactive download will still get a virtual or local download
 // path.
 TEST_F(DownloadTargetDeterminerTest, InactiveDownload) {
@@ -1092,10 +1120,17 @@
                              arraysize(kLocalPathFailedCases));
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_VisitedReferrer DISABLED_VisitedReferrer
+#else
+#define MAYBE_VisitedReferrer VisitedReferrer
+#endif
+
 // Downloads that have a danger level of ALLOW_ON_USER_GESTURE should be marked
 // as safe depending on whether there was a user gesture associated with the
 // download and whether the referrer was visited prior to today.
-TEST_F(DownloadTargetDeterminerTest, VisitedReferrer) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_VisitedReferrer) {
   const DownloadTestCase kVisitedReferrerCases[] = {
       // http://visited.example.com/ is added to the history as a visit that
       // happened prior to today.
@@ -1287,9 +1322,16 @@
   }
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_PromptAlways_SafeAutomatic DISABLED_PromptAlways_SafeAutomatic
+#else
+#define MAYBE_PromptAlways_SafeAutomatic PromptAlways_SafeAutomatic
+#endif
+
 // These test cases are run with "Prompt for download" user preference set to
 // true.
-TEST_F(DownloadTargetDeterminerTest, PromptAlways_SafeAutomatic) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_PromptAlways_SafeAutomatic) {
   const DownloadTestCase kSafeAutomatic = {
       // 0: Safe Automatic - Should prompt because of "Prompt for download"
       //    preference setting.
@@ -1313,7 +1355,14 @@
   RunTestCasesWithActiveItem(&kSafeAutomatic, 1);
 }
 
-TEST_F(DownloadTargetDeterminerTest, PromptAlways_SafeSaveAs) {
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_PromptAlways_SafeSaveAs DISABLED_PromptAlways_SafeSaveAs
+#else
+#define MAYBE_PromptAlways_SafeSaveAs PromptAlways_SafeSaveAs
+#endif
+
+TEST_F(DownloadTargetDeterminerTest, MAYBE_PromptAlways_SafeSaveAs) {
   const DownloadTestCase kSafeSaveAs = {
       // 1: Safe Save As - Should prompt because of "Save as" invocation.
       SAVE_AS,
@@ -1355,7 +1404,14 @@
   RunTestCasesWithActiveItem(&kSafeForced, 1);
 }
 
-TEST_F(DownloadTargetDeterminerTest, PromptAlways_AutoOpen) {
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_PromptAlways_AutoOpen DISABLED_PromptAlways_AutoOpen
+#else
+#define MAYBE_PromptAlways_AutoOpen PromptAlways_AutoOpen
+#endif
+
+TEST_F(DownloadTargetDeterminerTest, MAYBE_PromptAlways_AutoOpen) {
   const DownloadTestCase kAutoOpen = {
       // 3: Automatic - The filename extension is marked as one that we will
       //    open automatically. Shouldn't prompt.
@@ -1376,9 +1432,18 @@
   RunTestCasesWithActiveItem(&kAutoOpen, 1);
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_ContinueWithoutConfirmation_SaveAs \
+  DISABLED_ContinueWithoutConfirmation_SaveAs
+#else
+#define MAYBE_ContinueWithoutConfirmation_SaveAs \
+  ContinueWithoutConfirmation_SaveAs
+#endif
+
 // If an embedder responds to a RequestConfirmation with a new path and a
 // CONTINUE_WITHOUT_CONFIRMATION, then we shouldn't consider the file as safe.
-TEST_F(DownloadTargetDeterminerTest, ContinueWithoutConfirmation_SaveAs) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_ContinueWithoutConfirmation_SaveAs) {
   const DownloadTestCase kTestCase = {
       SAVE_AS,
       download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
@@ -1497,9 +1562,16 @@
                              arraysize(kManagedPathTestCases));
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_NotifyExtensionsSafe DISABLED_NotifyExtensionsSafe
+#else
+#define MAYBE_NotifyExtensionsSafe NotifyExtensionsSafe
+#endif
+
 // Test basic functionality supporting extensions that want to override download
 // filenames.
-TEST_F(DownloadTargetDeterminerTest, NotifyExtensionsSafe) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_NotifyExtensionsSafe) {
   const DownloadTestCase kNotifyExtensionsTestCases[] = {
       {// 0: Automatic Safe
        AUTOMATIC, download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
@@ -1587,9 +1659,16 @@
   RunTestCasesWithActiveItem(&kHandledBySafeBrowsing, 1);
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_NotifyExtensionsConflict DISABLED_NotifyExtensionsConflict
+#else
+#define MAYBE_NotifyExtensionsConflict NotifyExtensionsConflict
+#endif
+
 // Test that conflict actions set by extensions are passed correctly into
 // ReserveVirtualPath.
-TEST_F(DownloadTargetDeterminerTest, NotifyExtensionsConflict) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_NotifyExtensionsConflict) {
   const DownloadTestCase kNotifyExtensionsTestCase = {
       AUTOMATIC,
       download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
@@ -1636,9 +1715,16 @@
   RunTestCase(test_case, base::FilePath(), item.get());
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_NotifyExtensionsDefaultPath DISABLED_NotifyExtensionsDefaultPath
+#else
+#define MAYBE_NotifyExtensionsDefaultPath NotifyExtensionsDefaultPath
+#endif
+
 // Test that relative paths returned by extensions are always relative to the
 // default downloads path.
-TEST_F(DownloadTargetDeterminerTest, NotifyExtensionsDefaultPath) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_NotifyExtensionsDefaultPath) {
   const DownloadTestCase kNotifyExtensionsTestCase = {
       AUTOMATIC,
       download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
@@ -1700,12 +1786,19 @@
   RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get());
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_ResumedNoPrompt DISABLED_ResumedNoPrompt
+#else
+#define MAYBE_ResumedNoPrompt ResumedNoPrompt
+#endif
+
 // Prompting behavior for resumed downloads is based on the last interrupt
 // reason. If the reason indicates that the target path may not be suitable for
 // the download (ACCESS_DENIED, NO_SPACE, etc..), then the user should be
 // prompted, and not otherwise. These test cases shouldn't result in prompting
 // since the error is set to NETWORK_FAILED.
-TEST_F(DownloadTargetDeterminerTest, ResumedNoPrompt) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_ResumedNoPrompt) {
   // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
   // path.
   const base::FilePath::CharType* kInitialPath =
@@ -1891,8 +1984,15 @@
   }
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_IntermediateNameForResumed DISABLED_IntermediateNameForResumed
+#else
+#define MAYBE_IntermediateNameForResumed IntermediateNameForResumed
+#endif
+
 // Test intermediate filename generation for resumed downloads.
-TEST_F(DownloadTargetDeterminerTest, IntermediateNameForResumed) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_IntermediateNameForResumed) {
   // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
   // path.
   const base::FilePath::CharType kInitialPath[] =
@@ -2006,8 +2106,15 @@
   }
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_MIMETypeDetermination DISABLED_MIMETypeDetermination
+#else
+#define MAYBE_MIMETypeDetermination MIMETypeDetermination
+#endif
+
 // Test MIME type determination based on the target filename.
-TEST_F(DownloadTargetDeterminerTest, MIMETypeDetermination) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_MIMETypeDetermination) {
   // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
   // path.
   const base::FilePath::CharType kInitialPath[] =
@@ -2099,8 +2206,16 @@
   }
 }
 
+// Flaky on Nexus 5x.  http://crbug.com/877026
+#if defined(OS_ANDROID)
+#define MAYBE_ResumedWithUserValidatedDownload \
+  DISABLED_ResumedWithUserValidatedDownload
+#else
+#define MAYBE_ResumedWithUserValidatedDownload ResumedWithUserValidatedDownload
+#endif
+
 // Test that a user validated download won't be treated as dangerous.
-TEST_F(DownloadTargetDeterminerTest, ResumedWithUserValidatedDownload) {
+TEST_F(DownloadTargetDeterminerTest, MAYBE_ResumedWithUserValidatedDownload) {
   const base::FilePath::CharType kInitialPath[] =
       FILE_PATH_LITERAL("some_path/bar.txt");
   const base::FilePath::CharType* kIntermediatePath =
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
index a56f2d27..090b3a16 100644
--- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
+++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -52,6 +52,7 @@
 #include "extensions/browser/api/declarative_net_request/ruleset_manager.h"
 #include "extensions/browser/api/declarative_net_request/ruleset_matcher.h"
 #include "extensions/browser/api/declarative_net_request/test_utils.h"
+#include "extensions/browser/api/declarative_net_request/utils.h"
 #include "extensions/browser/api/web_request/web_request_info.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
@@ -1808,10 +1809,11 @@
     verify_page_load(false);
   }
 
-  // Overwrite the indexed ruleset file with arbitrary data to mimic corruption.
+  // Overwrite the indexed ruleset file with arbitrary data to mimic corruption,
+  // while maintaining the correct version header.
   {
     base::ScopedAllowBlockingForTesting scoped_allow_blocking;
-    std::string corrupted_data = "data";
+    std::string corrupted_data = GetVersionHeaderForTesting() + "data";
     ASSERT_EQ(static_cast<int>(corrupted_data.size()),
               base::WriteFile(file_util::GetIndexedRulesetPath(extension_path),
                               corrupted_data.c_str(), corrupted_data.size()));
@@ -1869,7 +1871,7 @@
   // Mimic extension prefs corruption by overwriting the indexed ruleset
   // checksum.
   const int kInvalidRulesetChecksum = -1;
-  ExtensionPrefs::Get(profile())->SetDNRRulesetChecksumForTesting(
+  ExtensionPrefs::Get(profile())->SetDNRRulesetChecksum(
       extension_id, kInvalidRulesetChecksum);
 
   TestExtensionRegistryObserver registry_observer(
@@ -1904,6 +1906,60 @@
       false /*sample*/, 1 /*count*/);
 }
 
+// Tests that we reindex the extension ruleset in case its ruleset format
+// version is not the same as one used by Chrome.
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest_Packed,
+                       ReindexOnRulesetVersionMismatch) {
+  // Set up an observer for RulesetMatcher to monitor the number of extension
+  // rulesets.
+  RulesetCountWaiter ruleset_count_waiter;
+  ScopedRulesetManagerTestObserver scoped_observer(
+      &ruleset_count_waiter,
+      base::WrapRefCounted(ExtensionSystem::Get(profile())->info_map()));
+
+  TestRule rule = CreateGenericRule();
+  rule.condition->url_filter = std::string("*");
+  ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules({rule}));
+  ruleset_count_waiter.WaitForRulesetCount(1);
+
+  const ExtensionId extension_id = last_loaded_extension_id();
+  const auto* rules_monitor_service = BrowserContextKeyedAPIFactory<
+      declarative_net_request::RulesMonitorService>::Get(profile());
+  EXPECT_TRUE(rules_monitor_service->HasRegisteredRuleset(extension_id));
+
+  DisableExtension(extension_id);
+  ruleset_count_waiter.WaitForRulesetCount(0);
+  EXPECT_FALSE(rules_monitor_service->HasRegisteredRuleset(extension_id));
+
+  // Now change the current indexed ruleset format version. This should cause a
+  // version mismatch when the extension is loaded again, but reindexing should
+  // still succeed.
+  const int kIndexedRulesetFormatVersion = 100;
+  std::string old_version_header = GetVersionHeaderForTesting();
+  SetIndexedRulesetFormatVersionForTesting(kIndexedRulesetFormatVersion);
+  ASSERT_NE(old_version_header, GetVersionHeaderForTesting());
+
+  base::HistogramTester tester;
+  EnableExtension(extension_id);
+  ruleset_count_waiter.WaitForRulesetCount(1);
+  EXPECT_TRUE(rules_monitor_service->HasRegisteredRuleset(extension_id));
+
+  // Verify that loading the ruleset would have failed initially due to
+  // version header mismatch and later succeeded.
+  EXPECT_EQ(1, tester.GetBucketCount(
+                   "Extensions.DeclarativeNetRequest.LoadRulesetResult",
+                   RulesetMatcher::LoadRulesetResult::
+                       kLoadErrorVersionMismatch /*sample*/));
+  EXPECT_EQ(1, tester.GetBucketCount(
+                   "Extensions.DeclarativeNetRequest.LoadRulesetResult",
+                   RulesetMatcher::LoadRulesetResult::kLoadSuccess /*sample*/));
+
+  // Verify that reindexing succeeded.
+  tester.ExpectUniqueSample(
+      "Extensions.DeclarativeNetRequest.RulesetReindexSuccessful",
+      true /*sample*/, 1 /*count*/);
+}
+
 // Test fixture to verify that host permissions for the request url and the
 // request initiator are properly checked. Loads an example.com url with four
 // sub-frames named frame_[1..4] from hosts frame_[1..4].com. The initiator for
diff --git a/chrome/browser/extensions/api/declarative_net_request/ruleset_matcher_unittest.cc b/chrome/browser/extensions/api/declarative_net_request/ruleset_matcher_unittest.cc
index 9020986..4e6f395 100644
--- a/chrome/browser/extensions/api/declarative_net_request/ruleset_matcher_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_net_request/ruleset_matcher_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/url_pattern_index/flat/url_pattern_index_generated.h"
 #include "extensions/browser/api/declarative_net_request/test_utils.h"
+#include "extensions/browser/api/declarative_net_request/utils.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/common/api/declarative_net_request/constants.h"
 #include "extensions/common/api/declarative_net_request/test_utils.h"
@@ -123,7 +124,8 @@
   base::FilePath indexed_ruleset_path =
       file_util::GetIndexedRulesetPath(extension()->path());
 
-  // Persist invalid data to the ruleset file.
+  // Persist invalid data to the ruleset file and ensure that a version mismatch
+  // occurs.
   std::string data = "invalid data";
   ASSERT_EQ(static_cast<int>(data.size()),
             base::WriteFile(indexed_ruleset_path, data.c_str(), data.size()));
@@ -134,6 +136,16 @@
           ->GetDNRRulesetChecksum(extension()->id(), &expected_checksum));
 
   std::unique_ptr<RulesetMatcher> matcher;
+  EXPECT_EQ(RulesetMatcher::kLoadErrorVersionMismatch,
+            RulesetMatcher::CreateVerifiedMatcher(indexed_ruleset_path,
+                                                  expected_checksum, &matcher));
+
+  // Now, persist invalid data to the ruleset file, while maintaining the
+  // correct version header. Ensure that it fails verification due to checksum
+  // mismatch.
+  data = GetVersionHeaderForTesting() + "invalid data";
+  ASSERT_EQ(static_cast<int>(data.size()),
+            base::WriteFile(indexed_ruleset_path, data.c_str(), data.size()));
   EXPECT_EQ(RulesetMatcher::kLoadErrorRulesetVerification,
             RulesetMatcher::CreateVerifiedMatcher(indexed_ruleset_path,
                                                   expected_checksum, &matcher));
diff --git a/chrome/browser/media/router/BUILD.gn b/chrome/browser/media/router/BUILD.gn
index 62caf98..4774e72 100644
--- a/chrome/browser/media/router/BUILD.gn
+++ b/chrome/browser/media/router/BUILD.gn
@@ -55,7 +55,6 @@
     "presentation/presentation_service_delegate_observers.h",
     "presentation/receiver_presentation_service_delegate_impl.cc",
     "presentation/receiver_presentation_service_delegate_impl.h",
-    "presentation/render_frame_host_id.h",
     "route_message_observer.cc",
     "route_message_observer.h",
     "route_message_util.cc",
diff --git a/chrome/browser/media/router/presentation/local_presentation_manager.cc b/chrome/browser/media/router/presentation/local_presentation_manager.cc
index 21a75f3..a578750 100644
--- a/chrome/browser/media/router/presentation/local_presentation_manager.cc
+++ b/chrome/browser/media/router/presentation/local_presentation_manager.cc
@@ -36,12 +36,13 @@
 
 void LocalPresentationManager::RegisterLocalPresentationController(
     const PresentationInfo& presentation_info,
-    const RenderFrameHostId& render_frame_host_id,
+    const content::GlobalFrameRoutingId& render_frame_host_id,
     content::PresentationConnectionPtr controller_connection_ptr,
     content::PresentationConnectionRequest receiver_connection_request,
     const MediaRoute& route) {
   DVLOG(2) << __func__ << " [presentation_id]: " << presentation_info.id
-           << ", [render_frame_host_id]: " << render_frame_host_id.second;
+           << ", [render_frame_host_id]: "
+           << render_frame_host_id.frame_routing_id;
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   auto* presentation = GetOrCreateLocalPresentation(presentation_info);
@@ -52,9 +53,10 @@
 
 void LocalPresentationManager::UnregisterLocalPresentationController(
     const std::string& presentation_id,
-    const RenderFrameHostId& render_frame_host_id) {
+    const content::GlobalFrameRoutingId& render_frame_host_id) {
   DVLOG(2) << __func__ << " [presentation_id]: " << presentation_id
-           << ", [render_frame_host_id]: " << render_frame_host_id.second;
+           << ", [render_frame_host_id]: "
+           << render_frame_host_id.frame_routing_id;
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   auto it = local_presentations_.find(presentation_id);
@@ -108,7 +110,7 @@
 LocalPresentationManager::LocalPresentation::~LocalPresentation() {}
 
 void LocalPresentationManager::LocalPresentation::RegisterController(
-    const RenderFrameHostId& render_frame_host_id,
+    const content::GlobalFrameRoutingId& render_frame_host_id,
     content::PresentationConnectionPtr controller_connection_ptr,
     content::PresentationConnectionRequest receiver_connection_request,
     const MediaRoute& route) {
@@ -127,7 +129,7 @@
 }
 
 void LocalPresentationManager::LocalPresentation::UnregisterController(
-    const RenderFrameHostId& render_frame_host_id) {
+    const content::GlobalFrameRoutingId& render_frame_host_id) {
   pending_controllers_.erase(render_frame_host_id);
 }
 
diff --git a/chrome/browser/media/router/presentation/local_presentation_manager.h b/chrome/browser/media/router/presentation/local_presentation_manager.h
index 820aa7d..bcddd4f 100644
--- a/chrome/browser/media/router/presentation/local_presentation_manager.h
+++ b/chrome/browser/media/router/presentation/local_presentation_manager.h
@@ -13,9 +13,9 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/threading/thread_checker.h"
-#include "chrome/browser/media/router/presentation/render_frame_host_id.h"
 #include "chrome/common/media_router/media_route.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/presentation_service_delegate.h"
 #include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
 
@@ -114,7 +114,7 @@
   // |receiver_callback| passed below.
   virtual void RegisterLocalPresentationController(
       const blink::mojom::PresentationInfo& presentation_info,
-      const RenderFrameHostId& render_frame_id,
+      const content::GlobalFrameRoutingId& render_frame_id,
       content::PresentationConnectionPtr controller_connection_ptr,
       content::PresentationConnectionRequest receiver_connection_request,
       const MediaRoute& route);
@@ -126,7 +126,7 @@
   // and any other pending controller.
   virtual void UnregisterLocalPresentationController(
       const std::string& presentation_id,
-      const RenderFrameHostId& render_frame_id);
+      const content::GlobalFrameRoutingId& render_frame_id);
 
   // Registers |receiver_callback| to presentation with |presentation_info|.
   virtual void OnLocalPresentationReceiverCreated(
@@ -165,14 +165,15 @@
     // |receiver_connection_request|, and store it in |pending_controllers_|
     // map.
     void RegisterController(
-        const RenderFrameHostId& render_frame_id,
+        const content::GlobalFrameRoutingId& render_frame_id,
         content::PresentationConnectionPtr controller_connection_ptr,
         content::PresentationConnectionRequest receiver_connection_request,
         const MediaRoute& route);
 
     // Unregister controller with |render_frame_id|. Do nothing if there is no
     // pending controller with |render_frame_id|.
-    void UnregisterController(const RenderFrameHostId& render_frame_id);
+    void UnregisterController(
+        const content::GlobalFrameRoutingId& render_frame_id);
 
     // Register |receiver_callback| to current local_presentation object.
     // For each controller in |pending_controllers_| map, invoke
@@ -213,9 +214,9 @@
 
     // Contains ControllerConnection objects registered via
     // |RegisterController()| before |receiver_callback_| is set.
-    std::unordered_map<RenderFrameHostId,
+    std::unordered_map<content::GlobalFrameRoutingId,
                        std::unique_ptr<ControllerConnection>,
-                       RenderFrameHostIdHasher>
+                       content::GlobalFrameRoutingIdHasher>
         pending_controllers_;
 
     DISALLOW_COPY_AND_ASSIGN(LocalPresentation);
diff --git a/chrome/browser/media/router/presentation/local_presentation_manager_unittest.cc b/chrome/browser/media/router/presentation/local_presentation_manager_unittest.cc
index e999f38..bf63bba 100644
--- a/chrome/browser/media/router/presentation/local_presentation_manager_unittest.cc
+++ b/chrome/browser/media/router/presentation/local_presentation_manager_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -67,7 +68,7 @@
         render_frame_host_id_, std::move(controller));
   }
 
-  void RegisterController(const RenderFrameHostId& render_frame_id,
+  void RegisterController(const content::GlobalFrameRoutingId& render_frame_id,
                           content::PresentationConnectionPtr controller) {
     RegisterController(presentation_info_, render_frame_id,
                        std::move(controller));
@@ -79,7 +80,7 @@
   }
 
   void RegisterController(const PresentationInfo& presentation_info,
-                          const RenderFrameHostId& render_frame_id,
+                          const content::GlobalFrameRoutingId& render_frame_id,
                           content::PresentationConnectionPtr controller) {
     content::PresentationConnectionRequest receiver_conn_request;
     manager()->RegisterLocalPresentationController(
@@ -102,7 +103,8 @@
                             base::Unretained(&receiver_callback)));
   }
 
-  void UnregisterController(const RenderFrameHostId& render_frame_id) {
+  void UnregisterController(
+      const content::GlobalFrameRoutingId& render_frame_id) {
     manager()->UnregisterLocalPresentationController(kPresentationId,
                                                      render_frame_id);
   }
@@ -117,7 +119,7 @@
   }
 
  private:
-  const RenderFrameHostId render_frame_host_id_;
+  const content::GlobalFrameRoutingId render_frame_host_id_;
   const PresentationInfo presentation_info_;
   LocalPresentationManager manager_;
   MediaRoute route_;
@@ -152,9 +154,11 @@
 TEST_F(LocalPresentationManagerTest,
        RegisterMultipleControllersSamePresentation) {
   content::PresentationConnectionPtr controller1;
-  RegisterController(RenderFrameHostId(1, 1), std::move(controller1));
+  RegisterController(content::GlobalFrameRoutingId(1, 1),
+                     std::move(controller1));
   content::PresentationConnectionPtr controller2;
-  RegisterController(RenderFrameHostId(1, 2), std::move(controller2));
+  RegisterController(content::GlobalFrameRoutingId(1, 2),
+                     std::move(controller2));
   VerifyPresentationsSize(1);
 }
 
@@ -244,9 +248,11 @@
 TEST_F(LocalPresentationManagerTest,
        RegisterTwoControllersThenReceiverInvokesCallbackTwice) {
   content::PresentationConnectionPtr controller1;
-  RegisterController(RenderFrameHostId(1, 1), std::move(controller1));
+  RegisterController(content::GlobalFrameRoutingId(1, 1),
+                     std::move(controller1));
   content::PresentationConnectionPtr controller2;
-  RegisterController(RenderFrameHostId(1, 2), std::move(controller2));
+  RegisterController(content::GlobalFrameRoutingId(1, 2),
+                     std::move(controller2));
 
   MockReceiverConnectionAvailableCallback receiver_callback;
   EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailableRaw(_, _))
@@ -257,7 +263,8 @@
 TEST_F(LocalPresentationManagerTest,
        RegisterControllerReceiverConontrollerInvokesCallbackTwice) {
   content::PresentationConnectionPtr controller1;
-  RegisterController(RenderFrameHostId(1, 1), std::move(controller1));
+  RegisterController(content::GlobalFrameRoutingId(1, 1),
+                     std::move(controller1));
 
   MockReceiverConnectionAvailableCallback receiver_callback;
   EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailableRaw(_, _))
@@ -265,22 +272,25 @@
   RegisterReceiver(receiver_callback);
 
   content::PresentationConnectionPtr controller2;
-  RegisterController(RenderFrameHostId(1, 2), std::move(controller2));
+  RegisterController(content::GlobalFrameRoutingId(1, 2),
+                     std::move(controller2));
 }
 
 TEST_F(LocalPresentationManagerTest,
        UnregisterFirstControllerFromeConnectedPresentation) {
   content::PresentationConnectionPtr controller1;
-  RegisterController(RenderFrameHostId(1, 1), std::move(controller1));
+  RegisterController(content::GlobalFrameRoutingId(1, 1),
+                     std::move(controller1));
   content::PresentationConnectionPtr controller2;
-  RegisterController(RenderFrameHostId(1, 2), std::move(controller2));
+  RegisterController(content::GlobalFrameRoutingId(1, 2),
+                     std::move(controller2));
 
   MockReceiverConnectionAvailableCallback receiver_callback;
   EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailableRaw(_, _))
       .Times(2);
   RegisterReceiver(receiver_callback);
-  UnregisterController(RenderFrameHostId(1, 1));
-  UnregisterController(RenderFrameHostId(1, 1));
+  UnregisterController(content::GlobalFrameRoutingId(1, 1));
+  UnregisterController(content::GlobalFrameRoutingId(1, 1));
 
   VerifyPresentationsSize(1);
 }
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 f8b7743b..6aa8a4cd 100644
--- a/chrome/browser/media/router/presentation/presentation_service_delegate_impl.cc
+++ b/chrome/browser/media/router/presentation/presentation_service_delegate_impl.cc
@@ -53,9 +53,9 @@
 // Gets the last committed URL for the render frame specified by
 // |render_frame_host_id|.
 url::Origin GetLastCommittedURLForFrame(
-    RenderFrameHostId render_frame_host_id) {
+    content::GlobalFrameRoutingId render_frame_host_id) {
   RenderFrameHost* render_frame_host = RenderFrameHost::FromID(
-      render_frame_host_id.first, render_frame_host_id.second);
+      render_frame_host_id.child_id, render_frame_host_id.frame_routing_id);
   DCHECK(render_frame_host);
   return render_frame_host->GetLastCommittedOrigin();
 }
@@ -80,7 +80,7 @@
 // is destroyed.
 class PresentationFrame {
  public:
-  PresentationFrame(const RenderFrameHostId& render_frame_host_id,
+  PresentationFrame(const content::GlobalFrameRoutingId& render_frame_host_id,
                     content::WebContents* web_contents,
                     MediaRouter* router);
   ~PresentationFrame();
@@ -121,7 +121,7 @@
                      std::unique_ptr<BrowserPresentationConnectionProxy>>
       browser_connection_proxies_;
 
-  RenderFrameHostId render_frame_host_id_;
+  content::GlobalFrameRoutingId render_frame_host_id_;
 
   // References to the owning WebContents, and the corresponding MediaRouter.
   content::WebContents* web_contents_;
@@ -129,7 +129,7 @@
 };
 
 PresentationFrame::PresentationFrame(
-    const RenderFrameHostId& render_frame_host_id,
+    const content::GlobalFrameRoutingId& render_frame_host_id,
     content::WebContents* web_contents,
     MediaRouter* router)
     : render_frame_host_id_(render_frame_host_id),
@@ -333,7 +333,8 @@
     int render_frame_id,
     content::PresentationScreenAvailabilityListener* listener) {
   DCHECK(listener);
-  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
+  content::GlobalFrameRoutingId render_frame_host_id(render_process_id,
+                                                     render_frame_id);
   auto* presentation_frame = GetOrAddPresentationFrame(render_frame_host_id);
   return presentation_frame->SetScreenAvailabilityListener(listener);
 }
@@ -343,7 +344,8 @@
     int render_frame_id,
     content::PresentationScreenAvailabilityListener* listener) {
   DCHECK(listener);
-  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
+  content::GlobalFrameRoutingId render_frame_host_id(render_process_id,
+                                                     render_frame_id);
   const auto it = presentation_frames_.find(render_frame_host_id);
   if (it != presentation_frames_.end())
     it->second->RemoveScreenAvailabilityListener(listener);
@@ -351,7 +353,8 @@
 
 void PresentationServiceDelegateImpl::Reset(int render_process_id,
                                             int render_frame_id) {
-  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
+  content::GlobalFrameRoutingId render_frame_host_id(render_process_id,
+                                                     render_frame_id);
   const auto it = presentation_frames_.find(render_frame_host_id);
   if (it != presentation_frames_.end()) {
     it->second->Reset();
@@ -366,7 +369,7 @@
 }
 
 PresentationFrame* PresentationServiceDelegateImpl::GetOrAddPresentationFrame(
-    const RenderFrameHostId& render_frame_host_id) {
+    const content::GlobalFrameRoutingId& render_frame_host_id) {
   auto& presentation_frame = presentation_frames_[render_frame_host_id];
   if (!presentation_frame) {
     presentation_frame.reset(
@@ -391,7 +394,7 @@
 }
 
 void PresentationServiceDelegateImpl::OnJoinRouteResponse(
-    const RenderFrameHostId& render_frame_host_id,
+    const content::GlobalFrameRoutingId& render_frame_host_id,
     const GURL& presentation_url,
     const std::string& presentation_id,
     content::PresentationConnectionCallback success_cb,
@@ -414,7 +417,7 @@
 }
 
 void PresentationServiceDelegateImpl::OnStartPresentationSucceeded(
-    const RenderFrameHostId& render_frame_host_id,
+    const content::GlobalFrameRoutingId& render_frame_host_id,
     content::PresentationConnectionCallback success_cb,
     const PresentationInfo& new_presentation_info,
     const MediaRoute& route) {
@@ -427,7 +430,7 @@
 }
 
 void PresentationServiceDelegateImpl::AddPresentation(
-    const RenderFrameHostId& render_frame_host_id,
+    const content::GlobalFrameRoutingId& render_frame_host_id,
     const PresentationInfo& presentation_info,
     const MediaRoute& route) {
   auto* presentation_frame = GetOrAddPresentationFrame(render_frame_host_id);
@@ -435,7 +438,7 @@
 }
 
 void PresentationServiceDelegateImpl::RemovePresentation(
-    const RenderFrameHostId& render_frame_host_id,
+    const content::GlobalFrameRoutingId& render_frame_host_id,
     const std::string& presentation_id) {
   const auto it = presentation_frames_.find(render_frame_host_id);
   if (it != presentation_frames_.end())
@@ -544,7 +547,8 @@
     int render_process_id,
     int render_frame_id,
     const std::string& presentation_id) {
-  const RenderFrameHostId rfh_id(render_process_id, render_frame_id);
+  const content::GlobalFrameRoutingId rfh_id(render_process_id,
+                                             render_frame_id);
   auto route_id = GetRouteId(rfh_id, presentation_id);
   if (route_id.empty()) {
     DVLOG(1) << "No active route for: " << presentation_id;
@@ -570,7 +574,8 @@
     int render_process_id,
     int render_frame_id,
     const std::string& presentation_id) {
-  const RenderFrameHostId rfh_id(render_process_id, render_frame_id);
+  const content::GlobalFrameRoutingId rfh_id(render_process_id,
+                                             render_frame_id);
   auto route_id = GetRouteId(rfh_id, presentation_id);
   if (route_id.empty()) {
     DVLOG(1) << "No active route for: " << presentation_id;
@@ -586,7 +591,8 @@
     const PresentationInfo& connection,
     const content::PresentationConnectionStateChangedCallback&
         state_changed_cb) {
-  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
+  content::GlobalFrameRoutingId render_frame_host_id(render_process_id,
+                                                     render_frame_id);
   const auto it = presentation_frames_.find(render_frame_host_id);
   if (it != presentation_frames_.end())
     it->second->ListenForConnectionStateChange(connection, state_changed_cb);
@@ -598,7 +604,8 @@
     const PresentationInfo& presentation_info,
     content::PresentationConnectionPtr controller_connection_ptr,
     content::PresentationConnectionRequest receiver_connection_request) {
-  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
+  content::GlobalFrameRoutingId render_frame_host_id(render_process_id,
+                                                     render_frame_id);
   auto* presentation_frame = GetOrAddPresentationFrame(render_frame_host_id);
   presentation_frame->ConnectToPresentation(
       presentation_info, std::move(controller_connection_ptr),
@@ -654,7 +661,8 @@
     int render_process_id,
     int render_frame_id,
     const MediaSource::Id& source_id) const {
-  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
+  content::GlobalFrameRoutingId render_frame_host_id(render_process_id,
+                                                     render_frame_id);
   const auto it = presentation_frames_.find(render_frame_host_id);
   return it != presentation_frames_.end() &&
          it->second->HasScreenAvailabilityListenerForTest(source_id);
@@ -675,7 +683,8 @@
     int render_process_id,
     int render_frame_id,
     const std::string& presentation_id) {
-  const RenderFrameHostId rfh_id(render_process_id, render_frame_id);
+  const content::GlobalFrameRoutingId rfh_id(render_process_id,
+                                             render_frame_id);
   MediaRoute::Id route_id = GetRouteId(rfh_id, presentation_id);
 
   if (route_id.empty())
@@ -685,7 +694,7 @@
 }
 
 MediaRoute::Id PresentationServiceDelegateImpl::GetRouteId(
-    const RenderFrameHostId& render_frame_host_id,
+    const content::GlobalFrameRoutingId& render_frame_host_id,
     const std::string& presentation_id) const {
   const auto it = presentation_frames_.find(render_frame_host_id);
   return it != presentation_frames_.end()
diff --git a/chrome/browser/media/router/presentation/presentation_service_delegate_impl.h b/chrome/browser/media/router/presentation/presentation_service_delegate_impl.h
index 287b241a..2f10f532 100644
--- a/chrome/browser/media/router/presentation/presentation_service_delegate_impl.h
+++ b/chrome/browser/media/router/presentation/presentation_service_delegate_impl.h
@@ -5,9 +5,9 @@
 #ifndef CHROME_BROWSER_MEDIA_ROUTER_PRESENTATION_PRESENTATION_SERVICE_DELEGATE_IMPL_H_
 #define CHROME_BROWSER_MEDIA_ROUTER_PRESENTATION_PRESENTATION_SERVICE_DELEGATE_IMPL_H_
 
-#include <map>
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -19,7 +19,6 @@
 #include "build/build_config.h"
 #include "chrome/browser/media/router/media_router.h"
 #include "chrome/browser/media/router/presentation/presentation_service_delegate_observers.h"
-#include "chrome/browser/media/router/presentation/render_frame_host_id.h"
 #include "chrome/common/media_router/media_source.h"
 #include "content/public/browser/presentation_request.h"
 #include "content/public/browser/presentation_service_delegate.h"
@@ -179,10 +178,10 @@
   explicit PresentationServiceDelegateImpl(content::WebContents* web_contents);
 
   PresentationFrame* GetOrAddPresentationFrame(
-      const RenderFrameHostId& render_frame_host_id);
+      const content::GlobalFrameRoutingId& render_frame_host_id);
 
   void OnJoinRouteResponse(
-      const RenderFrameHostId& render_frame_host_id,
+      const content::GlobalFrameRoutingId& render_frame_host_id,
       const GURL& presentation_url,
       const std::string& presentation_id,
       content::PresentationConnectionCallback success_cb,
@@ -190,7 +189,7 @@
       const RouteRequestResult& result);
 
   void OnStartPresentationSucceeded(
-      const RenderFrameHostId& render_frame_host_id,
+      const content::GlobalFrameRoutingId& render_frame_host_id,
       content::PresentationConnectionCallback success_cb,
       const blink::mojom::PresentationInfo& new_presentation_info,
       const MediaRoute& route);
@@ -199,14 +198,16 @@
   // presentation and its corresponding MediaRoute has been created.
   // The PresentationFrame will be created if it does not already exist.
   // This must be called before |ConnectToPresentation()|.
-  void AddPresentation(const RenderFrameHostId& render_frame_host_id,
-                       const blink::mojom::PresentationInfo& presentation_info,
-                       const MediaRoute& route);
+  void AddPresentation(
+      const content::GlobalFrameRoutingId& render_frame_host_id,
+      const blink::mojom::PresentationInfo& presentation_info,
+      const MediaRoute& route);
 
   // Notifies the PresentationFrame of |render_frame_host_id| that a
   // presentation and its corresponding MediaRoute has been removed.
-  void RemovePresentation(const RenderFrameHostId& render_frame_host_id,
-                          const std::string& presentation_id);
+  void RemovePresentation(
+      const content::GlobalFrameRoutingId& render_frame_host_id,
+      const std::string& presentation_id);
 
   // Clears the default presentation request for the owning WebContents and
   // notifies observers of changes. Also resets
@@ -215,8 +216,9 @@
 
   // Returns the ID of the route corresponding to |presentation_id| in the given
   // frame, or empty if no such route exist.
-  MediaRoute::Id GetRouteId(const RenderFrameHostId& render_frame_host_id,
-                            const std::string& presentation_id) const;
+  MediaRoute::Id GetRouteId(
+      const content::GlobalFrameRoutingId& render_frame_host_id,
+      const std::string& presentation_id) const;
 
 #if !defined(OS_ANDROID)
   // Returns true if auto-join requests should be cancelled for |origin|.
@@ -242,9 +244,9 @@
 
   // Maps a frame identifier to a PresentationFrame object for frames
   // that are using Presentation API.
-  std::unordered_map<RenderFrameHostId,
+  std::unordered_map<content::GlobalFrameRoutingId,
                      std::unique_ptr<PresentationFrame>,
-                     RenderFrameHostIdHasher>
+                     content::GlobalFrameRoutingIdHasher>
       presentation_frames_;
 
   PresentationServiceDelegateObservers observers_;
diff --git a/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc b/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc
index 187ab7d..9f8479a 100644
--- a/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc
+++ b/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc
@@ -82,7 +82,7 @@
  public:
   void RegisterLocalPresentationController(
       const PresentationInfo& presentation_info,
-      const RenderFrameHostId& render_frame_id,
+      const content::GlobalFrameRoutingId& render_frame_id,
       content::PresentationConnectionPtr controller,
       content::PresentationConnectionRequest,
       const MediaRoute& route) override {
@@ -92,11 +92,11 @@
 
   MOCK_METHOD3(RegisterLocalPresentationController,
                void(const PresentationInfo& presentation_info,
-                    const RenderFrameHostId& render_frame_id,
+                    const content::GlobalFrameRoutingId& render_frame_id,
                     const MediaRoute& route));
   MOCK_METHOD2(UnregisterLocalPresentationController,
                void(const std::string& presentation_id,
-                    const RenderFrameHostId& render_frame_id));
+                    const content::GlobalFrameRoutingId& render_frame_id));
   MOCK_METHOD2(OnLocalPresentationReceiverCreated,
                void(const PresentationInfo& presentation_info,
                     const content::ReceiverConnectionAvailableCallback&
@@ -139,7 +139,8 @@
     delegate_impl_ = PresentationServiceDelegateImpl::FromWebContents(wc);
     SetMainFrame();
     presentation_request_ = std::make_unique<content::PresentationRequest>(
-        RenderFrameHostId(main_frame_process_id_, main_frame_routing_id_),
+        content::GlobalFrameRoutingId(main_frame_process_id_,
+                                      main_frame_routing_id_),
         presentation_urls_, frame_origin_);
     SetMockLocalPresentationManager();
   }
@@ -173,7 +174,8 @@
 
     // Should not trigger callback since request doesn't match.
     content::PresentationRequest different_request(
-        RenderFrameHostId(100, 200), {presentation_url2_}, frame_origin_);
+        content::GlobalFrameRoutingId(100, 200), {presentation_url2_},
+        frame_origin_);
     MediaRoute media_route("differentRouteId", source2_, "mediaSinkId", "",
                            true, true);
     media_route.set_incognito(incognito);
@@ -494,7 +496,8 @@
        TestCloseConnectionForLocalPresentation) {
   GURL presentation_url = GURL("http://www.example.com/presentation.html");
   PresentationInfo presentation_info(presentation_url, kPresentationId);
-  RenderFrameHostId rfh_id(main_frame_process_id_, main_frame_routing_id_);
+  content::GlobalFrameRoutingId rfh_id(main_frame_process_id_,
+                                       main_frame_routing_id_);
   MediaRoute media_route("route_id",
                          MediaSourceForPresentationUrl(presentation_url),
                          "mediaSinkId", "", true, true);
@@ -537,8 +540,9 @@
   EXPECT_CALL(success_cb, Run(_));
   EXPECT_CALL(mock_local_manager,
               UnregisterLocalPresentationController(
-                  kPresentationId, RenderFrameHostId(main_frame_process_id_,
-                                                     main_frame_routing_id_)));
+                  kPresentationId,
+                  content::GlobalFrameRoutingId(main_frame_process_id_,
+                                                main_frame_routing_id_)));
 
   delegate_impl_->ReconnectPresentation(*presentation_request_, kPresentationId,
                                         success_cb.Get(), error_cb.Get());
@@ -546,7 +550,8 @@
 }
 
 TEST_F(PresentationServiceDelegateImplTest, ConnectToLocalPresentation) {
-  RenderFrameHostId rfh_id(main_frame_process_id_, main_frame_routing_id_);
+  content::GlobalFrameRoutingId rfh_id(main_frame_process_id_,
+                                       main_frame_routing_id_);
   PresentationInfo presentation_info(presentation_url1_, kPresentationId);
 
   MediaRoute media_route("route_id",
@@ -578,7 +583,8 @@
 }
 
 TEST_F(PresentationServiceDelegateImplTest, ConnectToPresentation) {
-  RenderFrameHostId rfh_id(main_frame_process_id_, main_frame_routing_id_);
+  content::GlobalFrameRoutingId rfh_id(main_frame_process_id_,
+                                       main_frame_routing_id_);
   PresentationInfo presentation_info(presentation_url1_, kPresentationId);
 
   MediaRoute media_route("route_id",
diff --git a/chrome/browser/media/router/presentation/presentation_service_delegate_observers.cc b/chrome/browser/media/router/presentation/presentation_service_delegate_observers.cc
index 8c6c0e4..4d8f90d4 100644
--- a/chrome/browser/media/router/presentation/presentation_service_delegate_observers.cc
+++ b/chrome/browser/media/router/presentation/presentation_service_delegate_observers.cc
@@ -21,14 +21,15 @@
     content::PresentationServiceDelegate::Observer* observer) {
   DCHECK(observer);
 
-  RenderFrameHostId rfh_id(render_process_id, render_frame_id);
+  content::GlobalFrameRoutingId rfh_id(render_process_id, render_frame_id);
   DCHECK(!base::ContainsKey(observers_, rfh_id));
   observers_[rfh_id] = observer;
 }
 
 void PresentationServiceDelegateObservers::RemoveObserver(int render_process_id,
                                                           int render_frame_id) {
-  observers_.erase(RenderFrameHostId(render_process_id, render_frame_id));
+  observers_.erase(
+      content::GlobalFrameRoutingId(render_process_id, render_frame_id));
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/presentation/presentation_service_delegate_observers.h b/chrome/browser/media/router/presentation/presentation_service_delegate_observers.h
index 1491176..3c30c15 100644
--- a/chrome/browser/media/router/presentation/presentation_service_delegate_observers.h
+++ b/chrome/browser/media/router/presentation/presentation_service_delegate_observers.h
@@ -7,7 +7,7 @@
 
 #include <map>
 
-#include "chrome/browser/media/router/presentation/render_frame_host_id.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/presentation_service_delegate.h"
 
 namespace media_router {
@@ -33,7 +33,8 @@
   virtual void RemoveObserver(int render_process_id, int render_frame_id);
 
  private:
-  std::map<RenderFrameHostId, content::PresentationServiceDelegate::Observer*>
+  std::map<content::GlobalFrameRoutingId,
+           content::PresentationServiceDelegate::Observer*>
       observers_;
 };
 
diff --git a/chrome/browser/media/router/presentation/render_frame_host_id.h b/chrome/browser/media/router/presentation/render_frame_host_id.h
deleted file mode 100644
index f139d5d..0000000
--- a/chrome/browser/media/router/presentation/render_frame_host_id.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_ROUTER_PRESENTATION_RENDER_FRAME_HOST_ID_H_
-#define CHROME_BROWSER_MEDIA_ROUTER_PRESENTATION_RENDER_FRAME_HOST_ID_H_
-
-#include <utility>
-
-#include "base/hash.h"
-
-namespace media_router {
-
-using RenderFrameHostId = std::pair<int, int>;
-
-struct RenderFrameHostIdHasher {
-  std::size_t operator()(const RenderFrameHostId id) const {
-    return base::HashInts(id.first, id.second);
-  }
-};
-
-}  // namespace media_router
-
-#endif  // CHROME_BROWSER_MEDIA_ROUTER_PRESENTATION_RENDER_FRAME_HOST_ID_H_
diff --git a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
index 38cae30..714c4f2 100644
--- a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
@@ -28,7 +28,6 @@
 #include "components/variations/variations_associated_data.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/network_service_instance.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 #if defined(OS_ANDROID)
@@ -241,8 +240,7 @@
   return variations::VariationsService::Create(
       std::make_unique<ChromeVariationsServiceClient>(), local_state_,
       GetMetricsStateManager(), switches::kDisableBackgroundNetworking,
-      chrome_variations::CreateUIStringOverrider(),
-      base::BindOnce(&content::GetNetworkConnectionTracker));
+      chrome_variations::CreateUIStringOverrider());
 }
 
 std::unique_ptr<metrics::MetricsServiceClient>
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 5e0398d..239321e 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -777,7 +777,9 @@
   auto* driver = driver_factory_->GetDriverForFrame(
       password_manager_client_bindings_.GetCurrentTargetFrame());
   DCHECK(driver);
-  gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
+  gfx::RectF element_bounds_in_screen_space =
+      GetBoundsInScreenSpace(TransformToRootCoordinates(
+          password_manager_driver_bindings_.GetCurrentTargetFrame(), bounds));
   popup_controller_ = PasswordGenerationPopupControllerImpl::GetOrCreate(
       popup_controller_, element_bounds_in_screen_space, form,
       base::string16(),  // No generation_element needed for editing.
@@ -1065,17 +1067,18 @@
   auto* driver = driver_factory_->GetDriverForFrame(
       password_manager_client_bindings_.GetCurrentTargetFrame());
   DCHECK(driver);
-  // Autofill drop-down and password generation use different coordinates.
-  gfx::RectF element_bounds_in_screen_space = TransformToRootCoordinates(
+  gfx::RectF element_bounds_in_top_frame_space = TransformToRootCoordinates(
       password_manager_client_bindings_.GetCurrentTargetFrame(),
       ui_data.bounds);
   if (!is_manually_triggered &&
       driver->GetPasswordAutofillManager()
           ->MaybeShowPasswordSuggestionsWithGeneration(
-              element_bounds_in_screen_space, ui_data.text_direction))
+              element_bounds_in_top_frame_space, ui_data.text_direction)) {
     return;
+  }
 
-  element_bounds_in_screen_space = GetBoundsInScreenSpace(ui_data.bounds);
+  gfx::RectF element_bounds_in_screen_space =
+      GetBoundsInScreenSpace(element_bounds_in_top_frame_space);
   password_manager_.SetGenerationElementAndReasonForForm(
       driver, ui_data.password_form, ui_data.generation_element,
       is_manually_triggered);
diff --git a/chrome/browser/password_manager/password_accessory_controller.cc b/chrome/browser/password_manager/password_accessory_controller.cc
index c4866e05..cd3ae17 100644
--- a/chrome/browser/password_manager/password_accessory_controller.cc
+++ b/chrome/browser/password_manager/password_accessory_controller.cc
@@ -173,7 +173,7 @@
     autofill::FillingStatus status) {
   if (status != autofill::FillingStatus::SUCCESS)
     return;                      // TODO(crbug/853766): Record success rate.
-  view_->OpenKeyboard();  // Bring up the keyboard for the still focused field.
+  view_->SwapSheetWithKeyboard();
 }
 
 void PasswordAccessoryController::RefreshSuggestionsForField(
@@ -184,7 +184,7 @@
     current_origin_ = origin;
     view_->OnItemsAvailable(CreateViewItems(origin, origin_suggestions_[origin],
                                             is_password_field));
-    view_->OpenKeyboard();  // Should happen automatically.
+    view_->SwapSheetWithKeyboard();
   } else {
     // For unfillable fields, reset the origin and send the empty state message.
     current_origin_ = url::Origin();
diff --git a/chrome/browser/password_manager/password_accessory_controller_unittest.cc b/chrome/browser/password_manager/password_accessory_controller_unittest.cc
index 9f2ffb3..df23aec 100644
--- a/chrome/browser/password_manager/password_accessory_controller_unittest.cc
+++ b/chrome/browser/password_manager/password_accessory_controller_unittest.cc
@@ -65,7 +65,7 @@
   MOCK_METHOD0(OnViewDestroyed, void());
   MOCK_METHOD1(OnAutomaticGenerationStatusChanged, void(bool));
   MOCK_METHOD0(CloseAccessorySheet, void());
-  MOCK_METHOD0(OpenKeyboard, void());
+  MOCK_METHOD0(SwapSheetWithKeyboard, void());
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockPasswordAccessoryView);
@@ -259,7 +259,7 @@
         mock_dialog_factory_.Get(), favicon_service());
     NavigateAndCommit(GURL(kExampleSite));
     EXPECT_CALL(*view(), CloseAccessorySheet()).Times(AnyNumber());
-    EXPECT_CALL(*view(), OpenKeyboard()).Times(AnyNumber());
+    EXPECT_CALL(*view(), SwapSheetWithKeyboard()).Times(AnyNumber());
   }
 
   PasswordAccessoryController* controller() {
@@ -406,12 +406,12 @@
 TEST_F(PasswordAccessoryControllerTest, ClosesViewOnSuccessfullFillingOnly) {
   // If the filling wasn't successful, no call is expected.
   EXPECT_CALL(*view(), CloseAccessorySheet()).Times(0);
-  EXPECT_CALL(*view(), OpenKeyboard()).Times(0);
+  EXPECT_CALL(*view(), SwapSheetWithKeyboard()).Times(0);
   controller()->OnFilledIntoFocusedField(FillingStatus::ERROR_NOT_ALLOWED);
   controller()->OnFilledIntoFocusedField(FillingStatus::ERROR_NO_VALID_FIELD);
 
   // If the filling completed successfully, let the view know.
-  EXPECT_CALL(*view(), OpenKeyboard());
+  EXPECT_CALL(*view(), SwapSheetWithKeyboard());
   controller()->OnFilledIntoFocusedField(FillingStatus::SUCCESS);
 }
 
@@ -421,7 +421,8 @@
   EXPECT_CALL(*view(), OnItemsAvailable(_)).Times(AnyNumber());
 
   EXPECT_CALL(*view(), CloseAccessorySheet());
-  EXPECT_CALL(*view(), OpenKeyboard()).Times(0);  // Don't touch the keyboard!
+  EXPECT_CALL(*view(), SwapSheetWithKeyboard())
+      .Times(0);  // Don't touch the keyboard!
   controller()->RefreshSuggestionsForField(
       url::Origin::Create(GURL(kExampleSite)),
       /*is_fillable=*/false,
diff --git a/chrome/browser/password_manager/password_accessory_view_interface.h b/chrome/browser/password_manager/password_accessory_view_interface.h
index 6bc3fd8f..77c3e09 100644
--- a/chrome/browser/password_manager/password_accessory_view_interface.h
+++ b/chrome/browser/password_manager/password_accessory_view_interface.h
@@ -74,8 +74,8 @@
   // Called to inform the view that the accessory sheet should be closed now.
   virtual void CloseAccessorySheet() = 0;
 
-  // Called to inform the view that the accessory sheet should be closed now.
-  virtual void OpenKeyboard() = 0;
+  // Opens a keyboard which dismisses the sheet. NoOp without open sheet.
+  virtual void SwapSheetWithKeyboard() = 0;
 
  private:
   friend class PasswordAccessoryController;
diff --git a/chrome/browser/plugins/plugins_resource_service.cc b/chrome/browser/plugins/plugins_resource_service.cc
index 8223414..b553264 100644
--- a/chrome/browser/plugins/plugins_resource_service.cc
+++ b/chrome/browser/plugins/plugins_resource_service.cc
@@ -14,7 +14,6 @@
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
-#include "content/public/browser/network_service_instance.h"
 #include "content/public/common/service_manager_connection.h"
 #include "services/data_decoder/public/cpp/safe_json_parser.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -90,8 +89,7 @@
           base::Bind(data_decoder::SafeJsonParser::Parse,
                      content::ServiceManagerConnection::GetForProcess()
                          ->GetConnector()),
-          kPluginResourceServiceTrafficAnnotation,
-          base::BindOnce(&content::GetNetworkConnectionTracker)) {}
+          kPluginResourceServiceTrafficAnnotation) {}
 
 void PluginsResourceService::Init() {
   const base::DictionaryValue* metadata =
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index e87e5e8..bb8db7b 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1000,6 +1000,11 @@
   handlers->AddHandler(
       std::make_unique<extensions::ExtensionSettingsPolicyHandler>(
           chrome_schema));
+  handlers->AddHandler(std::make_unique<SimpleSchemaValidatingPolicyHandler>(
+      key::kWebAppInstallForceList, prefs::kWebAppInstallForceList,
+      chrome_schema, SCHEMA_STRICT,
+      SimpleSchemaValidatingPolicyHandler::RECOMMENDED_PROHIBITED,
+      SimpleSchemaValidatingPolicyHandler::MANDATORY_ALLOWED));
 #endif
 
 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index aadab97..6963d95 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -114,6 +114,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_test_util.h"
+#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/net/safe_search_util.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
@@ -6284,6 +6285,54 @@
   EXPECT_TRUE(context->CanRequestObjectPermission(kTestUrl, kTestUrl));
 }
 
+// Similar to PolicyTest but sets the WebAppInstallForceList policy before the
+// browser is started.
+class WebAppInstallForceListPolicyTest : public PolicyTest {
+ public:
+  WebAppInstallForceListPolicyTest() {}
+  ~WebAppInstallForceListPolicyTest() override {}
+
+  void SetUpInProcessBrowserTestFixture() override {
+    PolicyTest::SetUpInProcessBrowserTestFixture();
+    ASSERT_TRUE(embedded_test_server()->Start());
+
+    policy_app_url_ =
+        embedded_test_server()->GetURL("/banners/manifest_test_page.html");
+    base::Value url(policy_app_url_.spec());
+    base::Value launch_container("window");
+
+    base::Value item(base::Value::Type::DICTIONARY);
+    item.SetKey("url", std::move(url));
+    item.SetKey("launch_container", std::move(launch_container));
+
+    base::Value list(base::Value::Type::LIST);
+    list.GetList().push_back(std::move(item));
+
+    PolicyMap policies;
+    SetPolicy(&policies, key::kWebAppInstallForceList,
+              base::Value::ToUniquePtrValue(std::move(list)));
+    provider_.UpdateChromePolicy(policies);
+  }
+
+ protected:
+  GURL policy_app_url_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebAppInstallForceListPolicyTest);
+};
+
+IN_PROC_BROWSER_TEST_F(WebAppInstallForceListPolicyTest, StartUpInstallation) {
+  extensions::TestExtensionRegistryObserver observer(
+      extensions::ExtensionRegistry::Get(browser()->profile()));
+  const extensions::Extension* installed_extension =
+      observer.WaitForExtensionWillBeInstalled();
+
+  ASSERT_TRUE(installed_extension);
+  const GURL installed_app_url =
+      extensions::AppLaunchInfo::GetFullLaunchURL(installed_extension);
+  EXPECT_EQ(policy_app_url_, installed_app_url);
+}
+
 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
 
 // The possibilities for a boolean policy.
diff --git a/chrome/browser/prefs/pref_service_incognito_whitelist.cc b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
index 9413624..61b3980 100644
--- a/chrome/browser/prefs/pref_service_incognito_whitelist.cc
+++ b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
@@ -131,6 +131,9 @@
     // they need to be persisted.
     rappor::prefs::kRapporCohortSeed, rappor::prefs::kRapporSecret,
 
+    // Reading list preferences are common between incognito and regular mode.
+    reading_list::prefs::kReadingListHasUnseenEntries,
+
     // Although UKMs are not collected in incognito, theses preferences may be
     // changed by UMA/Sync/Unity consent, and need to be the same between
     // incognito and regular modes.
@@ -297,22 +300,6 @@
 
     prefs::kInvertNotificationShown,
 
-    prefs::kPrintingEnabled, prefs::kPrintPreviewDisabled,
-    prefs::kPrintPreviewDefaultDestinationSelectionRules,
-
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
-    prefs::kPrintPreviewUseSystemDefaultPrinter,
-#endif
-
-#if defined(OS_CHROMEOS)
-    prefs::kPrintingDevices, prefs::kRecommendedNativePrinters,
-    prefs::kRecommendedNativePrintersFile,
-    prefs::kRecommendedNativePrintersAccessMode,
-    prefs::kRecommendedNativePrintersBlacklist,
-    prefs::kRecommendedNativePrintersWhitelist,
-    prefs::kUserNativePrintersAllowed,
-#endif  // OS_CHROMEOS
-
     prefs::kMessageCenterDisabledExtensionIds,
     prefs::kMessageCenterDisabledSystemComponentIds,
 
@@ -418,8 +405,6 @@
     prefs::kDefaultAudioCaptureDevice, prefs::kDefaultVideoCaptureDevice,
     prefs::kMediaDeviceIdSalt, prefs::kMediaStorageIdSalt,
 
-    prefs::kPrintPreviewStickySettings,
-
     prefs::kMaxConnectionsPerProxy,
 
     prefs::kAudioCaptureAllowed, prefs::kAudioCaptureAllowedUrls,
@@ -608,9 +593,6 @@
     onc::prefs::kDeviceOpenNetworkConfiguration,
     onc::prefs::kOpenNetworkConfiguration,
 
-    // components/reading_list/core/reading_list_pref_names.h
-    reading_list::prefs::kReadingListHasUnseenEntries,
-
     // components/search_engines/search_engines_pref_names.h
     prefs::kSyncedDefaultSearchProviderGUID,
     prefs::kDefaultSearchProviderEnabled, prefs::kSearchProviderOverrides,
diff --git a/chrome/browser/prerender/OWNERS b/chrome/browser/prerender/OWNERS
index 03f1a3b..61337163 100644
--- a/chrome/browser/prerender/OWNERS
+++ b/chrome/browser/prerender/OWNERS
@@ -1,7 +1,5 @@
-davidben@chromium.org
 droger@chromium.org
 mattcary@chromium.org
-mmenke@chromium.org
 pasko@chromium.org
 
 # COMPONENT: Internals>Preload
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index dfb91c5..83fb836 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -428,21 +428,27 @@
   }
 
   // TabStripModelObserver implementation:
-  void TabReplacedAt(TabStripModel* tab_strip_model,
-                     WebContents* old_contents,
-                     WebContents* new_contents,
-                     int index) override {
-    if (old_contents != web_contents())
+  void OnTabStripModelChanged(
+      TabStripModel* tab_strip_model,
+      const TabStripModelChange& change,
+      const TabStripSelectionChange& selection) override {
+    if (change.type() != TabStripModelChange::kReplaced)
       return;
-    // Switch to observing the new WebContents.
-    Observe(new_contents);
-    if (new_contents->IsLoading()) {
-      // If the new WebContents is still loading, wait for it to complete. Only
-      // one load post-swap is supported.
-      did_start_loading_ = true;
-      number_of_loads_ = 1;
-    } else {
-      loop_.Quit();
+
+    for (const auto& delta : change.deltas()) {
+      if (delta.replace.old_contents != web_contents())
+        continue;
+
+      // Switch to observing the new WebContents.
+      Observe(delta.replace.new_contents);
+      if (delta.replace.new_contents->IsLoading()) {
+        // If the new WebContents is still loading, wait for it to complete.
+        // Only one load post-swap is supported.
+        did_start_loading_ = true;
+        number_of_loads_ = 1;
+      } else {
+        loop_.Quit();
+      }
     }
   }
 
@@ -1430,8 +1436,9 @@
 // http://crbug.com/100514
 #define MAYBE_PrerenderIframeDelayLoadPlugin \
         DISABLED_PrerenderIframeDelayLoadPlugin
-#elif defined(OS_WIN) && defined(ARCH_CPU_X86_64)
-// TODO(jschuh): Failing plugin tests. crbug.com/244653
+#elif defined(OS_WIN)
+// TODO(jschuh): Failing plugin tests. https://crbug.com/244653,
+// https://crbug.com/876872
 #define MAYBE_PrerenderIframeDelayLoadPlugin \
         DISABLED_PrerenderIframeDelayLoadPlugin
 #else
diff --git a/chrome/browser/previews/previews_service_unittest.cc b/chrome/browser/previews/previews_service_unittest.cc
index e5c1e3c..244ccf2 100644
--- a/chrome/browser/previews/previews_service_unittest.cc
+++ b/chrome/browser/previews/previews_service_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/time/default_clock.h"
+#include "build/build_config.h"
 #include "components/blacklist/opt_out_blacklist/opt_out_blacklist_data.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/previews/content/previews_decider_impl.h"
@@ -187,8 +188,12 @@
 }
 
 TEST_F(PreviewsServiceTest, TestNoScriptPreviewsEnabledByFeature) {
+#if !defined(OS_ANDROID)
+  // For non-android, default is disabled.
   EXPECT_FALSE(previews_decider_impl()->IsPreviewEnabled(
       previews::PreviewsType::NOSCRIPT));
+#endif  // defined(OS_ANDROID)
+
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
       previews::features::kNoScriptPreviews);
diff --git a/chrome/browser/resources/chromeos/login/demo_preferences.js b/chrome/browser/resources/chromeos/login/demo_preferences.js
index ca1b2809..5952902 100644
--- a/chrome/browser/resources/chromeos/login/demo_preferences.js
+++ b/chrome/browser/resources/chromeos/login/demo_preferences.js
@@ -8,25 +8,12 @@
   behaviors: [I18nBehavior, OobeDialogHostBehavior],
 
   properties: {
-    /** Currently selected system language (display name). */
-    currentLanguage: {
-      type: String,
-      value: '',
-    },
-
-    /** Currently selected input method (display name). */
-    currentKeyboard: {
-      type: String,
-      value: '',
-    },
-
     /**
      * List of languages for language selector dropdown.
      * @type {!Array<!OobeTypes.LanguageDsc>}
      */
     languages: {
       type: Array,
-      observer: 'onLanguagesChanged_',
     },
 
     /**
@@ -35,25 +22,40 @@
      */
     keyboards: {
       type: Array,
-      observer: 'onKeyboardsChanged_',
     },
   },
 
-  /** @override */
-  ready: function() {
-    this.i18nUpdateLocale();
-
+  /** Called after resources are updated. */
+  updateLocalizedContent: function() {
     assert(loadTimeData);
     var languageList = loadTimeData.getValue('languageList');
     this.setLanguageList_(languageList);
 
     var inputMethodsList = loadTimeData.getValue('inputMethodsList');
     this.setInputMethods_(inputMethodsList);
+
+    this.i18nUpdateLocale();
   },
 
-  /** Called after resources are updated. */
-  updateLocalizedContent: function() {
-    this.i18nUpdateLocale();
+  /**
+   * Sets selected keyboard.
+   * @param {string} keyboardId
+   */
+  setSelectedKeyboard: function(keyboardId) {
+    var found = false;
+    for (var keyboard of this.keyboards) {
+      if (keyboard.value != keyboardId) {
+        keyboard.selected = false;
+        continue;
+      }
+      keyboard.selected = true;
+      found = true;
+    }
+    if (!found)
+      return;
+
+    // Force i18n-dropdown to refresh.
+    this.keyboards = this.keyboards.slice();
   },
 
   /**
@@ -75,29 +77,6 @@
   },
 
   /**
-   * Sets selected keyboard.
-   * @param {string} keyboardId
-   * @private
-   */
-  setSelectedKeyboard_: function(keyboardId) {
-    var found = false;
-    for (var keyboard of this.keyboards) {
-      if (keyboard.value != keyboardId) {
-        keyboard.selected = false;
-        continue;
-      }
-      keyboard.selected = true;
-      found = true;
-    }
-    if (!found)
-      return;
-
-    // Force i18n-dropdown to refresh.
-    this.keyboards = this.keyboards.slice();
-    this.onKeyboardsChanged_();
-  },
-
-  /**
    * Handle language selection.
    * @param {!{detail: {!OobeTypes.LanguageDsc}}} event
    * @private
@@ -105,7 +84,6 @@
   onLanguageSelected_: function(event) {
     var item = event.detail;
     var languageId = item.value;
-    this.currentLanguage = item.title;
     this.screen.onLanguageSelected_(languageId);
   },
 
@@ -117,27 +95,10 @@
   onKeyboardSelected_: function(event) {
     var item = event.detail;
     var inputMethodId = item.value;
-    this.currentKeyboard = item.title;
     this.screen.onKeyboardSelected_(inputMethodId);
   },
 
   /**
-   * Language changes handler.
-   * @private
-   */
-  onLanguagesChanged_: function() {
-    this.currentLanguage = getSelectedTitle(this.languages);
-  },
-
-  /**
-   * Keyboard changes handler.
-   * @private
-   */
-  onKeyboardsChanged_: function() {
-    this.currentKeyboard = getSelectedTitle(this.keyboards);
-  },
-
-  /**
    * Back button click handler.
    * @private
    */
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_demo_preferences.js b/chrome/browser/resources/chromeos/login/oobe_screen_demo_preferences.js
index 005f1bdc..2f984ff 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_demo_preferences.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_demo_preferences.js
@@ -10,26 +10,30 @@
   var CONTEXT_KEY_LOCALE = 'locale';
   var CONTEXT_KEY_INPUT_METHOD = 'input-method';
 
+  var demoPreferencesModule = null;
+
   return {
+
     /** @override */
     decorate: function() {
-      var demoPreferences = $('demo-preferences-content');
-      demoPreferences.screen = this;
+      demoPreferencesModule = $('demo-preferences-content');
+      demoPreferencesModule.screen = this;
 
       this.context.addObserver(
           CONTEXT_KEY_INPUT_METHOD, function(inputMethodId) {
             $('demo-preferences-content').setSelectedKeyboard(inputMethodId);
           });
+      this.updateLocalizedContent();
     },
 
     /** Returns a control which should receive an initial focus. */
     get defaultControl() {
-      return $('demo-preferences-content');
+      return demoPreferencesModule;
     },
 
     /** Called after resources are updated. */
     updateLocalizedContent: function() {
-      $('demo-preferences-content').updateLocalizedContent();
+      demoPreferencesModule.updateLocalizedContent();
     },
 
     /**
diff --git a/chrome/browser/resources/webauthn/2x/error_timeout.png b/chrome/browser/resources/webauthn/2x/error.png
similarity index 100%
rename from chrome/browser/resources/webauthn/2x/error_timeout.png
rename to chrome/browser/resources/webauthn/2x/error.png
Binary files differ
diff --git a/chrome/browser/resources/webauthn/error_timeout.png b/chrome/browser/resources/webauthn/error.png
similarity index 100%
rename from chrome/browser/resources/webauthn/error_timeout.png
rename to chrome/browser/resources/webauthn/error.png
Binary files differ
diff --git a/chrome/browser/signin/account_tracker_service_factory.cc b/chrome/browser/signin/account_tracker_service_factory.cc
index 75a061e..6551c56 100644
--- a/chrome/browser/signin/account_tracker_service_factory.cc
+++ b/chrome/browser/signin/account_tracker_service_factory.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/signin/core/browser/account_tracker_service.h"
 
@@ -15,7 +14,6 @@
     : BrowserContextKeyedServiceFactory(
         "AccountTrackerServiceFactory",
         BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(ChromeSigninClientFactory::GetInstance());
 }
 
 AccountTrackerServiceFactory::~AccountTrackerServiceFactory() {
@@ -42,7 +40,6 @@
     content::BrowserContext* context) const {
   Profile* profile = static_cast<Profile*>(context);
   AccountTrackerService* service = new AccountTrackerService();
-  service->Initialize(ChromeSigninClientFactory::GetForProfile(profile),
-                      profile->GetPath());
+  service->Initialize(profile->GetPrefs(), profile->GetPath());
   return service;
 }
diff --git a/chrome/browser/signin/dice_response_handler_unittest.cc b/chrome/browser/signin/dice_response_handler_unittest.cc
index 9e1ef9be..9ea632c1 100644
--- a/chrome/browser/signin/dice_response_handler_unittest.cc
+++ b/chrome/browser/signin/dice_response_handler_unittest.cc
@@ -153,7 +153,7 @@
         &token_service_, &signin_manager_, &signin_client_, nullptr,
         std::move(account_reconcilor_delegate));
     about_signin_internals_.Initialize(&signin_client_);
-    account_tracker_service_.Initialize(&signin_client_);
+    account_tracker_service_.Initialize(&pref_service_, base::FilePath());
     account_reconcilor_->AddObserver(this);
   }
 
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h
index 7043b02c..82da56e9 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h
@@ -22,6 +22,7 @@
 #include "net/base/backoff_entry.h"
 #include "services/network/public/cpp/network_connection_tracker.h"
 
+class SigninClient;
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
index eada98a..555797e 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -110,7 +110,7 @@
     client_->test_url_loader_factory()->AddResponse(
         GaiaUrls::GetInstance()->oauth2_revoke_url().spec(), "");
     LoadTokenDatabase();
-    account_tracker_service_.Initialize(client_.get());
+    account_tracker_service_.Initialize(&pref_service_, base::FilePath());
   }
 
   void TearDown() override {
@@ -1045,7 +1045,7 @@
     dict->SetString("gaia", base::UTF8ToUTF16(gaia_id));
     update->Append(std::move(dict));
     account_tracker_service_.Shutdown();
-    account_tracker_service_.Initialize(client_.get());
+    account_tracker_service_.Initialize(&pref_service_, base::FilePath());
 
     AddAuthTokenManually("AccountId-" + email, "refresh_token");
     oauth2_service_delegate_->LoadCredentials(gaia_id);
@@ -1108,7 +1108,7 @@
     dict->SetString("gaia", base::UTF8ToUTF16(gaia_id2));
     update->Append(std::move(dict));
     account_tracker_service_.Shutdown();
-    account_tracker_service_.Initialize(client_.get());
+    account_tracker_service_.Initialize(&pref_service_, base::FilePath());
 
     AddAuthTokenManually("AccountId-" + email1, "refresh_token");
     AddAuthTokenManually("AccountId-" + email2, "refresh_token");
diff --git a/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc b/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc
index cc15bc3..fd1f8aa 100644
--- a/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc
+++ b/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc
@@ -48,7 +48,7 @@
         auth_error_(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
     AccountTrackerService::RegisterPrefs(pref_service_.registry());
     SigninManager::RegisterProfilePrefs(pref_service_.registry());
-    account_tracker_service_.Initialize(&signin_client_);
+    account_tracker_service_.Initialize(&pref_service_, base::FilePath());
   }
 
   ~ProcessDiceHeaderDelegateImplTest() override {
diff --git a/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc b/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc
index 4c9896d..cc3550f8 100644
--- a/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc
+++ b/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc
@@ -16,6 +16,21 @@
 
 namespace {
 
+// Compares two serialized progress markers for equivalence to determine client
+// side progress. Some aspects of the progress markers like
+// GarbageCollectionDirectives are irrelevant for this, as they can vary between
+// requests -- for example a version_watermark could be based on request time.
+bool AreProgressMarkersEquivalent(const std::string& serialized1,
+                                  const std::string& serialized2) {
+  sync_pb::DataTypeProgressMarker marker1;
+  sync_pb::DataTypeProgressMarker marker2;
+  CHECK(marker1.ParseFromString(serialized1));
+  CHECK(marker2.ParseFromString(serialized2));
+  marker1.clear_gc_directive();
+  marker2.clear_gc_directive();
+  return marker1.SerializeAsString() == marker2.SerializeAsString();
+}
+
 // Returns true if these services have matching progress markers.
 bool ProgressMarkersMatch(const browser_sync::ProfileSyncService* service1,
                           const browser_sync::ProfileSyncService* service2) {
@@ -50,7 +65,7 @@
     }
 
     // Fail if any of them don't match.
-    if (pm_it1->second != pm_it2->second) {
+    if (!AreProgressMarkersEquivalent(pm_it1->second, pm_it2->second)) {
       return false;
     }
   }
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index e624001..bfffa42 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -32,9 +32,9 @@
 using autofill::AutofillProfile;
 using autofill::CreditCard;
 using autofill::data_util::TruncateUTF8;
+using autofill_helper::GetAccountWebDataService;
 using autofill_helper::GetPersonalDataManager;
 using autofill_helper::GetProfileWebDataService;
-using autofill_helper::GetAccountWebDataService;
 using base::ASCIIToUTF16;
 
 namespace {
@@ -121,10 +121,15 @@
   return std::move(consumer.result());
 }
 
-void AddDefaultCard(fake_server::FakeServer* server) {
-  sync_pb::EntitySpecifics specifics;
+sync_pb::SyncEntity CreateDefaultSyncWalletCard() {
+  sync_pb::SyncEntity entity;
+  entity.set_name(kDefaultCardID);
+  entity.set_id_string(kDefaultCardID);
+  entity.set_version(0);  // Will be overridden by the fake server.
+  entity.set_ctime(12345);
+  entity.set_mtime(12345);
   sync_pb::AutofillWalletSpecifics* wallet_specifics =
-      specifics.mutable_autofill_wallet();
+      entity.mutable_specifics()->mutable_autofill_wallet();
   wallet_specifics->set_type(
       sync_pb::AutofillWalletSpecifics::MASKED_CREDIT_CARD);
 
@@ -138,10 +143,7 @@
   credit_card->set_status(sync_pb::WalletMaskedCreditCard::VALID);
   credit_card->set_type(kDefaultCardType);
   credit_card->set_billing_address_id(kDefaultBillingAddressId);
-
-  server->InjectEntity(
-      syncer::PersistentUniqueClientEntity::CreateFromEntitySpecifics(
-          kDefaultCardID, specifics, 12345, 12345));
+  return entity;
 }
 
 CreditCard GetDefaultCreditCard() {
@@ -158,10 +160,16 @@
   return card;
 }
 
-void AddDefaultProfile(fake_server::FakeServer* server) {
-  sync_pb::EntitySpecifics specifics;
+sync_pb::SyncEntity CreateDefaultSyncWalletAddress() {
+  sync_pb::SyncEntity entity;
+  entity.set_name(kDefaultAddressID);
+  entity.set_id_string(kDefaultAddressID);
+  entity.set_version(0);  // Will be overridden by the fake server.
+  entity.set_ctime(12345);
+  entity.set_mtime(12345);
+
   sync_pb::AutofillWalletSpecifics* wallet_specifics =
-      specifics.mutable_autofill_wallet();
+      entity.mutable_specifics()->mutable_autofill_wallet();
   wallet_specifics->set_type(sync_pb::AutofillWalletSpecifics::POSTAL_ADDRESS);
 
   sync_pb::WalletPostalAddress* wallet_address =
@@ -179,9 +187,7 @@
   wallet_address->set_sorting_code(kDefaultSortingCode);
   wallet_address->set_language_code(kDefaultLanguageCode);
 
-  server->InjectEntity(
-      syncer::PersistentUniqueClientEntity::CreateFromEntitySpecifics(
-          kDefaultAddressID, specifics, 12345, 12345));
+  return entity;
 }
 
 // TODO(sebsg): Instead add a function to create a card, and one to inject in
@@ -279,7 +285,7 @@
     : public UssSwitchToggler,
       public SingleClientWalletSyncTest {
  public:
-  SingleClientWalletSyncTestIncludingUssTests(){};
+  SingleClientWalletSyncTestIncludingUssTests() {}
   ~SingleClientWalletSyncTestIncludingUssTests() override {}
 
  private:
@@ -304,8 +310,8 @@
       {},
       // Disabled.
       {autofill::features::kAutofillEnableAccountWalletStorage});
-  AddDefaultProfile(GetFakeServer());
-  AddDefaultCard(GetFakeServer());
+  GetFakeServer()->SetWalletData(
+      {CreateDefaultSyncWalletAddress(), CreateDefaultSyncWalletCard()});
   ASSERT_TRUE(SetupSync());
 
   auto profile_data = GetProfileWebDataService(0);
@@ -345,8 +351,9 @@
       {});
 
   ASSERT_TRUE(SetupClients());
-  AddDefaultCard(GetFakeServer());
-  AddDefaultProfile(GetFakeServer());
+
+  GetFakeServer()->SetWalletData(
+      {CreateDefaultSyncWalletAddress(), CreateDefaultSyncWalletCard()});
 
   ASSERT_TRUE(GetClient(0)->SignIn());
   ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization(
@@ -384,8 +391,8 @@
 
 // Wallet data should get cleared from the database when sync is disabled.
 IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ClearOnDisableSync) {
-  AddDefaultCard(GetFakeServer());
-  AddDefaultProfile(GetFakeServer());
+  GetFakeServer()->SetWalletData(
+      {CreateDefaultSyncWalletAddress(), CreateDefaultSyncWalletCard()});
   ASSERT_TRUE(SetupSync());
 
   // Make sure the card is in the DB.
@@ -403,8 +410,8 @@
 // Wallet data should get cleared from the database when the wallet sync type
 // flag is disabled.
 IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ClearOnDisableWalletSync) {
-  AddDefaultCard(GetFakeServer());
-  AddDefaultProfile(GetFakeServer());
+  GetFakeServer()->SetWalletData(
+      {CreateDefaultSyncWalletAddress(), CreateDefaultSyncWalletCard()});
   ASSERT_TRUE(SetupSync());
 
   // Make sure the card is in the DB.
@@ -423,8 +430,8 @@
 // integration flag is disabled.
 IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        ClearOnDisableWalletAutofill) {
-  AddDefaultCard(GetFakeServer());
-  AddDefaultProfile(GetFakeServer());
+  GetFakeServer()->SetWalletData(
+      {CreateDefaultSyncWalletAddress(), CreateDefaultSyncWalletCard()});
   ASSERT_TRUE(SetupSync());
 
   // Make sure the card is in the DB.
@@ -475,7 +482,7 @@
                              profiles[0]->GetRawInfo(autofill::COMPANY_NAME))));
 
   // Add a new card from the server and sync it down.
-  AddDefaultCard(GetFakeServer());
+  GetFakeServer()->SetWalletData({CreateDefaultSyncWalletCard()});
   ASSERT_TRUE(SetupSync());
 
   // The only card present on the client should be the one from the server.
@@ -522,7 +529,7 @@
   EXPECT_EQ("a123", cards[0]->server_id());
 
   // Add a new profile from the server and sync it down.
-  AddDefaultProfile(GetFakeServer());
+  GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress()});
   ASSERT_TRUE(SetupSync());
 
   // The only profile present on the client should be the one from the server.
@@ -562,7 +569,7 @@
 
   // Sync the same card from the server, except with a default billing address
   // id.
-  AddDefaultCard(GetFakeServer());
+  GetFakeServer()->SetWalletData({CreateDefaultSyncWalletCard()});
   ASSERT_TRUE(SetupSync());
 
   // The billing address is should still refer to the local profile.
@@ -597,7 +604,7 @@
 
   // Sync the same card from the server, except with a default billing address
   // id.
-  AddDefaultCard(GetFakeServer());
+  GetFakeServer()->SetWalletData({CreateDefaultSyncWalletCard()});
   ASSERT_TRUE(SetupSync());
 
   // The billing address should be the one from the server card.
diff --git a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
index 24ba4a2..d56e4c1 100644
--- a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
+++ b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
@@ -474,8 +474,7 @@
     // Clears the translate script so it is fetched every time and sets the
     // expiration delay to a large value by default (in case it was zeroed in a
     // previous test).
-    TranslateService::InitializeForTesting(
-        network::mojom::ConnectionType::CONNECTION_WIFI);
+    TranslateService::InitializeForTesting();
     translate::TranslateDownloadManager* download_manager =
         translate::TranslateDownloadManager::GetInstance();
     download_manager->ClearTranslateScriptForTesting();
diff --git a/chrome/browser/translate/translate_service.cc b/chrome/browser/translate/translate_service.cc
index 14be91b..aa44331 100644
--- a/chrome/browser/translate/translate_service.cc
+++ b/chrome/browser/translate/translate_service.cc
@@ -19,7 +19,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "components/translate/core/browser/translate_manager.h"
-#include "content/public/browser/network_service_instance.h"
 #include "content/public/common/url_constants.h"
 #include "url/gurl.h"
 
@@ -30,15 +29,14 @@
 
 namespace {
 // The singleton instance of TranslateService.
-TranslateService* g_translate_service = nullptr;
+TranslateService* g_translate_service = NULL;
 }
 
 TranslateService::TranslateService()
     : resource_request_allowed_notifier_(
           g_browser_process->local_state(),
-          switches::kDisableBackgroundNetworking,
-          base::BindOnce(&content::GetNetworkConnectionTracker)) {
-  resource_request_allowed_notifier_.Init(this, true /* leaky */);
+          switches::kDisableBackgroundNetworking) {
+  resource_request_allowed_notifier_.Init(this);
 }
 
 TranslateService::~TranslateService() {}
@@ -77,18 +75,14 @@
 }
 
 // static
-void TranslateService::InitializeForTesting(
-    network::mojom::ConnectionType type) {
+void TranslateService::InitializeForTesting() {
   if (!g_translate_service) {
     TranslateService::Initialize();
     translate::TranslateManager::SetIgnoreMissingKeyForTesting(true);
   } else {
     translate::TranslateDownloadManager::GetInstance()->ResetForTesting();
+    g_translate_service->OnResourceRequestsAllowed();
   }
-
-  g_translate_service->resource_request_allowed_notifier_
-      .SetConnectionTypeForTesting(type);
-  g_translate_service->OnResourceRequestsAllowed();
 }
 
 // static
diff --git a/chrome/browser/translate/translate_service.h b/chrome/browser/translate/translate_service.h
index 8cd6b36..8b8901d 100644
--- a/chrome/browser/translate/translate_service.h
+++ b/chrome/browser/translate/translate_service.h
@@ -27,7 +27,7 @@
   // Initializes the TranslateService in a way that it can be initialized
   // multiple times in a unit test suite (once for each test). Should be paired
   // with ShutdownForTesting at the end of the test.
-  static void InitializeForTesting(network::mojom::ConnectionType type);
+  static void InitializeForTesting();
 
   // Shuts down the TranslateService at the end of a test in a way that the next
   // test can initialize and use the service.
diff --git a/chrome/browser/translate/translate_service_unittest.cc b/chrome/browser/translate/translate_service_unittest.cc
index 99c79b5..5e925d16 100644
--- a/chrome/browser/translate/translate_service_unittest.cc
+++ b/chrome/browser/translate/translate_service_unittest.cc
@@ -10,7 +10,6 @@
 #include "components/prefs/testing_pref_service.h"
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "content/public/common/url_constants.h"
-#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -50,9 +49,7 @@
 
 // Tests that download and history URLs are not translatable.
 TEST(TranslateServiceTest, DownloadsAndHistoryNotTranslated) {
-  content::TestBrowserThreadBundle thread_bundle;
-  TranslateService::InitializeForTesting(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  TranslateService::InitializeForTesting();
   EXPECT_FALSE(
       TranslateService::IsTranslatableURL(GURL(chrome::kChromeUIDownloadsURL)));
   EXPECT_FALSE(
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index 45631b6d..d2dd126d 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -107,6 +107,7 @@
 #include "extensions/browser/app_window/native_app_window.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest_constants.h"
+#include "extensions/grit/extensions_browser_resources.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/client/window_parenting_client.h"
 #include "ui/aura/window.h"
@@ -116,6 +117,7 @@
 #include "ui/display/screen.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/event_constants.h"
+#include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/image/image_unittest_util.h"
 #include "ui/views/widget/widget.h"
 
@@ -313,6 +315,35 @@
     set_delegate_count_++;
   }
 
+  // Helper that waits for idle and extracts the non-default bitmap from the
+  // last updated item in shelf controller.
+  SkBitmap GetLastItemImage() {
+    if (default_app_image_.isNull()) {
+      default_app_image_ =
+          *gfx::ImageSkiaOperations::CreateResizedImage(
+               *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+                   IDR_APP_DEFAULT_ICON),
+               skia::ImageOperations::RESIZE_BEST,
+               gfx::Size(extension_misc::EXTENSION_ICON_SMALL,
+                         extension_misc::EXTENSION_ICON_SMALL))
+               .bitmap();
+    }
+
+    // Loading icon is multistep process. At first step default app icon is
+    // loaded while real icon is requested and decoded.
+    // base::RunLoop().RunUntilIdle() hides these steps and in most cases real
+    // icon is returned afterward. However in rare cases default icon is left
+    // after base::RunLoop().RunUntilIdle(). So make sure we don't return
+    // default icon that may fail test expectations.
+    while (true) {
+      base::RunLoop().RunUntilIdle();
+      const SkBitmap* bitmap = last_item().image.bitmap();
+      CHECK(bitmap);
+      if (!gfx::test::AreBitmapsEqual(default_app_image_, *bitmap))
+        return *bitmap;
+    }
+  }
+
  private:
   size_t added_count_ = 0;
   size_t removed_count_ = 0;
@@ -323,6 +354,9 @@
   ash::mojom::ShelfObserverAssociatedPtr observer_;
   mojo::Binding<ash::mojom::ShelfController> binding_;
 
+  // Used to cache default app image.
+  SkBitmap default_app_image_;
+
   DISALLOW_COPY_AND_ASSIGN(TestShelfController);
 };
 
@@ -335,15 +369,6 @@
                          ash::LAUNCH_FROM_UNKNOWN, base::DoNothing());
 }
 
-// Helper that waits for idle and extracts the bitmap from the last updated item
-// in shelf controller.
-SkBitmap GetLastItemImage(TestShelfController* shelf_controller) {
-  base::RunLoop().RunUntilIdle();
-  const SkBitmap* bitmap = shelf_controller->last_item().image.bitmap();
-  CHECK(bitmap);
-  return *bitmap;
-}
-
 // Creates a window with TYPE_APP shelf item type and the given app_id.
 views::Widget* CreateShelfAppWindow(const std::string& app_id) {
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
@@ -2409,7 +2434,7 @@
             GetPinnedAppStatus());
 }
 
-TEST_P(ChromeLauncherControllerWithArcTest, DISABLED_ArcCustomAppIcon) {
+TEST_P(ChromeLauncherControllerWithArcTest, ArcCustomAppIcon) {
   InitLauncherController();
 
   TestShelfController* shelf_controller =
@@ -2450,55 +2475,55 @@
       model_->GetShelfItemDelegate(ash::ShelfID(arc_app_id));
   ASSERT_TRUE(item_delegate);
   base::RunLoop().RunUntilIdle();
-  const SkBitmap default_icon = GetLastItemImage(shelf_controller);
+  const SkBitmap default_icon = shelf_controller->GetLastItemImage();
 
   // No custom icon set. Acitivating windows should not change icon.
   window1->Activate();
   EXPECT_TRUE(gfx::test::AreBitmapsEqual(default_icon,
-                                         GetLastItemImage(shelf_controller)));
+                                         shelf_controller->GetLastItemImage()));
   window2->Activate();
   EXPECT_TRUE(gfx::test::AreBitmapsEqual(default_icon,
-                                         GetLastItemImage(shelf_controller)));
+                                         shelf_controller->GetLastItemImage()));
 
   // Set custom icon on active item. Icon should change to custom.
   arc_test_.app_instance()->SendTaskDescription(2, std::string(), png_data);
-  const SkBitmap custom_icon = GetLastItemImage(shelf_controller);
+  const SkBitmap custom_icon = shelf_controller->GetLastItemImage();
   EXPECT_FALSE(gfx::test::AreBitmapsEqual(default_icon, custom_icon));
 
   // Switch back to the item without custom icon. Icon should be changed to
   // default.
   window1->Activate();
   EXPECT_TRUE(gfx::test::AreBitmapsEqual(default_icon,
-                                         GetLastItemImage(shelf_controller)));
+                                         shelf_controller->GetLastItemImage()));
 
   // Test that setting an invalid icon should not change custom icon.
   arc_test_.app_instance()->SendTaskDescription(1, std::string(), png_data);
   EXPECT_TRUE(gfx::test::AreBitmapsEqual(custom_icon,
-                                         GetLastItemImage(shelf_controller)));
+                                         shelf_controller->GetLastItemImage()));
   arc_test_.app_instance()->SendTaskDescription(1, std::string(),
                                                 invalid_png_data);
   EXPECT_TRUE(gfx::test::AreBitmapsEqual(custom_icon,
-                                         GetLastItemImage(shelf_controller)));
+                                         shelf_controller->GetLastItemImage()));
 
   // Check window removing with active custom icon. Reseting custom icon of
   // inactive window doesn't reset shelf icon.
   arc_test_.app_instance()->SendTaskDescription(2, std::string(),
                                                 std::string());
   EXPECT_TRUE(gfx::test::AreBitmapsEqual(custom_icon,
-                                         GetLastItemImage(shelf_controller)));
+                                         shelf_controller->GetLastItemImage()));
   // Set custom icon back to validate closing active window later.
   arc_test_.app_instance()->SendTaskDescription(2, std::string(), png_data);
   EXPECT_TRUE(gfx::test::AreBitmapsEqual(custom_icon,
-                                         GetLastItemImage(shelf_controller)));
+                                         shelf_controller->GetLastItemImage()));
 
   // Reseting custom icon of active window resets shelf icon.
   arc_test_.app_instance()->SendTaskDescription(1, std::string(),
                                                 std::string());
   EXPECT_TRUE(gfx::test::AreBitmapsEqual(default_icon,
-                                         GetLastItemImage(shelf_controller)));
+                                         shelf_controller->GetLastItemImage()));
   window1->CloseNow();
   EXPECT_TRUE(gfx::test::AreBitmapsEqual(custom_icon,
-                                         GetLastItemImage(shelf_controller)));
+                                         shelf_controller->GetLastItemImage()));
 }
 
 // Check that with multi profile V1 apps are properly added / removed from the
diff --git a/chrome/browser/ui/media_router/presentation_receiver_window_controller_browsertest.cc b/chrome/browser/ui/media_router/presentation_receiver_window_controller_browsertest.cc
index 52bd8f6..f57076e6e 100644
--- a/chrome/browser/ui/media_router/presentation_receiver_window_controller_browsertest.cc
+++ b/chrome/browser/ui/media_router/presentation_receiver_window_controller_browsertest.cc
@@ -40,8 +40,6 @@
 
 namespace {
 
-using RenderFrameHostId = std::pair<int, int>;
-
 constexpr char kPresentationId[] = "test_id";
 const base::FilePath::StringPieceType kResourcePath =
     FILE_PATH_LITERAL("media/router/");
@@ -294,7 +292,7 @@
       browser()->profile())
       ->RegisterLocalPresentationController(
           blink::mojom::PresentationInfo(presentation_url, kPresentationId),
-          RenderFrameHostId(0, 0), std::move(controller_ptr),
+          content::GlobalFrameRoutingId(0, 0), std::move(controller_ptr),
           controller_connection.MakeConnectionRequest(),
           media_router::MediaRoute("route",
                                    media_router::MediaSource(presentation_url),
diff --git a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc
index 19258bf..982cb16 100644
--- a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc
+++ b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc
@@ -70,3 +70,8 @@
   if (IsActiveInputContextHandler(input_method_chromeos_.get()))
     input_method_chromeos_->CancelComposition(client_.get());
 }
+
+void InputMethodBridge::ShowVirtualKeyboardIfEnabled() {
+  if (IsActiveInputContextHandler(input_method_chromeos_.get()))
+    input_method_chromeos_->ShowVirtualKeyboardIfEnabled();
+}
diff --git a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.h b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.h
index 0d99164..90610b6 100644
--- a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.h
+++ b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.h
@@ -32,6 +32,7 @@
   void ProcessKeyEvent(std::unique_ptr<ui::Event> key_event,
                        ProcessKeyEventCallback callback) override;
   void CancelComposition() override;
+  void ShowVirtualKeyboardIfEnabled() override;
 
  private:
   std::unique_ptr<RemoteTextInputClient> client_;
diff --git a/chrome/browser/ui/views/ime_driver/simple_input_method.cc b/chrome/browser/ui/views/ime_driver/simple_input_method.cc
index 0dd51a3..dcde6e6 100644
--- a/chrome/browser/ui/views/ime_driver/simple_input_method.cc
+++ b/chrome/browser/ui/views/ime_driver/simple_input_method.cc
@@ -11,13 +11,24 @@
 SimpleInputMethod::~SimpleInputMethod() {}
 
 void SimpleInputMethod::OnTextInputTypeChanged(
-    ui::TextInputType text_input_type) {}
+    ui::TextInputType text_input_type) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
 
-void SimpleInputMethod::OnCaretBoundsChanged(const gfx::Rect& caret_bounds) {}
+void SimpleInputMethod::OnCaretBoundsChanged(const gfx::Rect& caret_bounds) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
 
 void SimpleInputMethod::ProcessKeyEvent(std::unique_ptr<ui::Event> key_event,
                                         ProcessKeyEventCallback callback) {
+  NOTIMPLEMENTED_LOG_ONCE();
   std::move(callback).Run(false);
 }
 
-void SimpleInputMethod::CancelComposition() {}
+void SimpleInputMethod::CancelComposition() {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void SimpleInputMethod::ShowVirtualKeyboardIfEnabled() {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
diff --git a/chrome/browser/ui/views/ime_driver/simple_input_method.h b/chrome/browser/ui/views/ime_driver/simple_input_method.h
index f262c21..4b9f33e 100644
--- a/chrome/browser/ui/views/ime_driver/simple_input_method.h
+++ b/chrome/browser/ui/views/ime_driver/simple_input_method.h
@@ -22,6 +22,7 @@
   void ProcessKeyEvent(std::unique_ptr<ui::Event> key_event,
                        ProcessKeyEventCallback callback) override;
   void CancelComposition() override;
+  void ShowVirtualKeyboardIfEnabled() override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SimpleInputMethod);
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
index 5d4f784a..6668837 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -146,19 +146,6 @@
   constrained_window::ShowWebModalDialogViews(this, request_->web_contents());
 }
 
-void PaymentRequestDialogView::ShowDialogAtPaymentHandlerSheet(
-    const GURL& url,
-    PaymentHandlerOpenWindowCallback callback) {
-  view_stack_->Push(CreateViewAndInstallController(
-                        std::make_unique<PaymentHandlerWebFlowViewController>(
-                            request_->spec(), request_->state(), this,
-                            GetProfile(), url, std::move(callback)),
-                        &controller_map_),
-                    /* animate = */ false);
-  HideProcessingSpinner();
-  ShowDialog();
-}
-
 void PaymentRequestDialogView::CloseDialog() {
   // This calls PaymentRequestDialogView::Cancel() before closing.
   // ViewHierarchyChanged() also gets called after Cancel().
@@ -235,6 +222,14 @@
 }
 
 void PaymentRequestDialogView::GoBack() {
+  // If payment request UI is skipped when calling PaymentRequest.show, then
+  // abort payment request when back button is clicked. This only happens for
+  // service worker based payment handler under circumstance.
+  if (request_->skipped_payment_request_ui()) {
+    CloseDialog();
+    return;
+  }
+
   view_stack_->Pop();
 
   if (observer_for_testing_)
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.h b/chrome/browser/ui/views/payments/payment_request_dialog_view.h
index 6037b176..652570d 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view.h
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.h
@@ -106,9 +106,6 @@
 
   // payments::PaymentRequestDialog:
   void ShowDialog() override;
-  void ShowDialogAtPaymentHandlerSheet(
-      const GURL& url,
-      PaymentHandlerOpenWindowCallback callback) override;
   void CloseDialog() override;
   void ShowErrorMessage() override;
   void ShowProcessingSpinner() override;
diff --git a/chrome/browser/ui/views/webauthn/sheet_view_factory.cc b/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
index 8056592..0af22da 100644
--- a/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
+++ b/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
@@ -57,6 +57,15 @@
           std::make_unique<AuthenticatorNoAvailableTransportsErrorModel>(
               dialog_model));
       break;
+    case Step::kErrorKeyNotRegistered:
+      sheet_view = std::make_unique<AuthenticatorRequestSheetView>(
+          std::make_unique<AuthenticatorNotRegisteredErrorModel>(dialog_model));
+      break;
+    case Step::kErrorKeyAlreadyRegistered:
+      sheet_view = std::make_unique<AuthenticatorRequestSheetView>(
+          std::make_unique<AuthenticatorAlreadyRegisteredErrorModel>(
+              dialog_model));
+      break;
     case Step::kBlePowerOnManual:
       sheet_view = std::make_unique<AuthenticatorRequestSheetView>(
           std::make_unique<AuthenticatorBlePowerOnManualSheetModel>(
diff --git a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
index 3eb7696..ebdfd3e 100644
--- a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
+++ b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
@@ -42,12 +42,18 @@
     } else if (name == "activate_usb") {
       model->SetCurrentStep(
           AuthenticatorRequestDialogModel::Step::kUsbInsertAndActivate);
-    } else if (name == "no_available_transports") {
-      model->SetCurrentStep(
-          AuthenticatorRequestDialogModel::Step::kErrorNoAvailableTransports);
     } else if (name == "timeout") {
       model->SetCurrentStep(
           AuthenticatorRequestDialogModel::Step::kErrorTimedOut);
+    } else if (name == "no_available_transports") {
+      model->SetCurrentStep(
+          AuthenticatorRequestDialogModel::Step::kErrorNoAvailableTransports);
+    } else if (name == "key_not_registered") {
+      model->SetCurrentStep(
+          AuthenticatorRequestDialogModel::Step::kErrorKeyNotRegistered);
+    } else if (name == "key_already_registered") {
+      model->SetCurrentStep(
+          AuthenticatorRequestDialogModel::Step::kErrorKeyAlreadyRegistered);
     } else if (name == "ble_power_on_manual") {
       model->SetCurrentStep(
           AuthenticatorRequestDialogModel::Step::kBlePowerOnManual);
@@ -112,6 +118,15 @@
   ShowAndVerifyUi();
 }
 
+IN_PROC_BROWSER_TEST_F(AuthenticatorDialogTest, InvokeUi_key_not_registered) {
+  ShowAndVerifyUi();
+}
+
+IN_PROC_BROWSER_TEST_F(AuthenticatorDialogTest,
+                       InvokeUi_key_already_registered) {
+  ShowAndVerifyUi();
+}
+
 IN_PROC_BROWSER_TEST_F(AuthenticatorDialogTest, InvokeUi_ble_power_on_manual) {
   ShowAndVerifyUi();
 }
diff --git a/chrome/browser/ui/webauthn/sheet_models.cc b/chrome/browser/ui/webauthn/sheet_models.cc
index 78a9090..815616f 100644
--- a/chrome/browser/ui/webauthn/sheet_models.cc
+++ b/chrome/browser/ui/webauthn/sheet_models.cc
@@ -170,7 +170,7 @@
 // AuthenticatorTimeoutErrorModel ---------------------------------------------
 
 gfx::ImageSkia* AuthenticatorTimeoutErrorModel::GetStepIllustration() const {
-  return GetImage(IDR_WEBAUTHN_ILLUSTRATION_ERROR_TIMEOUT_1X);
+  return GetImage(IDR_WEBAUTHN_ILLUSTRATION_ERROR_1X);
 }
 
 base::string16 AuthenticatorTimeoutErrorModel::GetStepTitle() const {
@@ -194,7 +194,7 @@
 
 gfx::ImageSkia*
 AuthenticatorNoAvailableTransportsErrorModel::GetStepIllustration() const {
-  return GetImage(IDR_WEBAUTHN_ILLUSTRATION_ERROR_TIMEOUT_1X);
+  return GetImage(IDR_WEBAUTHN_ILLUSTRATION_ERROR_1X);
 }
 
 base::string16 AuthenticatorNoAvailableTransportsErrorModel::GetStepTitle()
@@ -208,6 +208,72 @@
       IDS_WEBAUTHN_ERROR_NO_TRANSPORTS_DESCRIPTION);
 }
 
+// AuthenticatorNotRegisteredErrorModel ---------------------------------------
+
+gfx::ImageSkia* AuthenticatorNotRegisteredErrorModel::GetStepIllustration()
+    const {
+  return GetImage(IDR_WEBAUTHN_ILLUSTRATION_ERROR_1X);
+}
+
+base::string16 AuthenticatorNotRegisteredErrorModel::GetStepTitle() const {
+  return l10n_util::GetStringUTF16(IDS_WEBAUTHN_ERROR_WRONG_KEY_SIGN_TITLE);
+}
+
+base::string16 AuthenticatorNotRegisteredErrorModel::GetStepDescription()
+    const {
+  return l10n_util::GetStringUTF16(
+      IDS_WEBAUTHN_ERROR_WRONG_KEY_SIGN_DESCRIPTION);
+}
+
+bool AuthenticatorNotRegisteredErrorModel::IsAcceptButtonVisible() const {
+  return true;
+}
+
+bool AuthenticatorNotRegisteredErrorModel::IsAcceptButtonEnabled() const {
+  return true;
+}
+
+base::string16 AuthenticatorNotRegisteredErrorModel::GetAcceptButtonLabel()
+    const {
+  // TODO(engedy): This should use a separate string resource.
+  return l10n_util::GetStringUTF16(IDS_WEBAUTHN_BLUETOOTH_POWER_ON_MANUAL_NEXT);
+}
+
+void AuthenticatorNotRegisteredErrorModel::OnAccept() {}
+
+// AuthenticatorAlreadyRegisteredErrorModel -----------------------------------
+
+gfx::ImageSkia* AuthenticatorAlreadyRegisteredErrorModel::GetStepIllustration()
+    const {
+  return GetImage(IDR_WEBAUTHN_ILLUSTRATION_ERROR_1X);
+}
+
+base::string16 AuthenticatorAlreadyRegisteredErrorModel::GetStepTitle() const {
+  return l10n_util::GetStringUTF16(IDS_WEBAUTHN_ERROR_WRONG_KEY_REGISTER_TITLE);
+}
+
+base::string16 AuthenticatorAlreadyRegisteredErrorModel::GetStepDescription()
+    const {
+  return l10n_util::GetStringUTF16(
+      IDS_WEBAUTHN_ERROR_WRONG_KEY_REGISTER_DESCRIPTION);
+}
+
+bool AuthenticatorAlreadyRegisteredErrorModel::IsAcceptButtonVisible() const {
+  return true;
+}
+
+bool AuthenticatorAlreadyRegisteredErrorModel::IsAcceptButtonEnabled() const {
+  return true;
+}
+
+base::string16 AuthenticatorAlreadyRegisteredErrorModel::GetAcceptButtonLabel()
+    const {
+  // TODO(engedy): This should use a separate string resource.
+  return l10n_util::GetStringUTF16(IDS_WEBAUTHN_BLUETOOTH_POWER_ON_MANUAL_NEXT);
+}
+
+void AuthenticatorAlreadyRegisteredErrorModel::OnAccept() {}
+
 // AuthenticatorBlePowerOnManualSheetModel ------------------------------------
 
 gfx::ImageSkia* AuthenticatorBlePowerOnManualSheetModel::GetStepIllustration()
diff --git a/chrome/browser/ui/webauthn/sheet_models.h b/chrome/browser/ui/webauthn/sheet_models.h
index 315b103..2d9b3835 100644
--- a/chrome/browser/ui/webauthn/sheet_models.h
+++ b/chrome/browser/ui/webauthn/sheet_models.h
@@ -125,6 +125,38 @@
   base::string16 GetStepDescription() const override;
 };
 
+class AuthenticatorNotRegisteredErrorModel
+    : public AuthenticatorSheetModelBase {
+ public:
+  using AuthenticatorSheetModelBase::AuthenticatorSheetModelBase;
+
+ private:
+  // AuthenticatorSheetModelBase:
+  gfx::ImageSkia* GetStepIllustration() const override;
+  base::string16 GetStepTitle() const override;
+  base::string16 GetStepDescription() const override;
+  bool IsAcceptButtonVisible() const override;
+  bool IsAcceptButtonEnabled() const override;
+  base::string16 GetAcceptButtonLabel() const override;
+  void OnAccept() override;
+};
+
+class AuthenticatorAlreadyRegisteredErrorModel
+    : public AuthenticatorSheetModelBase {
+ public:
+  using AuthenticatorSheetModelBase::AuthenticatorSheetModelBase;
+
+ private:
+  // AuthenticatorSheetModelBase:
+  gfx::ImageSkia* GetStepIllustration() const override;
+  base::string16 GetStepTitle() const override;
+  base::string16 GetStepDescription() const override;
+  bool IsAcceptButtonVisible() const override;
+  bool IsAcceptButtonEnabled() const override;
+  base::string16 GetAcceptButtonLabel() const override;
+  void OnAccept() override;
+};
+
 class AuthenticatorBlePowerOnManualSheetModel
     : public AuthenticatorSheetModelBase {
  public:
diff --git a/chrome/browser/ui/webui/certificates_handler.cc b/chrome/browser/ui/webui/certificates_handler.cc
index 655fcbe..57ccbca 100644
--- a/chrome/browser/ui/webui/certificates_handler.cc
+++ b/chrome/browser/ui/webui/certificates_handler.cc
@@ -42,11 +42,6 @@
 #include "net/der/parser.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
-#include "chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h"
-#endif
-
 using base::UTF8ToUTF16;
 
 namespace {
@@ -57,10 +52,13 @@
 static const char kCertificatesHandlerKeyField[] = "id";
 static const char kCertificatesHandlerNameField[] = "name";
 static const char kCertificatesHandlerObjSignField[] = "objSign";
-static const char kCertificatesHandlerPolicyField[] = "policy";
+static const char kCertificatesHandlerPolicyInstalledField[] = "policy";
+static const char kCertificatesHandlerWebTrustAnchorField[] = "webTrustAnchor";
 static const char kCertificatesHandlerReadonlyField[] = "readonly";
 static const char kCertificatesHandlerSslField[] = "ssl";
 static const char kCertificatesHandlerSubnodesField[] = "subnodes";
+static const char kCertificatesHandlerContainsPolicyCertsField[] =
+    "containsPolicyCerts";
 static const char kCertificatesHandlerUntrustedField[] = "untrusted";
 
 // Field names for communicating erros to JS.
@@ -70,7 +68,7 @@
 static const char kCertificatesHandlerErrorTitle[] = "title";
 
 // Enumeration of different callers of SelectFile.  (Start counting at 1 so
-// if SelectFile is accidentally called with params=NULL it won't match any.)
+// if SelectFile is accidentally called with params=nullptr it won't match any.)
 enum {
   EXPORT_PERSONAL_FILE_SELECTED = 1,
   IMPORT_PERSONAL_FILE_SELECTED,
@@ -99,7 +97,7 @@
     base::string16 b_str;
     a_dict->GetString(kCertificatesHandlerNameField, &a_str);
     b_dict->GetString(kCertificatesHandlerNameField, &b_str);
-    if (collator_ == NULL)
+    if (collator_ == nullptr)
       return a_str < b_str;
     return base::i18n::CompareString16WithCollator(*collator_, a_str, b_str) ==
            UCOL_LESS;
@@ -132,13 +130,6 @@
   CERTCertificate* cert_;
 };
 
-// Determine whether a certificate was stored with web trust by a policy.
-bool IsPolicyInstalledWithWebTrust(const net::CertificateList& web_trust_certs,
-                                   CERTCertificate* cert) {
-  return std::find_if(web_trust_certs.begin(), web_trust_certs.end(),
-                      CertEquals(cert)) != web_trust_certs.end();
-}
-
 // Determine if |data| could be a PFX Protocol Data Unit.
 // This only does the minimum parsing necessary to distinguish a PFX file from a
 // DER encoded Certificate.
@@ -226,12 +217,12 @@
 CERTCertificate* CertIdMap::CallbackArgsToCert(const base::ListValue* args) {
   std::string node_id;
   if (!args->GetString(0, &node_id))
-    return NULL;
+    return nullptr;
 
   CERTCertificate* cert = IdToCert(node_id);
   if (!cert) {
     NOTREACHED();
-    return NULL;
+    return nullptr;
   }
 
   return cert;
@@ -414,18 +405,10 @@
 }
 
 void CertificatesHandler::CertificatesRefreshed() {
-  net::CertificateList web_trusted_certs;
-#if defined(OS_CHROMEOS)
-  policy::UserNetworkConfigurationUpdater* service =
-      policy::UserNetworkConfigurationUpdaterFactory::GetForProfile(
-          Profile::FromWebUI(web_ui()));
-  if (service)
-    web_trusted_certs = service->GetWebTrustedCertificates();
-#endif
-  PopulateTree("personalCerts", net::USER_CERT, web_trusted_certs);
-  PopulateTree("serverCerts", net::SERVER_CERT, web_trusted_certs);
-  PopulateTree("caCerts", net::CA_CERT, web_trusted_certs);
-  PopulateTree("otherCerts", net::OTHER_CERT, web_trusted_certs);
+  PopulateTree("personalCerts", net::USER_CERT);
+  PopulateTree("serverCerts", net::SERVER_CERT);
+  PopulateTree("caCerts", net::CA_CERT);
+  PopulateTree("otherCerts", net::OTHER_CERT);
 }
 
 void CertificatesHandler::FileSelected(const base::FilePath& path,
@@ -785,7 +768,7 @@
   // away so they don't try and call back to us.
   if (select_file_dialog_.get())
     select_file_dialog_->ListenerDestroyed();
-  select_file_dialog_ = NULL;
+  select_file_dialog_ = nullptr;
 }
 
 void CertificatesHandler::HandleImportServer(const base::ListValue* args) {
@@ -1023,74 +1006,72 @@
   // to do anything.
 }
 
-void CertificatesHandler::PopulateTree(
-    const std::string& tab_name,
-    net::CertType type,
-    const net::CertificateList& web_trust_certs) {
+void CertificatesHandler::PopulateTree(const std::string& tab_name,
+                                       net::CertType type) {
   std::unique_ptr<icu::Collator> collator;
   UErrorCode error = U_ZERO_ERROR;
   collator.reset(icu::Collator::createInstance(
       icu::Locale(g_browser_process->GetApplicationLocale().c_str()), error));
   if (U_FAILURE(error))
-    collator.reset(NULL);
+    collator.reset();
   DictionaryIdComparator comparator(collator.get());
-  CertificateManagerModel::OrgGroupingMap map;
+  CertificateManagerModel::OrgGroupingMap org_grouping_map;
 
-  certificate_manager_model_->FilterAndBuildOrgGroupingMap(type, &map);
+  certificate_manager_model_->FilterAndBuildOrgGroupingMap(type,
+                                                           &org_grouping_map);
 
-  {
-    std::unique_ptr<base::ListValue> nodes =
-        std::make_unique<base::ListValue>();
-    for (CertificateManagerModel::OrgGroupingMap::iterator i = map.begin();
-         i != map.end(); ++i) {
-      // Populate first level (org name).
-      std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
-      dict->SetString(kCertificatesHandlerKeyField, OrgNameToId(i->first));
-      dict->SetString(kCertificatesHandlerNameField, i->first);
+  base::ListValue nodes;
+  for (const auto& org_grouping_map_entry : org_grouping_map) {
+    // Populate first level (org name).
+    base::DictionaryValue org_dict;
+    org_dict.SetKey(kCertificatesHandlerKeyField,
+                    base::Value(OrgNameToId(org_grouping_map_entry.first)));
+    org_dict.SetKey(kCertificatesHandlerNameField,
+                    base::Value(org_grouping_map_entry.first));
 
-      // Populate second level (certs).
-      auto subnodes = std::make_unique<base::ListValue>();
-      for (net::ScopedCERTCertificateList::const_iterator org_cert_it =
-               i->second.begin();
-           org_cert_it != i->second.end(); ++org_cert_it) {
-        std::unique_ptr<base::DictionaryValue> cert_dict(
-            new base::DictionaryValue);
-        CERTCertificate* cert = org_cert_it->get();
-        cert_dict->SetString(kCertificatesHandlerKeyField,
-                             cert_id_map_->CertToId(cert));
-        cert_dict->SetString(
-            kCertificatesHandlerNameField,
-            certificate_manager_model_->GetColumnText(
-                cert, CertificateManagerModel::COL_SUBJECT_NAME));
-        cert_dict->SetBoolean(
-            kCertificatesHandlerReadonlyField,
-            certificate_manager_model_->cert_db()->IsReadOnly(cert));
-        // Policy-installed certificates with web trust are trusted.
-        bool policy_trusted =
-            IsPolicyInstalledWithWebTrust(web_trust_certs, cert);
-        cert_dict->SetBoolean(
-            kCertificatesHandlerUntrustedField,
-            !policy_trusted &&
-                certificate_manager_model_->cert_db()->IsUntrusted(cert));
-        cert_dict->SetBoolean(kCertificatesHandlerPolicyField, policy_trusted);
-        // TODO(hshi): This should be determined by testing for PKCS #11
-        // CKA_EXTRACTABLE attribute. We may need to use the NSS function
-        // PK11_ReadRawAttribute to do that.
-        cert_dict->SetBoolean(
-            kCertificatesHandlerExtractableField,
-            !certificate_manager_model_->IsHardwareBacked(cert));
-        // TODO(mattm): Other columns.
-        subnodes->Append(std::move(cert_dict));
-      }
-      std::sort(subnodes->begin(), subnodes->end(), comparator);
+    // Populate second level (certs).
+    base::ListValue subnodes;
+    bool contains_policy_certs = false;
+    for (const auto& org_cert : org_grouping_map_entry.second) {
+      base::DictionaryValue cert_dict;
+      CERTCertificate* cert = org_cert->cert();
+      cert_dict.SetKey(kCertificatesHandlerKeyField,
+                       base::Value(cert_id_map_->CertToId(cert)));
+      cert_dict.SetKey(kCertificatesHandlerNameField,
+                       base::Value(org_cert->name()));
+      cert_dict.SetKey(kCertificatesHandlerReadonlyField,
+                       base::Value(org_cert->read_only()));
+      cert_dict.SetKey(kCertificatesHandlerUntrustedField,
+                       base::Value(org_cert->untrusted()));
+      cert_dict.SetKey(
+          kCertificatesHandlerPolicyInstalledField,
+          base::Value(org_cert->source() ==
+                      CertificateManagerModel::CertInfo::Source::kPolicy));
+      cert_dict.SetKey(kCertificatesHandlerWebTrustAnchorField,
+                       base::Value(org_cert->web_trust_anchor()));
+      // TODO(hshi): This should be determined by testing for PKCS #11
+      // CKA_EXTRACTABLE attribute. We may need to use the NSS function
+      // PK11_ReadRawAttribute to do that.
+      cert_dict.SetKey(kCertificatesHandlerExtractableField,
+                       base::Value(!org_cert->hardware_backed()));
+      // TODO(mattm): Other columns.
+      subnodes.GetList().push_back(std::move(cert_dict));
 
-      dict->Set(kCertificatesHandlerSubnodesField, std::move(subnodes));
-      nodes->Append(std::move(dict));
+      contains_policy_certs |=
+          org_cert->source() ==
+          CertificateManagerModel::CertInfo::Source::kPolicy;
     }
-    std::sort(nodes->begin(), nodes->end(), comparator);
+    std::sort(subnodes.GetList().begin(), subnodes.GetList().end(), comparator);
 
-    FireWebUIListener("certificates-changed", base::Value(tab_name), *nodes);
+    org_dict.SetKey(kCertificatesHandlerContainsPolicyCertsField,
+                    base::Value(contains_policy_certs));
+    org_dict.SetKey(kCertificatesHandlerSubnodesField, std::move(subnodes));
+    nodes.GetList().push_back(std::move(org_dict));
   }
+  std::sort(nodes.GetList().begin(), nodes.GetList().end(), comparator);
+
+  FireWebUIListener("certificates-changed", base::Value(tab_name),
+                    std::move(nodes));
 }
 
 void CertificatesHandler::ResolveCallback(const base::Value& response) {
diff --git a/chrome/browser/ui/webui/certificates_handler.h b/chrome/browser/ui/webui/certificates_handler.h
index fa60476..3e69636 100644
--- a/chrome/browser/ui/webui/certificates_handler.h
+++ b/chrome/browser/ui/webui/certificates_handler.h
@@ -136,14 +136,7 @@
   void HandleRefreshCertificates(const base::ListValue* args);
 
   // Populate the given tab's tree.
-  void PopulateTree(const std::string& tab_name,
-                    net::CertType type,
-                    const net::CertificateList& web_trust_certs);
-
-  // Populate the tree after retrieving the list of policy-installed
-  // web-trusted certificates.
-  void OnPolicyWebTrustCertsRetrieved(
-      const net::CertificateList& web_trust_certs);
+  void PopulateTree(const std::string& tab_name, net::CertType type);
 
   void ResolveCallback(const base::Value& response);
   void RejectCallback(const base::Value& response);
diff --git a/chrome/browser/vr/OWNERS b/chrome/browser/vr/OWNERS
index a89c9964..5a930f06 100644
--- a/chrome/browser/vr/OWNERS
+++ b/chrome/browser/vr/OWNERS
@@ -1,4 +1,3 @@
-asimjour@chromium.org
 cjgrant@chromium.org
 mthiesse@chromium.org
 tiborg@chromium.org
diff --git a/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager.cc b/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager.cc
index 0109c0b..9d01827 100644
--- a/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager.cc
+++ b/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager.cc
@@ -8,6 +8,8 @@
 
 #include "base/bind.h"
 #include "base/values.h"
+#include "build/build_config.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_constants.h"
 #include "chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h"
 #include "chrome/common/pref_names.h"
@@ -15,6 +17,10 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#endif  // OS_CHROMEOS
+
 namespace web_app {
 
 WebAppPolicyManager::WebAppPolicyManager(PrefService* pref_service,
@@ -36,6 +42,22 @@
   registry->RegisterListPref(prefs::kWebAppInstallForceList);
 }
 
+// static
+bool WebAppPolicyManager::ShouldEnableForProfile(Profile* profile) {
+// PolicyBrowserTests applies test policies to all profiles, including the
+// sign-in profile. This causes tests to become flaky since the tests could
+// finish before, during, or after the policy apps fail to install in the
+// sign-in profile. So we temporarily add a guard to ignore the policy for the
+// sign-in profile.
+// TODO(crbug.com/876705): Remove once the policy no longer applies to the
+// sign-in profile during tests.
+#if defined(OS_CHROMEOS)
+  return !chromeos::ProfileHelper::IsSigninProfile(profile);
+#else  // !OS_CHROMEOS
+  return true;
+#endif
+}
+
 void WebAppPolicyManager::RefreshPolicyInstalledApps() {
   const base::Value* web_apps =
       pref_service_->GetList(prefs::kWebAppInstallForceList);
@@ -43,16 +65,24 @@
   std::vector<PendingAppManager::AppInfo> apps_to_install;
   for (const base::Value& info : web_apps->GetList()) {
     const base::Value& url = *info.FindKey(kUrlKey);
-    const base::Value& launch_container = *info.FindKey(kLaunchContainerKey);
+    const base::Value* launch_container = info.FindKey(kLaunchContainerKey);
 
-    DCHECK(launch_container.GetString() == kLaunchContainerWindowValue ||
-           launch_container.GetString() == kLaunchContainerTabValue);
+    DCHECK(!launch_container ||
+           launch_container->GetString() == kLaunchContainerWindowValue ||
+           launch_container->GetString() == kLaunchContainerTabValue);
 
-    apps_to_install.emplace_back(
-        GURL(url.GetString()),
-        launch_container.GetString() == kLaunchContainerWindowValue
-            ? PendingAppManager::LaunchContainer::kWindow
-            : PendingAppManager::LaunchContainer::kTab);
+    PendingAppManager::LaunchContainer container;
+
+    // TODO(crbug.com/864904): Remove this default once PendingAppManager
+    // supports not setting the launch container.
+    if (!launch_container)
+      container = PendingAppManager::LaunchContainer::kTab;
+    else if (launch_container->GetString() == kLaunchContainerWindowValue)
+      container = PendingAppManager::LaunchContainer::kWindow;
+    else
+      container = PendingAppManager::LaunchContainer::kTab;
+
+    apps_to_install.emplace_back(GURL(url.GetString()), container);
   }
   pending_app_manager_->InstallApps(std::move(apps_to_install),
                                     base::DoNothing());
diff --git a/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager.h b/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager.h
index ec83957..7e6ce3b 100644
--- a/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager.h
+++ b/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager.h
@@ -13,6 +13,7 @@
 #include "url/gurl.h"
 
 class PrefService;
+class Profile;
 
 namespace user_prefs {
 class PrefRegistrySyncable;
@@ -34,6 +35,8 @@
 
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
+  static bool ShouldEnableForProfile(Profile* profile);
+
  private:
   void RefreshPolicyInstalledApps();
 
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
index c8441209..fa4f87bd 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
@@ -52,8 +52,11 @@
   favicon::CreateContentFaviconDriverForWebContents(web_contents);
 }
 
-BookmarkAppInstallationTask::BookmarkAppInstallationTask(Profile* profile)
+BookmarkAppInstallationTask::BookmarkAppInstallationTask(
+    Profile* profile,
+    web_app::PendingAppManager::AppInfo app_info)
     : profile_(profile),
+      app_info_(std::move(app_info)),
       helper_factory_(base::BindRepeating(&BookmarkAppHelperCreateWrapper)),
       data_retriever_(std::make_unique<BookmarkAppDataRetriever>()),
       installer_(std::make_unique<BookmarkAppInstaller>(profile)) {}
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h
index 20f7a22..eb745d4 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/web_applications/components/pending_app_manager.h"
 
 class Profile;
 enum class WebappInstallSource;
@@ -60,7 +61,13 @@
   // Ensures the tab helpers necessary for installing an app are present.
   static void CreateTabHelpers(content::WebContents* web_contents);
 
-  explicit BookmarkAppInstallationTask(Profile* profile);
+  // Constructs a task that will install a BookmarkApp-based Shortcut or Web App
+  // for |profile|. |app_info| will be used to decide some of the
+  // properties of the installed app e.g. open in a tab vs. window, installed by
+  // policy, etc.
+  explicit BookmarkAppInstallationTask(
+      Profile* profile,
+      web_app::PendingAppManager::AppInfo app_info);
 
   virtual ~BookmarkAppInstallationTask();
 
@@ -68,6 +75,8 @@
       content::WebContents* web_contents,
       ResultCallback callback);
 
+  const web_app::PendingAppManager::AppInfo& app_info() { return app_info_; }
+
   void SetBookmarkAppHelperFactoryForTesting(
       BookmarkAppHelperFactory helper_factory);
   void SetDataRetrieverForTesting(
@@ -89,6 +98,8 @@
 
   Profile* profile_;
 
+  const web_app::PendingAppManager::AppInfo app_info_;
+
   // We temporarily use a BookmarkAppHelper until the WebApp and WebShortcut
   // installation tasks reach feature parity with BookmarkAppHelper.
   std::unique_ptr<BookmarkAppHelper> helper_;
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
index 26e90e92..dc6eb1bd 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
@@ -278,9 +278,15 @@
 
 TEST_F(BookmarkAppInstallationTaskTest,
        WebAppOrShortcutFromContents_InstallationSucceeds) {
-  auto task = std::make_unique<BookmarkAppInstallationTask>(profile());
+  const GURL app_url(kWebAppUrl);
+
+  auto task = std::make_unique<BookmarkAppInstallationTask>(
+      profile(),
+      web_app::PendingAppManager::AppInfo(
+          app_url, web_app::PendingAppManager::LaunchContainer::kWindow));
+
   WebApplicationInfo info;
-  info.app_url = GURL(kWebAppUrl);
+  info.app_url = app_url;
   info.title = base::UTF8ToUTF16(kWebAppTitle);
   task->SetDataRetrieverForTesting(std::make_unique<TestDataRetriever>(
       std::make_unique<WebApplicationInfo>(std::move(info))));
@@ -303,9 +309,15 @@
 
 TEST_F(BookmarkAppInstallationTaskTest,
        WebAppOrShortcutFromContents_InstallationFails) {
-  auto task = std::make_unique<BookmarkAppInstallationTask>(profile());
+  const GURL app_url(kWebAppUrl);
+
+  auto task = std::make_unique<BookmarkAppInstallationTask>(
+      profile(),
+      web_app::PendingAppManager::AppInfo(
+          app_url, web_app::PendingAppManager::LaunchContainer::kWindow));
+
   WebApplicationInfo info;
-  info.app_url = GURL(kWebAppUrl);
+  info.app_url = app_url;
   info.title = base::UTF8ToUTF16(kWebAppTitle);
   task->SetDataRetrieverForTesting(std::make_unique<TestDataRetriever>(
       std::make_unique<WebApplicationInfo>(std::move(info))));
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.cc b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.cc
index e2f117b6..30e31ae 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.cc
@@ -20,7 +20,15 @@
 
 BookmarkAppShortcutInstallationTask::BookmarkAppShortcutInstallationTask(
     Profile* profile)
-    : BookmarkAppInstallationTask(profile) {}
+    : BookmarkAppInstallationTask(
+          profile,
+          // Pass an empty AppInfo since it doesn't influence the installation
+          // right now.
+          // TODO(crbug.com/864904): Take an AppInfo object once the installer
+          // can use the information.
+          web_app::PendingAppManager::AppInfo(
+              GURL(),
+              web_app::PendingAppManager::LaunchContainer::kTab)) {}
 
 BookmarkAppShortcutInstallationTask::~BookmarkAppShortcutInstallationTask() =
     default;
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
index f6961d4f..a561939 100644
--- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
+++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
@@ -28,18 +28,21 @@
 }
 
 std::unique_ptr<BookmarkAppInstallationTask> InstallationTaskCreateWrapper(
-    Profile* profile) {
-  return std::make_unique<BookmarkAppInstallationTask>(profile);
+    Profile* profile,
+    web_app::PendingAppManager::AppInfo app_info) {
+  return std::make_unique<BookmarkAppInstallationTask>(profile,
+                                                       std::move(app_info));
 }
 
 }  // namespace
 
-struct PendingBookmarkAppManager::Installation {
-  Installation(AppInfo info, OnceInstallCallback callback)
-      : info(std::move(info)), callback(std::move(callback)) {}
-  ~Installation() = default;
+struct PendingBookmarkAppManager::TaskAndCallback {
+  TaskAndCallback(std::unique_ptr<BookmarkAppInstallationTask> task,
+                  OnceInstallCallback callback)
+      : task(std::move(task)), callback(std::move(callback)) {}
+  ~TaskAndCallback() = default;
 
-  AppInfo info;
+  std::unique_ptr<BookmarkAppInstallationTask> task;
   OnceInstallCallback callback;
 };
 
@@ -54,19 +57,21 @@
 void PendingBookmarkAppManager::Install(AppInfo app_to_install,
                                         OnceInstallCallback callback) {
   // Check that we are not already installing the same app.
-  if (current_installation_ && current_installation_->info == app_to_install) {
+  if (current_task_and_callback_ &&
+      current_task_and_callback_->task->app_info() == app_to_install) {
     std::move(callback).Run(app_to_install.url, std::string());
     return;
   }
-  for (const auto& installation : installation_queue_) {
-    if (installation->info == app_to_install) {
+  for (const auto& installation : pending_tasks_and_callbacks_) {
+    if (installation->task->app_info() == app_to_install) {
       std::move(callback).Run(app_to_install.url, std::string());
       return;
     }
   }
 
-  installation_queue_.push_front(std::make_unique<Installation>(
-      std::move(app_to_install), std::move(callback)));
+  pending_tasks_and_callbacks_.push_front(std::make_unique<TaskAndCallback>(
+      task_factory_.Run(profile_, std::move(app_to_install)),
+      std::move(callback)));
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
@@ -78,8 +83,8 @@
     std::vector<AppInfo> apps_to_install,
     const RepeatingInstallCallback& callback) {
   for (auto& app_to_install : apps_to_install) {
-    installation_queue_.push_back(
-        std::make_unique<Installation>(std::move(app_to_install), callback));
+    pending_tasks_and_callbacks_.push_back(std::make_unique<TaskAndCallback>(
+        task_factory_.Run(profile_, std::move(app_to_install)), callback));
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -101,22 +106,22 @@
 }
 
 void PendingBookmarkAppManager::MaybeStartNextInstallation() {
-  if (current_installation_)
+  if (current_task_and_callback_)
     return;
 
-  if (installation_queue_.empty()) {
+  if (pending_tasks_and_callbacks_.empty()) {
     web_contents_.reset();
     return;
   }
 
-  current_installation_ = std::move(installation_queue_.front());
-  installation_queue_.pop_front();
+  current_task_and_callback_ = std::move(pending_tasks_and_callbacks_.front());
+  pending_tasks_and_callbacks_.pop_front();
 
   CreateWebContentsIfNecessary();
   Observe(web_contents_.get());
 
   content::NavigationController::LoadURLParams load_params(
-      current_installation_->info.url);
+      current_task_and_callback_->task->app_info().url);
   load_params.transition_type = ui::PAGE_TRANSITION_GENERATED;
   web_contents_->GetController().LoadURLWithParams(load_params);
   timer_->Start(
@@ -155,9 +160,10 @@
       base::BindOnce(&PendingBookmarkAppManager::MaybeStartNextInstallation,
                      weak_ptr_factory_.GetWeakPtr()));
 
-  std::unique_ptr<Installation> installation;
-  installation.swap(current_installation_);
-  std::move(installation->callback).Run(installation->info.url, app_id);
+  std::unique_ptr<TaskAndCallback> task_and_callback;
+  task_and_callback.swap(current_task_and_callback_);
+  std::move(task_and_callback->callback)
+      .Run(task_and_callback->task->app_info().url, app_id);
 }
 
 void PendingBookmarkAppManager::DidFinishLoad(
@@ -168,14 +174,13 @@
     return;
   }
 
-  if (validated_url != current_installation_->info.url) {
+  if (validated_url != current_task_and_callback_->task->app_info().url) {
     CurrentInstallationFinished(std::string());
     return;
   }
 
   Observe(nullptr);
-  current_installation_task_ = task_factory_.Run(profile_);
-  current_installation_task_->InstallWebAppOrShortcutFromWebContents(
+  current_task_and_callback_->task->InstallWebAppOrShortcutFromWebContents(
       web_contents_.get(),
       base::BindOnce(&PendingBookmarkAppManager::OnInstalled,
                      // Safe because the installation task will not run its
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h
index d52a857..1c48cec 100644
--- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h
+++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h
@@ -38,9 +38,8 @@
  public:
   using WebContentsFactory =
       base::RepeatingCallback<std::unique_ptr<content::WebContents>(Profile*)>;
-  using TaskFactory =
-      base::RepeatingCallback<std::unique_ptr<BookmarkAppInstallationTask>(
-          Profile*)>;
+  using TaskFactory = base::RepeatingCallback<
+      std::unique_ptr<BookmarkAppInstallationTask>(Profile*, AppInfo)>;
 
   explicit PendingBookmarkAppManager(Profile* profile);
   ~PendingBookmarkAppManager() override;
@@ -56,7 +55,7 @@
   void SetTimerForTesting(std::unique_ptr<base::OneShotTimer> timer);
 
  private:
-  struct Installation;
+  struct TaskAndCallback;
 
   void MaybeStartNextInstallation();
 
@@ -84,10 +83,9 @@
   std::unique_ptr<content::WebContents> web_contents_;
   std::unique_ptr<base::OneShotTimer> timer_;
 
-  std::unique_ptr<Installation> current_installation_;
-  std::unique_ptr<BookmarkAppInstallationTask> current_installation_task_;
+  std::unique_ptr<TaskAndCallback> current_task_and_callback_;
 
-  std::deque<std::unique_ptr<Installation>> installation_queue_;
+  std::deque<std::unique_ptr<TaskAndCallback>> pending_tasks_and_callbacks_;
 
   base::WeakPtrFactory<PendingBookmarkAppManager> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
index 92098340..5e88dda5 100644
--- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
+++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
@@ -53,8 +53,11 @@
 
 class TestBookmarkAppInstallationTask : public BookmarkAppInstallationTask {
  public:
-  TestBookmarkAppInstallationTask(Profile* profile, bool succeeds)
-      : BookmarkAppInstallationTask(profile), succeeds_(succeeds) {}
+  TestBookmarkAppInstallationTask(Profile* profile,
+                                  web_app::PendingAppManager::AppInfo app_info,
+                                  bool succeeds)
+      : BookmarkAppInstallationTask(profile, std::move(app_info)),
+        succeeds_(succeeds) {}
   ~TestBookmarkAppInstallationTask() override = default;
 
   void InstallWebAppOrShortcutFromWebContents(
@@ -110,13 +113,17 @@
   }
 
   std::unique_ptr<BookmarkAppInstallationTask> CreateSuccessfulInstallationTask(
-      Profile* profile) {
-    return std::make_unique<TestBookmarkAppInstallationTask>(profile, true);
+      Profile* profile,
+      web_app::PendingAppManager::AppInfo app_info) {
+    return std::make_unique<TestBookmarkAppInstallationTask>(
+        profile, std::move(app_info), true);
   }
 
   std::unique_ptr<BookmarkAppInstallationTask> CreateFailingInstallationTask(
-      Profile* profile) {
-    return std::make_unique<TestBookmarkAppInstallationTask>(profile, false);
+      Profile* profile,
+      web_app::PendingAppManager::AppInfo app_info) {
+    return std::make_unique<TestBookmarkAppInstallationTask>(
+        profile, std::move(app_info), false);
   }
 
   void InstallCallback(const GURL& url, const std::string& app_id) {
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 596e7d83..61e6e60 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -22,10 +22,12 @@
 
 WebAppProvider::WebAppProvider(Profile* profile)
     : pending_app_manager_(
-          std::make_unique<extensions::PendingBookmarkAppManager>(profile)),
-      web_app_policy_manager_(
-          std::make_unique<WebAppPolicyManager>(profile->GetPrefs(),
-                                                pending_app_manager_.get())) {
+          std::make_unique<extensions::PendingBookmarkAppManager>(profile)) {
+  if (WebAppPolicyManager::ShouldEnableForProfile(profile)) {
+    web_app_policy_manager_ = std::make_unique<WebAppPolicyManager>(
+        profile->GetPrefs(), pending_app_manager_.get());
+  }
+
   web_app::ScanForExternalWebApps(
       profile, base::BindOnce(&WebAppProvider::OnScanForExternalWebApps,
                               weak_ptr_factory_.GetWeakPtr()));
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
index b9a8cc0..8890c703 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -6,7 +6,9 @@
 
 #include <utility>
 
+#include "base/bind.h"
 #include "base/stl_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 
 namespace {
 
@@ -120,6 +122,7 @@
       SetCurrentStep(Step::kTransportSelection);
       break;
     case AuthenticatorTransport::kInternal:
+      SetCurrentStep(Step::kTouchId);
       TryTouchId();
       break;
     case AuthenticatorTransport::kBluetoothLowEnergy:
@@ -160,7 +163,6 @@
 }
 
 void AuthenticatorRequestDialogModel::TryTouchId() {
-  SetCurrentStep(Step::kTouchId);
   if (!request_callback_)
     return;
 
@@ -174,7 +176,14 @@
   if (touch_id_authenticator == saved_authenticators_.end())
     return;
 
-  request_callback_.Run(touch_id_authenticator->authenticator_id);
+  static base::TimeDelta kTouchIdDispatchDelay =
+      base::TimeDelta::FromMilliseconds(1000);
+
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(request_callback_,
+                     touch_id_authenticator->authenticator_id),
+      kTouchIdDispatchDelay);
 }
 
 void AuthenticatorRequestDialogModel::Cancel() {
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.h b/chrome/browser/webauthn/authenticator_request_dialog_model.h
index 9f95091..12d4c894 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.h
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.h
@@ -36,6 +36,8 @@
     kTransportSelection,
     kErrorTimedOut,
     kErrorNoAvailableTransports,
+    kErrorKeyNotRegistered,
+    kErrorKeyAlreadyRegistered,
     kCompleted,
 
     // Universal Serial Bus (USB).
diff --git a/chrome/chrome_cleaner/BUILD.gn b/chrome/chrome_cleaner/BUILD.gn
index b688db9..ede274ae 100644
--- a/chrome/chrome_cleaner/BUILD.gn
+++ b/chrome/chrome_cleaner/BUILD.gn
@@ -36,6 +36,7 @@
     "//chrome/chrome_cleaner/logging:unittest_sources",
     "//chrome/chrome_cleaner/os:unittest_sources",
     "//chrome/chrome_cleaner/pup_data:unittest_sources",
+    "//chrome/chrome_cleaner/scanner:unittest_sources",
     "//chrome/chrome_cleaner/settings:unittest_sources",
     "//chrome/chrome_cleaner/strings:unittest_sources",
     "//chrome/chrome_cleaner/test:unittest_sources",
diff --git a/chrome/chrome_cleaner/interfaces/BUILD.gn b/chrome/chrome_cleaner/interfaces/BUILD.gn
deleted file mode 100644
index 7f48e4ca..0000000
--- a/chrome/chrome_cleaner/interfaces/BUILD.gn
+++ /dev/null
@@ -1,21 +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.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("engine_sandbox_interface") {
-  sources = [
-    "cleaner_engine_requests.mojom",
-    "engine_file_requests.mojom",
-    "engine_requests.mojom",
-    "engine_sandbox.mojom",
-    "pup.mojom",
-    "string16_embedded_nulls.mojom",
-    "windows_handle.mojom",
-  ]
-  deps = [
-    "//components/chrome_cleaner/public/interfaces:interfaces",
-    "//mojo/public/mojom/base",
-  ]
-}
diff --git a/chrome/chrome_cleaner/interfaces/OWNERS b/chrome/chrome_cleaner/interfaces/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/chrome/chrome_cleaner/interfaces/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/chrome_cleaner/interfaces/cleaner_engine_requests.mojom b/chrome/chrome_cleaner/interfaces/cleaner_engine_requests.mojom
deleted file mode 100644
index 7eb77f1..0000000
--- a/chrome/chrome_cleaner/interfaces/cleaner_engine_requests.mojom
+++ /dev/null
@@ -1,53 +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.
-
-module chrome_cleaner.mojom;
-
-import "chrome/chrome_cleaner/interfaces/string16_embedded_nulls.mojom";
-import "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom";
-import "mojo/public/mojom/base/string16.mojom";
-
-// Passes requests that can mutate the system from the low-privilege sandbox
-// target process to the high-privilege broker process. It is implemented in
-// CleanerEngineRequestsImpl in engines/broker.
-//
-// This interface is only used when in cleaning mode, in which case the broker
-// process runs with administrator privileges, so the parameters of each method
-// must be carefully validated to ensure that the requests are safe.
-interface CleanerEngineRequests {
-  // Attempts to deletes the given file, applying some basic checks to ensure
-  // the file is safe to delete.
-  SandboxDeleteFile(FilePath file_name) => (bool result);
-
-  // Schedules the given file for post-reboot removal, applying some basic
-  // checks to ensure the file is safe to delete.
-  SandboxDeleteFilePostReboot(FilePath file_name) => (bool result);
-
-  // Deletes the given registry key. |key| may contain null characters.
-  SandboxNtDeleteRegistryKey(String16EmbeddedNulls key) => (bool result);
-
-  // Deletes the given value for the given registry key. |key| and |key_name|
-  // may contain null characters.
-  SandboxNtDeleteRegistryValue(String16EmbeddedNulls key,
-                               String16EmbeddedNulls value_name)
-    => (bool result);
-
-  // Updates the value of the given key's value to |new_value|.
-  // |new_value| must be a subset of the existing value. This is intended to be
-  // used to delete parts of a value, not to set a new value.
-  SandboxNtChangeRegistryValue(String16EmbeddedNulls key,
-                               String16EmbeddedNulls value_name,
-                               String16EmbeddedNulls new_value)
-    => (bool result);
-
-  // Deletes the given service.
-  SandboxDeleteService(mojo_base.mojom.String16 name) => (bool result);
-
-  // Deletes the given task.
-  SandboxDeleteTask(mojo_base.mojom.String16 name) => (bool result);
-
-  // Terminates the given process.
-  // The broker process can't be terminated.
-  SandboxTerminateProcess(uint32 process_id) => (bool result);
-};
diff --git a/chrome/chrome_cleaner/interfaces/engine_file_requests.mojom b/chrome/chrome_cleaner/interfaces/engine_file_requests.mojom
deleted file mode 100644
index beba962e..0000000
--- a/chrome/chrome_cleaner/interfaces/engine_file_requests.mojom
+++ /dev/null
@@ -1,46 +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.
-
-module chrome_cleaner.mojom;
-
-import "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom";
-
-// Handles returned by FindFirstFile aren't real handles, so we can't pass them
-// through mojo as handles, since they can't be duplicated.
-struct FindHandle {
-  int64 find_handle;
-};
-
-struct FindFileData {
-  array<uint8> data;
-};
-
-// Passes file handling requests from the low-privilege sandbox target process
-// to the high-privilege broker process. It is implemented in
-// EngineFileRequestsImpl in engines/broker.
-//
-// This interface is used in scanning and cleaning mode, and when initializing
-// the engine (which may need to load auxiliary file resources.)
-interface EngineFileRequests {
-  // Calls ::FindFirstFile for the given path, returning the results from
-  // ::FindFirstFile.
-  SandboxFindFirstFile(FilePath file_name) =>
-    (uint32 result, FindFileData win32_find_data, FindHandle find_handle);
-
-  // Calls ::FindNextFile for the given handle, returning the results from
-  // ::FindNextFile.
-  SandboxFindNextFile(FindHandle find_handle) =>
-    (uint32 result, FindFileData win32_find_data);
-
-  // Calls ::FindClose on the given handle, returning the results from
-  // ::FindClose.
-  SandboxFindClose(FindHandle find_handle) => (uint32 result);
-
-  // Returns a read-only file handle for the given file. The only acceptable
-  // values for |dwFlagsAndAttributes| are FILE_FLAG_NO_BUFFERING,
-  // FILE_FLAG_SEQUENTIAL_SCAN, FILE_FLAG_RANDOM_ACCESS, and
-  // FILE_FLAG_OPEN_REPARSE_POINT.
-  SandboxOpenReadOnlyFile(FilePath file_name, uint32 dwFlagsAndAttributes) =>
-    (handle result);
-};
diff --git a/chrome/chrome_cleaner/interfaces/engine_requests.mojom b/chrome/chrome_cleaner/interfaces/engine_requests.mojom
deleted file mode 100644
index a816495..0000000
--- a/chrome/chrome_cleaner/interfaces/engine_requests.mojom
+++ /dev/null
@@ -1,90 +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.
-module chrome_cleaner.mojom;
-
-import "chrome/chrome_cleaner/interfaces/string16_embedded_nulls.mojom";
-import "chrome/chrome_cleaner/interfaces/windows_handle.mojom";
-import "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom";
-import "mojo/public/mojom/base/process_id.mojom";
-import "mojo/public/mojom/base/string16.mojom";
-
-enum KnownFolder {
-  kWindows = 0,
-  kProgramFiles = 1,
-  kProgramFilesX86 = 2,
-  kAppData = 3,
-};
-
-struct StringSid {
-  mojo_base.mojom.String16 value;
-};
-
-struct ScheduledTaskAction {
-  FilePath path;
-  FilePath working_dir;
-  mojo_base.mojom.String16 arguments;
-};
-
-struct ScheduledTask {
-  mojo_base.mojom.String16 name;
-  mojo_base.mojom.String16 description;
-  array<ScheduledTaskAction> actions;
-};
-
-struct UserInformation {
-  mojo_base.mojom.String16 name;
-  mojo_base.mojom.String16 domain;
-  // User account type (SID_NAME_USE). See
-  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa379601(v=vs.85).aspx
-  uint32 account_type;
-};
-
-// Passes requests that do not mutate the system from the low-privilege sandbox
-// target process to the high-privilege broker process. It is implemented in
-// EngineRequestsImpl in engines/broker.
-//
-// This interface is used in scanning and cleaning mode.
-interface EngineRequests {
-  // Converts the given KnownFolder Id to its folder path.
-  SandboxGetKnownFolderPath(KnownFolder folder_id) =>
-    (bool result, FilePath folder_path);
-
-  // Gets all of the processes currently running on the machine.
-  SandboxGetProcesses() =>
-      (bool result, array<mojo_base.mojom.ProcessId> processes);
-
-  // Gets all the tasks on the system.
-  SandboxGetTasks() => (bool result, array<ScheduledTask> tasks);
-
-  // Returns the path to the executable of the given process.
-  SandboxGetProcessImagePath(mojo_base.mojom.ProcessId pid) =>
-    (bool result, FilePath image_path);
-
-  // Gets all of the modules loaded into memory for the given process.
-  SandboxGetLoadedModules(mojo_base.mojom.ProcessId pid) =>
-    (bool result, array<mojo_base.mojom.String16> modules);
-
-  // Gets the command line for the given process.
-  SandboxGetProcessCommandLine(mojo_base.mojom.ProcessId pid) =>
-    (bool result, mojo_base.mojom.String16 command_line);
-
-  // Gets the given UserInformation values for |sid|.
-  SandboxGetUserInfoFromSID(StringSid sid) => (bool result,
-                                               UserInformation user_info);
-
-  // Gets a read-only registry key handle to the given key.
-  // |dw_access| may specify KEY_WOW64_32KEY or KEY_WOW64_64KEY. |root_key| must
-  // be non-null, and |sub_key| can't have any null characters.
-  SandboxOpenReadOnlyRegistry(WindowsHandle root_key,
-          mojo_base.mojom.String16 sub_key, uint32 dw_access) =>
-    (uint32 result, WindowsHandle reg_handle);
-
-  // Gets a read-only registry key handle to the given key.
-  // |dw_access| may not specify KEY_WOW64_32KEY or KEY_WOW64_64KEY.
-  // ||root_key| may be null, and |sub_key| may have null characters.
-  SandboxNtOpenReadOnlyRegistry(WindowsHandle root_key,
-                                String16EmbeddedNulls sub_key,
-                                uint32 dw_access) =>
-    (uint32 result, WindowsHandle reg_handle);
-};
diff --git a/chrome/chrome_cleaner/interfaces/engine_sandbox.mojom b/chrome/chrome_cleaner/interfaces/engine_sandbox.mojom
deleted file mode 100644
index 78f33be..0000000
--- a/chrome/chrome_cleaner/interfaces/engine_sandbox.mojom
+++ /dev/null
@@ -1,79 +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.
-
-module chrome_cleaner.mojom;
-
-import "chrome/chrome_cleaner/interfaces/cleaner_engine_requests.mojom";
-import "chrome/chrome_cleaner/interfaces/engine_requests.mojom";
-import "chrome/chrome_cleaner/interfaces/engine_file_requests.mojom";
-import "chrome/chrome_cleaner/interfaces/pup.mojom";
-import "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom";
-
-// All result_code parameters and return values in these interfaces correspond
-// to ESETResultCode values for the ESET engine, and to
-// EngineOperationStatus::ResultCode values the Urza engine.
-
-// This interface passes scan results back from the target process to the
-// broker process.
-interface EngineScanResults {
-  // Called zero or more times with details of UwS.
-  FoundUwS(uint32 pup_id, PUP pup);
-
-  // Called exactly once, after any calls to FoundUwS.
-  Done(uint32 result_code);
-};
-
-// This interface passes cleanup results back from the target process to the
-// broker process.
-interface EngineCleanupResults {
-  // Called once the cleaner has finished cleaning.
-  Done(uint32 result_code);
-};
-
-// This interface connects the sandbox broker process to the sandbox target
-// process, which implements the interface using functions declared in
-// third_party/eset_lib/src/api/eset_cleaner.h.
-interface EngineCommands {
-  // Runs the engine's initialization routine.
-  Initialize(associated EngineFileRequests file_requests,
-             FilePath log_directory) => (uint32 result_code);
-
-  // Starts scanning the user's system.
-  // |enabled_uws| contains a list of UwS IDs to scan for.
-  // |enabled_trace_locations| is a list of trace locations, to which scanning
-  // should be limited.
-  // |include_details| is true if the results should include full details of
-  // each UwS found, false if the results should include only the ID.
-  // |results| is an interface which will be used to return results:
-  // FoundUwS will be called 0 or more times with details of the UwS found,
-  // followed by exactly one call to Done.
-  //
-  // If the scan request returns an error immediately, that error is returned
-  // and |results| is not used. Otherwise a success result code is returned and
-  // any further errors will be reported by calling Done on the |results|
-  // interface.
-  StartScan(array<uint32> enabled_uws,
-            array<TraceLocation> enabled_trace_locations,
-            bool include_details,
-            associated EngineFileRequests file_requests,
-            associated EngineRequests sandboxed_engine_requests,
-            associated EngineScanResults results) => (uint32 result_code);
-
-  // Starts cleaning up the user's system. |enabled_uws| contains a list of UwS
-  // IDs to cleanup.
-  //
-  // If the cleanup request returns an error immediately, that error is returned
-  // and |results| is not used. Otherwise a success result code is returned and
-  // any further errors will be reported by calling Done on the |results|
-  // interface.
-  StartCleanup(array<uint32> enabled_uws,
-               associated EngineFileRequests file_requests,
-               associated EngineRequests sandboxed_engine_requests,
-               associated CleanerEngineRequests
-                 sandboxed_cleaner_engine_requests,
-               associated EngineCleanupResults results) => (uint32 result_code);
-
-  // Runs the engine's finalization routine.
-  Finalize() => (uint32 result_code);
-};
diff --git a/chrome/chrome_cleaner/interfaces/pup.mojom b/chrome/chrome_cleaner/interfaces/pup.mojom
deleted file mode 100644
index 3b871c8..0000000
--- a/chrome/chrome_cleaner/interfaces/pup.mojom
+++ /dev/null
@@ -1,61 +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.
-
-module chrome_cleaner.mojom;
-
-import "chrome/chrome_cleaner/interfaces/string16_embedded_nulls.mojom";
-import "chrome/chrome_cleaner/interfaces/windows_handle.mojom";
-import "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom";
-import "mojo/public/mojom/base/string16.mojom";
-
-// Source:
-//   https://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx
-enum Wow64Access {
-  kNone = 0,
-  // KEY_WOW64_64KEY
-  k64Key = 0x0100,
-  // KEY_WOW64_32KEY
-  k32Key = 0x0200,
-};
-
-// Typemapped to chrome_cleaner::RegKeyPath.
-struct RegKeyPath {
-  WindowsHandle rootkey;
-  // This is only sent by URZA, which currently doesn't support registry paths
-  // with embedded nulls.
-  mojo_base.mojom.String16 subkey;
-  Wow64Access wow64access;
-};
-
-// Used for reporting detected registry footprints.
-// Typemapped to chrome_cleaner::PUPData::RegistryFootprint.
-struct RegistryFootprint {
-  RegKeyPath key_path;
-  String16EmbeddedNulls value_name;
-  String16EmbeddedNulls value_substring;
-  // An enumerator of chrome_cleaner::RegistryMatchRule.
-  uint32 rule;
-};
-
-// Typemapped to chrome_cleaner::UwS::TraceLocation enumeration from
-// chrome_cleaner/logging/proto/shared_data.proto.
-// The struct is used here as a work-around to make Mojo check passed values
-// without having to duplicate the enum definition.
-struct TraceLocation {
-  int32 value;
-};
-
-// Typemapped to chrome_cleaner::PUPData::FileInfo.
-struct FileInfo {
-  array<TraceLocation> found_in;
-};
-
-// Partially typemapped to chrome_cleaner::PUPData::PUP.
-// UwS signatures are not included.
-struct PUP {
-  array<FilePath> expanded_disk_footprints;
-  array<RegistryFootprint> expanded_registry_footprints;
-  array<mojo_base.mojom.String16> expanded_scheduled_tasks;
-  map<FilePath, FileInfo> disk_footprints_info;
-};
diff --git a/chrome/chrome_cleaner/interfaces/string16_embedded_nulls.mojom b/chrome/chrome_cleaner/interfaces/string16_embedded_nulls.mojom
deleted file mode 100644
index a8aa080e..0000000
--- a/chrome/chrome_cleaner/interfaces/string16_embedded_nulls.mojom
+++ /dev/null
@@ -1,24 +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.
-
-module chrome_cleaner.mojom;
-
-// Typemapped to chrome_cleaner::String16EmbeddedNulls.
-//
-// Note: Mojo doesn't allow sending null arrays over the wire, and the strings
-//       represented by this type can be empty (without a null at the end).
-//       Because of that, represented as a union of either something that is
-//       always empty (NullValue) or a non-empty array of uint16.
-union String16EmbeddedNulls {
-  // The underlying string is a null array (not the same as an empty string,
-  // which has at least one character '\0').
-  NullValue? null_value;
-
-  // The underlying string is either a null-terminated empty string (size is 1),
-  // or a non-empty string that can be either null-terminated or not.
-  array<uint16> value;
-};
-
-struct NullValue {
-};
diff --git a/chrome/chrome_cleaner/interfaces/windows_handle.mojom b/chrome/chrome_cleaner/interfaces/windows_handle.mojom
deleted file mode 100644
index 5fb1f61..0000000
--- a/chrome/chrome_cleaner/interfaces/windows_handle.mojom
+++ /dev/null
@@ -1,31 +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.
-
-module chrome_cleaner.mojom;
-
-enum SpecialWindowsHandle {
-  NULL_HANDLE,
-  INVALID_HANDLE,
-  CLASSES_ROOT,
-  CURRENT_CONFIG,
-  CURRENT_USER,
-  LOCAL_MACHINE,
-  USERS,
-};
-
-// Mojo's |handle| type passes handles with DUPLICATE_CLOSE_SOURCE. The special
-// handles above can't be closed, so they can't be passed as |handle|. Use a
-// wrapper that puts these in |special_handle| and plain handles in
-// |raw_handle|. Typemapped to HANDLE.
-union WindowsHandle {
-  handle raw_handle;
-  SpecialWindowsHandle special_handle;
-};
-
-interface TestWindowsHandle {
-  EchoHandle(WindowsHandle in_WindowsHandle) =>
-    (WindowsHandle out_WindowsHandle);
-
-  EchoRawHandle(handle in_handle) => (handle out_handle);
-};
diff --git a/chrome/chrome_cleaner/logging/cleaner_logging_service_unittest.cc b/chrome/chrome_cleaner/logging/cleaner_logging_service_unittest.cc
index 7232959..3b5125a5 100644
--- a/chrome/chrome_cleaner/logging/cleaner_logging_service_unittest.cc
+++ b/chrome/chrome_cleaner/logging/cleaner_logging_service_unittest.cc
@@ -1363,8 +1363,8 @@
 
 TEST_P(CleanerLoggingServiceTest, AllExpectedRemovalsConfirmed) {
   const base::FilePath kFile1(L"C:\\Program Files\\uws.exe");
-  const base::FilePath kFile2(L"C:\\Program Files\\virus.exe");
-  const base::FilePath kFile3(L"C:\\Program Files\\malware.exe");
+  const base::FilePath kFile2(L"C:\\Program Files\\persistant.exe");
+  const base::FilePath kFile3(L"C:\\Program Files\\another_uws.exe");
   const base::FilePath kFile4(L"C:\\Program Files\\inactive.txt");
 
   logging_service_->EnableUploads(true, registry_logger_.get());
diff --git a/chrome/chrome_cleaner/scanner/BUILD.gn b/chrome/chrome_cleaner/scanner/BUILD.gn
new file mode 100644
index 0000000..d472c85
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/BUILD.gn
@@ -0,0 +1,143 @@
+# 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("signature_matcher_api") {
+  sources = [
+    "signature_matcher_api.h",
+  ]
+
+  deps = [
+    "//base:base",
+  ]
+}
+
+source_set("matcher_util") {
+  sources = [
+    "matcher_util.cc",
+    "matcher_util.h",
+  ]
+
+  deps = [
+    "//base:base",
+    "//chrome/chrome_cleaner/constants:common_strings",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//chrome/chrome_cleaner/scanner:signature_matcher_api",
+    "//chrome/chrome_cleaner/settings:settings",
+    "//chrome/chrome_cleaner/strings",
+  ]
+
+  public_deps = [
+    "//chrome/chrome_cleaner/pup_data:pup_data_base",
+  ]
+}
+
+source_set("signature_matcher") {
+  sources = [
+    "signature_matcher.cc",
+    "signature_matcher.h",
+  ]
+
+  deps = [
+    ":matcher_util",
+    ":signature_matcher_api",
+    "//base",
+    "//chrome/chrome_cleaner/os:common_os",
+  ]
+}
+
+source_set("scanner_api") {
+  sources = [
+    "scanner.h",
+  ]
+
+  deps = [
+    "//base",
+    "//chrome/chrome_cleaner/constants:uws_id",
+    "//components/chrome_cleaner/public/constants",
+  ]
+}
+
+source_set("scanner") {
+  sources = [
+    "urza_scanner_impl.cc",
+    "urza_scanner_impl.h",
+  ]
+
+  deps = [
+    ":matcher_util",
+    ":scanner_api",
+    ":signature_matcher_api",
+    "//base:base",
+    "//chrome/chrome_cleaner/chrome_utils:chrome_util_lib",
+    "//chrome/chrome_cleaner/constants:common_strings",
+    "//chrome/chrome_cleaner/logging:common",
+    "//chrome/chrome_cleaner/logging:logging_definitions",
+    "//chrome/chrome_cleaner/logging:scoped_timed_task_logger",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//chrome/chrome_cleaner/proto:shared_pup_enums_proto",
+    "//chrome/chrome_cleaner/pup_data:pup_data_base",
+    "//chrome/chrome_cleaner/settings",
+    "//chrome/chrome_cleaner/settings:settings_definitions",
+    "//chrome/chrome_cleaner/strings",
+    "//components/chrome_cleaner/public/interfaces",
+  ]
+}
+
+source_set("reporter_scanner") {
+  sources = [
+    "scanner_controller.cc",
+    "scanner_controller.h",
+    "urza_scanner_controller.cc",
+    "urza_scanner_controller.h",
+  ]
+
+  deps = [
+    ":scanner",
+    ":signature_matcher",
+    "//base",
+    "//chrome/chrome_cleaner/crash:crash_keys",
+    "//chrome/chrome_cleaner/ipc:sandbox",
+    "//chrome/chrome_cleaner/logging:common",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//chrome/chrome_cleaner/pup_data:pup_data_base",
+    "//chrome/chrome_cleaner/scanner:signature_matcher_api",
+    "//chrome/chrome_cleaner/settings:settings",
+    "//components/chrome_cleaner/public/constants:constants",
+    "//third_party/crashpad/crashpad/client",
+    "//third_party/crashpad/crashpad/util",
+  ]
+}
+
+source_set("unittest_sources") {
+  testonly = true
+
+  sources = [
+    "matcher_util_unittest.cc",
+    "signature_matcher_unittest.cc",
+    "urza_scanner_impl_unittest.cc",
+  ]
+
+  deps = [
+    ":matcher_util",
+    ":scanner",
+    ":signature_matcher",
+    "//base:base",
+    "//base/test:test_support",
+    "//chrome/chrome_cleaner/chrome_utils:chrome_util_lib",
+    "//chrome/chrome_cleaner/constants:common_strings",
+    "//chrome/chrome_cleaner/logging:common",
+    "//chrome/chrome_cleaner/logging:mock_logging_service",
+    "//chrome/chrome_cleaner/logging/proto:shared_data_proto",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//chrome/chrome_cleaner/proto:shared_pup_enums_proto",
+    "//chrome/chrome_cleaner/strings",
+    "//chrome/chrome_cleaner/test:test_pup_data",
+    "//chrome/chrome_cleaner/test:test_strings",
+    "//chrome/chrome_cleaner/test:test_util",
+    "//chrome/chrome_cleaner/test/resources:test_resources",
+    "//sandbox/win:sandbox",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/chrome_cleaner/scanner/matcher_util.cc b/chrome/chrome_cleaner/scanner/matcher_util.cc
new file mode 100644
index 0000000..5897d3d
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/matcher_util.cc
@@ -0,0 +1,275 @@
+// 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/scanner/matcher_util.h"
+
+#include <stdint.h>
+
+#include <cctype>
+#include <memory>
+#include <set>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/file_version_info.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/registry.h"
+#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "chrome/chrome_cleaner/os/file_path_sanitization.h"
+#include "chrome/chrome_cleaner/os/registry_util.h"
+#include "chrome/chrome_cleaner/os/task_scheduler.h"
+#include "chrome/chrome_cleaner/pup_data/pup_disk_util.h"
+#include "chrome/chrome_cleaner/scanner/signature_matcher_api.h"
+#include "chrome/chrome_cleaner/strings/string_util.h"
+
+namespace chrome_cleaner {
+
+namespace {
+// The maximum file size for computing the digest of listed files.
+const size_t kMaxFileSizeToLog = 2 * kMegaByte;
+
+void LogFile(const base::FilePath& file_path) {
+  if (IsFileSizeLessThan(file_path, kMaxFileSizeToLog)) {
+    std::string digest;
+    if (ComputeSHA256DigestOfPath(file_path, &digest)) {
+      LOG(INFO) << " -- '" << SanitizePath(file_path)
+                << "' digest = " << digest;
+    } else {
+      LOG(ERROR) << "Failed to get digest for : '" << SanitizePath(file_path)
+                 << "'.";
+    }
+  } else {
+    LOG(INFO) << " -- '" << SanitizePath(file_path) << "'";
+  }
+}
+
+}  // namespace
+
+const size_t kKiloByte = 1024;         // File size in bytes.
+const size_t kMegaByte = 1024 * 1024;  // File size in bytes.
+// The maximum number of files to log when listing the content of a folder.
+const size_t kMaxFilesInFolderToLog = 10;
+
+bool IsFileSizeLessThan(const base::FilePath& path, size_t size) {
+  int64_t file_size = 0;
+  return (base::GetFileSize(path, &file_size) &&
+          static_cast<size_t>(file_size) < size);
+}
+
+bool MatchSingleFileWithPattern(const base::FilePath& root_path,
+                                const base::string16& pattern,
+                                bool include_folders,
+                                base::FilePath* match) {
+  DCHECK(match);
+
+  base::FilePath match_found;
+  bool found_one = false;
+
+  int file_type = base::FileEnumerator::FILES;
+  if (include_folders)
+    file_type |= base::FileEnumerator::DIRECTORIES;
+
+  if (NameContainsWildcards(pattern)) {
+    base::FileEnumerator file_enum(root_path, false, file_type, pattern);
+    for (base::FilePath file = file_enum.Next(); !file.empty();
+         file = file_enum.Next()) {
+      if (NameMatchesPattern(file.BaseName().value(), pattern, 0)) {
+        if (found_one) {
+          return false;
+        } else {
+          match_found = file;
+          found_one = true;
+        }
+      }
+    }
+  } else {
+    match_found = root_path.Append(pattern);
+    if (base::PathExists(match_found))
+      found_one = true;
+  }
+
+  if (found_one)
+    *match = match_found;
+  return found_one;
+}
+
+void DeleteSoftwareRegistryKeys(const base::string16& software_key_path,
+                                PUPData::PUP* pup) {
+  DCHECK(pup);
+  PUPData::DeleteRegistryKeyIfPresent(
+      RegKeyPath(HKEY_CURRENT_USER, software_key_path.c_str(), KEY_WOW64_32KEY),
+      pup);
+  PUPData::DeleteRegistryKeyIfPresent(
+      RegKeyPath(HKEY_LOCAL_MACHINE, software_key_path.c_str(),
+                 KEY_WOW64_32KEY),
+      pup);
+  PUPData::DeleteRegistryKeyIfPresent(
+      RegKeyPath(HKEY_CURRENT_USER, software_key_path.c_str(), KEY_WOW64_64KEY),
+      pup);
+  PUPData::DeleteRegistryKeyIfPresent(
+      RegKeyPath(HKEY_LOCAL_MACHINE, software_key_path.c_str(),
+                 KEY_WOW64_64KEY),
+      pup);
+}
+
+void CollectPathRecursively(const base::FilePath& path, PUPData::PUP* pup) {
+  DCHECK(pup);
+  if (base::PathExists(path))
+    CollectPathsRecursively(path, pup);
+}
+
+void CollectSinglePath(const base::FilePath& path, PUPData::PUP* pup) {
+  DCHECK(pup);
+  if (base::PathExists(path) && !base::DirectoryExists(path))
+    pup->AddDiskFootprint(path);
+}
+
+void CollectDiskFootprintRecursively(int csidl,
+                                     const base::char16* path,
+                                     PUPData::PUP* pup) {
+  DCHECK_NE(csidl, PUPData::kInvalidCsidl);
+  DCHECK(path);
+
+  base::FilePath expanded_path(
+      ExpandSpecialFolderPath(csidl, base::FilePath(path)));
+  if (expanded_path.empty())
+    return;
+  CollectPathRecursively(expanded_path, pup);
+}
+
+bool IsKnownFileByDigest(const base::FilePath& path,
+                         const SignatureMatcherAPI* signature_matcher,
+                         const char* const digests[],
+                         size_t digests_length) {
+  DCHECK(signature_matcher);
+  if (base::DirectoryExists(path) || !base::PathExists(path))
+    return false;
+
+  std::string path_digest;
+  if (!signature_matcher->ComputeSHA256DigestOfPath(path, &path_digest)) {
+    PLOG(ERROR) << "Can't compute file digest: '" << SanitizePath(path) << "'.";
+    return false;
+  }
+
+  for (size_t index = 0; index < digests_length; ++index) {
+    const char* expected_digest = digests[index];
+    DCHECK(expected_digest);
+    DCHECK_EQ(expected_digest, base::ToUpperASCII(expected_digest));
+    DCHECK_EQ(64UL, strlen(expected_digest));
+    if (path_digest.compare(expected_digest) == 0)
+      return true;
+  }
+
+  return false;
+}
+
+bool IsKnownFileByDigestInfo(const base::FilePath& fullpath,
+                             const SignatureMatcherAPI* signature_matcher,
+                             const FileDigestInfo* digests,
+                             size_t digests_length) {
+  DCHECK(signature_matcher);
+  DCHECK(digests);
+
+  if (base::DirectoryExists(fullpath) || !base::PathExists(fullpath))
+    return false;
+
+  size_t filesize = 0;
+  std::string digest;
+  for (size_t index = 0; index < digests_length; ++index) {
+    if (signature_matcher->MatchFileDigestInfo(fullpath, &filesize, &digest,
+                                               digests[index])) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool IsKnownFileByOriginalFilename(const base::FilePath& path,
+                                   const SignatureMatcherAPI* signature_matcher,
+                                   const base::char16* const names[],
+                                   size_t names_length) {
+  DCHECK(signature_matcher);
+  DCHECK(names);
+  VersionInformation version_information;
+  if (base::DirectoryExists(path) || !base::PathExists(path) ||
+      !signature_matcher->RetrieveVersionInformation(path,
+                                                     &version_information)) {
+    return false;
+  }
+
+  for (size_t i = 0; i < names_length; ++i) {
+    if (String16EqualsCaseInsensitive(version_information.original_filename,
+                                      names[i])) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool IsKnownFileByCompanyName(const base::FilePath& path,
+                              const SignatureMatcherAPI* signature_matcher,
+                              const base::char16* const names[],
+                              size_t names_length) {
+  DCHECK(signature_matcher);
+  DCHECK(names);
+  VersionInformation version_information;
+  if (base::DirectoryExists(path) || !base::PathExists(path) ||
+      !signature_matcher->RetrieveVersionInformation(path,
+                                                     &version_information)) {
+    return false;
+  }
+
+  for (size_t i = 0; i < names_length; ++i) {
+    if (String16EqualsCaseInsensitive(version_information.company_name,
+                                      names[i])) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void LogFoundDigest(const base::FilePath file_path,
+                    const char* prefix,
+                    PUPData::PUP* pup) {
+  DCHECK(prefix);
+  std::string digest;
+  int64_t size = -1;
+  if (!base::GetFileSize(file_path, &size))
+    PLOG(ERROR) << "Failed to get size for: '" << SanitizePath(file_path)
+                << "'.";
+
+  if (ComputeSHA256DigestOfPath(file_path, &digest)) {
+    LOG(INFO) << "Found digest for " << prefix << ", path: '"
+              << SanitizePath(file_path) << "', digest: '" << digest
+              << "', size: '" << size << "'.";
+  } else {
+    LOG(INFO) << "Failed to get digest for " << prefix << ", path: '"
+              << SanitizePath(file_path) << "', size: '" << size << "'.";
+  }
+}
+
+void LogFoundDigest(const base::FilePath file_path, const char* prefix) {
+  LogFoundDigest(file_path, prefix, nullptr);
+}
+
+void LogFolderContent(const base::FilePath& folder_path) {
+  base::FileEnumerator file_enum(folder_path, true,
+                                 base::FileEnumerator::FILES);
+  size_t nb_files = 0;
+  for (base::FilePath file_path = file_enum.Next(); !file_path.empty();
+       file_path = file_enum.Next()) {
+    LogFile(file_path);
+    if (++nb_files > kMaxFilesInFolderToLog) {
+      LOG(INFO) << "The folder contains too many files.";
+      return;
+    }
+  }
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/scanner/matcher_util.h b/chrome/chrome_cleaner/scanner/matcher_util.h
new file mode 100644
index 0000000..c792c14
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/matcher_util.h
@@ -0,0 +1,93 @@
+// 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_SCANNER_MATCHER_UTIL_H_
+#define CHROME_CHROME_CLEANER_SCANNER_MATCHER_UTIL_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "chrome/chrome_cleaner/pup_data/pup_data.h"
+#include "chrome/chrome_cleaner/settings/matching_options.h"
+
+namespace base {
+class FilePath;
+}  // namespace base
+
+namespace chrome_cleaner {
+
+class SignatureMatcherAPI;
+
+extern const size_t kKiloByte;
+extern const size_t kMegaByte;
+extern const size_t kMaxFilesInFolderToLog;  // Exposed for unittests.
+
+// Return whether the file |path| has a smaller size than |size|.
+bool IsFileSizeLessThan(const base::FilePath& path, size_t size);
+
+// Find a single matching file for |pattern| located in |root_path|. Wild-cards
+// are allowed in |pattern| only. |include_folders| flag controls whether or not
+// the folders should be taken into account. |match| is set to the matching file
+// path. If none or more than one file are found, the function returns false.
+bool MatchSingleFileWithPattern(const base::FilePath& root_path,
+                                const base::string16& pattern,
+                                bool include_folders,
+                                base::FilePath* match);
+
+void DeleteSoftwareRegistryKeys(const base::string16& software_key_path,
+                                PUPData::PUP* pup);
+
+void CollectSinglePath(const base::FilePath& path, PUPData::PUP* pup);
+
+void CollectPathRecursively(const base::FilePath& path, PUPData::PUP* pup);
+
+void CollectDiskFootprintRecursively(int csidl,
+                                     const base::char16* path,
+                                     PUPData::PUP* pup);
+
+bool IsKnownFileByDigest(const base::FilePath& path,
+                         const SignatureMatcherAPI* signature_matcher,
+                         const char* const digests[],
+                         size_t digests_length);
+
+// A pair of filesize and digest. The filesize is used to avoid computing the
+// digest of a file.
+struct FileDigestInfo {
+  const char* const digest;
+  size_t filesize;
+};
+
+// Check whether the checksum (sha256) of a given file is part of a sorted
+// array of |FileDigestInfo|.
+bool IsKnownFileByDigestInfo(const base::FilePath& path,
+                             const SignatureMatcherAPI* signature_matcher,
+                             const FileDigestInfo* digests,
+                             size_t digests_length);
+
+bool IsKnownFileByOriginalFilename(const base::FilePath& path,
+                                   const SignatureMatcherAPI* signature_matcher,
+                                   const base::char16* const names[],
+                                   size_t names_length);
+
+bool IsKnownFileByCompanyName(const base::FilePath& path,
+                              const SignatureMatcherAPI* signature_matcher,
+                              const base::char16* const names[],
+                              size_t names_length);
+
+// Log the found digest of |file_path| described by |prefix|.
+void LogFoundDigest(const base::FilePath file_path,
+                    const char* prefix,
+                    PUPData::PUP* pup);
+
+// This is equivalent to the above LogFoundDigest(file_path, prefix, nullptr).
+void LogFoundDigest(const base::FilePath file_path, const char* prefix);
+
+// This is equivalent to the above LogFolderContent(folder_path, nullptr).
+void LogFolderContent(const base::FilePath& folder_path);
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_SCANNER_MATCHER_UTIL_H_
diff --git a/chrome/chrome_cleaner/scanner/matcher_util_unittest.cc b/chrome/chrome_cleaner/scanner/matcher_util_unittest.cc
new file mode 100644
index 0000000..3dc353b9
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/matcher_util_unittest.cc
@@ -0,0 +1,448 @@
+// 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/scanner/matcher_util.h"
+
+#include <shlobj.h>
+
+#include <memory>
+#include <string>
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_path_override.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/win/registry.h"
+#include "chrome/chrome_cleaner/os/file_path_sanitization.h"
+#include "chrome/chrome_cleaner/scanner/signature_matcher.h"
+#include "chrome/chrome_cleaner/test/resources/grit/test_resources.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_signature_matcher.h"
+#include "chrome/chrome_cleaner/test/test_task_scheduler.h"
+#include "chrome/chrome_cleaner/test/test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+constexpr base::char16 kFileName1[] = L"File1";
+constexpr base::char16 kFileName2[] = L"File2";
+constexpr base::char16 kFileName3[] = L"File3";
+constexpr base::char16 kFileName4[] = L"File4";
+
+constexpr char kFileContent1[] = "This is the file content.";
+constexpr char kFileContent2[] = "Hi!";
+constexpr char kFileContent3[] = "Hello World!";
+constexpr char kFileContent4[] = "Ho!";
+
+constexpr char kFileContent[] = "This is the file content.";
+
+const char* const kKnownContentDigests[] = {
+    "00D2BB3E285BA62224888A9AD874AC2787D4CF681F30A2FD8EE2873859ECE1DC",
+    // Hash for content: |kFileContent|.
+    "BD283E41A3672B6BDAA574F8BD7176F8BCA95BD81383CDE32AA6D78B1DB0E371",
+};
+
+constexpr base::char16 kKnownOriginalFilename[] = L"uws.exe";
+constexpr base::char16 kUnknownOriginalFilename[] = L"knowngood.exe";
+const base::char16* const kKnownOriginalFilenames[] = {
+    L"dummy entry", L"uws.exe", L"zombie uws.exe",
+};
+
+constexpr base::char16 kKnownCompanyName[] = L"uws vendor inc";
+constexpr base::char16 kUnknownCompanyName[] = L"paradise";
+const base::char16* const kKnownCompanyNames[] = {
+    L"dummy entry", L"uws vendor inc", L"ACME",
+};
+
+constexpr FileDigestInfo kFileContentDigestInfos[] = {
+    {"02544E052F29BBA79C81243EC63B43B6CD85B185461928E65BFF501346C62A75", 33},
+    {"04614470DDF4939091F5EC4A13C92A9EAAACF07CA5C3F713E792E2D21CD24075", 21},
+    // Hash for content: |kFileContent2|.
+    {"82E0B92772BC0DA59AAB0B9231AA006FB37B4F99EC3E853C5A62786A1C7215BD", 4},
+    {"9000000000000000000000000000000000000000000000000000000000000009", 4},
+    {"94F7BDF53CDFDE7AA5E5C90BCDA6793B7377CE39E2591ABC758EBAE8072A275C", 12},
+    // Hash for content: |kFileContent1|.
+    {"BD283E41A3672B6BDAA574F8BD7176F8BCA95BD81383CDE32AA6D78B1DB0E371", 26},
+};
+
+// Messages are logged to a vector for testing.
+class LoggingTest : public testing::Test {
+ public:
+  LoggingOverride logger_;
+};
+
+}  // namespace
+
+TEST(MatcherUtilTest, IsKnownFileByDigest) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath file_path1(temp_dir.GetPath().Append(kFileName1));
+  base::FilePath file_path2(temp_dir.GetPath().Append(kFileName2));
+  base::FilePath file_path3(temp_dir.GetPath().Append(kFileName3));
+
+  CreateFileWithContent(file_path1, kFileContent, sizeof(kFileContent));
+  CreateFileWithRepeatedContent(file_path2, kFileContent, sizeof(kFileContent),
+                                2);
+
+  std::unique_ptr<SignatureMatcher> signature_matcher =
+      std::make_unique<SignatureMatcher>();
+  ASSERT_TRUE(signature_matcher);
+
+  // Hash: BD283E41A3672B6BDAA574F8BD7176F8BCA95BD81383CDE32AA6D78B1DB0E371.
+  EXPECT_TRUE(IsKnownFileByDigest(file_path1, signature_matcher.get(),
+                                  kKnownContentDigests,
+                                  base::size(kKnownContentDigests)));
+  // Hash: not present.
+  EXPECT_FALSE(IsKnownFileByDigest(file_path2, signature_matcher.get(),
+                                   kKnownContentDigests,
+                                   base::size(kKnownContentDigests)));
+  // The file doesn't exist.
+  EXPECT_FALSE(IsKnownFileByDigest(file_path3, signature_matcher.get(),
+                                   kKnownContentDigests,
+                                   base::size(kKnownContentDigests)));
+}
+
+TEST(MatcherUtilTest, IsKnownFileByDigestInfo) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath file_path1(temp_dir.GetPath().Append(kFileName1));
+  base::FilePath file_path2(temp_dir.GetPath().Append(kFileName2));
+  base::FilePath file_path3(temp_dir.GetPath().Append(kFileName3));
+  base::FilePath file_path4(temp_dir.GetPath().Append(kFileName4));
+
+  CreateFileWithContent(file_path1, kFileContent1, sizeof(kFileContent1));
+  CreateFileWithContent(file_path2, kFileContent2, sizeof(kFileContent2));
+  CreateFileWithContent(file_path3, kFileContent3, sizeof(kFileContent3));
+
+  std::unique_ptr<SignatureMatcher> signature_matcher =
+      std::make_unique<SignatureMatcher>();
+
+  // Search BD283E41A3672B6BDAA574F8BD7176F8BCA95BD81383CDE32AA6D78B1DB0E371.
+  EXPECT_TRUE(IsKnownFileByDigestInfo(file_path1, signature_matcher.get(),
+                                      kFileContentDigestInfos,
+                                      base::size(kFileContentDigestInfos)));
+  // Search 82E0B92772BC0DA59AAB0B9231AA006FB37B4F99EC3E853C5A62786A1C7215BD.
+  EXPECT_TRUE(IsKnownFileByDigestInfo(file_path2, signature_matcher.get(),
+                                      kFileContentDigestInfos,
+                                      base::size(kFileContentDigestInfos)));
+
+  // Replace the content of file_path2 with a content of the same size, it
+  // must no longer match.
+  ASSERT_EQ(sizeof(kFileContent2), sizeof(kFileContent4));
+  CreateFileWithContent(file_path2, kFileContent4, sizeof(kFileContent4));
+  EXPECT_FALSE(IsKnownFileByDigestInfo(file_path2, signature_matcher.get(),
+                                       kFileContentDigestInfos,
+                                       base::size(kFileContentDigestInfos)));
+
+  // The digest of |file_path3| is not in the array.
+  EXPECT_FALSE(IsKnownFileByDigestInfo(file_path3, signature_matcher.get(),
+                                       kFileContentDigestInfos,
+                                       base::size(kFileContentDigestInfos)));
+  // The |file_path4| doesn't exist.
+  EXPECT_FALSE(IsKnownFileByDigestInfo(file_path4, signature_matcher.get(),
+                                       kFileContentDigestInfos,
+                                       base::size(kFileContentDigestInfos)));
+}
+
+TEST(MatcherUtilTest, IsKnownFileByOriginalFilename) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  TestSignatureMatcher signature_matcher;
+
+  const base::FilePath normalized_temp_dir_path =
+      NormalizePath(temp_dir.GetPath());
+
+  // A non-existing file should not be recognized.
+  base::FilePath nonexistent_file_path(
+      normalized_temp_dir_path.Append(kFileName1));
+  EXPECT_FALSE(IsKnownFileByOriginalFilename(
+      nonexistent_file_path, &signature_matcher, kKnownOriginalFilenames,
+      base::size(kKnownOriginalFilenames)));
+
+  // An existing file without version information should not be recognized.
+  base::FilePath file_path2(normalized_temp_dir_path.Append(kFileName2));
+  CreateFileWithContent(file_path2, kFileContent, sizeof(kFileContent));
+  EXPECT_FALSE(IsKnownFileByOriginalFilename(
+      file_path2, &signature_matcher, kKnownOriginalFilenames,
+      base::size(kKnownOriginalFilenames)));
+
+  // A file with version information but not in the array should not be
+  // recognized.
+  base::FilePath file_path3(normalized_temp_dir_path.Append(kFileName3));
+
+  VersionInformation goodware_information = {};
+  goodware_information.original_filename = kUnknownOriginalFilename;
+  signature_matcher.MatchVersionInformation(file_path3, goodware_information);
+
+  CreateFileWithContent(file_path3, kFileContent, sizeof(kFileContent));
+  EXPECT_FALSE(IsKnownFileByOriginalFilename(
+      file_path3, &signature_matcher, kKnownOriginalFilenames,
+      base::size(kKnownOriginalFilenames)));
+
+  // A file with version information present in the array should be recognized.
+  base::FilePath file_path4(normalized_temp_dir_path.Append(kFileName4));
+
+  VersionInformation badware_information = {};
+  badware_information.original_filename = kKnownOriginalFilename;
+  signature_matcher.MatchVersionInformation(file_path4, badware_information);
+
+  CreateFileWithContent(file_path4, kFileContent, sizeof(kFileContent));
+  EXPECT_TRUE(IsKnownFileByOriginalFilename(
+      file_path4, &signature_matcher, kKnownOriginalFilenames,
+      base::size(kKnownOriginalFilenames)));
+}
+
+TEST(MatcherUtilTest, IsKnownFileByCompanyName) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  const base::FilePath normalized_temp_dir_path =
+      NormalizePath(temp_dir.GetPath());
+
+  TestSignatureMatcher signature_matcher;
+
+  // A non-existing file should not be recognized.
+  base::FilePath nonexistent_file_path(
+      normalized_temp_dir_path.Append(kFileName1));
+  EXPECT_FALSE(IsKnownFileByCompanyName(nonexistent_file_path,
+                                        &signature_matcher, kKnownCompanyNames,
+                                        base::size(kKnownCompanyNames)));
+
+  // An existing file without version information should not be recognized.
+  base::FilePath file_path2(normalized_temp_dir_path.Append(kFileName2));
+  CreateFileWithContent(file_path2, kFileContent, sizeof(kFileContent));
+  EXPECT_FALSE(IsKnownFileByCompanyName(file_path2, &signature_matcher,
+                                        kKnownCompanyNames,
+                                        base::size(kKnownCompanyNames)));
+
+  // A file with version information but not in the array should not be
+  // recognized.
+  base::FilePath file_path3(normalized_temp_dir_path.Append(kFileName3));
+
+  VersionInformation goodware_information = {};
+  goodware_information.company_name = kUnknownCompanyName;
+  signature_matcher.MatchVersionInformation(file_path3, goodware_information);
+
+  CreateFileWithContent(file_path3, kFileContent, sizeof(kFileContent));
+  EXPECT_FALSE(IsKnownFileByCompanyName(file_path3, &signature_matcher,
+                                        kKnownCompanyNames,
+                                        base::size(kKnownCompanyNames)));
+
+  // A file with version information present in the array should be recognized.
+  base::FilePath file_path4(normalized_temp_dir_path.Append(kFileName4));
+
+  VersionInformation badware_information = {};
+  badware_information.company_name = kKnownCompanyName;
+  signature_matcher.MatchVersionInformation(file_path4, badware_information);
+
+  CreateFileWithContent(file_path4, kFileContent, sizeof(kFileContent));
+  EXPECT_TRUE(IsKnownFileByCompanyName(file_path4, &signature_matcher,
+                                       kKnownCompanyNames,
+                                       base::size(kKnownCompanyNames)));
+}
+
+TEST(MatcherUtilTest, MatchSingleFileWithPattern) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath match;
+
+  // Collect no path.
+  EXPECT_FALSE(
+      MatchSingleFileWithPattern(temp_dir.GetPath(), L"*", false, &match));
+
+  // Collect exactly one path matching the pattern.
+  base::FilePath file_path1(temp_dir.GetPath().Append(L"dummy.1.tar.gz"));
+  base::FilePath file_path2(temp_dir.GetPath().Append(L"uws-name.exe"));
+  CreateFileWithContent(file_path1, kFileContent, sizeof(kFileContent));
+  CreateFileWithContent(file_path2, kFileContent, sizeof(kFileContent));
+  match.clear();
+  EXPECT_TRUE(MatchSingleFileWithPattern(temp_dir.GetPath(), L"*.*.*.*", false,
+                                         &match));
+  EXPECT_EQ(file_path1, match);
+  match.clear();
+  EXPECT_TRUE(MatchSingleFileWithPattern(temp_dir.GetPath(), L"uws*.exe", false,
+                                         &match));
+  EXPECT_EQ(file_path2, match);
+  match.clear();
+  EXPECT_TRUE(MatchSingleFileWithPattern(temp_dir.GetPath(), LR"(uws-????.exe)",
+                                         false, &match));
+  EXPECT_EQ(file_path2, match);
+
+  // Collecting multiple paths should fail.
+  base::FilePath file_path3(temp_dir.GetPath().Append(L"dummy.2.tar.gz"));
+  CreateFileWithContent(file_path3, kFileContent, sizeof(kFileContent));
+  EXPECT_FALSE(MatchSingleFileWithPattern(temp_dir.GetPath(), L"*.*.*.*", false,
+                                          &match));
+}
+
+TEST(MatcherUtilTest, MatchSingleFileWithPatternWithFolders) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath match;
+
+  // Collect no path.
+  EXPECT_FALSE(
+      MatchSingleFileWithPattern(temp_dir.GetPath(), L"*", true, &match));
+
+  // Add a folder to the main folder.
+  base::FilePath folder = temp_dir.GetPath().Append(L"folder");
+  ASSERT_TRUE(base::CreateDirectory(folder));
+
+  // Collect exactly one path matching the pattern.
+  base::FilePath file_path(temp_dir.GetPath().Append(L"dummy.1.tar.gz"));
+  CreateFileWithContent(file_path, kFileContent, sizeof(kFileContent));
+
+  match.clear();
+  EXPECT_TRUE(MatchSingleFileWithPattern(temp_dir.GetPath(), L"*.*.*.*", false,
+                                         &match));
+  EXPECT_EQ(file_path, match);
+
+  match.clear();
+  EXPECT_TRUE(
+      MatchSingleFileWithPattern(temp_dir.GetPath(), L"*.*.*.*", true, &match));
+  EXPECT_EQ(file_path, match);
+
+  // Collect with a wild-card matching everything.
+  match.clear();
+  EXPECT_TRUE(
+      MatchSingleFileWithPattern(temp_dir.GetPath(), L"*", false, &match));
+  EXPECT_EQ(file_path, match);
+
+  match.clear();
+  EXPECT_FALSE(
+      MatchSingleFileWithPattern(temp_dir.GetPath(), L"*", true, &match));
+  EXPECT_TRUE(match.empty());
+
+  // Collecting the folder.
+  EXPECT_FALSE(
+      MatchSingleFileWithPattern(temp_dir.GetPath(), L"fold?r", false, &match));
+  EXPECT_TRUE(match.empty());
+
+  EXPECT_TRUE(
+      MatchSingleFileWithPattern(temp_dir.GetPath(), L"fold?r", true, &match));
+  EXPECT_EQ(folder, match);
+}
+
+TEST(MatcherUtilTest, CollectPathRecursively) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  // Add a folder to the main folder.
+  base::FilePath folder = temp_dir.GetPath().Append(L"folder");
+  ASSERT_TRUE(base::CreateDirectory(folder));
+  base::FilePath subfolder = folder.Append(L"subfolder");
+  ASSERT_TRUE(base::CreateDirectory(subfolder));
+
+  base::FilePath file_path1(folder.Append(kFileName1));
+  CreateFileWithContent(file_path1, kFileContent, sizeof(kFileContent));
+  base::FilePath file_path2(subfolder.Append(kFileName2));
+  CreateFileWithContent(file_path2, kFileContent, sizeof(kFileContent));
+
+  base::FilePath nonexistent_path = temp_dir.GetPath().Append(L"nonexistent");
+
+  SimpleTestPUP pup;
+  CollectPathRecursively(nonexistent_path, &pup);
+  EXPECT_TRUE(pup.expanded_disk_footprints.empty());
+
+  CollectPathRecursively(folder, &pup);
+  EXPECT_FALSE(pup.expanded_disk_footprints.empty());
+
+  ExpectDiskFootprint(pup, folder);
+  ExpectDiskFootprint(pup, subfolder);
+  ExpectDiskFootprint(pup, file_path1);
+  ExpectDiskFootprint(pup, file_path2);
+}
+
+TEST(MatcherUtilTest, CollectDiskFootprintRecursively) {
+  base::FilePath local_appdata_path(
+      ExpandSpecialFolderPath(CSIDL_LOCAL_APPDATA, base::FilePath()));
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDirUnderPath(local_appdata_path));
+
+  // Add a folder to the main folder.
+  base::FilePath folder = temp_dir.GetPath().Append(L"folder");
+  ASSERT_TRUE(base::CreateDirectory(folder));
+  base::FilePath subfolder = folder.Append(L"subfolder");
+  ASSERT_TRUE(base::CreateDirectory(subfolder));
+
+  base::FilePath file_path1(folder.Append(kFileName1));
+  CreateFileWithContent(file_path1, kFileContent, sizeof(kFileContent));
+  base::FilePath file_path2(subfolder.Append(kFileName2));
+  CreateFileWithContent(file_path2, kFileContent, sizeof(kFileContent));
+
+  // Create the relative paths.
+  base::FilePath basename = temp_dir.GetPath().BaseName();
+  base::FilePath folder_path = basename.Append(L"Folder");
+  base::FilePath not_folder_path = basename.Append(L"not_Folder");
+
+  SimpleTestPUP pup;
+  // Collect in the wrong CSIDL.
+  CollectDiskFootprintRecursively(CSIDL_APPDATA, folder_path.value().c_str(),
+                                  &pup);
+  EXPECT_TRUE(pup.expanded_disk_footprints.empty());
+
+  // Collect in the good CSIDL but an inexisting folder.
+  CollectDiskFootprintRecursively(CSIDL_LOCAL_APPDATA,
+                                  not_folder_path.value().c_str(), &pup);
+  EXPECT_TRUE(pup.expanded_disk_footprints.empty());
+
+  // Collect the right files.
+  CollectDiskFootprintRecursively(CSIDL_LOCAL_APPDATA,
+                                  folder_path.value().c_str(), &pup);
+  EXPECT_FALSE(pup.expanded_disk_footprints.empty());
+
+  ExpectDiskFootprint(pup, folder);
+  ExpectDiskFootprint(pup, subfolder);
+  ExpectDiskFootprint(pup, file_path1);
+  ExpectDiskFootprint(pup, file_path2);
+}
+
+TEST_F(LoggingTest, LogFolderContent) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath temp_dir_path = temp_dir.GetPath();
+  base::FilePath file_path1(temp_dir_path.Append(kFileName1));
+  base::FilePath file_path2(temp_dir_path.Append(kFileName2));
+  CreateFileWithContent(file_path1, kFileContent, sizeof(kFileContent));
+  CreateFileWithContent(file_path2, kFileContent, sizeof(kFileContent));
+
+  // Add a folder to the main folder.
+  base::FilePath subfolder = temp_dir.GetPath().Append(L"folder");
+  ASSERT_TRUE(base::CreateDirectory(subfolder));
+  base::FilePath file_path3(subfolder.Append(kFileName3));
+  CreateFileWithContent(file_path3, kFileContent, sizeof(kFileContent));
+
+  LOG(INFO) << "Logging content of " << temp_dir.GetPath().value();
+
+  LogFolderContent(temp_dir.GetPath());
+
+  const std::string filename1 = base::WideToUTF8(kFileName1);
+  const std::string filename2 = base::WideToUTF8(kFileName2);
+  const std::string filename3 = base::WideToUTF8(kFileName3);
+  EXPECT_TRUE(logger_.LoggingMessagesContain(filename1));
+  EXPECT_TRUE(logger_.LoggingMessagesContain(filename2));
+  EXPECT_TRUE(logger_.LoggingMessagesContain(filename3));
+
+  // Add more files in the folder than maximum to be logged.
+  logger_.FlushMessages();
+  for (size_t count = 0; count < kMaxFilesInFolderToLog; ++count) {
+    base::FilePath file_path(temp_dir_path.Append(
+        base::StrCat({L"dummy", base::NumberToString16(count)})));
+    CreateFileWithContent(file_path, kFileContent, sizeof(kFileContent));
+  }
+
+  LOG(INFO) << "Logging content of " << temp_dir.GetPath().value();
+  LogFolderContent(temp_dir.GetPath());
+
+  EXPECT_TRUE(
+      logger_.LoggingMessagesContain("The folder contains too many files"));
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/scanner/scanner.h b/chrome/chrome_cleaner/scanner/scanner.h
new file mode 100644
index 0000000..b80c64c
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/scanner.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_SCANNER_SCANNER_H_
+#define CHROME_CHROME_CLEANER_SCANNER_SCANNER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/callback.h"
+#include "chrome/chrome_cleaner/constants/uws_id.h"
+#include "components/chrome_cleaner/public/constants/result_codes.h"
+
+namespace chrome_cleaner {
+
+// This class defines the scanning interface and is used as a base for the
+// scanners for different engines.
+class Scanner {
+ public:
+  // The type of callback to be called when an UwS is detected.
+  typedef base::RepeatingCallback<void(UwSId found_uws)> FoundUwSCallback;
+
+  // The type of callback that is called when the scan completes.
+  // |status| should contain RESULT_CODE_SUCCESS if no failures were encountered
+  // or error status code otherwise.
+  typedef base::OnceCallback<void(ResultCode status,
+                                  const std::vector<UwSId>& found_pups)>
+      DoneCallback;
+
+  virtual ~Scanner() {}
+
+  // Start scanning for UwS. When an UwS is detected and if |Stop| has not been
+  // called, |found_uws_callback| is called. If scan is done in number of tasks,
+  // |progress_callback| may be called to report ratio of completed tasks. If
+  // the scan completes before |Stop| is called, then |done_callback| is called.
+  // Returns true if startup succeeded. If the startup fails, |done_callback|
+  // will be called with the failure code.
+  virtual bool Start(const FoundUwSCallback& found_uws_callback,
+                     const DoneCallback done_callback) = 0;
+
+  // Interrupts the current scanning. It's a noop when scanning has not started
+  // or is already done, or has already been stopped.
+  virtual void Stop() = 0;
+
+  // When calling |Stop|, some tasks may still be running, so make sure to call
+  // |IsCompletelyDone| and allow the main UI to pump messages to let the task
+  // tracker mark all tasks as done before clearing data passed to the scanner.
+  virtual bool IsCompletelyDone() const = 0;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_SCANNER_SCANNER_H_
diff --git a/chrome/chrome_cleaner/scanner/scanner_controller.cc b/chrome/chrome_cleaner/scanner/scanner_controller.cc
new file mode 100644
index 0000000..8c32d70
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/scanner_controller.cc
@@ -0,0 +1,164 @@
+// 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/scanner/scanner_controller.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <memory>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/chrome_cleaner/ipc/sandbox.h"
+#include "chrome/chrome_cleaner/logging/logging_service_api.h"
+#include "chrome/chrome_cleaner/os/process.h"
+#include "chrome/chrome_cleaner/os/shutdown_watchdog.h"
+#include "chrome/chrome_cleaner/settings/settings.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+// The maximal allowed time to run the scanner (5 minutes).
+const uint32_t kWatchdogTimeoutInSeconds = 5 * 60;
+
+ResultCode GetResultCodeFromFoundUws(const std::vector<UwSId>& found_uws) {
+  for (UwSId uws_id : found_uws) {
+    if (!PUPData::IsKnownPUP(uws_id))
+      return RESULT_CODE_ENGINE_REPORTED_UNSUPPORTED_UWS;
+  }
+
+  // Removal has precedence over other states.
+  if (PUPData::HasFlaggedPUP(found_uws, &PUPData::HasRemovalFlag)) {
+    return RESULT_CODE_SUCCESS;
+  }
+
+  if (PUPData::HasFlaggedPUP(found_uws, &PUPData::HasConfirmedUwSFlag)) {
+    return RESULT_CODE_EXAMINED_FOR_REMOVAL_ONLY;
+  }
+
+  if (PUPData::HasFlaggedPUP(found_uws, &PUPData::HasReportOnlyFlag)) {
+    return RESULT_CODE_REPORT_ONLY_PUPS_FOUND;
+  }
+
+  DCHECK(found_uws.empty());
+  return RESULT_CODE_NO_PUPS_FOUND;
+}
+
+}  // namespace
+
+ScannerController::~ScannerController() = default;
+
+int ScannerController::ScanOnly() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Make sure the scanning process gets completed in a reasonable amount of
+  // time, otherwise log it and terminate the process.
+  base::TimeDelta watchdog_timeout =
+      base::TimeDelta::FromSeconds(watchdog_timeout_in_seconds_);
+
+  Settings* settings = Settings::GetInstance();
+  if (settings->scanning_timeout_overridden())
+    watchdog_timeout = settings->scanning_timeout();
+
+  std::unique_ptr<ShutdownWatchdog> watchdog;
+  if (!watchdog_timeout.is_zero()) {
+    watchdog = std::make_unique<ShutdownWatchdog>(
+        watchdog_timeout,
+        base::BindOnce(&ScannerController::WatchdogTimeoutCallback,
+                       base::Unretained(this)));
+    watchdog->Arm();
+  }
+
+  base::RunLoop run_loop;
+  quit_closure_ = run_loop.QuitWhenIdleClosure();
+  StartScan();
+  run_loop.Run();
+
+  if (watchdog)
+    watchdog->Disarm();
+
+  DCHECK_NE(RESULT_CODE_INVALID, result_code_);
+  return static_cast<int>(result_code_);
+}
+
+ScannerController::ScannerController(RegistryLogger* registry_logger)
+    : registry_logger_(registry_logger),
+      watchdog_timeout_in_seconds_(kWatchdogTimeoutInSeconds) {
+  DCHECK(registry_logger);
+}
+
+void ScannerController::DoneScanning(ResultCode status,
+                                     const std::vector<UwSId>& found_pups) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  UpdateScanResults(found_pups);
+  if (status == RESULT_CODE_SUCCESS)
+    status = GetResultCodeFromFoundUws(found_pups);
+  {
+    base::AutoLock lock(lock_);
+    result_code_ = status;
+  }
+
+  LoggingServiceAPI* logging_service_api = LoggingServiceAPI::GetInstance();
+
+  SystemResourceUsage stats;
+  if (GetSystemResourceUsage(::GetCurrentProcess(), &stats))
+    logging_service_api->LogProcessInformation(SandboxType::kNonSandboxed,
+                                               stats);
+  std::map<SandboxType, SystemResourceUsage> sbox_process_usage =
+      GetSandboxSystemResourceUsage();
+  for (const auto& type_usage : sbox_process_usage) {
+    LoggingServiceAPI::GetInstance()->LogProcessInformation(type_usage.first,
+                                                            type_usage.second);
+  }
+
+  logging_service_api->SetExitCode(status);
+  logging_service_api->MaybeSaveLogsToFile(L"");
+  logging_service_api->SendLogsToSafeBrowsing(
+      base::BindRepeating(&ScannerController::LogsUploadComplete,
+                          base::Unretained(this)),
+      registry_logger_);
+}
+
+void ScannerController::UpdateScanResults(
+    const std::vector<UwSId>& found_pups) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Log which PUPs were found.
+  registry_logger_->RecordFoundPUPs(found_pups);
+
+  ResultCode result = GetResultCodeFromFoundUws(found_pups);
+  {
+    base::AutoLock lock(lock_);
+    result_code_ = result;
+  }
+}
+
+int ScannerController::WatchdogTimeoutCallback() {
+  ResultCode result_code;
+  {
+    base::AutoLock lock(lock_);
+    result_code = result_code_;
+  }
+
+  int watchdog_result_code =
+      result_code == RESULT_CODE_SUCCESS
+          ? RESULT_CODE_WATCHDOG_TIMEOUT_WITH_REMOVABLE_UWS
+          : RESULT_CODE_WATCHDOG_TIMEOUT_WITHOUT_REMOVABLE_UWS;
+
+  registry_logger_->WriteExitCode(watchdog_result_code);
+  registry_logger_->WriteEndTime();
+
+  return watchdog_result_code;
+}
+
+void ScannerController::LogsUploadComplete(bool success) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                std::move(quit_closure_));
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/scanner/scanner_controller.h b/chrome/chrome_cleaner/scanner/scanner_controller.h
new file mode 100644
index 0000000..a584f676
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/scanner_controller.h
@@ -0,0 +1,71 @@
+// 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_SCANNER_SCANNER_CONTROLLER_H_
+#define CHROME_CHROME_CLEANER_SCANNER_SCANNER_CONTROLLER_H_
+
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/sequence_checker.h"
+#include "base/synchronization/lock.h"
+#include "chrome/chrome_cleaner/constants/uws_id.h"
+#include "chrome/chrome_cleaner/logging/registry_logger.h"
+#include "components/chrome_cleaner/public/constants/result_codes.h"
+
+namespace chrome_cleaner {
+
+// An abstract class which handles synchronization for the scan loop.
+class ScannerController {
+ public:
+  virtual ~ScannerController();
+
+  int ScanOnly();
+
+ protected:
+  explicit ScannerController(RegistryLogger* registry_logger);
+
+  virtual void StartScan() = 0;
+
+  // Callback for StartScan which records which PUPs were found.
+  // Expects |status| to be RESULT_CODE_SUCCESS if there were no failures.
+  virtual void DoneScanning(ResultCode status,
+                            const std::vector<UwSId>& found_pups);
+
+  // Record |found_pups| to the registry and update |result_code_| in a
+  // thread-safe manner.
+  void UpdateScanResults(const std::vector<UwSId>& found_pups);
+
+  // This callback is called from the watchdog's thread and must synchronize
+  // access to result_code_.
+  virtual int WatchdogTimeoutCallback();
+
+  RegistryLogger* registry_logger_;
+  SEQUENCE_CHECKER(sequence_checker_);
+  // Defines a task runner for the current thread, which will be accessible
+  // via base::ThreadTaskRunnerHandle::Get().
+  base::MessageLoopForUI ui_message_loop_;
+
+  // Allow subclasses to override the default watchdog timeout.
+  uint32_t watchdog_timeout_in_seconds_;
+
+ private:
+  // Callback for LoggingServiceAPI::SendLogsToSafeBrowsing() that finishes the
+  // current run loop.
+  void LogsUploadComplete(bool success);
+
+  mutable base::Lock lock_;  // Protects |result_code_|.
+  ResultCode result_code_ = RESULT_CODE_INVALID;
+
+  // Called by LogsUploadComplete() to quit the current run loop.
+  base::OnceClosure quit_closure_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScannerController);
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_SCANNER_SCANNER_CONTROLLER_H_
diff --git a/chrome/chrome_cleaner/scanner/signature_matcher.cc b/chrome/chrome_cleaner/scanner/signature_matcher.cc
new file mode 100644
index 0000000..a74eec5
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/signature_matcher.cc
@@ -0,0 +1,99 @@
+// 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/scanner/signature_matcher.h"
+
+#include <windows.h>
+
+#include <stdint.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/file_version_info.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/sha1.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "chrome/chrome_cleaner/os/file_path_sanitization.h"
+#include "chrome/chrome_cleaner/os/system_util.h"
+#include "chrome/chrome_cleaner/scanner/matcher_util.h"
+
+namespace chrome_cleaner {
+
+bool SignatureMatcher::MatchFileDigestInfo(
+    const base::FilePath& path,
+    size_t* filesize,
+    std::string* digest,
+    const FileDigestInfo& digest_info) const {
+  DCHECK(filesize);
+  DCHECK(digest);
+
+  if (*filesize == 0) {
+    DCHECK(digest->empty());
+    int64_t local_filesize = 0;
+    if (!base::GetFileSize(path, &local_filesize)) {
+      LOG(ERROR) << "Failed to get filesize of path: '" << SanitizePath(path)
+                 << "'.";
+      return false;
+    }
+    *filesize = local_filesize;
+  } else {
+    int64_t dcheck_filesize = 0;
+    DCHECK(base::GetFileSize(path, &dcheck_filesize) &&
+           *filesize == static_cast<size_t>(dcheck_filesize));
+  }
+
+  if (digest_info.filesize != *filesize)
+    return false;
+
+  if (digest->empty()) {
+    if (!ComputeSHA256DigestOfPath(path, digest)) {
+      digest->clear();
+      LOG(ERROR) << "Unable to compute digest SHA256 for: '"
+                 << SanitizePath(path) << "'.";
+      return false;
+    }
+  } else {
+    std::string dcheck_digest;
+    DCHECK(ComputeSHA256DigestOfPath(path, &dcheck_digest) &&
+           *digest == dcheck_digest);
+  }
+
+  return digest->compare(digest_info.digest) == 0;
+}
+
+bool SignatureMatcher::ComputeSHA256DigestOfPath(const base::FilePath& path,
+                                                 std::string* digest) const {
+  // TODO(pmbureau): Add caching to avoid recomputing digests.
+  // TODO(pmbureau): Add synchronization to avoid multiple file operation.
+  // TODO(pmbureau): Add copy of locked files.
+  return chrome_cleaner::ComputeSHA256DigestOfPath(path, digest);
+}
+
+// TODO(pmbureau): Add a unittest for this function.
+bool SignatureMatcher::RetrieveVersionInformation(
+    const base::FilePath& path,
+    VersionInformation* information) const {
+  DCHECK(information);
+  // TODO(pmbureau): Add caching to avoid recomputing information.
+
+  std::unique_ptr<FileVersionInfo> version(
+      FileVersionInfo::CreateFileVersionInfo(path));
+  if (!version.get())
+    return false;
+
+  information->company_name = version->company_name();
+  information->original_filename = version->original_filename();
+  return true;
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/scanner/signature_matcher.h b/chrome/chrome_cleaner/scanner/signature_matcher.h
new file mode 100644
index 0000000..db0fe3f9
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/signature_matcher.h
@@ -0,0 +1,31 @@
+// 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_SCANNER_SIGNATURE_MATCHER_H_
+#define CHROME_CHROME_CLEANER_SCANNER_SIGNATURE_MATCHER_H_
+
+#include "chrome/chrome_cleaner/scanner/signature_matcher_api.h"
+
+namespace chrome_cleaner {
+
+class SignatureMatcher : public SignatureMatcherAPI {
+ public:
+  SignatureMatcher() = default;
+  virtual ~SignatureMatcher() = default;
+
+  // SignatureMatcherAPI implementation.
+  bool MatchFileDigestInfo(const base::FilePath& path,
+                           size_t* filesize,
+                           std::string* digest,
+                           const FileDigestInfo& digest_info) const override;
+  bool ComputeSHA256DigestOfPath(const base::FilePath& path,
+                                 std::string* digest) const override;
+  bool RetrieveVersionInformation(
+      const base::FilePath& path,
+      VersionInformation* information) const override;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_SCANNER_SIGNATURE_MATCHER_H_
diff --git a/chrome/chrome_cleaner/scanner/signature_matcher_api.h b/chrome/chrome_cleaner/scanner/signature_matcher_api.h
new file mode 100644
index 0000000..882f826
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/signature_matcher_api.h
@@ -0,0 +1,55 @@
+// 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_SCANNER_SIGNATURE_MATCHER_API_H_
+#define CHROME_CHROME_CLEANER_SCANNER_SIGNATURE_MATCHER_API_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+
+namespace chrome_cleaner {
+
+struct FileDigestInfo;
+
+// This structure holds version information about an executable.
+// (see: base/file_version_info.h)
+struct VersionInformation {
+  base::string16 company_name;
+  base::string16 original_filename;
+};
+
+// This class is used as a wrapper around the signature matcher calls. The
+// purpose of the signature matcher is to match a sequence of bytes against
+// a set of known signals and report the name of the rules that matches.
+class SignatureMatcherAPI {
+ public:
+  virtual ~SignatureMatcherAPI() {}
+
+  // Compare the file's digest info and return true on a successful match.
+  // |filesize| & |digest| are used if they are not initialized (e.g., 0 for
+  // |filesize| and an empty string for |digest|), and otherwise they are set
+  // using |path|. This is mainly so that tests can overload it.
+  virtual bool MatchFileDigestInfo(const base::FilePath& path,
+                                   size_t* filesize,
+                                   std::string* digest,
+                                   const FileDigestInfo& digest_info) const = 0;
+
+  // Compute the SHA256 checksum of |path| and store it as base16 into |digest|.
+  // Return true on success.
+  virtual bool ComputeSHA256DigestOfPath(const base::FilePath& path,
+                                         std::string* digest) const = 0;
+
+  // Retrieve version information fields of a given executable |path|. Return
+  // false if an error occurred.
+  virtual bool RetrieveVersionInformation(
+      const base::FilePath& path,
+      VersionInformation* information) const = 0;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_SCANNER_SIGNATURE_MATCHER_API_H_
diff --git a/chrome/chrome_cleaner/scanner/signature_matcher_unittest.cc b/chrome/chrome_cleaner/scanner/signature_matcher_unittest.cc
new file mode 100644
index 0000000..a242e706
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/signature_matcher_unittest.cc
@@ -0,0 +1,103 @@
+// 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/scanner/signature_matcher.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "chrome/chrome_cleaner/scanner/matcher_util.h"
+#include "chrome/chrome_cleaner/test/resources/grit/test_resources.h"
+#include "chrome/chrome_cleaner/test/test_file_util.h"
+#include "chrome/chrome_cleaner/test/test_strings.h"
+#include "chrome/chrome_cleaner/test/test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_cleaner {
+
+// Contents to be scanned.
+const char kGoogleName1[] = "This is Google.";
+const char kGoogleName2[] = "This is G00gle.";
+
+namespace {
+
+class SignatureMatcherTest : public testing::Test {
+ public:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    signature_matcher_ = std::make_unique<SignatureMatcher>();
+  }
+
+  SignatureMatcherAPI* signature_matcher() const {
+    return signature_matcher_.get();
+  }
+
+ private:
+  // The root of the scoped temporary folder that is used by some tests.
+  base::ScopedTempDir temp_dir_;
+
+  // The signature matcher under test.
+  std::unique_ptr<SignatureMatcherAPI> signature_matcher_;
+};
+
+}  // namespace
+
+TEST_F(SignatureMatcherTest, MatchFileDigestInfo) {
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+
+  size_t filesize = 0;
+  std::string digest;
+
+  // Inexistent file.
+  base::FilePath path1(scoped_temp_dir.GetPath().Append(L"file1"));
+  EXPECT_FALSE(signature_matcher()->MatchFileDigestInfo(path1, &filesize,
+                                                        &digest, {"", 0}));
+  // Wrong size.
+  CreateFileWithContent(path1, kGoogleName1, sizeof(kGoogleName1));
+  EXPECT_FALSE(signature_matcher()->MatchFileDigestInfo(path1, &filesize,
+                                                        &digest, {"", 0}));
+  EXPECT_EQ(sizeof(kGoogleName1), filesize);
+  filesize = 0;
+
+  // Wrong digest.
+  EXPECT_FALSE(signature_matcher()->MatchFileDigestInfo(
+      path1, &filesize, &digest, {"", sizeof(kGoogleName1)}));
+  EXPECT_EQ(sizeof(kGoogleName1), filesize);
+  std::string digest1;
+  ASSERT_TRUE(signature_matcher()->ComputeSHA256DigestOfPath(path1, &digest1));
+  EXPECT_EQ(digest1, digest);
+
+  // Successful match.
+  EXPECT_TRUE(signature_matcher()->MatchFileDigestInfo(
+      path1, &filesize, &digest, {digest1.c_str(), sizeof(kGoogleName1)}));
+  // Should work again.
+  EXPECT_TRUE(signature_matcher()->MatchFileDigestInfo(
+      path1, &filesize, &digest, {digest1.c_str(), sizeof(kGoogleName1)}));
+  // And now with another file.
+  filesize = 0;
+  digest.clear();
+
+  base::FilePath path2(scoped_temp_dir.GetPath().Append(L"file2"));
+  EXPECT_FALSE(signature_matcher()->MatchFileDigestInfo(
+      path2, &filesize, &digest, {digest1.c_str(), sizeof(kGoogleName1)}));
+
+  CreateFileWithContent(path2, kGoogleName2, sizeof(kGoogleName2));
+
+  std::string digest2;
+  ASSERT_TRUE(signature_matcher()->ComputeSHA256DigestOfPath(path2, &digest2));
+  EXPECT_TRUE(signature_matcher()->MatchFileDigestInfo(
+      path2, &filesize, &digest, {digest2.c_str(), sizeof(kGoogleName2)}));
+  EXPECT_EQ(sizeof(kGoogleName2), filesize);
+  EXPECT_EQ(digest2, digest);
+  EXPECT_TRUE(signature_matcher()->MatchFileDigestInfo(
+      path2, &filesize, &digest, {digest2.c_str(), sizeof(kGoogleName2)}));
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/scanner/urza_scanner_controller.cc b/chrome/chrome_cleaner/scanner/urza_scanner_controller.cc
new file mode 100644
index 0000000..12358210
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/urza_scanner_controller.cc
@@ -0,0 +1,46 @@
+// 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/scanner/urza_scanner_controller.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/run_loop.h"
+
+namespace chrome_cleaner {
+
+UrzaScannerController::UrzaScannerController(
+    MatchingOptions* options,
+    std::unique_ptr<SignatureMatcherAPI> signature_matcher,
+    RegistryLogger* registry_logger)
+    : ScannerController(registry_logger),
+      signature_matcher_(std::move(signature_matcher)),
+      scanner_(*options, signature_matcher_.get(), registry_logger) {
+  DCHECK(signature_matcher_);
+}
+
+UrzaScannerController::~UrzaScannerController() {
+  CHECK(!base::RunLoop::IsRunningOnCurrentThread());
+  // TODO(joenotcharles): Clean up RunUntilIdle usage in loops.
+  while (!scanner_.IsCompletelyDone())
+    base::RunLoop().RunUntilIdle();
+}
+
+void UrzaScannerController::StartScan() {
+  found_pups_.clear();
+  scanner_.Start(base::BindRepeating(&UrzaScannerController::FoundUwSCallback,
+                                     base::Unretained(this)),
+                 base::BindOnce(&UrzaScannerController::DoneScanning,
+                                base::Unretained(this)));
+}
+
+void UrzaScannerController::FoundUwSCallback(UwSId pup_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // UrzaScannerImpl reports PUP only once when they are found, so the result
+  // code is updated only when necessary.
+  found_pups_.push_back(pup_id);
+  UpdateScanResults(found_pups_);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/scanner/urza_scanner_controller.h b/chrome/chrome_cleaner/scanner/urza_scanner_controller.h
new file mode 100644
index 0000000..f08a046
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/urza_scanner_controller.h
@@ -0,0 +1,42 @@
+// 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_SCANNER_URZA_SCANNER_CONTROLLER_H_
+#define CHROME_CHROME_CLEANER_SCANNER_URZA_SCANNER_CONTROLLER_H_
+
+#include <vector>
+
+#include "chrome/chrome_cleaner/constants/uws_id.h"
+#include "chrome/chrome_cleaner/logging/registry_logger.h"
+#include "chrome/chrome_cleaner/scanner/scanner_controller.h"
+#include "chrome/chrome_cleaner/scanner/signature_matcher_api.h"
+#include "chrome/chrome_cleaner/scanner/urza_scanner_impl.h"
+#include "chrome/chrome_cleaner/settings/matching_options.h"
+
+namespace chrome_cleaner {
+
+// The Urza (pre-ESET) implementation of the ScannerController.
+class UrzaScannerController : public ScannerController {
+ public:
+  UrzaScannerController(MatchingOptions* options,
+                        std::unique_ptr<SignatureMatcherAPI> signature_matcher,
+                        RegistryLogger* registry_logger);
+  ~UrzaScannerController() override;
+
+ protected:
+  void StartScan() override;
+
+ private:
+  void FoundUwSCallback(UwSId pup_id);
+
+  std::unique_ptr<SignatureMatcherAPI> signature_matcher_;
+  UrzaScannerImpl scanner_;
+  std::vector<UwSId> found_pups_;
+
+  DISALLOW_COPY_AND_ASSIGN(UrzaScannerController);
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_SCANNER_URZA_SCANNER_CONTROLLER_H_
diff --git a/chrome/chrome_cleaner/scanner/urza_scanner_impl.cc b/chrome/chrome_cleaner/scanner/urza_scanner_impl.cc
new file mode 100644
index 0000000..045fd010e
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/urza_scanner_impl.cc
@@ -0,0 +1,627 @@
+// 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/scanner/urza_scanner_impl.h"
+
+#include <shlobj.h>
+
+#include <locale>
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/barrier_closure.h"
+#include "base/bind.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/logging.h"
+#include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "base/task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/win/registry.h"
+#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
+#include "chrome/chrome_cleaner/logging/logging_definitions.h"
+#include "chrome/chrome_cleaner/logging/logging_service_api.h"
+#include "chrome/chrome_cleaner/logging/registry_logger.h"
+#include "chrome/chrome_cleaner/logging/scoped_timed_task_logger.h"
+#include "chrome/chrome_cleaner/logging/utils.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "chrome/chrome_cleaner/os/file_path_sanitization.h"
+#include "chrome/chrome_cleaner/os/file_path_set.h"
+#include "chrome/chrome_cleaner/os/pre_fetched_paths.h"
+#include "chrome/chrome_cleaner/os/registry_util.h"
+#include "chrome/chrome_cleaner/proto/shared_pup_enums.pb.h"
+#include "chrome/chrome_cleaner/pup_data/pup_disk_util.h"
+#include "chrome/chrome_cleaner/scanner/matcher_util.h"
+#include "chrome/chrome_cleaner/scanner/signature_matcher_api.h"
+#include "chrome/chrome_cleaner/settings/settings_definitions.h"
+#include "chrome/chrome_cleaner/strings/string_util.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+bool FileMatchesRule(const base::FilePath& file_path,
+                     PUPData::DiskMatchRule rule) {
+  if (rule == PUPData::DISK_MATCH_ANY_FILE ||
+      (PUPData::DISK_MATCH_FILE_IN_FOLDER_DEPTH_1 <= rule &&
+       rule < PUPData::DISK_MATCH_FILE_IN_FOLDER_END)) {
+    return !file_path.empty();
+  }
+  // This is the only other rule we support so far.
+  DCHECK(rule == PUPData::DISK_MATCH_BINARY_FILE);
+  return PathHasActiveExtension(file_path);
+}
+
+base::FilePath FolderToRemove(const base::FilePath& file,
+                              PUPData::DiskMatchRule rule) {
+  DCHECK(PUPData::DISK_MATCH_FILE_IN_FOLDER_DEPTH_1 <= rule &&
+         rule < PUPData::DISK_MATCH_FILE_IN_FOLDER_END);
+  base::FilePath folder_to_remove(file);
+  for (int i = PUPData::DISK_MATCH_FILE_IN_FOLDER_DEPTH_1; i <= rule; ++i) {
+    folder_to_remove = folder_to_remove.DirName();
+  }
+  return folder_to_remove;
+}
+
+// Return true if the file matches |rule| or if at least one file that matches
+// |rule| can be found in the hierarchy of descendant if |file_path| is a
+// directory. Also update |expanded_disk_footprints| with the full path of all
+// matched files, or just the first one if |options.only_one_footprint()| is
+// true.
+bool AnyFileMatches(const base::FilePath& file_path,
+                    PUPData::DiskMatchRule rule,
+                    const MatchingOptions& options,
+                    PUPData::PUP* pup) {
+  DCHECK(pup);
+  if (!base::PathExists(file_path))
+    return false;
+  // If the path isn't a folder, then simply check if it matches |rule|.
+  if (!base::DirectoryExists(file_path)) {
+    if (FileMatchesRule(file_path, rule)) {
+      // When we match a file in a folder structure, remove the appropriate
+      // folder.
+      if (PUPData::DISK_MATCH_FILE_IN_FOLDER_DEPTH_1 <= rule &&
+          rule < PUPData::DISK_MATCH_FILE_IN_FOLDER_END) {
+        if (options.only_one_footprint())
+          pup->AddDiskFootprint(file_path);
+        else
+          CollectPathsRecursively(FolderToRemove(file_path, rule), pup);
+      } else {
+        // No need to know if the file had already been added or not, it will
+        // simply be ignored by the file path set of |pup|.
+        pup->AddDiskFootprint(file_path);
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  // Look for files recursively, and find at least one that matches |rule|, yet
+  // collect all the files, since we'll need to delete them all if a match is
+  // found. Unless this folder has already been matched (|AddDiskFootprint|
+  // returns false when the item already exists).
+  if (!pup->AddDiskFootprint(file_path))
+    return true;
+
+  base::FileEnumerator file_enum(
+      file_path, true,
+      base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
+  bool found_file = false;
+  for (base::FilePath file = file_enum.Next(); !file.empty();
+       file = file_enum.Next()) {
+    pup->AddDiskFootprint(file);
+    if (!base::DirectoryExists(file) && FileMatchesRule(file, rule)) {
+      if (options.only_one_footprint())
+        return true;
+      found_file = true;
+    }
+  }
+  return found_file;
+}
+
+// Performs expansion of |path|. If |csidl| is not |kInvalidCsidl|, |path| is
+// expanded under that CSIDL. If a path can be expanded to multiple paths (e.g.
+// if it's under Program Files), all expansions will be returned.
+FilePathSet ExpandPath(int csidl, const base::FilePath& path) {
+  FilePathSet expanded_paths;
+
+  base::FilePath expanded_path;
+  if (!ExpandEnvPath(path, &expanded_path))
+    expanded_path = path;
+
+  if (csidl == PUPData::kInvalidCsidl) {
+    expanded_paths.Insert(expanded_path);
+  } else {
+    expanded_paths.Insert(ExpandSpecialFolderPath(csidl, expanded_path));
+    switch (csidl) {
+      case CSIDL_PROGRAM_FILES:
+#if defined(_WIN64)
+        expanded_paths.Insert(GetX86ProgramFilesPath(expanded_path));
+#else
+        expanded_paths.Insert(GetX64ProgramFilesPath(expanded_path));
+#endif  // defined(_WIN64)
+        break;
+      case CSIDL_SYSTEM: {
+        const base::FilePath system_path =
+            PreFetchedPaths::GetInstance()->GetWindowsFolder();
+        expanded_paths.Insert(system_path.Append(L"sysnative").Append(path));
+        break;
+      }
+    }
+  }
+
+  return expanded_paths;
+}
+
+// Fill the |expanded_disk_footprints| field of |pup| and set
+// |footprint_found| to true when a scan and remove footprint was found.
+// When |options.only_one_footprint()| is true, this function returns as soon as
+// one footprint is found (or immediately if |footprint_found| == true).
+// Return false if an error occurred and scanning |pup| must be cancelled and
+// marked as not found.
+bool ExpandDiskFootprint(const MatchingOptions& options,
+                         PUPData::PUP* pup,
+                         bool* footprint_found) {
+  DCHECK(pup);
+  DCHECK(footprint_found);
+
+  if (options.only_one_footprint() && *footprint_found)
+    return true;
+
+  // String format: Expanding disk footprints for: '%s'
+  const std::string logging_text = base::StrCat(
+      {"Expanding disk footprints for: '", PUPData::GetPUPName(pup), "'"});
+  ScopedTimedTaskLogger scoped_timed_task_logger(logging_text.c_str());
+
+  const PUPData::StaticDiskFootprint* disk_footprints =
+      pup->signature().disk_footprints;
+  for (size_t i = 0; disk_footprints[i].path != nullptr; ++i) {
+    // Make sure to never try to remove a whole CSIDL folder.
+    if (disk_footprints[i].csidl != PUPData::kInvalidCsidl &&
+        wcslen(disk_footprints[i].path) == 0) {
+      NOTREACHED() << "A CSIDL with no path!!!";
+      pup->ClearDiskFootprints();
+      return false;
+    }
+
+    const FilePathSet expanded_paths = ExpandPath(
+        disk_footprints[i].csidl, base::FilePath(disk_footprints[i].path));
+
+    std::vector<base::FilePath> matches;
+    for (const auto& expanded_path : expanded_paths.file_paths())
+      CollectMatchingPaths(expanded_path, &matches);
+    for (const auto& file_path : matches) {
+      if (AnyFileMatches(file_path, disk_footprints[i].rule, options, pup)) {
+        *footprint_found = true;
+        LOG(INFO) << "Found disk footprint: " << SanitizePath(file_path);
+        if (options.only_one_footprint())
+          return true;
+      }
+    }
+  }
+  return true;
+}
+
+bool DoesValueMatchAgainstRegistryRule(const base::string16& value,
+                                       const base::string16& value_substring,
+                                       RegistryMatchRule rule) {
+  switch (rule) {
+    case REGISTRY_VALUE_MATCH_EXACT:
+      if (String16EqualsCaseInsensitive(value, value_substring))
+        return true;
+      break;
+    case REGISTRY_VALUE_MATCH_CONTAINS:
+    case REGISTRY_VALUE_MATCH_PARTIAL:
+      if (String16ContainsCaseInsensitive(value, value_substring))
+        return true;
+      break;
+    case REGISTRY_VALUE_MATCH_COMMON_SEPARATED_SET_EXACT: {
+      // This variable is needed to call the string constructor with size to
+      // keep the null characters.
+      base::string16 delimiters(PUPData::kCommonDelimiters,
+                                PUPData::kCommonDelimitersLength);
+      if (String16SetMatchEntry(value, delimiters, value_substring,
+                                String16EqualsCaseInsensitive)) {
+        return true;
+      }
+      break;
+    }
+    case REGISTRY_VALUE_MATCH_COMMON_SEPARATED_SET_CONTAINS: {
+      // This variable is needed to call the string constructor with size to
+      // keep the null characters.
+      base::string16 delimiters(PUPData::kCommonDelimiters,
+                                PUPData::kCommonDelimitersLength);
+      if (String16SetMatchEntry(value, delimiters, value_substring,
+                                String16ContainsCaseInsensitive)) {
+        return true;
+      }
+      break;
+    }
+    case REGISTRY_VALUE_MATCH_COMMA_SEPARATED_SET_EXACT:
+      if (String16SetMatchEntry(value, PUPData::kCommaDelimiter,
+                                value_substring,
+                                String16EqualsCaseInsensitive)) {
+        return true;
+      }
+      break;
+    case REGISTRY_VALUE_MATCH_COMMA_SEPARATED_SET_CONTAINS:
+      if (String16SetMatchEntry(value, PUPData::kCommaDelimiter,
+                                value_substring,
+                                String16ContainsCaseInsensitive)) {
+        return true;
+      }
+      FALLTHROUGH;
+    case REGISTRY_VALUE_MATCH_COMMON_SEPARATED_SET_CONTAINS_PATH:
+      if (String16SetMatchEntry(value, PUPData::kCommonDelimiters,
+                                value_substring,
+                                ShortPathContainsCaseInsensitive)) {
+        return true;
+      }
+      break;
+    default:
+      LOG(ERROR) << "Missing rule to match registry key value.";
+      return false;
+  }
+
+  return false;
+}
+
+// Set |footprint_found| to true when a scan and remove registry
+// footprint was found. When |options.only_one_footprint()| is true, this
+// function returns as
+// soon as one footprint is found (or immediately if |footprint_found|
+// == true). Return false if an error occurred and scanning |pup| must be
+// cancelled and marked as not found.
+bool ExpandRegistryFootprint(const MatchingOptions& options,
+                             PUPData::PUP* pup,
+                             bool* footprint_found) {
+  DCHECK(pup);
+  DCHECK(footprint_found);
+
+  if (options.only_one_footprint() && *footprint_found)
+    return true;
+
+  // String format: Expanding registry footprints for: '%s'
+  const std::string logging_text = base::StrCat(
+      {"Expanding registry footprints for: '", PUPData::GetPUPName(pup), "'"});
+  ScopedTimedTaskLogger scoped_timed_task_logger(logging_text.c_str());
+
+  const PUPData::StaticRegistryFootprint* registry_footprints =
+      pup->signature().registry_footprints;
+  for (const PUPData::StaticRegistryFootprint* footprint =
+           &registry_footprints[0];
+       footprint->key_path != nullptr; ++footprint) {
+    RegistryRoot registry_root = footprint->registry_root;
+    base::FilePath policy_file;
+    HKEY hkroot = nullptr;
+
+    bool success = PUPData::GetRootKeyFromRegistryRoot(registry_root, &hkroot,
+                                                       &policy_file);
+    CHECK(success) << "Internal data should not have invalid registry roots.";
+
+    // The function |CollectMatchingRegistryPaths| enumerates registry paths
+    // matching the regular expression in both 32 and 64-bit view.
+    std::vector<RegKeyPath> key_paths;
+    CollectMatchingRegistryPaths(hkroot, footprint->key_path,
+                                 PUPData::kRegistryPatternEscapeCharacter,
+                                 &key_paths);
+
+    for (const auto& key_path : key_paths) {
+      base::win::RegKey reg_key;
+      base::FilePath policy_file;
+
+      if (!key_path.Open(KEY_READ, &reg_key))
+        continue;
+      LOG_IF(WARNING, !policy_file.empty())
+          << "Group Policies are not supported.";
+      DCHECK(reg_key.Valid());
+
+      // If we are not looking for a value name, then we have already found the
+      // footprint, which is simply a valid key path.
+      if (footprint->rule == REGISTRY_VALUE_MATCH_KEY) {
+        PUPData::DeleteRegistryKey(key_path, pup);
+
+        LOG(INFO) << "Found registry key: " << key_path.FullPath();
+        *footprint_found = true;
+        if (options.only_one_footprint())
+          return true;
+
+        continue;
+      }
+
+      // Collect the matching value names from the registry key.
+      std::vector<base::string16> value_names;
+      CollectMatchingRegistryNames(reg_key, footprint->value_name,
+                                   PUPData::kRegistryPatternEscapeCharacter,
+                                   &value_names);
+
+      for (const auto& value_name : value_names) {
+        // If the value doesn't exists, do not perform any rules matching.
+        if (!reg_key.HasValue(value_name.c_str()))
+          continue;
+
+        base::string16 value;
+        if (!ReadRegistryValue(reg_key, value_name.c_str(), &value, nullptr,
+                               nullptr)) {
+          DVPLOG(1) << "Failed to read value: " << key_path.FullPath();
+        }
+
+        // When looking for a value name, collect the footprint as soon as the
+        // value name is matching.
+        if (footprint->rule == REGISTRY_VALUE_MATCH_VALUE_NAME) {
+          DCHECK(!footprint->value_substring);
+          PUPData::DeleteRegistryValue(key_path, value_name.c_str(), pup);
+
+          LOG(INFO) << "Found registry value: " << key_path.FullPath() << ", "
+                    << value_name << ", with value: " << value;
+          *footprint_found = true;
+          if (options.only_one_footprint())
+            return true;
+          continue;
+        }
+        DCHECK(footprint->value_substring);
+
+        // Match against pre-defined PUPData registry rules.
+        if (DoesValueMatchAgainstRegistryRule(value, footprint->value_substring,
+                                              footprint->rule)) {
+          PUPData::UpdateRegistryValue(key_path, value_name.c_str(),
+                                       footprint->value_substring,
+                                       footprint->rule, pup);
+
+          // TODO(csharp): Sanitize footprint->value_substring which is a
+          // path.
+          LOG(INFO) << "Found registry value: " << key_path.FullPath() << ", "
+                    << value_name << ", " << footprint->value_substring;
+          *footprint_found = true;
+          if (options.only_one_footprint())
+            return true;
+
+          continue;
+        }
+      }
+    }
+  }
+
+  // No footprint found, but no errors occurred.
+  return true;
+}
+
+// Runs the custom matchers to fill the fields of |pup| and set
+// |footprint_found| to true when a scan and remove footprint was found.
+// When |options.only_one_footprint()| is true, returns as soon as one
+// footprint is found (or immediately if |footprint_found| == true).
+// Returns false if an error occurred and scanning |pup| must be cancelled and
+// marked as not found.
+bool RunCustomMatchers(const MatchingOptions& options,
+                       const SignatureMatcherAPI* signature_matcher,
+                       PUPData::PUP* pup,
+                       bool* footprint_found) {
+  DCHECK(pup);
+  DCHECK(footprint_found);
+
+  if (options.only_one_footprint() && *footprint_found)
+    return true;
+
+  int custom_matcher_index = 0;
+  const PUPData::CustomMatcher* custom_matchers =
+      pup->signature().custom_matchers;
+  for (const PUPData::CustomMatcher *custom_matcher = custom_matchers;
+       *custom_matcher; ++custom_matcher, ++custom_matcher_index) {
+    // String format: Running custom matcher %d for UwS '%s'
+    const std::string logging_text = base::StrCat(
+        {"Running custom matcher ", base::NumberToString(custom_matcher_index),
+         " for UwS '", PUPData::GetPUPName(pup), "'"});
+    ScopedTimedTaskLogger scoped_timed_task_logger(logging_text.c_str());
+
+    // Pass a copy of |footprint_found| to ensure custom matchers don't
+    // change the state from true to false.
+    bool current_matcher_footprint_found = *footprint_found;
+    if (!(*custom_matcher)(options, signature_matcher, pup,
+                           &current_matcher_footprint_found))
+      return false;
+
+    // Try and detect if any custom matchers incorrectly set
+    // |current_matcher_footprint_found| to false.
+    DCHECK(!(*footprint_found && !current_matcher_footprint_found));
+
+    if (current_matcher_footprint_found) {
+      *footprint_found = true;
+      if (options.only_one_footprint())
+        return true;
+    }
+  }
+  return true;
+}
+
+void LogAndWriteScanTimeToRegistry(RegistryLogger* registry_logger,
+                                   const PUPData::PUP* const pup,
+                                   const base::TimeDelta& scan_time) {
+  DCHECK(pup);
+  // String format: Scanning of: '%s'
+  const std::string logging_text =
+      base::StrCat({"Scanning of: '", PUPData::GetPUPName(pup), "'"});
+  ScopedTimedTaskLogger::LogIfExceedThreshold(
+      logging_text.c_str(), base::TimeDelta::FromSeconds(1), scan_time);
+
+  if (registry_logger)
+    registry_logger->WriteScanTime(pup->signature().id, scan_time);
+}
+
+// Scan the footprint of the PUP identified by |pup_id|, run all the collectors
+// by calling |run_collectors|. If the UwS was found, call |uws_found|.
+// The collectors are run via a callback to enable tests to skip running the
+// collectors for performance reasons.
+// |task_done| will run whenever it goes out of scope, either when this function
+// ends, or when |uws_found| ends (since it is passed as an argument to it).
+void ScanThisPUP(
+    UwSId pup_id,
+    const MatchingOptions& options,
+    const SignatureMatcherAPI* signature_matcher,
+    scoped_refptr<base::TaskRunner> task_runner,
+    RegistryLogger* registry_logger,
+    base::RepeatingCallback<void(UwSId, base::ScopedClosureRunner)> uws_found,
+    base::ScopedClosureRunner task_done) {
+  DCHECK(task_runner);
+  DCHECK(signature_matcher);
+  PUPData::PUP* pup = PUPData::GetPUP(pup_id);
+
+  ScopedTimedTaskLogger scoped_timed_task_logger(
+      base::BindOnce(&LogAndWriteScanTimeToRegistry, registry_logger, pup));
+
+  // Make sure to start from scratch, mainly important for tests for now.
+  pup->ClearDiskFootprints();
+  pup->expanded_registry_footprints.clear();
+  pup->expanded_scheduled_tasks.clear();
+
+  UwSId found_pup_id = PUPData::kInvalidUwSId;
+  bool footprint_found = false;
+
+  // The functions below will return true immediately if
+  // |options.only_one_footprint()| and |uws_detected| are both true.
+  if (ExpandDiskFootprint(options, pup, &footprint_found) &&
+      ExpandRegistryFootprint(options, pup, &footprint_found) &&
+      RunCustomMatchers(options, signature_matcher, pup, &footprint_found) &&
+      footprint_found) {
+    found_pup_id = pup_id;
+  }
+
+  bool uws_detected = found_pup_id != PUPData::kInvalidUwSId;
+  if (uws_detected) {
+    UwSDetectedFlags flags = kUwSDetectedFlagsNone;
+
+    if (options.only_one_footprint())
+      flags |= kUwSDetectedFlagsOnlyOneFootprint;
+
+    LoggingServiceAPI::GetInstance()->AddDetectedUwS(pup, flags);
+  }
+
+  if (uws_detected) {
+    task_runner->PostTask(
+        FROM_HERE,
+        base::BindRepeating(uws_found, found_pup_id, base::Passed(&task_done)));
+  }
+}
+
+}  // namespace
+
+UrzaScannerImpl::UrzaScannerImpl(const MatchingOptions& options,
+                                 SignatureMatcherAPI* signature_matcher,
+                                 RegistryLogger* registry_logger)
+    : options_(options),
+      signature_matcher_(signature_matcher),
+      registry_logger_(registry_logger),
+      all_tasks_done_(false),
+      num_pups_(0),
+      stopped_(false) {}
+
+UrzaScannerImpl::~UrzaScannerImpl() {}
+
+bool UrzaScannerImpl::Start(const FoundUwSCallback& found_uws_callback,
+                            DoneCallback done_callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  stopped_ = false;
+  found_uws_callback_ = found_uws_callback;
+  done_callback_ = std::move(done_callback);
+
+  // It's not a valid state to have no PUPs at all.
+  num_pups_ = PUPData::GetUwSIds()->size();
+  DCHECK(num_pups_);
+
+  // We currently create one task per PUP to scan.
+  auto task_runner = base::CreateTaskRunnerWithTraits({base::MayBlock()});
+  all_tasks_done_ = false;
+  base::RepeatingClosure task_done_closure = base::BarrierClosure(
+      num_pups_, base::BindOnce(&UrzaScannerImpl::InvokeAllTasksDone,
+                                base::Unretained(this),
+                                base::SequencedTaskRunnerHandle::Get()));
+  for (const auto& pup_id : *PUPData::GetUwSIds()) {
+    // The ScopedClosureRunner will be executed whenever it falls out of scope,
+    // which ensures that |task_done_closure| will be executed whenever the task
+    // finishes or is cancelled.
+    cancelable_task_tracker_.PostTask(
+        task_runner.get(), FROM_HERE,
+        base::BindOnce(
+            &ScanThisPUP, pup_id, options_, signature_matcher_,
+            base::SequencedTaskRunnerHandle::Get(), registry_logger_,
+            base::BindRepeating(&UrzaScannerImpl::UwSFound,
+                                base::Unretained(this)),
+            base::Passed(base::ScopedClosureRunner(task_done_closure))));
+  }
+  return true;
+}
+
+void UrzaScannerImpl::Stop() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  cancelable_task_tracker_.TryCancelAll();
+  stopped_ = true;
+}
+
+bool UrzaScannerImpl::IsCompletelyDone() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // If some cleanup code does not run we get hangs in ScannerTest.Nonexistent*
+  return all_tasks_done_ && !cancelable_task_tracker_.HasTrackedTasks();
+}
+
+// |task_done| will run whenever it falls out of scoped, so it doesn't need to
+// be directly called.
+void UrzaScannerImpl::UwSFound(UwSId found_pup_id,
+                               base::ScopedClosureRunner task_done) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_NE(found_pup_id, PUPData::kInvalidUwSId);
+  if (stopped_)
+    return;
+
+  found_pups_.push_back(found_pup_id);
+
+  // Report the detected PUP.
+  const PUPData::UwSSignature& signature =
+      PUPData::GetPUP(found_pup_id)->signature();
+
+  if (signature.name) {
+    LoggingServiceAPI::GetInstance()->AddFoundUwS(signature.name);
+    if (PUPData::HasReportOnlyFlag(signature.flags)) {
+      LOG(INFO) << "Report only UwS detected: " << signature.name;
+    } else {
+      LOG(INFO) << "UwS detected: " << signature.name;
+    }
+  } else {
+    LOG(ERROR) << "Missing name for detected UwS with id " << found_pup_id;
+  }
+
+  found_uws_callback_.Run(found_pup_id);
+}
+
+void UrzaScannerImpl::InvokeAllTasksDone(
+    scoped_refptr<base::TaskRunner> task_runner) {
+  task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(&UrzaScannerImpl::AllTasksDone, base::Unretained(this)));
+}
+
+void UrzaScannerImpl::AllTasksDone() {
+  all_tasks_done_ = true;
+  if (stopped_)
+    return;
+
+  std::move(done_callback_).Run(RESULT_CODE_SUCCESS, found_pups_);
+  found_pups_.clear();
+  done_callback_.Reset();
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/scanner/urza_scanner_impl.h b/chrome/chrome_cleaner/scanner/urza_scanner_impl.h
new file mode 100644
index 0000000..5e92740
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/urza_scanner_impl.h
@@ -0,0 +1,94 @@
+// 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_SCANNER_URZA_SCANNER_IMPL_H_
+#define CHROME_CHROME_CLEANER_SCANNER_URZA_SCANNER_IMPL_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/sequence_checker.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "chrome/chrome_cleaner/pup_data/pup_data.h"
+#include "chrome/chrome_cleaner/scanner/scanner.h"
+#include "chrome/chrome_cleaner/settings/matching_options.h"
+
+namespace chrome_cleaner {
+
+// Forward declarations.
+class SignatureMatcherAPI;
+class RegistryLogger;
+
+// This class is used to scan for the footprints of all PUPs in PUPData. It uses
+// a worker thread pool to scan asynchronously and be interruptable, but is not
+// thread safe, in the sense that the Start/Stop/IsStopDone methods must all be
+// called from the same thread that created the class instance.
+class UrzaScannerImpl : public Scanner {
+ public:
+  // Create instance of scanner that uses Urza engine.
+  // If |registry_logger| is not null, write scan times of individual PUPs to
+  // the registry. Any |RegistryLogger| object pointed to by |registry_logger|
+  // must stay alive for the entire lifetime of this scanner instance.
+  UrzaScannerImpl(const MatchingOptions& options,
+                  SignatureMatcherAPI* signature_matcher,
+                  RegistryLogger* registry_logger);
+
+  ~UrzaScannerImpl() override;
+
+  // UrzaScanner.
+
+  // Start a set of tasks in worker pool threads to scan the disk and registry
+  // for PUP footprints. A PUP is deemed "found" if at least one of its
+  // footprints can be found. If a PUP was found, |found_uws_callback| is
+  // called. If the scan completes before |Stop| is called, then |done_callback|
+  // is called. Returns true if scan startup succeeds.
+  bool Start(const FoundUwSCallback& found_uws_callback,
+             DoneCallback done_callback) override;
+  void Stop() override;
+
+  // When calling |Stop|, some tasks may still be running, so make sure to call
+  // |IsCompletelyDone| and allow the main UI to pump messages to let the task
+  // tracker mark all tasks as done before clearing PUPData, which should not be
+  // an issue in production code where it's all static, but can be an issue with
+  // dynamic PUPData in test code. Return true if there's nothing left to be
+  // completed asynchronously by the scanner (i.e, a stop was started and
+  // finished, or everything was completely done).
+  bool IsCompletelyDone() const override;
+
+ private:
+  void UwSFound(UwSId found_uws_id, base::ScopedClosureRunner task_done);
+
+  void InvokeAllTasksDone(scoped_refptr<base::TaskRunner> task_runner);
+
+  void AllTasksDone();
+
+  MatchingOptions options_;
+  SignatureMatcherAPI* signature_matcher_;
+  RegistryLogger* registry_logger_;
+
+  // The task tracker that can be used to cancel pending tasks.
+  base::CancelableTaskTracker cancelable_task_tracker_;
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  // Callbacks to report progress and completion.
+  FoundUwSCallback found_uws_callback_;
+  DoneCallback done_callback_;
+
+  // To accumulate the list of found PUPs passed to |TaskCompleted|.
+  std::vector<UwSId> found_pups_;
+
+  // Whether all tasks are done, either having been cancelled or completed.
+  bool all_tasks_done_;
+
+  // The number of PUPs, which is also the total number of tasks to run.
+  size_t num_pups_;
+
+  // Whether |Stop| has been called or not. Reset to false in |Start|.
+  bool stopped_;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_SCANNER_URZA_SCANNER_IMPL_H_
diff --git a/chrome/chrome_cleaner/scanner/urza_scanner_impl_unittest.cc b/chrome/chrome_cleaner/scanner/urza_scanner_impl_unittest.cc
new file mode 100644
index 0000000..dec29d90
--- /dev/null
+++ b/chrome/chrome_cleaner/scanner/urza_scanner_impl_unittest.cc
@@ -0,0 +1,2294 @@
+// 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/scanner/urza_scanner_impl.h"
+
+#include <shlobj.h>
+
+#include <algorithm>
+#include <iterator>
+#include <list>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/rand_util.h"
+#include "base/run_loop.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/test/scoped_path_override.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/test/test_shortcut_win.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/win/windows_version.h"
+#include "chrome/chrome_cleaner/logging/logging_service_api.h"
+#include "chrome/chrome_cleaner/logging/mock_logging_service.h"
+#include "chrome/chrome_cleaner/logging/proto/shared_data.pb.h"
+#include "chrome/chrome_cleaner/logging/utils.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "chrome/chrome_cleaner/proto/shared_pup_enums.pb.h"
+#include "chrome/chrome_cleaner/strings/string_util.h"
+#include "chrome/chrome_cleaner/test/test_file_util.h"
+#include "chrome/chrome_cleaner/test/test_name_helper.h"
+#include "chrome/chrome_cleaner/test/test_pup_data.h"
+#include "chrome/chrome_cleaner/test/test_registry_util.h"
+#include "chrome/chrome_cleaner/test/test_signature_matcher.h"
+#include "chrome/chrome_cleaner/test/test_strings.h"
+#include "chrome/chrome_cleaner/test/test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+using testing::_;
+using testing::Eq;
+
+// To make git cl lint happy.
+constexpr size_t kMaxPath = _MAX_PATH;
+
+constexpr UwSId k12ID = 12;
+constexpr UwSId k24ID = 24;
+constexpr UwSId k42ID = 42;
+constexpr UwSId k84ID = 84;
+
+constexpr UwSId kNonExistentID = 666;
+
+constexpr base::char16 kBaseName[] = L"foo";
+constexpr base::char16 kOtherBaseName[] = L"goo";
+constexpr base::char16 kBadBaseName[] = L"fo";
+constexpr base::char16 kValueName[] = L"bar";
+constexpr base::char16 kValue[] = L"bla";
+constexpr base::char16 kValueDifferentCase[] = L"bLa";
+constexpr base::char16 kBadValue[] = L"bl";
+constexpr base::char16 kBaValue[] = L"ba";
+constexpr base::char16 kFooValue[] = L"foo";
+constexpr base::char16 kComplexValue[] = L"bli bla blue";
+constexpr base::char16 kCommaSetValue[] = L"bli,bla,blue";
+constexpr base::char16 kCommonSetValue[] = L"bli,bla blue";
+constexpr base::char16 kCommonSetWithNullValue[] = L"bli\0bla\0blue";
+constexpr base::char16 kBiggerCommaSetValue[] = L"bli,blablabla,blue";
+constexpr base::char16 kBadCommaSetValue[] = L"bli,bah,blue";
+constexpr base::char16 kWildcardSearch1[] = L"*";
+constexpr base::char16 kWildcardSearch2[] = L"f??";
+constexpr base::char16 kDummyFullPath[] = L"c:\\foo\\bar\\bat.exe";
+constexpr base::char16 kOtherFullPath[] = L"c:\\foo\\bar.exe";
+constexpr base::char16 kLongFileName[] = L"bla bla bla.exe";
+
+constexpr base::char16 kRegistryKeyPath[] = L"software\\foo";
+constexpr base::char16 kValueName1[] = L"foo1";
+constexpr base::char16 kValueName2[] = L"foo2";
+constexpr base::char16 kValueName3[] = L"foo3";
+constexpr base::char16 kValueNameSingleWildcard[] = L"foo?";
+constexpr base::char16 kValueNameMultiWildcard[] = L"fo*";
+constexpr base::char16 kSetWithCommonValue1[] = L"foo bar bat";
+constexpr base::char16 kSetWithCommonValue2[] = L"bar foo bat";
+constexpr base::char16 kSetWithCommonValue3[] = L"bar bat foo";
+
+constexpr size_t kManyPUPs = 1000;
+constexpr size_t kSomePUPs = 20;
+constexpr size_t kFoundPUPsModuloBase = 10;
+
+bool g_test_custom_matcher1_called = false;
+bool g_test_custom_matcher2_called = false;
+bool g_test_custom_matcher3_called = false;
+bool g_test_custom_matcher5_found = false;
+
+// Computes the set difference between two sets and outputs to a vector.
+template <typename T>
+void set_difference(const std::set<T>& set1,
+                    const std::set<T>& set2,
+                    std::vector<T>* output) {
+  std::set_difference(set1.begin(), set1.end(), set2.begin(), set2.end(),
+                      std::back_inserter(*output));
+}
+
+class TestScanner : public UrzaScannerImpl {
+ public:
+  TestScanner() = default;
+  explicit TestScanner(const MatchingOptions& options,
+                       SignatureMatcherAPI* signature_matcher,
+                       RegistryLogger* registry_logger)
+      : UrzaScannerImpl(options, signature_matcher, registry_logger) {}
+  ~TestScanner() override = default;
+};
+
+// This test fixture is used to expose callbacks to the scanner and some utility
+// functions. It keeps data for the found PUPs, as well as the done and stopped
+// state. It also creates the main/UI task scheduler.
+class ScannerTest : public testing::Test {
+ public:
+  ScannerTest()
+      : done_scanning_(false),
+        found_report_only_(false),
+        found_pup_to_remove_(false),
+        stopped_(false),
+        scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
+
+  void TearDown() override {
+    // Even though not all tests override the logging instance, we reset it
+    // during test tear down, so test failures don't keep them in an invalid
+    // status.
+    LoggingServiceAPI::SetInstanceForTesting(nullptr);
+  }
+
+  // Scanner callbacks.
+  void DoneScanning(ResultCode status, const std::vector<UwSId>& found_pups) {
+    ASSERT_FALSE(done_scanning_);
+    found_pups_.insert(found_pups_.begin(), found_pups.begin(),
+                       found_pups.end());
+    done_scanning_ = true;
+
+    // Urza is so cool, it never fails.
+    EXPECT_EQ(RESULT_CODE_SUCCESS, status);
+
+    found_report_only_ =
+        PUPData::HasFlaggedPUP(found_pups, &PUPData::HasReportOnlyFlag);
+  }
+
+  void FoundUwS(UwSId found_pup) {
+    EXPECT_FALSE(done_scanning_);
+    EXPECT_EQ(pups_seen_in_progress_callback_.end(),
+              pups_seen_in_progress_callback_.find(found_pup));
+    pups_seen_in_progress_callback_.insert(found_pup);
+  }
+
+  // Start/Stop the scanner.
+  void Scan() {
+    done_scanning_ = false;
+    g_test_custom_matcher1_called = false;
+    g_test_custom_matcher2_called = false;
+    g_test_custom_matcher3_called = false;
+    g_test_custom_matcher5_found = false;
+    found_pups_.clear();
+    pups_seen_in_progress_callback_.clear();
+
+    test_scanner_.reset(
+        new TestScanner(options_, &test_signature_matcher_, nullptr));
+
+    test_scanner_->Start(
+        base::BindRepeating(&ScannerTest::FoundUwS, base::Unretained(this)),
+        base::BindOnce(&ScannerTest::DoneScanning, base::Unretained(this)));
+    // Now wait for the scanner to be done or stopped.
+    while (!(done_scanning_ || stopped_) || !test_scanner_->IsCompletelyDone())
+      base::RunLoop().RunUntilIdle();
+  }
+
+  void StopScanner() {
+    test_scanner_->Stop();
+    stopped_ = true;
+  }
+
+  // Expectations utility functions.
+  void ExpectNoPUPsFound() { ExpectFoundPUPs({}); }
+
+  void ExpectSinglePUP(UwSId pup_id) { ExpectFoundPUPs({pup_id}); }
+
+  void ExpectFoundPUPs(const std::set<UwSId>& pups) {
+    EXPECT_EQ(pups.size(), found_pups_.size());
+    std::set<UwSId>::const_iterator pup = pups.begin();
+    for (; pup != pups.end(); ++pup) {
+      EXPECT_NE(found_pups_.end(),
+                std::find(found_pups_.begin(), found_pups_.end(), *pup));
+    }
+    EXPECT_EQ(pups.size(), pups_seen_in_progress_callback_.size());
+    EXPECT_EQ(pups, pups_seen_in_progress_callback_);
+  }
+
+  // Add disk footprint for PUP |pup_id| to |test_pup_data|. If
+  // |disk_footprint_exist| is true, create files matching the newly created
+  // footprint.
+  // Return true on success.
+  bool SetupDiskFootprint(TestPUPData* test_pup_data,
+                          UwSId pup_id,
+                          bool disk_footprint_exist) {
+    // Create temporary directory.
+    std::shared_ptr<base::ScopedTempDir> temp_dir(new base::ScopedTempDir);
+    if (!temp_dir->CreateUniqueTempDir() || !temp_dir->IsValid())
+      return false;
+
+    // Setup disk footprint rule. PUPData holds C-style strings, so provide
+    // C string equivalent of the stored filepath.
+    pup_data_filepaths_.push_back(temp_dir->GetPath().value());
+    test_pup_data->AddDiskFootprint(pup_id, 0,
+                                    pup_data_filepaths_.back().c_str(),
+                                    PUPData::DISK_MATCH_ANY_FILE);
+
+    // If footprint rule should match, create a file and ensure the directory is
+    // not deleted until the end of the test.
+    if (disk_footprint_exist) {
+      base::FilePath temp_file;
+      if (!CreateTemporaryFileInDir(temp_dir->GetPath(), &temp_file))
+        return false;
+      pup_data_temp_dirs_.push_back(temp_dir);
+    }
+
+    return true;
+  }
+
+ protected:
+  std::unique_ptr<TestScanner> test_scanner_;
+  MatchingOptions options_;
+  TestSignatureMatcher test_signature_matcher_;
+  std::vector<UwSId> found_pups_;
+  std::set<UwSId> pups_seen_in_progress_callback_;
+  bool done_scanning_;
+  bool found_report_only_;
+  bool found_pup_to_remove_;
+  bool stopped_;
+
+ private:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+  // This vector holds temporary directories which should be released at the end
+  // of the test.
+  std::vector<std::shared_ptr<base::ScopedTempDir>> pup_data_temp_dirs_;
+  // This vector holds C++ strings representing PUP disk footprints filepaths.
+  // This is to allow proper memory management of C string equivalents in
+  // PUPData.
+  std::vector<base::string16> pup_data_filepaths_;
+};
+
+class ScannerTestWithBitness : public ScannerTest,
+                               public ::testing::WithParamInterface<int> {};
+
+INSTANTIATE_TEST_CASE_P(ScannerBitnessTest,
+                        ScannerTestWithBitness,
+                        testing::Values(32, 64),
+                        GetParamNameForTest());
+
+// A custom matcher finding an active disk footprint.
+bool TestCustomMatcher1(const MatchingOptions& options,
+                        const SignatureMatcherAPI* signature_matcher,
+                        PUPData::PUP* pup,
+                        bool* active_footprint_found) {
+  DCHECK(pup);
+  DCHECK(active_footprint_found);
+  base::FilePath path(kDummyFullPath);
+  pup->AddDiskFootprint(path);
+  *active_footprint_found = true;
+  g_test_custom_matcher1_called = true;
+  return true;
+}
+
+// A custom matcher finding an inactive (left-over) disk footprint.
+bool TestCustomMatcher2(const MatchingOptions& options,
+                        const SignatureMatcherAPI* signature_matcher,
+                        PUPData::PUP* pup,
+                        bool* active_footprint_found) {
+  DCHECK(pup);
+  DCHECK(active_footprint_found);
+  base::FilePath path(kOtherFullPath);
+  pup->AddDiskFootprint(path);
+  g_test_custom_matcher2_called = true;
+  return true;
+}
+
+// A custom matcher finding nothing.
+bool TestCustomMatcher3(const MatchingOptions& options,
+                        const SignatureMatcherAPI* signature_matcher,
+                        PUPData::PUP* pup,
+                        bool* active_footprint_found) {
+  DCHECK(pup);
+  DCHECK(active_footprint_found);
+  g_test_custom_matcher3_called = true;
+  return true;
+}
+
+// A custom matcher producing an error.
+bool TestCustomMatcher4(const MatchingOptions& options,
+                        const SignatureMatcherAPI* signature_matcher,
+                        PUPData::PUP* pup,
+                        bool* active_footprint_found) {
+  DCHECK(pup);
+  DCHECK(active_footprint_found);
+  base::FilePath path(kDummyFullPath);
+  pup->AddDiskFootprint(path);
+  *active_footprint_found = true;
+  // Return an error, abort scanning this pup.
+  return false;
+}
+
+// A custom matcher setting |g_test_custom_matcher5_found| to
+// |active_footprint_found|.
+bool TestCustomMatcher5(const MatchingOptions& options,
+                        const SignatureMatcherAPI* signature_matcher,
+                        PUPData::PUP* pup,
+                        bool* active_footprint_found) {
+  DCHECK(pup);
+  DCHECK(active_footprint_found);
+  g_test_custom_matcher5_found = *active_footprint_found;
+  return true;
+}
+
+}  // namespace
+
+TEST_F(ScannerTest, NonexistentDiskFootprint) {
+  // Set up a disk footprint.
+  base::ScopedTempDir scoped_temp_dir1;
+  ASSERT_TRUE(scoped_temp_dir1.CreateUniqueTempDir());
+  // Only the folder was actually created, so base name is nonexistent.
+  base::FilePath nonexistent_file(scoped_temp_dir1.GetPath().Append(kBaseName));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddDiskFootprint(k42ID, 0, nonexistent_file.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, NonexistentRelativeDiskFootprint) {
+  base::char16 special_folder_path[kMaxPath];
+  HRESULT hr = SHGetFolderPath(nullptr, CSIDL_LOCAL_APPDATA, nullptr,
+                               SHGFP_TYPE_CURRENT, special_folder_path);
+  ASSERT_EQ(S_OK, hr);
+
+  base::ScopedTempDir scoped_temp_dir2;
+  ASSERT_TRUE(scoped_temp_dir2.CreateUniqueTempDirUnderPath(
+      base::FilePath(special_folder_path)));
+  base::FilePath nonexistent_footprint(
+      scoped_temp_dir2.GetPath().BaseName().Append(kBaseName));
+  TestPUPData test_pup_data;
+  test_pup_data.AddDiskFootprint(k42ID, CSIDL_LOCAL_APPDATA,
+                                 nonexistent_footprint.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+  ASSERT_FALSE(base::PathExists(scoped_temp_dir2.GetPath().Append(kBaseName)));
+
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, NonexistentWildcardDiskFootprint) {
+  // Set up a disk footprint.
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+  base::FilePath existent_folder(scoped_temp_dir.GetPath());
+  // Only the folder was actually created, so base name is nonexistent.
+  base::FilePath nonexistent_file(
+      scoped_temp_dir.GetPath().Append(kWildcardSearch2));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddDiskFootprint(k42ID, 0, nonexistent_file.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+
+  // File should not be found because it doesn't match the pattern.
+  base::FilePath temp_file;
+  ASSERT_TRUE(CreateTemporaryFileInDir(existent_folder, &temp_file));
+
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, NonexistentRegistryFootprint) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  // Make sure the key doesn't exist.
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_FILE_NOT_FOUND,
+            system_registry_key.Open(HKEY_LOCAL_MACHINE, kBaseName, KEY_READ));
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, nullptr, nullptr,
+                                     REGISTRY_VALUE_MATCH_KEY);
+
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Now create the key, so that we can look for a nonexistent value.
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+
+  test_pup_data.Reset({});
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, kValueName, nullptr,
+                                     REGISTRY_VALUE_MATCH_VALUE_NAME);
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Now create the value, but with a bad name while we look for the good one.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kBadValue));
+
+  test_pup_data.Reset({});
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, kValueName, kValue,
+                                     REGISTRY_VALUE_MATCH_PARTIAL);
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, ExistentDiskFootprint) {
+  // Set up a folder only disk footprint.
+  base::ScopedTempDir scoped_temp_dir1;
+  ASSERT_TRUE(scoped_temp_dir1.CreateUniqueTempDir());
+  base::FilePath existent_folder(scoped_temp_dir1.GetPath());
+  ASSERT_TRUE(base::PathExists(existent_folder));
+
+  base::ScopedTempDir scoped_temp_dir2;
+  ASSERT_TRUE(scoped_temp_dir2.CreateUniqueTempDirUnderPath(
+      scoped_temp_dir1.GetPath()));
+  base::FilePath existent_subfolder(scoped_temp_dir2.GetPath());
+  ASSERT_TRUE(base::PathExists(existent_subfolder));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddDiskFootprint(k42ID, 0, existent_folder.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+
+  // No PUP should be found when only folders are under the marked footprints.
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Add a file, and it should be found.
+  base::FilePath temp_file;
+  ASSERT_TRUE(CreateTemporaryFileInDir(existent_subfolder, &temp_file));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  EXPECT_EQ(3UL, found_pup->expanded_disk_footprints.size());
+  ExpectDiskFootprint(*found_pup, existent_folder);
+  ExpectDiskFootprint(*found_pup, existent_subfolder);
+  ExpectDiskFootprint(*found_pup, temp_file);
+
+  ASSERT_TRUE(base::DeleteFile(temp_file, false));
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Add a file deeper in a folder hierarchy, and it should still be found.
+  base::FilePath temp_folder;
+  ASSERT_TRUE(CreateTemporaryDirInDir(existent_subfolder, L"", &temp_folder));
+  ASSERT_TRUE(CreateTemporaryFileInDir(temp_folder, &temp_file));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+  EXPECT_EQ(4UL, found_pup->expanded_disk_footprints.size());
+  ExpectDiskFootprint(*found_pup, existent_folder);
+  ExpectDiskFootprint(*found_pup, existent_subfolder);
+  ExpectDiskFootprint(*found_pup, temp_folder);
+  ExpectDiskFootprint(*found_pup, temp_file);
+}
+
+TEST_F(ScannerTest, ExistentRelativeDiskFootprint) {
+  // Set up a relative disk footprint.
+  base::char16 special_folder_path[kMaxPath];
+  HRESULT hr = SHGetFolderPath(nullptr, CSIDL_PROGRAM_FILES, nullptr,
+                               SHGFP_TYPE_CURRENT, special_folder_path);
+  ASSERT_EQ(S_OK, hr);
+
+  base::ScopedTempDir scoped_temp_dir3;
+  ASSERT_TRUE(scoped_temp_dir3.CreateUniqueTempDirUnderPath(
+      base::FilePath(special_folder_path)));
+  base::FilePath existent_relative_footprint(
+      scoped_temp_dir3.GetPath().BaseName());
+  TestPUPData test_pup_data;
+  test_pup_data.AddDiskFootprint(k24ID, CSIDL_PROGRAM_FILES,
+                                 existent_relative_footprint.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k24ID);
+
+  // Empty folder should not be found.
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Now create a file in it, so it can be found.
+  base::FilePath temp_file;
+  ASSERT_TRUE(CreateTemporaryFileInDir(scoped_temp_dir3.GetPath(), &temp_file));
+
+  Scan();
+  ExpectSinglePUP(k24ID);
+  EXPECT_EQ(2UL, found_pup->expanded_disk_footprints.size());
+  ExpectDiskFootprint(*found_pup, scoped_temp_dir3.GetPath());
+  ExpectDiskFootprint(*found_pup, temp_file);
+}
+
+TEST_P(ScannerTestWithBitness, ProgramFilesDiskFootprint) {
+  ASSERT_TRUE(GetParam() == 32 || GetParam() == 64);
+
+  base::FilePath program_files;
+  if (GetParam() == 32) {
+    program_files = GetX86ProgramFilesPath(base::FilePath());
+  } else {
+    program_files = GetX64ProgramFilesPath(base::FilePath());
+  }
+
+  if (program_files.empty()) {
+    ASSERT_EQ(64, GetParam());
+    ASSERT_EQ(base::win::OSInfo::X86_ARCHITECTURE,
+              base::win::OSInfo::GetInstance()->architecture());
+    return;
+  }
+
+  base::ScopedTempDir scoped_temp_dir3;
+  ASSERT_TRUE(scoped_temp_dir3.CreateUniqueTempDirUnderPath(program_files));
+  base::FilePath existent_relative_footprint(
+      scoped_temp_dir3.GetPath().BaseName());
+  TestPUPData test_pup_data;
+  test_pup_data.AddDiskFootprint(k24ID, CSIDL_PROGRAM_FILES,
+                                 existent_relative_footprint.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k24ID);
+
+  // Empty folder should not be found.
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Now create a file in it, so it can be found.
+  base::FilePath temp_file;
+  ASSERT_TRUE(CreateTemporaryFileInDir(scoped_temp_dir3.GetPath(), &temp_file));
+
+  Scan();
+  ExpectSinglePUP(k24ID);
+  EXPECT_EQ(2UL, found_pup->expanded_disk_footprints.size());
+  ExpectDiskFootprint(*found_pup, scoped_temp_dir3.GetPath());
+  ExpectDiskFootprint(*found_pup, temp_file);
+}
+
+TEST_F(ScannerTest, UnicodeDiskFootprint) {
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+  base::FilePath existent_folder(scoped_temp_dir.GetPath());
+  ASSERT_TRUE(base::PathExists(existent_folder));
+  base::FilePath sub_folder(scoped_temp_dir.GetPath().Append(kValidUtf8Name));
+  ASSERT_TRUE(base::CreateDirectory(sub_folder));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddDiskFootprint(k42ID, 0, sub_folder.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+
+  // Now create a file in it, so it can be found.
+  base::FilePath temp_file;
+  ASSERT_TRUE(CreateTemporaryFileInDir(sub_folder, &temp_file));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+  EXPECT_EQ(2UL, found_pup->expanded_disk_footprints.size());
+  ExpectDiskFootprint(*found_pup, sub_folder);
+  ExpectDiskFootprint(*found_pup, temp_file);
+}
+
+TEST_F(ScannerTest, ExistentWildcardDiskFootprint) {
+  // Set up a folder only disk footprint.
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+  base::FilePath existent_folder(scoped_temp_dir.GetPath());
+  ASSERT_TRUE(base::PathExists(existent_folder));
+
+  base::FilePath existent_file(
+      scoped_temp_dir.GetPath().Append(kWildcardSearch1));
+  TestPUPData test_pup_data;
+  test_pup_data.AddDiskFootprint(k42ID, 0, existent_file.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+
+  // Add a file, and it should be found.
+  base::FilePath temp_file;
+  ASSERT_TRUE(CreateTemporaryFileInDir(existent_folder, &temp_file));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+  EXPECT_EQ(1UL, found_pup->expanded_disk_footprints.size());
+  ExpectDiskFootprint(*found_pup, temp_file);
+
+  ASSERT_TRUE(base::DeleteFile(temp_file, false));
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, ExistentRegistryFootprint) {
+  // Set up a registry footprint.
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, nullptr, nullptr,
+                                     REGISTRY_VALUE_MATCH_KEY);
+
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  test_pup_data.Reset({});
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, kValueName, nullptr,
+                                     REGISTRY_VALUE_MATCH_VALUE_NAME);
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kComplexValue));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  test_pup_data.Reset({});
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, kValueName, kValue,
+                                     REGISTRY_VALUE_MATCH_PARTIAL);
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_P(ScannerTestWithBitness, RedirectedRegistryFootprint) {
+  // This test doesn't use registry overriding because it relies on registry
+  // redirection between 32 bit and 64 bit views, which is impossible with
+  // registry overriding.
+
+  // Skip the test about 64-bit registry on 32-bit platforms.
+  if (GetParam() == 64 &&
+      base::win::OSInfo::X86_ARCHITECTURE ==
+          base::win::OSInfo::GetInstance()->architecture()) {
+    return;
+  }
+
+  // Use a GUID for the subkey to reduce the risk of collisions with real
+  // software.
+  base::string16 subkey =
+      base::StrCat({L"software\\cct-", kGUID1Str, L"\\dummy"});
+
+  // Remove existing keys.
+  REGSAM registry_views[] = {KEY_WOW64_32KEY, KEY_WOW64_64KEY};
+  for (REGSAM view : registry_views) {
+    base::win::RegKey test_key;
+    if (ERROR_SUCCESS ==
+        test_key.Open(HKEY_LOCAL_MACHINE, subkey.c_str(), KEY_READ | view)) {
+      test_key.DeleteKey(L"");
+    }
+  }
+
+  // Add a registry footprint matching under software.
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     subkey.c_str(), nullptr, nullptr,
+                                     REGISTRY_VALUE_MATCH_KEY);
+
+  // Create the key, so that we can look for an existent value.
+  REGSAM registry_view = GetParam() == 32 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
+  ScopedTempRegistryKey system_registry_key(HKEY_LOCAL_MACHINE, subkey.c_str(),
+                                            KEY_WRITE | registry_view);
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.Get()->WriteValue(kValueName, kValue));
+
+  // If the current system is 64-bit, check that the created key is not visible
+  // under the other registry view, otherwise we test nothing here.
+  if (base::win::OSInfo::X64_ARCHITECTURE ==
+      base::win::OSInfo::GetInstance()->architecture()) {
+    REGSAM other_view = GetParam() == 32 ? KEY_WOW64_64KEY : KEY_WOW64_32KEY;
+    base::win::RegKey missing_registry_key;
+    EXPECT_EQ(ERROR_FILE_NOT_FOUND,
+              missing_registry_key.Open(HKEY_LOCAL_MACHINE, subkey.c_str(),
+                                        KEY_READ | other_view));
+  }
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+  EXPECT_EQ(1UL, found_pup->expanded_registry_footprints.size());
+  const RegKeyPath key_path(HKEY_LOCAL_MACHINE, subkey.c_str(), registry_view);
+  ExpectRegistryFootprint(*found_pup, key_path, L"", L"",
+                          REGISTRY_VALUE_MATCH_KEY);
+}
+
+TEST_F(ScannerTest, ExistentRegistryFootprintWithExactShortenPath) {
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+  base::FilePath long_name_path(
+      scoped_temp_dir.GetPath().Append(kLongFileName));
+
+  // The file must exist for the short to long path name conversion to work.
+  base::File file(long_name_path, base::File::FLAG_OPEN_ALWAYS);
+  file.Close();
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(
+      k42ID, REGISTRY_ROOT_USERS, kBaseName, kValueName,
+      long_name_path.value().c_str(),
+      REGISTRY_VALUE_MATCH_COMMON_SEPARATED_SET_CONTAINS_PATH);
+
+  DWORD short_name_len =
+      GetShortPathName(long_name_path.value().c_str(), nullptr, 0);
+  ASSERT_GT(short_name_len, 0UL);
+
+  base::string16 short_name_path;
+  short_name_len = ::GetShortPathName(
+      long_name_path.value().c_str(),
+      base::WriteInto(&short_name_path, short_name_len), short_name_len);
+  ASSERT_GT(short_name_len, 0UL);
+
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_CURRENT_USER);
+
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_CURRENT_USER,
+                                                      kBaseName, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(
+                               kValueName, short_name_path.c_str()));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, ExistentRegistryFootprintWithShortenPathSubString) {
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+
+  base::FilePath long_name_path(
+      scoped_temp_dir.GetPath().Append(kLongFileName));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(
+      k42ID, REGISTRY_ROOT_USERS, kBaseName, kValueName,
+      long_name_path.value().c_str(),
+      REGISTRY_VALUE_MATCH_COMMON_SEPARATED_SET_CONTAINS_PATH);
+
+  // The file must exist for the short to long path name conversion to work.
+  base::File file(long_name_path, base::File::FLAG_OPEN_ALWAYS);
+  file.Close();
+
+  DWORD short_name_len =
+      GetShortPathName(long_name_path.value().c_str(), nullptr, 0);
+  ASSERT_GT(short_name_len, 0UL);
+
+  base::string16 short_name_path;
+  short_name_len = ::GetShortPathName(
+      long_name_path.value().c_str(),
+      base::WriteInto(&short_name_path, short_name_len), short_name_len);
+  ASSERT_GT(short_name_len, 0UL);
+
+  DCHECK_GT(PUPData::kCommonDelimitersLength, 2UL);
+  base::string16 complete_substr(kDummyFullPath);
+  complete_substr += PUPData::kCommonDelimiters[0];
+  complete_substr += short_name_path.c_str();
+  complete_substr += PUPData::kCommonDelimiters[1];
+  complete_substr += kOtherFullPath;
+
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_CURRENT_USER);
+
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_CURRENT_USER,
+                                                      kBaseName, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(
+                               kValueName, complete_substr.c_str()));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Now try when the requested substring is at the beginning.
+  complete_substr = short_name_path.data();
+  complete_substr += PUPData::kCommonDelimiters[2];
+  complete_substr += kOtherFullPath;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(
+                               kValueName, complete_substr.c_str()));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Now try when the requested substring is at the end.
+  complete_substr = kOtherFullPath;
+  complete_substr += PUPData::kCommonDelimiters[0];
+  complete_substr += short_name_path.data();
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(
+                               kValueName, complete_substr.c_str()));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, ExistentUsersRegistryFootprint) {
+  // Set up a users registry footprint.
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_CURRENT_USER);
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k24ID, REGISTRY_ROOT_USERS, kBaseName,
+                                     nullptr, nullptr,
+                                     REGISTRY_VALUE_MATCH_KEY);
+
+  base::win::RegKey users_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            users_registry_key.Create(HKEY_CURRENT_USER, kBaseName, KEY_WRITE));
+
+  Scan();
+  ExpectSinglePUP(k24ID);
+
+  test_pup_data.Reset({});
+  test_pup_data.AddRegistryFootprint(k24ID, REGISTRY_ROOT_USERS, kBaseName,
+                                     kValueName, nullptr,
+                                     REGISTRY_VALUE_MATCH_VALUE_NAME);
+  ASSERT_EQ(ERROR_SUCCESS, users_registry_key.WriteValue(kValueName, kValue));
+
+  Scan();
+  ExpectSinglePUP(k24ID);
+
+  test_pup_data.Reset({});
+  test_pup_data.AddRegistryFootprint(k24ID, REGISTRY_ROOT_USERS, kBaseName,
+                                     kValueName, kValueDifferentCase,
+                                     REGISTRY_VALUE_MATCH_CONTAINS);
+
+  Scan();
+  ExpectSinglePUP(k24ID);
+}
+
+TEST_F(ScannerTest, NonexistentWildcardRegistryFootprint) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, kWildcardSearch2, nullptr,
+                                     REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  // Make sure the key doesn't exist.
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_FILE_NOT_FOUND,
+            system_registry_key.Open(HKEY_LOCAL_MACHINE, kBaseName, KEY_READ));
+
+  // Now create the key, so that we can look for a nonexistent value.
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kBadValue));
+
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, ExistentWildcardRegistryFootprint) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  // Add a registry footprint matching any value names (i.e. "*").
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, L"*", nullptr,
+                                     REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  // Create the key, so that we can look for an existent value.
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(kValueName, kValue));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, ExistentSingleCharacterWildcardRegistryFootprint) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  // Add a registry footprint matching any the "bar" name (i.e. "b?r").
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, L"b?r", nullptr,
+                                     REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  // Create the key, so that we can look for an existent value.
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(L"bar", kValue));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, ExistentMultiCharactersWildcardRegistryFootprint) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  // Add a registry footprint matching any the "bar" name (i.e. "b*").
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, L"b*", nullptr,
+                                     REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  // Create the key, so that we can look for an existent value.
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(L"bar", kValue));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, ExistentMixedWildcardRegistryFootprint) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  // Add a registry footprint matching a temporary filename (i.e. "tmp*.???")
+  // which should match the given filename "tmp123456.log".
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, LR"(tmp*.???)", nullptr,
+                                     REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  // Create the key, so that we can look for an existent value.
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(L"tmp123456.log", kValue));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, KeyPathWithWildCardRegistryFootprint) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  // Add a registry footprint matching under software.
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     L"software\\t?st\\d*y", kValueName,
+                                     nullptr, REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  // Create the key, so that we can look for an existent value.
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                       L"software\\test\\dummy", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(kValueName, kValue));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, KeyPathWithNotMatchingWildCardRegistryFootprint) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  // Add a registry footprint matching under software.
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     L"software\\t?st\\foo*", kValueName,
+                                     nullptr, REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  // Create the key and a value that doesn't match the registry footprint
+  // pattern.
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                       L"software\\test\\dummy", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(kValueName, kValue));
+
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, KeyPathWithEscapedWildCardRegistryFootprint) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  // Add a registry footprint matching under software with an escaped wild-card.
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(
+      k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+      L"software\\t?st\\d" ESCAPE_REGISTRY_STR("*") L"y", kValueName, nullptr,
+      REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  // Create the key, so that we can look for an existent value.
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                       L"software\\test\\dummy", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(kValueName, kValue));
+
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, MixedFootprints) {
+  // Set up disk footprints.
+  base::ScopedTempDir scoped_temp_dir1;
+  ASSERT_TRUE(scoped_temp_dir1.CreateUniqueTempDir());
+  base::FilePath existent_folder(scoped_temp_dir1.GetPath());
+  ASSERT_TRUE(base::PathExists(existent_folder));
+
+  base::FilePath temp_file1;
+  ASSERT_TRUE(CreateTemporaryFileInDir(existent_folder, &temp_file1));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddDiskFootprint(k42ID, 0, existent_folder.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+
+  std::set<UwSId> pups_to_be_scanned;
+  pups_to_be_scanned.insert(k42ID);
+  std::set<UwSId> pups_to_be_found;
+  pups_to_be_found.insert(k42ID);
+
+  base::FilePath nonexistent_file(scoped_temp_dir1.GetPath().Append(kBaseName));
+  test_pup_data.AddDiskFootprint(kNonExistentID, 0,
+                                 nonexistent_file.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+  pups_to_be_scanned.insert(kNonExistentID);
+
+  // Set up relative disk footprints.
+  base::char16 special_folder_path[kMaxPath];
+  HRESULT hr = SHGetFolderPath(nullptr, CSIDL_LOCAL_APPDATA, nullptr,
+                               SHGFP_TYPE_CURRENT, special_folder_path);
+  ASSERT_EQ(S_OK, hr);
+
+  base::ScopedTempDir scoped_temp_dir2;
+  ASSERT_TRUE(scoped_temp_dir2.CreateUniqueTempDirUnderPath(
+      base::FilePath(special_folder_path)));
+
+  base::FilePath relative_path(scoped_temp_dir2.GetPath().BaseName());
+  test_pup_data.AddDiskFootprint(k24ID, CSIDL_LOCAL_APPDATA,
+                                 relative_path.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+  pups_to_be_scanned.insert(k24ID);
+  pups_to_be_found.insert(k24ID);
+
+  base::string16 nonexistent_relative_path(
+      base::FilePath(relative_path).Append(kBaseName).value());
+  test_pup_data.AddDiskFootprint(kNonExistentID, 0,
+                                 nonexistent_relative_path.c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+  pups_to_be_scanned.insert(kNonExistentID);
+
+  test_pup_data.AddDiskFootprint(k42ID, CSIDL_LOCAL_APPDATA,
+                                 relative_path.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+  pups_to_be_scanned.insert(k42ID);
+  pups_to_be_found.insert(k42ID);
+
+  base::FilePath temp_file2;
+  ASSERT_TRUE(
+      CreateTemporaryFileInDir(scoped_temp_dir2.GetPath(), &temp_file2));
+
+  Scan();
+  ExpectFoundPUPs(pups_to_be_found);
+
+  // Set up registry footprints.
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  struct TestData {
+    UwSId id;
+    const base::char16* key_path;
+    const base::char16* value_name;
+    const base::char16* value;
+    RegistryMatchRule rule;
+  } test_data[] = {
+      {k24ID, kBaseName, nullptr, nullptr, REGISTRY_VALUE_MATCH_KEY},
+      {kNonExistentID, kBadBaseName, kValueName, kValue,
+       REGISTRY_VALUE_MATCH_PARTIAL},
+      {k12ID, kBaseName, kValueName, kValue, REGISTRY_VALUE_MATCH_PARTIAL},
+      {kNonExistentID, kBaseName, kValueName, kBaValue,
+       REGISTRY_VALUE_MATCH_PARTIAL},
+      {kNonExistentID, kBaseName, kBaValue, kValue,
+       REGISTRY_VALUE_MATCH_PARTIAL},
+      {k42ID, kBaseName, kValueName, nullptr, REGISTRY_VALUE_MATCH_VALUE_NAME},
+  };
+  for (size_t i = 0; i < base::size(test_data); ++i) {
+    test_pup_data.AddRegistryFootprint(
+        test_data[i].id, REGISTRY_ROOT_LOCAL_MACHINE, test_data[i].key_path,
+        test_data[i].value_name, test_data[i].value, test_data[i].rule);
+    pups_to_be_scanned.insert(test_data[i].id);
+  }
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+  pups_to_be_found.insert(k24ID);
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kComplexValue));
+  pups_to_be_found.insert(k12ID);
+  pups_to_be_found.insert(k42ID);
+
+  Scan();
+  ExpectFoundPUPs(pups_to_be_found);
+
+  // Set up users registry footprints.
+  registry_override.OverrideRegistry(HKEY_CURRENT_USER);
+
+  test_pup_data.AddRegistryFootprint(k12ID, REGISTRY_ROOT_USERS, kBaseName,
+                                     kValueName, nullptr,
+                                     REGISTRY_VALUE_MATCH_VALUE_NAME);
+  pups_to_be_scanned.insert(k12ID);
+  test_pup_data.AddRegistryFootprint(kNonExistentID, REGISTRY_ROOT_USERS,
+                                     kBadBaseName, kValueName, kValue,
+                                     REGISTRY_VALUE_MATCH_EXACT);
+  pups_to_be_scanned.insert(kNonExistentID);
+  test_pup_data.AddRegistryFootprint(k84ID, REGISTRY_ROOT_USERS, kBaseName,
+                                     nullptr, nullptr,
+                                     REGISTRY_VALUE_MATCH_KEY);
+  pups_to_be_scanned.insert(k84ID);
+
+  base::win::RegKey users_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            users_registry_key.Create(HKEY_CURRENT_USER, kBaseName, KEY_WRITE));
+  pups_to_be_found.insert(k84ID);
+  ASSERT_EQ(ERROR_SUCCESS, users_registry_key.WriteValue(kValueName, kValue));
+  pups_to_be_found.insert(k12ID);
+
+  Scan();
+  ExpectFoundPUPs(pups_to_be_found);
+}
+
+TEST_F(ScannerTest, FindSomeWithinMany) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_CURRENT_USER);
+
+  base::win::RegKey users_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            users_registry_key.Create(HKEY_CURRENT_USER, kBaseName, KEY_WRITE));
+
+  TestPUPData test_pup_data;
+  std::set<UwSId> pups_to_find;
+  for (UwSId pup_id = 0; pup_id < kManyPUPs; ++pup_id) {
+    if (base::RandGenerator(kManyPUPs) % kFoundPUPsModuloBase == 0) {
+      test_pup_data.AddRegistryFootprint(pup_id, REGISTRY_ROOT_USERS, kBaseName,
+                                         nullptr, nullptr,
+                                         REGISTRY_VALUE_MATCH_KEY);
+      pups_to_find.insert(pup_id);
+    } else {
+      test_pup_data.AddRegistryFootprint(pup_id, REGISTRY_ROOT_USERS,
+                                         kBadBaseName, nullptr, nullptr,
+                                         REGISTRY_VALUE_MATCH_KEY);
+    }
+  }
+
+  Scan();
+  ExpectFoundPUPs(pups_to_find);
+}
+
+TEST_F(ScannerTest, DiskMatchActiveFileRule) {
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+  base::FilePath existent_folder(scoped_temp_dir.GetPath());
+  ASSERT_TRUE(base::PathExists(existent_folder));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddDiskFootprint(k42ID, 0, existent_folder.value().c_str(),
+                                 PUPData::DISK_MATCH_BINARY_FILE);
+  const PUPData::PUP* pup42 = PUPData::GetPUP(k42ID);
+
+  // No PUP should be found when no files are found.
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Add a non-active file, and it should still not be found.
+  base::FilePath temp_file1 = existent_folder.Append(L"file.inactive");
+  ASSERT_TRUE(CreateEmptyFile(temp_file1));
+
+  // No PUP should be found when no active files are found.
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Add a active file, and it should be found.
+  base::FilePath temp_file2;
+  ASSERT_TRUE(CreateTemporaryFileInDir(existent_folder, &temp_file2));
+
+  const base::char16* extensions[] = {
+      L".bla", L".dLl", L".ExE", L".foo", L".mshxml", L".URL", L".sys",
+  };
+
+  bool found_active = false;
+  bool found_not_active = false;
+  for (size_t i = 0; i < base::size(extensions); ++i) {
+    base::FilePath previous_file(temp_file2);
+    temp_file2 = temp_file2.ReplaceExtension(extensions[i]);
+    ASSERT_TRUE(ReplaceFile(previous_file, temp_file2, nullptr));
+    Scan();
+    if (PathHasActiveExtension(temp_file2)) {
+      found_active = true;
+      ExpectSinglePUP(k42ID);
+      EXPECT_EQ(3UL, pup42->expanded_disk_footprints.size());
+      ExpectDiskFootprint(*pup42, existent_folder);
+      ExpectDiskFootprint(*pup42, temp_file1);
+      ExpectDiskFootprint(*pup42, temp_file2);
+    } else {
+      found_not_active = true;
+      ExpectNoPUPsFound();
+    }
+  }
+  EXPECT_TRUE(found_not_active);
+  EXPECT_TRUE(found_active);
+}
+
+// Creates |num_folders| in |root_folder| returning the deepest folder created.
+// All of the created folders are added to |folders_created|, which is
+// intentionally not cleared by this function.
+// If |num_folders| <= 0, |root_folder| is returned.
+// If the directories aren't created, an empty FilePath is returned.
+base::FilePath CreateNestedFolders(
+    const base::FilePath& root_folder,
+    const base::string16& folder_name,
+    int num_folders,
+    std::vector<base::FilePath>* folders_created) {
+  base::FilePath folder(root_folder);
+  for (int i = 0; i < num_folders; ++i) {
+    folder = folder.Append(base::FilePath(folder_name));
+    folders_created->push_back(folder);
+  }
+
+  if (!CreateDirectory(folder))
+    folder.clear();
+
+  return folder;
+}
+
+int DiskMatchFileInFolderDepth(PUPData::DiskMatchRule rule) {
+  return rule - PUPData::DISK_MATCH_FILE_IN_FOLDER_DEPTH_1 + 1;
+}
+
+TEST_F(ScannerTest, DiskMatchFileInFolderRule) {
+  for (auto rule = PUPData::DISK_MATCH_FILE_IN_FOLDER_DEPTH_1;
+       rule < PUPData::DISK_MATCH_FILE_IN_FOLDER_END;
+       rule = static_cast<PUPData::DiskMatchRule>(rule + 1)) {
+    base::ScopedTempDir scoped_temp_dir;
+    ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+    base::FilePath root_folder(scoped_temp_dir.GetPath());
+
+    std::vector<base::FilePath> folders;
+    base::FilePath sub_folder = CreateNestedFolders(
+        root_folder, kBaseName, DiskMatchFileInFolderDepth(rule), &folders);
+    ASSERT_FALSE(sub_folder.empty());
+    base::FilePath file_to_match(sub_folder.Append(kOtherBaseName));
+
+    TestPUPData test_pup_data;
+    test_pup_data.AddDiskFootprint(k42ID, 0, file_to_match.value().c_str(),
+                                   rule);
+    const PUPData::PUP* pup42 = PUPData::GetPUP(k42ID);
+
+    // No PUP should be found when no files are found.
+    Scan();
+    ExpectNoPUPsFound();
+
+    // Add the file, and it should be found, as well as all its siblings.
+    ASSERT_TRUE(CreateEmptyFile(file_to_match)) << "Rule: " << rule;
+    base::FilePath temp_file1;
+    ASSERT_TRUE(CreateTemporaryFileInDir(sub_folder, &temp_file1))
+        << "Rule: " << rule;
+    base::FilePath temp_file2;
+    ASSERT_TRUE(CreateTemporaryFileInDir(sub_folder, &temp_file2))
+        << "Rule: " << rule;
+
+    Scan();
+    ExpectSinglePUP(k42ID);
+    EXPECT_EQ(3UL + folders.size(), pup42->expanded_disk_footprints.size())
+        << "Rule: " << rule;
+    for (const auto& folder : folders) {
+      ExpectDiskFootprint(*pup42, folder);
+    }
+    ExpectDiskFootprint(*pup42, file_to_match);
+    ExpectDiskFootprint(*pup42, temp_file1);
+    ExpectDiskFootprint(*pup42, temp_file2);
+  }
+}
+
+TEST_F(ScannerTest, DiskMatchAllFilesInFolderRule) {
+  for (auto rule = PUPData::DISK_MATCH_FILE_IN_FOLDER_DEPTH_1;
+       rule < PUPData::DISK_MATCH_FILE_IN_FOLDER_END;
+       rule = static_cast<PUPData::DiskMatchRule>(rule + 1)) {
+    base::ScopedTempDir scoped_temp_dir;
+    ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+    base::FilePath root_folder(scoped_temp_dir.GetPath());
+
+    std::vector<base::FilePath> folders;
+    base::FilePath sub_folder = CreateNestedFolders(
+        root_folder, kBaseName, DiskMatchFileInFolderDepth(rule), &folders);
+    ASSERT_FALSE(sub_folder.empty());
+    base::FilePath file_to_match(sub_folder.Append(kOtherBaseName));
+
+    TestPUPData test_pup_data;
+    test_pup_data.AddDiskFootprint(k42ID, 0, file_to_match.value().c_str(),
+                                   rule);
+    const PUPData::PUP* pup42 = PUPData::GetPUP(k42ID);
+
+    // No PUP should be found when no files are found.
+    Scan();
+    ExpectNoPUPsFound();
+
+    // Add the file, and it should be found, as well as a file in each folder.
+    ASSERT_TRUE(CreateEmptyFile(file_to_match)) << "Rule: " << rule;
+    std::vector<base::FilePath> extra_files;
+    for (const auto& folder : folders) {
+      base::FilePath extra_file;
+      ASSERT_TRUE(CreateTemporaryFileInDir(folder, &extra_file))
+          << "Rule: " << rule;
+      extra_files.push_back(extra_file);
+    }
+
+    Scan();
+    ExpectSinglePUP(k42ID);
+    // The initial 1 below is for the initial file that is matched.
+    EXPECT_EQ(1UL + folders.size() + extra_files.size(),
+              pup42->expanded_disk_footprints.size())
+        << "Rule: " << rule;
+    ExpectDiskFootprint(*pup42, file_to_match);
+    for (const auto& folder : folders) {
+      ExpectDiskFootprint(*pup42, folder);
+    }
+    for (const auto& extra_file : extra_files) {
+      ExpectDiskFootprint(*pup42, extra_file);
+    }
+  }
+}
+
+TEST_F(ScannerTest, DiskMatchFileIn3FoldersRule) {
+  for (auto rule = PUPData::DISK_MATCH_FILE_IN_FOLDER_DEPTH_1;
+       rule < PUPData::DISK_MATCH_FILE_IN_FOLDER_END;
+       rule = static_cast<PUPData::DiskMatchRule>(rule + 1)) {
+    base::ScopedTempDir scoped_temp_dir;
+    ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+    base::FilePath root_folder(scoped_temp_dir.GetPath());
+    ASSERT_TRUE(base::PathExists(root_folder));
+
+    std::vector<base::FilePath> folders;
+
+    folders.push_back(root_folder.Append(L"abc1"));
+    base::FilePath sub_folder =
+        CreateNestedFolders(*folders.rbegin(), kBaseName,
+                            DiskMatchFileInFolderDepth(rule) - 1, &folders);
+    ASSERT_FALSE(sub_folder.empty());
+    base::FilePath file_in_folder1(sub_folder.Append(kOtherBaseName));
+
+    folders.push_back(root_folder.Append(L"abc2"));
+    sub_folder =
+        CreateNestedFolders(*folders.rbegin(), kBaseName,
+                            DiskMatchFileInFolderDepth(rule) - 1, &folders);
+    ASSERT_FALSE(sub_folder.empty());
+    base::FilePath file_in_folder2(sub_folder.Append(kOtherBaseName));
+
+    folders.push_back(root_folder.Append(L"abc3"));
+    sub_folder =
+        CreateNestedFolders(*folders.rbegin(), kBaseName,
+                            DiskMatchFileInFolderDepth(rule) - 1, &folders);
+    ASSERT_FALSE(sub_folder.empty());
+    base::FilePath file_in_folder3(sub_folder.Append(kOtherBaseName));
+
+    base::FilePath pattern(root_folder.Append(L"abc?"));
+    for (int i = 0; i < DiskMatchFileInFolderDepth(rule) - 1; ++i) {
+      pattern = pattern.Append(kBaseName);
+    }
+    pattern = pattern.Append(kOtherBaseName);
+
+    TestPUPData test_pup_data;
+    test_pup_data.AddDiskFootprint(k42ID, 0, pattern.value().c_str(), rule);
+    const PUPData::PUP* pup42 = PUPData::GetPUP(k42ID);
+
+    // No PUP should be found when no files are found.
+    Scan();
+    EXPECT_TRUE(found_pups_.empty()) << "Rule: " << rule;
+
+    // Add the files, and they should be found.
+    ASSERT_TRUE(CreateEmptyFile(file_in_folder1)) << "Rule: " << rule;
+    ASSERT_TRUE(CreateEmptyFile(file_in_folder2)) << "Rule: " << rule;
+    ASSERT_TRUE(CreateEmptyFile(file_in_folder3)) << "Rule: " << rule;
+
+    Scan();
+    ExpectSinglePUP(k42ID);
+    EXPECT_EQ(3UL + folders.size(), pup42->expanded_disk_footprints.size())
+        << "Rule: " << rule;
+    for (const auto& folder : folders) {
+      ExpectDiskFootprint(*pup42, folder);
+    }
+    ExpectDiskFootprint(*pup42, file_in_folder1);
+    ExpectDiskFootprint(*pup42, file_in_folder2);
+    ExpectDiskFootprint(*pup42, file_in_folder3);
+  }
+}
+
+TEST_F(ScannerTest, DiskDontMatchFolderInFolderRule) {
+  for (auto rule = PUPData::DISK_MATCH_FILE_IN_FOLDER_DEPTH_1;
+       rule < PUPData::DISK_MATCH_FILE_IN_FOLDER_END;
+       rule = static_cast<PUPData::DiskMatchRule>(1 + rule)) {
+    base::ScopedTempDir scoped_temp_dir;
+    ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+    base::FilePath root_folder(scoped_temp_dir.GetPath());
+
+    std::vector<base::FilePath> folders;
+    base::FilePath sub_folder = CreateNestedFolders(
+        root_folder, kBaseName, DiskMatchFileInFolderDepth(rule), &folders);
+    ASSERT_FALSE(sub_folder.empty());
+    base::FilePath file_to_match(sub_folder.Append(kBaseName));
+
+    TestPUPData test_pup_data;
+    test_pup_data.AddDiskFootprint(k42ID, 0, file_to_match.value().c_str(),
+                                   rule);
+
+    // No PUP should be found when no files are found.
+    Scan();
+    ExpectNoPUPsFound();
+
+    // Add the footprint as a folder, and it should not be found.
+    ASSERT_TRUE(CreateDirectory(file_to_match));
+
+    // No PUP should be found when no files are found.
+    Scan();
+    EXPECT_TRUE(found_pups_.empty()) << "Rule: " << rule;
+  }
+}
+
+TEST_F(ScannerTest, DiskWithWow64Entry) {
+  base::ScopedPathOverride windows_override(base::DIR_WINDOWS);
+  base::FilePath windows_dir;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_WINDOWS, &windows_dir));
+  base::FilePath native_dir(windows_dir.Append(L"sysnative"));
+  ASSERT_TRUE(CreateDirectory(native_dir));
+
+  // Set up a folder with a file in 64-bit system folder.
+  ASSERT_TRUE(CreateFileInFolder(native_dir, L"dummy"));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddPUP(k42ID, PUPData::FLAGS_ACTION_REMOVE, nullptr,
+                       PUPData::kMaxFilesToRemoveSmallUwS);
+  test_pup_data.AddDiskFootprint(k42ID, CSIDL_SYSTEM, L"d?mm?",
+                                 PUPData::DISK_MATCH_ANY_FILE);
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  const PUPData::PUP* pup = PUPData::GetPUP(k42ID);
+  ExpectDiskFootprint(*pup, native_dir.Append(L"dummy"));
+}
+
+TEST_F(ScannerTest, RegistryMatchRuleExactValue) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, kValueName, kComplexValue,
+                                     REGISTRY_VALUE_MATCH_EXACT);
+
+  // Empty key must not match.
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Write a different value.
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(kValueName, kValue));
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Write the same value.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kComplexValue));
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, RegistryMatchRuleContainsValue) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, kValueName, kValue,
+                                     REGISTRY_VALUE_MATCH_CONTAINS);
+
+  // Empty key must not match.
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Write a different value.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kValueDifferentCase));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Write a different value.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kBaValue));
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Write the same value.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kComplexValue));
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, RegistryMatchRulePartialValue) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, kValueName, kValue,
+                                     REGISTRY_VALUE_MATCH_PARTIAL);
+
+  // Empty key must not match.
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Write a same value with different case.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kValueDifferentCase));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Write a different value.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kBaValue));
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Write the complex value which contains the value.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kComplexValue));
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, RegistryMatchRuleCommonSetSeparatedExactValue) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(
+      k42ID, REGISTRY_ROOT_LOCAL_MACHINE, kBaseName, kValueName, kValue,
+      REGISTRY_VALUE_MATCH_COMMON_SEPARATED_SET_EXACT);
+
+  // Write a set separated by common delimiters with the value as an element.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kCommonSetValue));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Write a set separated by a null character.
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(
+                               kValueName, kCommonSetWithNullValue,
+                               sizeof(kCommonSetWithNullValue), REG_SZ));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Write a set which contains the value, but isn't equals to.
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(
+                               kValueName, kBiggerCommaSetValue,
+                               sizeof(kBiggerCommaSetValue), REG_SZ));
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, RegistryMatchRuleCommonSetSeparatedContainsValue) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(
+      k42ID, REGISTRY_ROOT_LOCAL_MACHINE, kBaseName, kValueName, kValue,
+      REGISTRY_VALUE_MATCH_COMMON_SEPARATED_SET_CONTAINS);
+
+  // Write a set separated by common delimiters with the value as an element.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kCommonSetValue));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Write a set separated by a null character.
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(
+                               kValueName, kCommonSetWithNullValue,
+                               sizeof(kCommonSetWithNullValue), REG_SZ));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Write a set which contains the value, but isn't equals to.
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(
+                               kValueName, kBiggerCommaSetValue,
+                               sizeof(kBiggerCommaSetValue), REG_SZ));
+  Scan();
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, RegistryMatchRuleCommaSetSeparatedExactValue) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(
+      k42ID, REGISTRY_ROOT_LOCAL_MACHINE, kBaseName, kValueName, kValue,
+      REGISTRY_VALUE_MATCH_COMMA_SEPARATED_SET_EXACT);
+
+  // Empty key must not match.
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Write the same value.
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(kValueName, kValue));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Write set which contains the exact value.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kCommaSetValue));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Write set which contains a partial match.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kBiggerCommaSetValue));
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Write set without the value.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kBadCommaSetValue));
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, RegistryMatchRuleCommaSetSeparatedContainstValue) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(
+      k42ID, REGISTRY_ROOT_LOCAL_MACHINE, kBaseName, kValueName, kValue,
+      REGISTRY_VALUE_MATCH_COMMA_SEPARATED_SET_CONTAINS);
+
+  // Empty key must not match.
+  Scan();
+  ExpectNoPUPsFound();
+
+  // Write the same value.
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.WriteValue(kValueName, kValue));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Write set which contains the exact value.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kCommaSetValue));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Write set which contains a partial match.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kBiggerCommaSetValue));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // Write set without the value.
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kBadCommaSetValue));
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, ReportOnlyPUP) {
+  // Set up a folder only disk footprint.
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+  base::FilePath existent_folder(scoped_temp_dir.GetPath());
+  ASSERT_TRUE(base::PathExists(existent_folder));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddPUP(k42ID, PUPData::FLAGS_NONE, nullptr,
+                       PUPData::kMaxFilesToRemoveSmallUwS);
+  test_pup_data.AddDiskFootprint(k42ID, 0, existent_folder.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+
+  // Add a file, and it should be reported but not found.
+  base::FilePath temp_file;
+  ASSERT_TRUE(CreateTemporaryFileInDir(existent_folder, &temp_file));
+
+  Scan();
+  EXPECT_FALSE(found_pups_.empty());
+  EXPECT_FALSE(found_pup_to_remove_);
+  EXPECT_TRUE(found_report_only_);
+}
+
+TEST_F(ScannerTest, StopScanning) {
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_CURRENT_USER);
+
+  base::win::RegKey users_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            users_registry_key.Create(HKEY_CURRENT_USER, kBaseName, KEY_WRITE));
+
+  TestPUPData test_pup_data;
+  std::set<UwSId> pups_to_find;
+  for (UwSId pup_id = 0; pup_id < kSomePUPs; ++pup_id) {
+    if (base::RandGenerator(kSomePUPs) % kFoundPUPsModuloBase == 0) {
+      test_pup_data.AddRegistryFootprint(pup_id, REGISTRY_ROOT_USERS, kBaseName,
+                                         nullptr, nullptr,
+                                         REGISTRY_VALUE_MATCH_KEY);
+      pups_to_find.insert(pup_id);
+    } else {
+      for (size_t i = 0; i < 100; ++i) {
+        test_pup_data.AddRegistryFootprint(pup_id, REGISTRY_ROOT_USERS,
+                                           kBadBaseName, nullptr, nullptr,
+                                           REGISTRY_VALUE_MATCH_KEY);
+        test_pup_data.AddDiskFootprint(pup_id, 0, kBadBaseName,
+                                       PUPData::DISK_MATCH_ANY_FILE);
+      }
+    }
+  }
+
+  // Post the stop call to the main loop so that we can start the scan and get
+  // it to stop while we wait for it to be done.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ScannerTest::StopScanner, base::Unretained(this)));
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, RunningCustomMatchers) {
+  TestPUPData test_pup_data;
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher1);
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher3);
+
+  g_test_custom_matcher1_called = false;
+  g_test_custom_matcher2_called = false;
+  g_test_custom_matcher3_called = false;
+  Scan();
+  ASSERT_TRUE(g_test_custom_matcher1_called);
+  ASSERT_FALSE(g_test_custom_matcher2_called);
+  ASSERT_TRUE(g_test_custom_matcher3_called);
+  ExpectSinglePUP(k42ID);
+}
+
+TEST_F(ScannerTest, RunningCustomMatchersNoScanAndRemove) {
+  TestPUPData test_pup_data;
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher2);
+
+  g_test_custom_matcher1_called = false;
+  g_test_custom_matcher2_called = false;
+  g_test_custom_matcher3_called = false;
+  Scan();
+  ASSERT_FALSE(g_test_custom_matcher1_called);
+  ASSERT_TRUE(g_test_custom_matcher2_called);
+  ASSERT_FALSE(g_test_custom_matcher3_called);
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, RunningCustomMatchersNothingFound) {
+  TestPUPData test_pup_data;
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher3);
+
+  g_test_custom_matcher1_called = false;
+  g_test_custom_matcher2_called = false;
+  g_test_custom_matcher3_called = false;
+  Scan();
+  ASSERT_FALSE(g_test_custom_matcher1_called);
+  ASSERT_FALSE(g_test_custom_matcher2_called);
+  ASSERT_TRUE(g_test_custom_matcher3_called);
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, RunningCustomMatchersWithError) {
+  TestPUPData test_pup_data;
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher4);
+
+  // The custom scanner returns an error, and scanning this pup is aborted.
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, RunningCustomMatchersWithErrorAndFootprint) {
+  TestPUPData test_pup_data;
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher1);
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher4);
+
+  // The custom scanner returns an error, and scanning this pup is aborted
+  // even if there is a footprint matched by |TestCustomMatcher1|.
+  Scan();
+  ExpectNoPUPsFound();
+}
+
+TEST_F(ScannerTest, RunningCustomMatchersKeepDiskActiveFootprintFound) {
+  TestPUPData test_pup_data;
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher5);
+
+  // Add a found disk footprint
+  base::ScopedTempDir scoped_temp_dir1;
+  ASSERT_TRUE(scoped_temp_dir1.CreateUniqueTempDir());
+  base::FilePath existent_folder(scoped_temp_dir1.GetPath());
+  ASSERT_TRUE(base::PathExists(existent_folder));
+  base::FilePath temp_file;
+  ASSERT_TRUE(CreateTemporaryFileInDir(existent_folder, &temp_file));
+
+  test_pup_data.AddDiskFootprint(k42ID, 0, existent_folder.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+
+  g_test_custom_matcher5_found = false;
+  Scan();
+  EXPECT_TRUE(g_test_custom_matcher5_found);
+}
+
+TEST_F(ScannerTest, RunningCustomMatchersDefaultActiveFootprintFound) {
+  TestPUPData test_pup_data;
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher5);
+
+  g_test_custom_matcher5_found = false;
+  Scan();
+  EXPECT_FALSE(g_test_custom_matcher5_found);
+}
+
+TEST_F(ScannerTest, ScanRegistrySingleCharacterWildcardFootprints) {
+  TestPUPData test_pup_data;
+  std::vector<UwSId> pup_ids;
+  pup_ids.push_back(k42ID);
+
+  // Set up a local machine registry footprint.
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kRegistryKeyPath, kValueNameSingleWildcard,
+                                     nullptr, REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  base::win::RegKey registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            registry_key.Create(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
+                                KEY_ALL_ACCESS));
+
+  ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(kValueName, kComplexValue));
+  ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(kValueName1, kComplexValue));
+  ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(kValueName2, kComplexValue));
+  ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(kValueName3, kComplexValue));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+  EXPECT_EQ(3UL, found_pup->expanded_registry_footprints.size());
+
+  // |kValueName| should not match the regular expression but |kValueName1|,
+  // |kValueName2| and |kValueName3| must be matched.
+  const RegKeyPath key_path(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
+                            KEY_WOW64_32KEY);
+  ExpectRegistryFootprint(*found_pup, key_path, kValueName1, L"",
+                          REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  ExpectRegistryFootprint(*found_pup, key_path, kValueName2, L"",
+                          REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  ExpectRegistryFootprint(*found_pup, key_path, kValueName3, L"",
+                          REGISTRY_VALUE_MATCH_VALUE_NAME);
+}
+
+TEST_F(ScannerTest, ScanWithRegistryMultiCharactersWildcardFootprints) {
+  TestPUPData test_pup_data;
+  std::vector<UwSId> pup_ids;
+  pup_ids.push_back(k42ID);
+
+  // Set up a local machine registry footprint.
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kRegistryKeyPath, kValueNameMultiWildcard,
+                                     nullptr, REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  base::win::RegKey registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            registry_key.Create(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
+                                KEY_ALL_ACCESS));
+
+  ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(kOtherBaseName, kFooValue));
+  ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(kBaseName, kComplexValue));
+  ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(kValueName1, kComplexValue));
+  ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(kValueName2, kComplexValue));
+  ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(kValueName3, kComplexValue));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // The footprint |kOtherBaseName| is not matched by the regular expression.
+  // |kBaseName|, |kValueName1|, |kValueName2| and |kValueName3| must be
+  // matched.
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+  EXPECT_EQ(4UL, found_pup->expanded_registry_footprints.size());
+
+  const RegKeyPath key_path(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
+                            KEY_WOW64_32KEY);
+  ExpectRegistryFootprint(*found_pup, key_path, kBaseName, L"",
+                          REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  ExpectRegistryFootprint(*found_pup, key_path, kValueName1, L"",
+                          REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  ExpectRegistryFootprint(*found_pup, key_path, kValueName2, L"",
+                          REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  ExpectRegistryFootprint(*found_pup, key_path, kValueName3, L"",
+                          REGISTRY_VALUE_MATCH_VALUE_NAME);
+}
+
+TEST_F(ScannerTest, ScanWithRegistryWildcardAndRuleFootprints) {
+  TestPUPData test_pup_data;
+  std::vector<UwSId> pup_ids;
+  pup_ids.push_back(k42ID);
+
+  // Set up a local machine registry footprint.
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  test_pup_data.AddRegistryFootprint(
+      k42ID, REGISTRY_ROOT_LOCAL_MACHINE, kRegistryKeyPath,
+      kValueNameSingleWildcard, kFooValue,
+      REGISTRY_VALUE_MATCH_COMMON_SEPARATED_SET_EXACT);
+
+  base::win::RegKey registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            registry_key.Create(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
+                                KEY_ALL_ACCESS));
+
+  ASSERT_EQ(ERROR_SUCCESS,
+            registry_key.WriteValue(kValueName1, kSetWithCommonValue1));
+  ASSERT_EQ(ERROR_SUCCESS,
+            registry_key.WriteValue(kValueName2, kSetWithCommonValue2));
+  ASSERT_EQ(ERROR_SUCCESS,
+            registry_key.WriteValue(kValueName3, kSetWithCommonValue3));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+  EXPECT_EQ(3UL, found_pup->expanded_registry_footprints.size());
+
+  const RegKeyPath key_path(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
+                            KEY_WOW64_32KEY);
+  ExpectRegistryFootprint(*found_pup, key_path, kValueName1, kFooValue,
+                          REGISTRY_VALUE_MATCH_COMMON_SEPARATED_SET_EXACT);
+
+  ExpectRegistryFootprint(*found_pup, key_path, kValueName2, kFooValue,
+                          REGISTRY_VALUE_MATCH_COMMON_SEPARATED_SET_EXACT);
+
+  ExpectRegistryFootprint(*found_pup, key_path, kValueName3, kFooValue,
+                          REGISTRY_VALUE_MATCH_COMMON_SEPARATED_SET_EXACT);
+}
+
+TEST_F(ScannerTest, ScanWithKeyPathWildCardsRegistryFootprints) {
+  TestPUPData test_pup_data;
+  std::vector<UwSId> pup_ids;
+  pup_ids.push_back(k42ID);
+
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     L"software\\t*\\du??y", L"b*", nullptr,
+                                     REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  base::win::RegKey test1_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            test1_registry_key.Create(
+                HKEY_LOCAL_MACHINE, L"software\\test1\\dummy", KEY_ALL_ACCESS));
+  base::win::RegKey test2_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            test2_registry_key.Create(
+                HKEY_LOCAL_MACHINE, L"software\\test2\\dummy", KEY_ALL_ACCESS));
+
+  base::win::RegKey best_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            best_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                     L"software\\best\\dummy", KEY_ALL_ACCESS));
+
+  base::win::RegKey unused_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            unused_registry_key.Create(HKEY_LOCAL_MACHINE, L"software\\best",
+                                       KEY_ALL_ACCESS));
+
+  ASSERT_EQ(ERROR_SUCCESS, test1_registry_key.WriteValue(L"foo", kValue));
+  ASSERT_EQ(ERROR_SUCCESS, test1_registry_key.WriteValue(L"bar", kValue));
+  ASSERT_EQ(ERROR_SUCCESS, test1_registry_key.WriteValue(L"bat", kValue));
+  ASSERT_EQ(ERROR_SUCCESS, test2_registry_key.WriteValue(L"foo", kValue));
+  ASSERT_EQ(ERROR_SUCCESS, test2_registry_key.WriteValue(L"bar", kValue));
+  ASSERT_EQ(ERROR_SUCCESS, test2_registry_key.WriteValue(L"bat", kValue));
+  ASSERT_EQ(ERROR_SUCCESS, best_registry_key.WriteValue(L"bat", kValue));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+  EXPECT_EQ(4UL, found_pup->expanded_registry_footprints.size());
+
+  const RegKeyPath key_path(HKEY_LOCAL_MACHINE, L"software\\test1\\dummy",
+                            KEY_WOW64_32KEY);
+  ExpectRegistryFootprint(*found_pup, key_path, L"bar", L"",
+                          REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  ExpectRegistryFootprint(*found_pup, key_path, L"bat", L"",
+                          REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  ExpectRegistryFootprint(*found_pup, key_path, L"bar", L"",
+                          REGISTRY_VALUE_MATCH_VALUE_NAME);
+
+  ExpectRegistryFootprint(*found_pup, key_path, L"bat", L"",
+                          REGISTRY_VALUE_MATCH_VALUE_NAME);
+}
+
+TEST_F(ScannerTest, ScanRegistryKeyWithEscapedStar) {
+  TestPUPData test_pup_data;
+  std::vector<UwSId> pup_ids;
+  pup_ids.push_back(k42ID);
+
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  constexpr base::char16 kRegistryPathWithStar[] = L"foo\\*";
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     L"foo\\" ESCAPE_REGISTRY_STR("*"), nullptr,
+                                     nullptr, REGISTRY_VALUE_MATCH_KEY);
+
+  base::win::RegKey test_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            test_registry_key.Create(HKEY_LOCAL_MACHINE, kRegistryPathWithStar,
+                                     KEY_ALL_ACCESS));
+
+  ASSERT_EQ(ERROR_SUCCESS,
+            test_registry_key.Create(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
+                                     KEY_ALL_ACCESS));
+  Scan();
+  ExpectSinglePUP(k42ID);
+
+  // As the regular expression contains an escaped wild-card, only the exact
+  // key |kRegistryPathWithStar| must be matched. |kRegistryKeyPath| must not
+  // be matched.
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+  EXPECT_EQ(1UL, found_pup->expanded_registry_footprints.size());
+
+  ExpectRegistryFootprint(
+      *found_pup, RegKeyPath(HKEY_LOCAL_MACHINE, L"foo\\*", KEY_WOW64_32KEY),
+      L"", L"", REGISTRY_VALUE_MATCH_KEY);
+}
+
+TEST_F(ScannerTest, RegistryFootprintForDetectOnlyUws) {
+  TestPUPData test_pup_data;
+  test_pup_data.AddPUP(k12ID, PUPData::FLAGS_NONE, "test",
+                       PUPData::kMaxFilesToRemoveSmallUwS);
+  test_pup_data.AddPUP(k24ID, PUPData::FLAGS_NONE, "test2",
+                       PUPData::kMaxFilesToRemoveSmallUwS);
+
+  // Set up a local machine registry footprint.
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  test_pup_data.AddRegistryFootprint(k12ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kRegistryKeyPath, nullptr, nullptr,
+                                     REGISTRY_VALUE_MATCH_KEY);
+
+  test_pup_data.AddRegistryFootprint(k24ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kRegistryKeyPath, nullptr, nullptr,
+                                     REGISTRY_VALUE_MATCH_KEY);
+
+  base::win::RegKey registry_key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            registry_key.Create(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
+                                KEY_ALL_ACCESS));
+
+  Scan();
+
+  const RegKeyPath key_path(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
+                            KEY_WOW64_32KEY);
+
+  std::set<UwSId> pups_to_be_found;
+  pups_to_be_found.insert(k12ID);
+  pups_to_be_found.insert(k24ID);
+  ExpectFoundPUPs(pups_to_be_found);
+
+  const PUPData::PUP* found_pup12 = PUPData::GetPUP(k12ID);
+  ExpectRegistryFootprint(*found_pup12, key_path, L"", L"",
+                          REGISTRY_VALUE_MATCH_KEY);
+
+  const PUPData::PUP* found_pup24 = PUPData::GetPUP(k24ID);
+  ExpectRegistryFootprint(*found_pup24, key_path, L"", L"",
+                          REGISTRY_VALUE_MATCH_KEY);
+}
+
+TEST_F(ScannerTest, FindOnlyOneDiskFootprint) {
+  base::ScopedTempDir scoped_temp_dir1;
+  ASSERT_TRUE(scoped_temp_dir1.CreateUniqueTempDir());
+  base::FilePath existent_folder_1(scoped_temp_dir1.GetPath());
+  ASSERT_TRUE(base::PathExists(existent_folder_1));
+  base::FilePath temp_file_1;
+  ASSERT_TRUE(CreateTemporaryFileInDir(existent_folder_1, &temp_file_1));
+  base::FilePath temp_file_2;
+  ASSERT_TRUE(CreateTemporaryFileInDir(existent_folder_1, &temp_file_2));
+
+  base::ScopedTempDir scoped_temp_dir2;
+  ASSERT_TRUE(scoped_temp_dir2.CreateUniqueTempDir());
+  base::FilePath existent_folder_2(scoped_temp_dir2.GetPath());
+  ASSERT_TRUE(base::PathExists(existent_folder_2));
+  base::FilePath temp_file_3;
+  ASSERT_TRUE(CreateTemporaryFileInDir(existent_folder_2, &temp_file_3));
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddDiskFootprint(k42ID, 0, temp_file_1.value().c_str(),
+                                 PUPData::DISK_MATCH_FILE_IN_FOLDER_DEPTH_1);
+  test_pup_data.AddDiskFootprint(k42ID, 0, temp_file_3.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+
+  options_.set_only_one_footprint(false);
+  Scan();
+  ExpectSinglePUP(k42ID);
+  EXPECT_EQ(4UL, found_pup->expanded_disk_footprints.size());
+  ExpectDiskFootprint(*found_pup, temp_file_1);
+  ExpectDiskFootprint(*found_pup, temp_file_2);
+  ExpectDiskFootprint(*found_pup, existent_folder_1);
+  ExpectDiskFootprint(*found_pup, temp_file_3);
+
+  options_.set_only_one_footprint(true);
+  Scan();
+  ExpectSinglePUP(k42ID);
+  ASSERT_EQ(1UL, found_pups_.size());
+  EXPECT_EQ(1UL, found_pup->expanded_disk_footprints.size());
+  ExpectDiskFootprint(*found_pup, temp_file_1);
+}
+
+TEST_F(ScannerTest, FindOnlyOneRegistryFootprints) {
+  // Set up a registry footprint.
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  TestPUPData test_pup_data;
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, nullptr, nullptr,
+                                     REGISTRY_VALUE_MATCH_KEY);
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, kValueName, nullptr,
+                                     REGISTRY_VALUE_MATCH_VALUE_NAME);
+  ASSERT_EQ(ERROR_SUCCESS,
+            system_registry_key.WriteValue(kValueName, kComplexValue));
+
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+
+  options_.set_only_one_footprint(false);
+  Scan();
+  ExpectSinglePUP(k42ID);
+  EXPECT_EQ(2UL, found_pup->expanded_registry_footprints.size());
+
+  options_.set_only_one_footprint(true);
+  Scan();
+  ExpectSinglePUP(k42ID);
+  EXPECT_EQ(1UL, found_pup->expanded_registry_footprints.size());
+}
+
+TEST_F(ScannerTest, FindOnlyOneCustomMatchers) {
+  TestPUPData test_pup_data;
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher1);
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher2);
+
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+
+  options_.set_only_one_footprint(false);
+  Scan();
+  ExpectSinglePUP(k42ID);
+  EXPECT_EQ(2UL, found_pup->expanded_disk_footprints.size());
+  ExpectDiskFootprint(*found_pup, base::FilePath(kDummyFullPath));
+  ExpectDiskFootprint(*found_pup, base::FilePath(kOtherFullPath));
+  EXPECT_TRUE(g_test_custom_matcher1_called);
+  EXPECT_TRUE(g_test_custom_matcher2_called);
+
+  options_.set_only_one_footprint(true);
+  Scan();
+  ExpectSinglePUP(k42ID);
+  EXPECT_EQ(1UL, found_pup->expanded_disk_footprints.size());
+  ExpectDiskFootprint(*found_pup, base::FilePath(kDummyFullPath));
+  EXPECT_TRUE(g_test_custom_matcher1_called);
+  EXPECT_FALSE(g_test_custom_matcher2_called);
+}
+
+TEST_F(ScannerTest, FindOnlyOneAmongAllTypes) {
+  // Start with just a custom matcher.
+  TestPUPData test_pup_data;
+  test_pup_data.AddCustomMatcher(k42ID, &TestCustomMatcher1);
+
+  const PUPData::PUP* found_pup = PUPData::GetPUP(k42ID);
+
+  options_.set_only_one_footprint(true);
+  Scan();
+  ExpectSinglePUP(k42ID);
+  EXPECT_EQ(1UL, found_pup->expanded_disk_footprints.size());
+  EXPECT_EQ(0UL, found_pup->expanded_registry_footprints.size());
+  ExpectDiskFootprint(*found_pup, base::FilePath(kDummyFullPath));
+  EXPECT_TRUE(g_test_custom_matcher1_called);
+
+  // Now add a registry footprint and only it should be found.
+  registry_util::RegistryOverrideManager registry_override;
+  registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
+
+  test_pup_data.AddRegistryFootprint(k42ID, REGISTRY_ROOT_LOCAL_MACHINE,
+                                     kBaseName, nullptr, nullptr,
+                                     REGISTRY_VALUE_MATCH_KEY);
+  base::win::RegKey system_registry_key;
+  ASSERT_EQ(ERROR_SUCCESS, system_registry_key.Create(HKEY_LOCAL_MACHINE,
+                                                      kBaseName, KEY_WRITE));
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+  EXPECT_EQ(0UL, found_pup->expanded_disk_footprints.size());
+  EXPECT_EQ(1UL, found_pup->expanded_registry_footprints.size());
+  EXPECT_FALSE(g_test_custom_matcher1_called);
+
+  // Now add a disk footprint and onlyit should be found.
+  // Set up a folder only disk footprint.
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+  base::FilePath existent_folder(scoped_temp_dir.GetPath());
+  ASSERT_TRUE(base::PathExists(existent_folder));
+  base::FilePath temp_file;
+  ASSERT_TRUE(CreateTemporaryFileInDir(existent_folder, &temp_file));
+
+  test_pup_data.AddDiskFootprint(k42ID, 0, temp_file.value().c_str(),
+                                 PUPData::DISK_MATCH_ANY_FILE);
+
+  Scan();
+  ExpectSinglePUP(k42ID);
+  EXPECT_EQ(1UL, found_pup->expanded_disk_footprints.size());
+  EXPECT_EQ(0UL, found_pup->expanded_registry_footprints.size());
+  ExpectDiskFootprint(*found_pup, temp_file);
+  EXPECT_FALSE(g_test_custom_matcher1_called);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/test/BUILD.gn b/chrome/chrome_cleaner/test/BUILD.gn
index 3a6894e1..e8201d9 100644
--- a/chrome/chrome_cleaner/test/BUILD.gn
+++ b/chrome/chrome_cleaner/test/BUILD.gn
@@ -67,6 +67,7 @@
     "test_registry_util.h",
     "test_settings_util.cc",
     "test_settings_util.h",
+    "test_signature_matcher.h",
     "test_task_scheduler.cc",
     "test_task_scheduler.h",
     "test_util.cc",
@@ -82,6 +83,8 @@
     "//chrome/chrome_cleaner/os:cleaner_os",
     "//chrome/chrome_cleaner/os:common_os",
     "//chrome/chrome_cleaner/pup_data:pup_data_base",
+    "//chrome/chrome_cleaner/scanner:matcher_util",
+    "//chrome/chrome_cleaner/scanner:signature_matcher_api",
     "//chrome/chrome_cleaner/settings:settings",
     "//chrome/chrome_cleaner/strings",
     "//components/chrome_cleaner/public/constants:constants",
diff --git a/chrome/chrome_cleaner/test/test_signature_matcher.h b/chrome/chrome_cleaner/test/test_signature_matcher.h
new file mode 100644
index 0000000..17266a83
--- /dev/null
+++ b/chrome/chrome_cleaner/test/test_signature_matcher.h
@@ -0,0 +1,150 @@
+// 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_SIGNATURE_MATCHER_H_
+#define CHROME_CHROME_CLEANER_TEST_TEST_SIGNATURE_MATCHER_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/file_version_info.h"
+#include "base/files/file_util.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/lock.h"
+#include "chrome/chrome_cleaner/os/file_path_sanitization.h"
+#include "chrome/chrome_cleaner/scanner/matcher_util.h"
+#include "chrome/chrome_cleaner/scanner/signature_matcher_api.h"
+
+namespace chrome_cleaner {
+
+// A signature matcher implementation used for testing.
+class TestSignatureMatcher : public SignatureMatcherAPI {
+ public:
+  TestSignatureMatcher() : scan_error_(false) {}
+
+  bool MatchFileDigestInfo(const base::FilePath& path,
+                           size_t* filesize,
+                           std::string* digest,
+                           const FileDigestInfo& digest_info) const override {
+    DCHECK(filesize);
+    DCHECK(digest);
+    base::AutoLock lock(lock_);
+    const auto& matched_digest_info =
+        matched_digest_info_.find(NormalizePath(path));
+    if (matched_digest_info == matched_digest_info_.end())
+      return false;
+    if (*filesize == 0) {
+      DCHECK(digest->empty());
+      *filesize = matched_digest_info->second.filesize;
+      *digest = matched_digest_info->second.digest;
+    } else {
+      DCHECK_EQ(matched_digest_info->second.filesize, *filesize);
+      DCHECK_EQ(matched_digest_info->second.digest, *digest);
+    }
+    return matched_digest_info->second.filesize == digest_info.filesize &&
+           matched_digest_info->second.digest == digest_info.digest;
+  }
+
+  bool ComputeSHA256DigestOfPath(const base::FilePath& path,
+                                 std::string* digest) const override {
+    DCHECK(digest);
+    base::AutoLock lock(lock_);
+    const auto& matched_digest = matched_digests_.find(NormalizePath(path));
+    if (matched_digest == matched_digests_.end())
+      return false;
+    *digest = matched_digest->second;
+    return true;
+  }
+
+  bool RetrieveVersionInformation(
+      const base::FilePath& path,
+      VersionInformation* information) const override {
+    DCHECK(information);
+    base::AutoLock lock(lock_);
+
+    const auto& matched_information =
+        matched_version_informations_.find(NormalizePath(path));
+    if (matched_information == matched_version_informations_.end())
+      return false;
+    *information = matched_information->second;
+    return true;
+  }
+
+  void Reset() {
+    base::AutoLock lock(lock_);
+    scan_error_ = false;
+    matched_basenames_.clear();
+    matched_digests_.clear();
+    computed_digests_.clear();
+    matched_version_informations_.clear();
+  }
+
+  void MatchDigest(const base::FilePath& path, const char* digest) {
+    base::AutoLock lock(lock_);
+    matched_digests_[NormalizePath(path)] = digest;
+  }
+
+  void MatchDigestInfo(const base::FilePath& path,
+                       const char* digest,
+                       size_t filesize) {
+    base::AutoLock lock(lock_);
+    const base::FilePath normalized_path = NormalizePath(path);
+    matched_digest_info_[normalized_path].digest = digest;
+    matched_digest_info_[normalized_path].filesize = filesize;
+  }
+
+  void MatchVersionInformation(const base::FilePath& path,
+                               const VersionInformation& information) {
+    matched_version_informations_[NormalizePath(path)] = information;
+  }
+
+  size_t CountMatchDigestCalled() {
+    base::AutoLock lock(lock_);
+    return matched_digests_.size();
+  }
+
+  bool IsMatchDigestCalled(const base::FilePath& path) {
+    base::AutoLock lock(lock_);
+    return matched_digests_.find(NormalizePath(path)) != matched_digests_.end();
+  }
+
+  void MatchBaseName(const base::FilePath& path,
+                     const std::string& identifier) {
+    base::AutoLock lock(lock_);
+    matched_basenames_[NormalizePath(path).BaseName()] = identifier;
+  }
+
+  void ForceScanFailure() {
+    base::AutoLock lock(lock_);
+    scan_error_ = true;
+  }
+
+ private:
+  struct TestFileDigestInfo {
+    std::string digest;
+    size_t filesize;
+  };
+
+  bool scan_error_;
+
+  // Map paths to signature identifiers. When the given path is scanned, the
+  // mapped identifier is returned.
+  std::map<base::FilePath, std::string> matched_basenames_;
+  std::map<base::FilePath, std::string> matched_digests_;
+  std::map<base::FilePath, TestFileDigestInfo> matched_digest_info_;
+  std::map<base::FilePath, VersionInformation> matched_version_informations_;
+
+  // Keep track of calls and parameters done.
+  std::set<base::FilePath> computed_digests_;
+
+  // Must be held for all access to all data since |ScanFile| can be called
+  // from other threads.
+  mutable base::Lock lock_;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_TEST_TEST_SIGNATURE_MATCHER_H_
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 7b7c6536..1c03afd7 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1148,17 +1148,10 @@
 #endif  // !OS_CHROMEOS && !OS_ANDROID
 
 #if defined(OS_CHROMEOS)
-// List of all printers that the user has configured.
-const char kPrintingDevices[] = "printing.devices";
-
 // List of printers configured by policy.
 const char kRecommendedNativePrinters[] =
     "native_printing.recommended_printers";
 
-// External resource containing all printer configurations for an enterprise.
-const char kRecommendedNativePrintersFile[] =
-    "native_printing.recommended_printers_file";
-
 // Enum designating the type of restrictions bulk printers are using.
 const char kRecommendedNativePrintersAccessMode[] =
     "native_printing.recommended_printers_access_mode";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 9d8c15f2..9336e07 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -386,9 +386,7 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-extern const char kPrintingDevices[];
 extern const char kRecommendedNativePrinters[];
-extern const char kRecommendedNativePrintersFile[];
 extern const char kRecommendedNativePrintersAccessMode[];
 extern const char kRecommendedNativePrintersBlacklist[];
 extern const char kRecommendedNativePrintersWhitelist[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 9408de4..3c86f62b 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4477,6 +4477,9 @@
       ]
     }
   }
+  if (use_nss_certs) {
+    sources += [ "../browser/certificate_manager_model_unittest.cc" ]
+  }
   if (!is_android && use_nss_certs) {
     sources += [ "../common/net/x509_certificate_model_nss_unittest.cc" ]
   }
diff --git a/chrome/test/data/background_fetch/background_fetch.js b/chrome/test/data/background_fetch/background_fetch.js
index 5586a31..8a3ffae 100644
--- a/chrome/test/data/background_fetch/background_fetch.js
+++ b/chrome/test/data/background_fetch/background_fetch.js
@@ -86,8 +86,13 @@
 }
 
 // Listens for a postMessage from sw.js and sends the result to the test.
-navigator.serviceWorker.addEventListener('message', (event) => {
-  if (['backgroundfetchsuccess', 'backgroundfetchfail'].includes(event.data))
+navigator.serviceWorker.addEventListener('message', event => {
+  const expectedResponses = [
+    'backgroundfetchsuccess',
+    'backgroundfetchfail',
+    'permissionerror',
+  ];
+  if (expectedResponses.includes(event.data))
     sendResultToTest(event.data);
   else
     sendErrorToTest(Error('Unexpected message received: ' + event.data));
@@ -116,3 +121,27 @@
         kBackgroundFetchId, resources);
   }).catch(sendErrorToTest);
 }
+
+// Starts a Background Fetch that should fail due to a missing resource.
+function RunFetchAnExpectAnException() {
+  const resources = [
+    '/background_fetch/types_of_cheese.txt',
+    '/background_fetch/missing_cat.txt',
+  ];
+  navigator.serviceWorker.ready.then(swRegistration => {
+    return swRegistration.backgroundFetch.fetch(kBackgroundFetchId, resources);
+  }).then(sendErrorToTest)
+    .catch(e => sendResultToTest(e.message));
+}
+
+function StartFetchFromServiceWorker() {
+  navigator.serviceWorker.ready.then(() => {
+    navigator.serviceWorker.controller.postMessage('fetch');
+  });
+}
+
+function StartFetchFromIframe() {
+  const iframe = document.createElement('iframe');
+  iframe.src = '/background_fetch/background_fetch_iframe.html';
+  document.body.appendChild(iframe);
+}
diff --git a/chrome/test/data/background_fetch/background_fetch_iframe.html b/chrome/test/data/background_fetch/background_fetch_iframe.html
new file mode 100644
index 0000000..80798ed
--- /dev/null
+++ b/chrome/test/data/background_fetch/background_fetch_iframe.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <script src="../result_queue.js"></script>
+  </head>
+  <body>
+    <script>
+      navigator.serviceWorker.ready.then(swRegistration => {
+        return swRegistration.backgroundFetch.fetch(
+            'iframe-fetch', '/background_fetch/types_of_cheese.txt');
+      }).catch(e => sendResultToTest('permissionerror'));
+    </script>
+  </body>
+</html>
diff --git a/chrome/test/data/background_fetch/sw.js b/chrome/test/data/background_fetch/sw.js
index 407f2c4..7105346 100644
--- a/chrome/test/data/background_fetch/sw.js
+++ b/chrome/test/data/background_fetch/sw.js
@@ -13,6 +13,14 @@
   });
 }
 
+self.addEventListener('message', e => {
+  if (e.data !== 'fetch') throw "unexpected message";
+
+  self.registration.backgroundFetch.fetch(
+      'sw-fetch', '/background_fetch/types_of_cheese.txt')
+    .catch(e => postToWindowClients('permissionerror'));
+});
+
 // Background Fetch event listeners.
 self.addEventListener('backgroundfetchsuccess', e => {
   e.waitUntil(e.updateUI({title: 'New Fetched Title!'}).then(
diff --git a/chrome/test/data/extensions/api_test/file_browser/file_watcher_test/test.js b/chrome/test/data/extensions/api_test/file_browser/file_watcher_test/test.js
index d99cfe43..fab6e70 100644
--- a/chrome/test/data/extensions/api_test/file_browser/file_watcher_test/test.js
+++ b/chrome/test/data/extensions/api_test/file_browser/file_watcher_test/test.js
@@ -235,7 +235,7 @@
     var sortedVolumeMetadataList = volumeMetadataList.filter(function(volume) {
       return possibleVolumeTypes.indexOf(volume.volumeType) != -1;
     }).sort(function(volumeA, volumeB) {
-      return possibleVolumeTypes.indexOf(volumeA.volumeType) >
+      return possibleVolumeTypes.indexOf(volumeA.volumeType) -
              possibleVolumeTypes.indexOf(volumeB.volumeType);
     });
 
diff --git a/chrome/test/data/extensions/api_test/file_browser/filesystem_operations_test/test.js b/chrome/test/data/extensions/api_test/file_browser/filesystem_operations_test/test.js
index e6ed5696..fc332bad 100644
--- a/chrome/test/data/extensions/api_test/file_browser/filesystem_operations_test/test.js
+++ b/chrome/test/data/extensions/api_test/file_browser/filesystem_operations_test/test.js
@@ -490,7 +490,7 @@
     var sortedVolumeMetadataList = volumeMetadataList.filter(function(volume) {
       return possibleVolumeTypes.indexOf(volume.volumeType) != -1;
     }).sort(function(volumeA, volumeB) {
-      return possibleVolumeTypes.indexOf(volumeA.volumeType) >
+      return possibleVolumeTypes.indexOf(volumeA.volumeType) -
              possibleVolumeTypes.indexOf(volumeB.volumeType);
     });
 
diff --git a/chrome/test/data/extensions/api_test/file_browser/handler_test_runner/test.js b/chrome/test/data/extensions/api_test/file_browser/handler_test_runner/test.js
index 514aeff..c32ebe5 100644
--- a/chrome/test/data/extensions/api_test/file_browser/handler_test_runner/test.js
+++ b/chrome/test/data/extensions/api_test/file_browser/handler_test_runner/test.js
@@ -194,7 +194,7 @@
     var sortedVolumeMetadataList = volumeMetadataList.filter(function(volume) {
       return possibleVolumeTypes.indexOf(volume.volumeType) != -1;
     }).sort(function(volumeA, volumeB) {
-      return possibleVolumeTypes.indexOf(volumeA.volumeType) >
+      return possibleVolumeTypes.indexOf(volumeA.volumeType) -
              possibleVolumeTypes.indexOf(volumeB.volumeType);
     });
     if (sortedVolumeMetadataList.length == 0) {
diff --git a/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js b/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js
index 36d9b45..4718974 100644
--- a/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js
+++ b/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js
@@ -179,6 +179,14 @@
 
 chrome.test.runTests([
   function removeMount() {
+    chrome.fileManagerPrivate.removeMount('removable:mount_path1');
+
+    // We actually check this one on C++ side. If MountLibrary.RemoveMount
+    // doesn't get called, test will fail.
+    chrome.test.succeed();
+  },
+
+  function removeMountArchive() {
     chrome.fileManagerPrivate.removeMount('archive:archive_mount_path');
 
     // We actually check this one on C++ side. If MountLibrary.RemoveMount
diff --git a/chrome/test/data/extensions/platform_apps/touchpad_pinch/background.js b/chrome/test/data/extensions/platform_apps/touchpad_pinch/background.js
new file mode 100644
index 0000000..3c9f502
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/touchpad_pinch/background.js
@@ -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.
+
+chrome.app.runtime.onLaunched.addListener(function() {
+  chrome.app.window.create('window.html');
+});
diff --git a/chrome/test/data/extensions/platform_apps/touchpad_pinch/manifest.json b/chrome/test/data/extensions/platform_apps/touchpad_pinch/manifest.json
new file mode 100644
index 0000000..c47a5d4
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/touchpad_pinch/manifest.json
@@ -0,0 +1,10 @@
+{
+  "name": "Touchpad pinch synthetic wheel event",
+  "version": "1",
+  "manifest_version": 2,
+  "app": {
+    "background": {
+      "scripts": ["background.js"]
+    }
+  }
+}
diff --git a/chrome/test/data/extensions/platform_apps/touchpad_pinch/window.html b/chrome/test/data/extensions/platform_apps/touchpad_pinch/window.html
new file mode 100644
index 0000000..8047bf9
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/touchpad_pinch/window.html
@@ -0,0 +1,18 @@
+<!--
+ * Copyright (c) 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.
+-->
+<html>
+<head>
+  <style>
+    html,body {
+     height: 100%;
+    }
+  </style>
+</head>
+<body>
+  <p>Hello.</p>
+  <script src="window.js"></script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/touchpad_pinch/window.js b/chrome/test/data/extensions/platform_apps/touchpad_pinch/window.js
new file mode 100644
index 0000000..f260647
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/touchpad_pinch/window.js
@@ -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.
+
+window.onload = () => {
+  document.body.addEventListener('wheel', (e) => {
+    chrome.test.sendMessage('Seen wheel event');
+  });
+  chrome.test.sendMessage('Launched');
+};
diff --git a/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/embedder.html b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/embedder.html
new file mode 100644
index 0000000..72a7e7af
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/embedder.html
@@ -0,0 +1,10 @@
+<!--
+ * Copyright (c) 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.
+-->
+<html>
+<body>
+<script src="embedder.js"></script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/embedder.js b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/embedder.js
new file mode 100644
index 0000000..7fc9d1a
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/embedder.js
@@ -0,0 +1,20 @@
+// 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.
+
+window.onload = () => {
+  chrome.test.getConfig(function(config) {
+    var guestURL = 'http://localhost:' + config.testServer.port +
+        '/extensions/platform_apps/web_view/touchpad_pinch/guest.html';
+    var webview = document.createElement('webview');
+    webview.src = guestURL;
+    webview.addEventListener('loadstop', () => {
+      webview.contentWindow.postMessage({}, '*');
+    });
+    document.body.appendChild(webview);
+  });
+};
+
+window.addEventListener('message', (e) => {
+  chrome.test.sendMessage(e.data);
+});
diff --git a/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/guest.html b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/guest.html
new file mode 100644
index 0000000..d2ae6764
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/guest.html
@@ -0,0 +1,18 @@
+<!--
+ * Copyright (c) 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.
+-->
+<html>
+<head>
+  <style>
+    html,body {
+     height: 100%;
+    }
+  </style>
+</head>
+<body>
+  <p>Hello.</p>
+  <script src="guest.js"></script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/guest.js b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/guest.js
new file mode 100644
index 0000000..bca3c5a4
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/guest.js
@@ -0,0 +1,16 @@
+// 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.
+
+var parentWindow = null;
+
+window.onload = () => {
+  document.body.addEventListener('wheel', (e) => {
+    parentWindow.postMessage('Seen wheel event', '*');
+  });
+};
+
+window.addEventListener('message', (e) => {
+  parentWindow = e.source;
+  parentWindow.postMessage('WebViewTest.LAUNCHED', '*');
+});
diff --git a/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/manifest.json b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/manifest.json
new file mode 100644
index 0000000..b58b16f
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/manifest.json
@@ -0,0 +1,13 @@
+{
+  "name": "<webview> Touchpad pinch synthetic wheel event",
+  "version": "1",
+  "manifest_version": 2,
+  "permissions": [
+    "webview"
+  ],
+  "app": {
+    "background": {
+      "scripts": ["test.js"]
+    }
+  }
+}
diff --git a/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/test.js b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/test.js
new file mode 100644
index 0000000..1bb2b22
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/touchpad_pinch/test.js
@@ -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.
+
+chrome.app.runtime.onLaunched.addListener(function() {
+  chrome.app.window.create('embedder.html');
+});
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 38d0d57..c0618e4 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -3861,6 +3861,22 @@
     "note": "Chrome OS device policy used by update_engine only, not used in Chrome."
   },
 
+  "WebAppInstallForceList": {
+    "os": ["win", "linux", "mac", "chromeos"],
+    "test_policy": {
+      "WebAppInstallForceList": [{
+        "url": "https://www.google.com",
+        "launch_container": "tab"
+      }, {
+        "url": "https://docs.google.com",
+        "launch_container": "window"
+      }]
+    },
+    "pref_mappings": [
+      { "pref": "profile.web_app.install.forcelist" }
+    ]
+  },
+
   "----- Chrome Frame policies -------------------------------------------": {},
 
   "ChromeFrameRendererSettings": {
diff --git a/chrome/test/data/webui/settings/certificate_manager_test.js b/chrome/test/data/webui/settings/certificate_manager_test.js
index 051d38f..d61fefb 100644
--- a/chrome/test/data/webui/settings/certificate_manager_test.js
+++ b/chrome/test/data/webui/settings/certificate_manager_test.js
@@ -143,11 +143,12 @@
     }
   }
 
-  /** @return {!Certificate} */
-  function createSampleCertificate() {
+  /** @return {!CertificatesOrgGroup} */
+  function createSampleCertificateOrgGroup() {
     return {
       id: 'dummyCertificateId',
       name: 'dummyCertificateName',
+      containsPolicyCerts: false,
       subnodes: [createSampleCertificateSubnode()],
     };
   }
@@ -682,10 +683,10 @@
         // Simulate response for personal and CA certificates.
         cr.webUIListenerCallback(
             'certificates-changed', 'personalCerts',
-            [createSampleCertificate()]);
-        cr.webUIListenerCallback(
-            'certificates-changed', 'caCerts',
-            [createSampleCertificate(), createSampleCertificate()]);
+            [createSampleCertificateOrgGroup()]);
+        cr.webUIListenerCallback('certificates-changed', 'caCerts', [
+          createSampleCertificateOrgGroup(), createSampleCertificateOrgGroup()
+        ]);
         Polymer.dom.flush();
 
         assertCertificateListLength(CertificateCategoryIndex.PERSONAL, 1);
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 4f18189a..ec28eaf 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-10974.0.0
\ No newline at end of file
+10993.0.0
\ No newline at end of file
diff --git a/chromeos/account_manager/account_manager.h b/chromeos/account_manager/account_manager.h
index 61e69e9..af6838f 100644
--- a/chromeos/account_manager/account_manager.h
+++ b/chromeos/account_manager/account_manager.h
@@ -102,7 +102,12 @@
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       DelayNetworkCallRunner delay_network_call_runner);
 
-  // Gets (async) a list of account keys known to |AccountManager|.
+  // Gets (async) a list of account keys known to |AccountManager|. Note that
+  // |callback| will be immediately called in the same thread if
+  // |AccountManager| has been fully initialized and hence it may not be safe to
+  // call this method directly in some class's constructor, with a callback on
+  // the same class, since it may result in a method call on a partially
+  // constructed object.
   void GetAccounts(AccountListCallback callback);
 
   // Removes an account. Does not do anything if |account_key| is not known by
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 8aa2cb1..31806d7 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -272,6 +272,7 @@
   if (is_android) {
     deps += [
       "//base:base_java_unittest_support",
+      "//components/autofill_assistant/browser:unit_tests",
       "//components/cdm/browser:unit_tests",
       "//components/gcm_driver/instance_id:test_support",
       "//components/gcm_driver/instance_id/android:instance_id_driver_java",
diff --git a/components/arc/common/auth.mojom b/components/arc/common/auth.mojom
index 4498975..9b64261 100644
--- a/components/arc/common/auth.mojom
+++ b/components/arc/common/auth.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Next MinVersion: 15
+// Next MinVersion: 17
 
 module arc.mojom;
 
@@ -170,6 +170,7 @@
 };
 
 // The necessary information for Android to sign in and provision itself.
+// Next ordinal value: 6.
 struct AccountInfo {
   // Name of account, used to map to existing Android account.
   [MinVersion=9] string? account_name@4;
@@ -189,6 +190,9 @@
 
   // Whether the account is managed from Chrome OS.
   bool is_managed@2;
+
+  // Whether this account is a Chrome OS Secondary Account.
+  [MinVersion=16] bool is_secondary_account@5;
 };
 
 // Next Method ID: 12.
@@ -209,7 +213,11 @@
   // Asynchronously requests an authorization code, as well as the account
   // information. If |initial_signin| is true then that means request is for
   // initial signin flow. Otherwise it is used for reauthorization flow.
-  [MinVersion=5] RequestAccountInfo@7([MinVersion=11] bool initial_signin);
+  // Optionally, an |account_name| can be provided to fetch |AccountInfo| for
+  // Secondary Accounts in Chrome OS Account Manager. Absence of |account_name|
+  // will default to the Device Account in Chrome OS.
+  [MinVersion=5] RequestAccountInfo@7([MinVersion=11] bool initial_signin,
+                                      [MinVersion=16] string? account_name);
 
   // Reports metrics to Chrome to be recorded in UMA.
   [MinVersion=7] ReportMetrics@8(MetricsType metrics_type, int32 value);
@@ -225,7 +233,7 @@
       SupervisionChangeStatus status);
 };
 
-// Next Method ID: 3
+// Next Method ID: 5
 interface AuthInstance {
   // DEPRECATED: Please use Init@2 instead.
   InitDeprecated@0(AuthHost host_ptr);
@@ -243,4 +251,13 @@
   [MinVersion=5] OnAccountInfoReady@1(
       AccountInfo? account_info, [MinVersion=10] ArcSignInStatus status);
 
+  // A notification that a Secondary Account has been updated or inserted in
+  // Chrome OS Account Manager. This API is guaranteed to be idempotent.
+  // Note: This notification is guaranteed to be called at least once for every
+  // Secondary Account in Chrome OS Account Manager at startup.
+  [MinVersion=15] OnSecondaryAccountUpserted@3(string account_name);
+
+  // A notification that a Secondary Account has been removed from Chrome OS
+  // Account Manager. This API is guaranteed to be idempotent.
+  [MinVersion=15] OnSecondaryAccountRemoved@4(string account_name);
 };
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc
index dc9b8a7..bd323689 100644
--- a/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -7402,7 +7402,13 @@
 }
 
 // Test the ukm recorded when Suggestion is shown.
-TEST_F(AutofillMetricsTest, AutofillSuggestionShownTest) {
+// Flaky on Win.  http://crbug.com/876954
+#if defined(OS_WIN)
+#define MAYBE_AutofillSuggestionShownTest DISABLED_AutofillSuggestionShownTest
+#else
+#define MAYBE_AutofillSuggestionShownTest AutofillSuggestionShownTest
+#endif
+TEST_F(AutofillMetricsTest, MAYBE_AutofillSuggestionShownTest) {
   RecreateCreditCards(true /* include_local_credit_card */,
                       false /* include_masked_server_credit_card */,
                       false /* include_full_server_credit_card */);
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn
index 6715198..e2280796 100644
--- a/components/autofill_assistant/browser/BUILD.gn
+++ b/components/autofill_assistant/browser/BUILD.gn
@@ -13,6 +13,7 @@
 
 jumbo_static_library("browser") {
   sources = [
+    "actions/assistant_action.cc",
     "actions/assistant_action.h",
     "actions/assistant_action_delegate.h",
     "actions/assistant_click_action.cc",
@@ -53,3 +54,26 @@
     "//net",
   ]
 }
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "assistant_script_executor_unittest.cc",
+    "mock_assistant_service.cc",
+    "mock_assistant_service.h",
+    "mock_assistant_ui_controller.cc",
+    "mock_assistant_ui_controller.h",
+    "mock_assistant_web_controller.cc",
+    "mock_assistant_web_controller.h",
+    "mock_run_once_callback.h",
+  ]
+
+  deps = [
+    ":browser",
+    ":proto",
+    "//base",
+    "//base/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/components/autofill_assistant/browser/actions/assistant_action.cc b/components/autofill_assistant/browser/actions/assistant_action.cc
new file mode 100644
index 0000000..6ceb7634
--- /dev/null
+++ b/components/autofill_assistant/browser/actions/assistant_action.cc
@@ -0,0 +1,12 @@
+// 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 "components/autofill_assistant/browser/actions/assistant_action.h"
+
+namespace autofill_assistant {
+
+AssistantAction::AssistantAction(const AssistantActionProto& proto)
+    : proto_(proto) {}
+
+}  // namespace autofill_assistant.
diff --git a/components/autofill_assistant/browser/actions/assistant_action.h b/components/autofill_assistant/browser/actions/assistant_action.h
index 599da96..cff7420 100644
--- a/components/autofill_assistant/browser/actions/assistant_action.h
+++ b/components/autofill_assistant/browser/actions/assistant_action.h
@@ -5,7 +5,8 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_ACTION_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_ACTION_H_
 
-#include "base/callback.h"
+#include "base/callback_forward.h"
+#include "components/autofill_assistant/browser/assistant.pb.h"
 
 namespace autofill_assistant {
 
@@ -22,8 +23,12 @@
   virtual void ProcessAction(AssistantActionDelegate* delegate,
                              ProcessActionCallback callback) = 0;
 
+  const AssistantActionProto& proto() const { return proto_; }
+
  protected:
-  AssistantAction() = default;
+  explicit AssistantAction(const AssistantActionProto& proto);
+
+  const AssistantActionProto proto_;
 };
 
 }  // namespace autofill_assistant.
diff --git a/components/autofill_assistant/browser/actions/assistant_action_delegate.h b/components/autofill_assistant/browser/actions/assistant_action_delegate.h
index cc7307d..fe92128 100644
--- a/components/autofill_assistant/browser/actions/assistant_action_delegate.h
+++ b/components/autofill_assistant/browser/actions/assistant_action_delegate.h
@@ -27,6 +27,30 @@
   virtual void ElementExists(const std::vector<std::string>& selectors,
                              base::OnceCallback<void(bool)> callback) = 0;
 
+  // Ask user to choose an address in personal data manager. GUID of the chosen
+  // address will be returned through callback if succeed, otherwise empty
+  // string is returned.
+  virtual void ChooseAddress(
+      base::OnceCallback<void(const std::string&)> callback) = 0;
+
+  // Fill the address form given by |selectors| with the given address |guid| in
+  // personal data manager.
+  virtual void FillAddressForm(const std::string& guid,
+                               const std::vector<std::string>& selectors,
+                               base::OnceCallback<void(bool)> callback) = 0;
+
+  // Ask user to choose a card in personal data manager. GUID of the chosen card
+  // will be returned through callback if succeed, otherwise empty string is
+  // returned.
+  virtual void ChooseCard(
+      base::OnceCallback<void(const std::string&)> callback) = 0;
+
+  // Fill the card form given by |selectors| with the given card |guid| in
+  // personal data manager.
+  virtual void FillCardForm(const std::string& guid,
+                            const std::vector<std::string>& selectors,
+                            base::OnceCallback<void(bool)> callback) = 0;
+
  protected:
   AssistantActionDelegate() = default;
 };
diff --git a/components/autofill_assistant/browser/actions/assistant_click_action.cc b/components/autofill_assistant/browser/actions/assistant_click_action.cc
index f79dca3..4b2dc72e 100644
--- a/components/autofill_assistant/browser/actions/assistant_click_action.cc
+++ b/components/autofill_assistant/browser/actions/assistant_click_action.cc
@@ -4,19 +4,28 @@
 
 #include "components/autofill_assistant/browser/actions/assistant_click_action.h"
 
+#include <utility>
+
+#include "base/callback.h"
 #include "components/autofill_assistant/browser/actions/assistant_action_delegate.h"
 
 namespace autofill_assistant {
 
-AssistantClickAction::AssistantClickAction(
-    const std::vector<std::string>& selectors)
-    : target_element_selectors_(selectors) {}
+AssistantClickAction::AssistantClickAction(const AssistantActionProto& proto)
+    : AssistantAction(proto) {
+  DCHECK(proto_.has_click());
+}
 
 AssistantClickAction::~AssistantClickAction() {}
 
 void AssistantClickAction::ProcessAction(AssistantActionDelegate* delegate,
                                          ProcessActionCallback callback) {
-  delegate->ClickElement(target_element_selectors_, std::move(callback));
+  std::vector<std::string> selectors;
+  for (const auto& selector : proto_.click().element_to_click().selectors()) {
+    selectors.emplace_back(selector);
+  }
+  DCHECK(!selectors.empty());
+  delegate->ClickElement(selectors, std::move(callback));
 }
 
-}  // namespace autofill_assistant.
\ No newline at end of file
+}  // namespace autofill_assistant.
diff --git a/components/autofill_assistant/browser/actions/assistant_click_action.h b/components/autofill_assistant/browser/actions/assistant_click_action.h
index 663a10a..c817e0d 100644
--- a/components/autofill_assistant/browser/actions/assistant_click_action.h
+++ b/components/autofill_assistant/browser/actions/assistant_click_action.h
@@ -16,9 +16,7 @@
 // An action to perform a mouse left button click on a given element on Web.
 class AssistantClickAction : public AssistantAction {
  public:
-  // CSS selectors in |selectors| are ordered from top frame to the frame
-  // contains the element and the element.
-  explicit AssistantClickAction(const std::vector<std::string>& selectors);
+  explicit AssistantClickAction(const AssistantActionProto& proto);
   ~AssistantClickAction() override;
 
   // Overrides AssistantAction:
@@ -32,4 +30,4 @@
 };
 
 }  // namespace autofill_assistant.
-#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_CLICK_ACTION_H_
\ No newline at end of file
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_CLICK_ACTION_H_
diff --git a/components/autofill_assistant/browser/actions/assistant_tell_action.cc b/components/autofill_assistant/browser/actions/assistant_tell_action.cc
index ab54192..943e8b6d 100644
--- a/components/autofill_assistant/browser/actions/assistant_tell_action.cc
+++ b/components/autofill_assistant/browser/actions/assistant_tell_action.cc
@@ -4,19 +4,25 @@
 
 #include "components/autofill_assistant/browser/actions/assistant_tell_action.h"
 
+#include <utility>
+
+#include "base/callback.h"
 #include "components/autofill_assistant/browser/actions/assistant_action_delegate.h"
 
 namespace autofill_assistant {
 
-AssistantTellAction::AssistantTellAction(const std::string& message)
-    : message_(message) {}
+AssistantTellAction::AssistantTellAction(const AssistantActionProto& proto)
+    : AssistantAction(proto) {
+  DCHECK(proto_.has_tell());
+}
 
 AssistantTellAction::~AssistantTellAction() {}
 
 void AssistantTellAction::ProcessAction(AssistantActionDelegate* delegate,
                                         ProcessActionCallback callback) {
-  delegate->ShowStatusMessage(message_);
+  // tell.message in the proto is localized.
+  delegate->ShowStatusMessage(proto_.tell().message());
   std::move(callback).Run(true);
 }
 
-}  // namespace autofill_assistant.
\ No newline at end of file
+}  // namespace autofill_assistant.
diff --git a/components/autofill_assistant/browser/actions/assistant_tell_action.h b/components/autofill_assistant/browser/actions/assistant_tell_action.h
index 3bcf2ff..e4855121 100644
--- a/components/autofill_assistant/browser/actions/assistant_tell_action.h
+++ b/components/autofill_assistant/browser/actions/assistant_tell_action.h
@@ -5,18 +5,16 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_TELL_ACTION_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_TELL_ACTION_H_
 
-#include "components/autofill_assistant/browser/actions/assistant_action.h"
-
 #include <string>
 
 #include "base/macros.h"
+#include "components/autofill_assistant/browser/actions/assistant_action.h"
 
 namespace autofill_assistant {
 // An action to display a message.
 class AssistantTellAction : public AssistantAction {
  public:
-  // The |message| is a localized text message from the server to show user.
-  explicit AssistantTellAction(const std::string& message);
+  explicit AssistantTellAction(const AssistantActionProto& proto);
   ~AssistantTellAction() override;
 
   // Overrides AssistantAction:
@@ -24,10 +22,8 @@
                      ProcessActionCallback callback) override;
 
  private:
-  std::string message_;
-
   DISALLOW_COPY_AND_ASSIGN(AssistantTellAction);
 };
 
 }  // namespace autofill_assistant.
-#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_TELL_ACTION_H_
\ No newline at end of file
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_TELL_ACTION_H_
diff --git a/components/autofill_assistant/browser/actions/assistant_use_address_action.cc b/components/autofill_assistant/browser/actions/assistant_use_address_action.cc
index 25b5f5d..d8a305a 100644
--- a/components/autofill_assistant/browser/actions/assistant_use_address_action.cc
+++ b/components/autofill_assistant/browser/actions/assistant_use_address_action.cc
@@ -4,20 +4,57 @@
 
 #include "components/autofill_assistant/browser/actions/assistant_use_address_action.h"
 
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
 #include "components/autofill_assistant/browser/actions/assistant_action_delegate.h"
 
 namespace autofill_assistant {
 
 AssistantUseAddressAction::AssistantUseAddressAction(
-    const std::string& usage_message,
-    const std::vector<std::string>& selectors)
-    : usage_message_(usage_message), target_element_selectors_(selectors) {}
+    const AssistantActionProto& proto)
+    : AssistantAction(proto), weak_ptr_factory_(this) {}
 
 AssistantUseAddressAction::~AssistantUseAddressAction() {}
 
 void AssistantUseAddressAction::ProcessAction(AssistantActionDelegate* delegate,
                                               ProcessActionCallback callback) {
-  NOTIMPLEMENTED();
+  if (proto_.use_address().has_usage()) {
+    delegate->ShowStatusMessage(proto_.use_address().usage());
+  }
+
+  delegate->ChooseAddress(base::BindOnce(
+      &AssistantUseAddressAction::OnChooseAddress,
+      weak_ptr_factory_.GetWeakPtr(), delegate, std::move(callback)));
+}
+
+void AssistantUseAddressAction::OnChooseAddress(
+    AssistantActionDelegate* delegate,
+    ProcessActionCallback callback,
+    const std::string& guid) {
+  if (guid.empty()) {
+    DVLOG(1) << "Failed to choose address.";
+    std::move(callback).Run(false);
+    return;
+  }
+
+  std::vector<std::string> selectors;
+  for (const auto& selector :
+       proto_.use_address().form_field_element().selectors()) {
+    selectors.emplace_back(selector);
+  }
+  DCHECK(!selectors.empty());
+  delegate->FillAddressForm(
+      guid, selectors,
+      base::BindOnce(&AssistantUseAddressAction::OnFillAddressForm,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void AssistantUseAddressAction::OnFillAddressForm(
+    ProcessActionCallback callback,
+    bool result) {
+  std::move(callback).Run(result);
 }
 
 }  // namespace autofill_assistant.
diff --git a/components/autofill_assistant/browser/actions/assistant_use_address_action.h b/components/autofill_assistant/browser/actions/assistant_use_address_action.h
index 1d08034..24a132a 100644
--- a/components/autofill_assistant/browser/actions/assistant_use_address_action.h
+++ b/components/autofill_assistant/browser/actions/assistant_use_address_action.h
@@ -5,22 +5,18 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_USE_ADDRESS_ACTION_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_USE_ADDRESS_ACTION_H_
 
-#include "components/autofill_assistant/browser/actions/assistant_action.h"
-
 #include <string>
-#include <vector>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/actions/assistant_action.h"
 
 namespace autofill_assistant {
 // An action to ask user to choose a local address to fill the form.
 class AssistantUseAddressAction : public AssistantAction {
  public:
-  // The |usage_message| indicates the usage of the address, like billing
-  // address or shipping address. The |selectors| specifies an element in the
-  // form to be filled.
-  AssistantUseAddressAction(const std::string& usage_message,
-                            const std::vector<std::string>& selectors);
+  explicit AssistantUseAddressAction(const AssistantActionProto& proto);
+
   ~AssistantUseAddressAction() override;
 
   // Overrides AssistantAction:
@@ -28,8 +24,12 @@
                      ProcessActionCallback callback) override;
 
  private:
-  std::string usage_message_;
-  std::vector<std::string> target_element_selectors_;
+  void OnChooseAddress(AssistantActionDelegate* delegate,
+                       ProcessActionCallback callback,
+                       const std::string& guid);
+  void OnFillAddressForm(ProcessActionCallback callback, bool result);
+
+  base::WeakPtrFactory<AssistantUseAddressAction> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AssistantUseAddressAction);
 };
diff --git a/components/autofill_assistant/browser/actions/assistant_use_card_action.cc b/components/autofill_assistant/browser/actions/assistant_use_card_action.cc
index d4952ac..f394ae4 100644
--- a/components/autofill_assistant/browser/actions/assistant_use_card_action.cc
+++ b/components/autofill_assistant/browser/actions/assistant_use_card_action.cc
@@ -4,19 +4,51 @@
 
 #include "components/autofill_assistant/browser/actions/assistant_use_card_action.h"
 
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
 #include "components/autofill_assistant/browser/actions/assistant_action_delegate.h"
 
 namespace autofill_assistant {
 
 AssistantUseCardAction::AssistantUseCardAction(
-    const std::vector<std::string>& selectors)
-    : target_element_selectors_(selectors) {}
+    const AssistantActionProto& proto)
+    : AssistantAction(proto), weak_ptr_factory_(this) {}
 
 AssistantUseCardAction::~AssistantUseCardAction() {}
 
 void AssistantUseCardAction::ProcessAction(AssistantActionDelegate* delegate,
                                            ProcessActionCallback callback) {
-  NOTIMPLEMENTED();
+  delegate->ChooseCard(base::BindOnce(&AssistantUseCardAction::OnChooseCard,
+                                      weak_ptr_factory_.GetWeakPtr(), delegate,
+                                      std::move(callback)));
+}
+
+void AssistantUseCardAction::OnChooseCard(AssistantActionDelegate* delegate,
+                                          ProcessActionCallback callback,
+                                          const std::string& guid) {
+  if (guid.empty()) {
+    DVLOG(1) << "Failed to choose card.";
+    std::move(callback).Run(false);
+    return;
+  }
+
+  std::vector<std::string> selectors;
+  for (const auto& selector :
+       proto_.use_card().form_field_element().selectors()) {
+    selectors.emplace_back(selector);
+  }
+  DCHECK(!selectors.empty());
+  delegate->FillCardForm(
+      guid, selectors,
+      base::BindOnce(&AssistantUseCardAction::OnFillCardForm,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void AssistantUseCardAction::OnFillCardForm(ProcessActionCallback callback,
+                                            bool result) {
+  std::move(callback).Run(result);
 }
 
 }  // namespace autofill_assistant.
diff --git a/components/autofill_assistant/browser/actions/assistant_use_card_action.h b/components/autofill_assistant/browser/actions/assistant_use_card_action.h
index b16ea6e..967f9524 100644
--- a/components/autofill_assistant/browser/actions/assistant_use_card_action.h
+++ b/components/autofill_assistant/browser/actions/assistant_use_card_action.h
@@ -5,19 +5,18 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_USE_CARD_ACTION_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_USE_CARD_ACTION_H_
 
-#include "components/autofill_assistant/browser/actions/assistant_action.h"
-
 #include <string>
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/actions/assistant_action.h"
 
 namespace autofill_assistant {
 // An action to ask user to choose a local card to fill the form.
 class AssistantUseCardAction : public AssistantAction {
  public:
-  // The |selectors| specifies the card number field in the form to be filled.
-  explicit AssistantUseCardAction(const std::vector<std::string>& selectors);
+  explicit AssistantUseCardAction(const AssistantActionProto& proto);
   ~AssistantUseCardAction() override;
 
   // Overrides AssistantAction:
@@ -25,7 +24,12 @@
                      ProcessActionCallback callback) override;
 
  private:
-  std::vector<std::string> target_element_selectors_;
+  void OnChooseCard(AssistantActionDelegate* delegate,
+                    ProcessActionCallback callback,
+                    const std::string& guid);
+  void OnFillCardForm(ProcessActionCallback callback, bool result);
+
+  base::WeakPtrFactory<AssistantUseCardAction> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AssistantUseCardAction);
 };
diff --git a/components/autofill_assistant/browser/actions/assistant_wait_for_dom_action.cc b/components/autofill_assistant/browser/actions/assistant_wait_for_dom_action.cc
index 008ef98..4916f0d 100644
--- a/components/autofill_assistant/browser/actions/assistant_wait_for_dom_action.cc
+++ b/components/autofill_assistant/browser/actions/assistant_wait_for_dom_action.cc
@@ -22,21 +22,18 @@
 namespace autofill_assistant {
 
 AssistantWaitForDomAction::AssistantWaitForDomAction(
-    int timeout_ms,
-    const std::vector<std::string>& selectors,
-    bool for_absence)
-    : timeout_ms_(timeout_ms),
-      target_element_selectors_(selectors),
-      for_absence_(for_absence),
-      weak_ptr_factory_(this) {}
+    const AssistantActionProto& proto)
+    : AssistantAction(proto), weak_ptr_factory_(this) {}
 
 AssistantWaitForDomAction::~AssistantWaitForDomAction() {}
 
 void AssistantWaitForDomAction::ProcessAction(AssistantActionDelegate* delegate,
                                               ProcessActionCallback callback) {
   int check_rounds = kDefaultCheckRounds;
-  if (timeout_ms_ > 0)
-    check_rounds = std::ceil(timeout_ms_ / kCheckPeriodInMilliseconds);
+
+  int timeout_ms = proto_.wait_for_dom().timeout_ms();
+  if (timeout_ms > 0)
+    check_rounds = std::ceil(timeout_ms / kCheckPeriodInMilliseconds);
 
   CheckElementExists(delegate, check_rounds, std::move(callback));
 }
@@ -46,9 +43,12 @@
     int rounds,
     ProcessActionCallback callback) {
   DCHECK(rounds > 0);
-
+  std::vector<std::string> selectors;
+  for (const auto& selector : proto_.wait_for_dom().element().selectors()) {
+    selectors.emplace_back(selector);
+  }
   delegate->ElementExists(
-      target_element_selectors_,
+      selectors,
       base::BindOnce(&AssistantWaitForDomAction::OnCheckElementExists,
                      weak_ptr_factory_.GetWeakPtr(), delegate, rounds,
                      std::move(callback)));
@@ -59,12 +59,13 @@
     int rounds,
     ProcessActionCallback callback,
     bool result) {
-  if (for_absence_ && !result) {
+  bool for_absence = proto_.wait_for_dom().check_for_absence();
+  if (for_absence && !result) {
     std::move(callback).Run(true);
     return;
   }
 
-  if (!for_absence_ && result) {
+  if (!for_absence && result) {
     std::move(callback).Run(true);
     return;
   }
diff --git a/components/autofill_assistant/browser/actions/assistant_wait_for_dom_action.h b/components/autofill_assistant/browser/actions/assistant_wait_for_dom_action.h
index 9501839..5cfe49f 100644
--- a/components/autofill_assistant/browser/actions/assistant_wait_for_dom_action.h
+++ b/components/autofill_assistant/browser/actions/assistant_wait_for_dom_action.h
@@ -5,25 +5,19 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_WAIT_FOR_DOM_ACTION_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_WAIT_FOR_DOM_ACTION_H_
 
-#include "components/autofill_assistant/browser/actions/assistant_action.h"
-
 #include <string>
 #include <vector>
 
-#include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/actions/assistant_action.h"
+#include "components/autofill_assistant/browser/assistant.pb.h"
 
 namespace autofill_assistant {
 // An action to ask Chrome to wait for a DOM element to process next action.
 class AssistantWaitForDomAction : public AssistantAction {
  public:
-  // |timeout_ms| indicates waiting timeout period. |selectors| specifies the
-  // DOM element to wait. |for_absence| indicates whether waiting for absence of
-  // the element.
-  AssistantWaitForDomAction(int timeout_ms,
-                            const std::vector<std::string>& selectors,
-                            bool for_absence);
+  explicit AssistantWaitForDomAction(const AssistantActionProto& proto);
   ~AssistantWaitForDomAction() override;
 
   // Overrides AssistantAction:
@@ -39,13 +33,9 @@
                             ProcessActionCallback callback,
                             bool result);
 
-  int timeout_ms_;
-  std::vector<std::string> target_element_selectors_;
-  bool for_absence_;
-
   base::WeakPtrFactory<AssistantWaitForDomAction> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(AssistantWaitForDomAction);
 };
 
 }  // namespace autofill_assistant.
-#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_WAIT_FOR_DOM_ACTION_H_
\ No newline at end of file
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ASSISTANT_WAIT_FOR_DOM_ACTION_H_
diff --git a/components/autofill_assistant/browser/assistant.proto b/components/autofill_assistant/browser/assistant.proto
index db48c24..fcd9ffd 100644
--- a/components/autofill_assistant/browser/assistant.proto
+++ b/components/autofill_assistant/browser/assistant.proto
@@ -55,6 +55,18 @@
   TRACE = 4;
 }
 
+message ScriptActionRequestProto {
+  optional ClientContextProto client_context = 7;
+
+  // The server payload received from the previous response.
+  optional bytes server_payload = 1;
+
+  oneof request {
+    InitialScriptActionsRequestProto initial_request = 4;
+    NextScriptActionsRequestProto next_request = 5;
+  }
+}
+
 // Initial request to get a script's actions.
 message InitialScriptActionsRequestProto {
   message QueryProto {
@@ -66,8 +78,10 @@
 
 // Next request to get a script's actions.
 message NextScriptActionsRequestProto {
-  // The server payload received from the previous response.
-  required bytes server_payload = 1;
+  // The result of processing each AssistantActionProto from the previous
+  // response. This field must be in the same order as the actions in the
+  // original response. It may have less actions in case of failure.
+  repeated ProcessedAssistantActionProto processed_actions = 1;
 }
 
 // Response of a script's actions.
@@ -83,16 +97,33 @@
 
 // An assistant action could be performed.
 message AssistantActionProto {
-  // Next action id: 3.
+  // Opaque data that should not be interpreted by the client. The client must
+  // pass this back unchanged in the next request
+  optional bytes server_payload = 4;
+
   oneof action_info {
-    ClickProto click = 1;
-    TellProto tell = 2;
-    UseAddressProto use_address = 3;
-    UseCreditCardProto use_card = 4;
-    WaitForDomProto wait_for_dom = 5;
+    ClickProto click = 5;
+    TellProto tell = 11;
+    WaitForDomProto wait_for_dom = 19;
+    UseCreditCardProto use_card = 28;
+    UseAddressProto use_address = 29;
   }
 }
 
+message ProcessedAssistantActionProto {
+  // The action that was processed.
+  optional AssistantActionProto action = 1;
+
+  optional ProcessedAssistantActionStatus status = 2;
+}
+
+enum ProcessedAssistantActionStatus {
+  UNKNOWN_ACTION_STATUS = 0;
+  ELEMENT_RESOLUTION_FAILED = 1;
+  ACTION_APPLIED = 2;
+  OTHER_ACTION_STATUS = 3;
+}
+
 // A reference to an unique element on the page, possibly nested in frames.
 message ElementReferenceProto {
   // A sequence of CSS selectors. Any non-final CSS selector is expected to
@@ -108,7 +139,7 @@
   required ElementReferenceProto element_to_click = 1;
 }
 
-// Contain a message to tell the user.
+// Contain a localized text message from the server to show to the user.
 message TellProto {
   required string message = 1;
 }
@@ -130,7 +161,7 @@
 // this action.
 message UseCreditCardProto {
   // A reference to the card number field in the form that should be filled.
-  optional ElementReferenceProto form_field_element = 1;
+  required ElementReferenceProto form_field_element = 1;
 }
 
 // Ask Chrome to wait for an element in the DOM. This can be used to only
diff --git a/components/autofill_assistant/browser/assistant_protocol_utils.cc b/components/autofill_assistant/browser/assistant_protocol_utils.cc
index 90304f7..78dcfd7 100644
--- a/components/autofill_assistant/browser/assistant_protocol_utils.cc
+++ b/components/autofill_assistant/browser/assistant_protocol_utils.cc
@@ -4,6 +4,8 @@
 
 #include "components/autofill_assistant/browser/assistant_protocol_utils.h"
 
+#include <utility>
+
 #include "base/logging.h"
 #include "components/autofill_assistant/browser/actions/assistant_click_action.h"
 #include "components/autofill_assistant/browser/actions/assistant_tell_action.h"
@@ -80,26 +82,30 @@
 // static
 std::string AssistantProtocolUtils::CreateInitialScriptActionsRequest(
     const std::string& script_path) {
-  InitialScriptActionsRequestProto::QueryProto query;
-  query.set_script_path(script_path);
-  query.set_policy(PolicyType::SCRIPT);
-
-  InitialScriptActionsRequestProto initial_request_proto;
-  initial_request_proto.set_allocated_query(&query);
+  ScriptActionRequestProto request_proto;
+  InitialScriptActionsRequestProto::QueryProto* query =
+      request_proto.mutable_initial_request()->mutable_query();
+  query->set_script_path(script_path);
+  query->set_policy(PolicyType::SCRIPT);
 
   std::string serialized_initial_request_proto;
-  bool success = initial_request_proto.SerializeToString(
-      &serialized_initial_request_proto);
+  bool success =
+      request_proto.SerializeToString(&serialized_initial_request_proto);
   DCHECK(success);
   return serialized_initial_request_proto;
 }
 
 // static
 std::string AssistantProtocolUtils::CreateNextScriptActionsRequest(
-    const std::string& previous_server_payload) {
-  NextScriptActionsRequestProto request_proto;
+    const std::string& previous_server_payload,
+    const std::vector<ProcessedAssistantActionProto>& processed_actions) {
+  ScriptActionRequestProto request_proto;
   request_proto.set_server_payload(previous_server_payload);
-
+  NextScriptActionsRequestProto* next_request =
+      request_proto.mutable_next_request();
+  for (const auto& processed_action : processed_actions) {
+    next_request->add_processed_actions()->MergeFrom(processed_action);
+  }
   std::string serialized_request_proto;
   bool success = request_proto.SerializeToString(&serialized_request_proto);
   DCHECK(success);
@@ -110,8 +116,7 @@
 bool AssistantProtocolUtils::ParseAssistantActions(
     const std::string& response,
     std::string* return_server_payload,
-    std::vector<std::unique_ptr<AssistantAction>>* assistant_actions) {
-  DCHECK(!response.empty());
+    std::deque<std::unique_ptr<AssistantAction>>* assistant_actions) {
   DCHECK(assistant_actions);
 
   ActionsResponseProto response_proto;
@@ -127,66 +132,28 @@
   for (const auto& action : response_proto.actions()) {
     switch (action.action_info_case()) {
       case AssistantActionProto::ActionInfoCase::kClick: {
-        DCHECK(action.has_click());
-        std::vector<std::string> selectors;
-        for (const auto& selector :
-             action.click().element_to_click().selectors()) {
-          selectors.emplace_back(selector);
-        }
-        DCHECK(!selectors.empty());
         assistant_actions->emplace_back(
-            std::make_unique<AssistantClickAction>(selectors));
+            std::make_unique<AssistantClickAction>(action));
         break;
       }
       case AssistantActionProto::ActionInfoCase::kTell: {
-        DCHECK(action.has_tell());
         assistant_actions->emplace_back(
-            std::make_unique<AssistantTellAction>(action.tell().message()));
+            std::make_unique<AssistantTellAction>(action));
         break;
       }
       case AssistantActionProto::ActionInfoCase::kUseAddress: {
-        DCHECK(action.has_use_address());
-        std::vector<std::string> selectors;
-        for (const auto& selector :
-             action.use_address().form_field_element().selectors()) {
-          selectors.emplace_back(selector);
-        }
-        DCHECK(!selectors.empty());
         assistant_actions->emplace_back(
-            std::make_unique<AssistantUseAddressAction>(
-                action.use_address().has_usage() ? action.use_address().usage()
-                                                 : "",
-                selectors));
+            std::make_unique<AssistantUseAddressAction>(action));
         break;
       }
       case AssistantActionProto::ActionInfoCase::kUseCard: {
-        DCHECK(action.has_use_card());
-        std::vector<std::string> selectors;
-        for (const auto& selector :
-             action.use_card().form_field_element().selectors()) {
-          selectors.emplace_back(selector);
-        }
-        DCHECK(!selectors.empty());
         assistant_actions->emplace_back(
-            std::make_unique<AssistantUseCardAction>(selectors));
+            std::make_unique<AssistantUseCardAction>(action));
         break;
       }
       case AssistantActionProto::ActionInfoCase::kWaitForDom: {
-        DCHECK(action.has_wait_for_dom());
-        std::vector<std::string> selectors;
-        for (const auto& selector :
-             action.wait_for_dom().element().selectors()) {
-          selectors.emplace_back(selector);
-        }
-        DCHECK(!selectors.empty());
         assistant_actions->emplace_back(
-            std::make_unique<AssistantWaitForDomAction>(
-                action.wait_for_dom().has_timeout_ms()
-                    ? action.wait_for_dom().timeout_ms()
-                    : 0,
-                selectors,
-                action.wait_for_dom().has_check_for_absence() &&
-                    action.wait_for_dom().check_for_absence()));
+            std::make_unique<AssistantUseCardAction>(action));
         break;
       }
       case AssistantActionProto::ActionInfoCase::ACTION_INFO_NOT_SET: {
diff --git a/components/autofill_assistant/browser/assistant_protocol_utils.h b/components/autofill_assistant/browser/assistant_protocol_utils.h
index 0bd54ed..616ca18 100644
--- a/components/autofill_assistant/browser/assistant_protocol_utils.h
+++ b/components/autofill_assistant/browser/assistant_protocol_utils.h
@@ -5,14 +5,16 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_PROTOCOL_UTILS_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_PROTOCOL_UTILS_H_
 
-#include "components/autofill_assistant/browser/actions/assistant_action.h"
-#include "components/autofill_assistant/browser/assistant_script.h"
-
+#include <deque>
 #include <map>
 #include <memory>
 #include <string>
 #include <vector>
 
+#include "components/autofill_assistant/browser/actions/assistant_action.h"
+#include "components/autofill_assistant/browser/assistant.pb.h"
+#include "components/autofill_assistant/browser/assistant_script.h"
+
 class GURL;
 
 namespace autofill_assistant {
@@ -40,7 +42,8 @@
 
   // Create request to get next sequence of actions for a script.
   static std::string CreateNextScriptActionsRequest(
-      const std::string& previous_server_payload);
+      const std::string& previous_server_payload,
+      const std::vector<ProcessedAssistantActionProto>& processed_actions);
 
   // Parse assistant actions from the given |response|, which should not be an
   // empty string.
@@ -51,7 +54,7 @@
   static bool ParseAssistantActions(
       const std::string& response,
       std::string* return_server_payload,
-      std::vector<std::unique_ptr<AssistantAction>>* assistant_actions);
+      std::deque<std::unique_ptr<AssistantAction>>* assistant_actions);
 
  private:
   // To avoid instantiate this class by accident.
@@ -60,4 +63,4 @@
 };
 }  // namespace autofill_assistant
 
-#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_PROTOCOL_UTILS_H_
\ No newline at end of file
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_PROTOCOL_UTILS_H_
diff --git a/components/autofill_assistant/browser/assistant_script_executor.cc b/components/autofill_assistant/browser/assistant_script_executor.cc
index d3b6767..872ad55 100644
--- a/components/autofill_assistant/browser/assistant_script_executor.cc
+++ b/components/autofill_assistant/browser/assistant_script_executor.cc
@@ -4,6 +4,9 @@
 
 #include "components/autofill_assistant/browser/assistant_script_executor.h"
 
+#include <string>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "components/autofill_assistant/browser/assistant_protocol_utils.h"
@@ -12,6 +15,7 @@
 #include "components/autofill_assistant/browser/assistant_web_controller.h"
 
 namespace autofill_assistant {
+
 AssistantScriptExecutor::AssistantScriptExecutor(
     AssistantScript* script,
     AssistantScriptExecutorDelegate* delegate)
@@ -49,6 +53,32 @@
                                                         std::move(callback));
 }
 
+void AssistantScriptExecutor::ChooseAddress(
+    base::OnceCallback<void(const std::string&)> callback) {
+  delegate_->GetAssistantUiController()->ChooseAddress(std::move(callback));
+}
+
+void AssistantScriptExecutor::FillAddressForm(
+    const std::string& guid,
+    const std::vector<std::string>& selectors,
+    base::OnceCallback<void(bool)> callback) {
+  delegate_->GetAssistantWebController()->FillAddressForm(guid, selectors,
+                                                          std::move(callback));
+}
+
+void AssistantScriptExecutor::ChooseCard(
+    base::OnceCallback<void(const std::string&)> callback) {
+  delegate_->GetAssistantUiController()->ChooseCard(std::move(callback));
+}
+
+void AssistantScriptExecutor::FillCardForm(
+    const std::string& guid,
+    const std::vector<std::string>& selectors,
+    base::OnceCallback<void(bool)> callback) {
+  delegate_->GetAssistantWebController()->FillCardForm(guid, selectors,
+                                                       std::move(callback));
+}
+
 void AssistantScriptExecutor::OnGetAssistantActions(
     bool result,
     const std::string& response) {
@@ -56,8 +86,9 @@
     std::move(callback_).Run(false);
     return;
   }
+  processed_actions_.clear();
+  actions_.clear();
 
-  DCHECK(!response.empty());
   bool parse_result = AssistantProtocolUtils::ParseAssistantActions(
       response, &last_server_payload_, &actions_);
   if (!parse_result) {
@@ -68,30 +99,48 @@
   if (actions_.empty()) {
     // Finished executing the script if there are no more actions.
     std::move(callback_).Run(true);
+    return;
   }
+  ProcessNextAction();
 }
 
-void AssistantScriptExecutor::ProcessActions(size_t index) {
-  // Request next sequence of actions after process current sequence of actions.
-  if (index >= actions_.size()) {
+void AssistantScriptExecutor::ProcessNextAction() {
+  if (actions_.empty()) {
+    // Request more actions to execute.
     GetNextAssistantActions();
     return;
   }
 
-  actions_[index]->ProcessAction(
+  std::unique_ptr<AssistantAction> action = std::move(actions_.front());
+  actions_.pop_front();
+  AssistantAction* action_ptr = action.get();
+  action_ptr->ProcessAction(
       this, base::BindOnce(&AssistantScriptExecutor::OnProcessedAction,
-                           weak_ptr_factory_.GetWeakPtr(), index));
+                           weak_ptr_factory_.GetWeakPtr(), std::move(action)));
 }
 
-void AssistantScriptExecutor::GetNextAssistantActions() {}
+void AssistantScriptExecutor::GetNextAssistantActions() {
+  delegate_->GetAssistantService()->GetNextAssistantActions(
+      last_server_payload_, processed_actions_,
+      base::BindOnce(&AssistantScriptExecutor::OnGetAssistantActions,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
 
-void AssistantScriptExecutor::OnProcessedAction(size_t index, bool status) {
-  if (!status) {
-    std::move(callback_).Run(false);
+void AssistantScriptExecutor::OnProcessedAction(
+    std::unique_ptr<AssistantAction> action,
+    bool success) {
+  processed_actions_.emplace_back();
+  ProcessedAssistantActionProto* proto = &processed_actions_.back();
+  proto->mutable_action()->MergeFrom(action->proto());
+  proto->set_status(success
+                        ? ProcessedAssistantActionStatus::ACTION_APPLIED
+                        : ProcessedAssistantActionStatus::OTHER_ACTION_STATUS);
+  if (!success) {
+    // Report error immediately, interrupting action processing.
+    GetNextAssistantActions();
     return;
   }
-
-  ProcessActions(index++);
+  ProcessNextAction();
 }
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/assistant_script_executor.h b/components/autofill_assistant/browser/assistant_script_executor.h
index 07cc415..8001a64 100644
--- a/components/autofill_assistant/browser/assistant_script_executor.h
+++ b/components/autofill_assistant/browser/assistant_script_executor.h
@@ -5,10 +5,16 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_H_
 
+#include <deque>
+#include <memory>
+#include <string>
+#include <vector>
+
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
 #include "components/autofill_assistant/browser/actions/assistant_action.h"
 #include "components/autofill_assistant/browser/actions/assistant_action_delegate.h"
+#include "components/autofill_assistant/browser/assistant.pb.h"
 #include "components/autofill_assistant/browser/assistant_script.h"
 #include "components/autofill_assistant/browser/assistant_script_executor_delegate.h"
 
@@ -31,18 +37,29 @@
                     base::OnceCallback<void(bool)> callback) override;
   void ElementExists(const std::vector<std::string>& selectors,
                      base::OnceCallback<void(bool)> callback) override;
+  void ChooseAddress(
+      base::OnceCallback<void(const std::string&)> callback) override;
+  void FillAddressForm(const std::string& guid,
+                       const std::vector<std::string>& selectors,
+                       base::OnceCallback<void(bool)> callback) override;
+  void ChooseCard(
+      base::OnceCallback<void(const std::string&)> callback) override;
+  void FillCardForm(const std::string& guid,
+                    const std::vector<std::string>& selectors,
+                    base::OnceCallback<void(bool)> callback) override;
 
  private:
   void OnGetAssistantActions(bool result, const std::string& response);
-  void ProcessActions(size_t index);
+  void ProcessNextAction();
   void GetNextAssistantActions();
-  void OnProcessedAction(size_t index, bool status);
+  void OnProcessedAction(std::unique_ptr<AssistantAction> action, bool status);
 
   AssistantScript* script_;
   AssistantScriptExecutorDelegate* delegate_;
   RunScriptCallback callback_;
 
-  std::vector<std::unique_ptr<AssistantAction>> actions_;
+  std::deque<std::unique_ptr<AssistantAction>> actions_;
+  std::vector<ProcessedAssistantActionProto> processed_actions_;
   std::string last_server_payload_;
 
   base::WeakPtrFactory<AssistantScriptExecutor> weak_ptr_factory_;
diff --git a/components/autofill_assistant/browser/assistant_script_executor_unittest.cc b/components/autofill_assistant/browser/assistant_script_executor_unittest.cc
new file mode 100644
index 0000000..47e8eba
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant_script_executor_unittest.cc
@@ -0,0 +1,169 @@
+// 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 "components/autofill_assistant/browser/assistant_script_executor.h"
+
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/browser/assistant_service.h"
+#include "components/autofill_assistant/browser/mock_assistant_service.h"
+#include "components/autofill_assistant/browser/mock_assistant_ui_controller.h"
+#include "components/autofill_assistant/browser/mock_assistant_web_controller.h"
+#include "components/autofill_assistant/browser/mock_run_once_callback.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+namespace {
+
+using ::testing::DoAll;
+using ::testing::SaveArg;
+using ::testing::StrEq;
+using ::testing::StrictMock;
+using ::testing::NiceMock;
+using ::testing::_;
+
+class AssistantScriptExecutorTest : public testing::Test,
+                                    public AssistantScriptExecutorDelegate {
+ public:
+  void SetUp() override {
+    script_.name = "script name";
+    script_.path = "script path";
+
+    executor_ = std::make_unique<AssistantScriptExecutor>(&script_, this);
+
+    // In this test, "tell" actions always succeed and "click" actions always
+    // fail.
+    ON_CALL(mock_assistant_web_controller_, OnClickElement(_, _))
+        .WillByDefault(RunOnceCallback<1>(false));
+  }
+
+ protected:
+  AssistantScriptExecutorTest() {}
+
+  AssistantService* GetAssistantService() override {
+    return &mock_assistant_service_;
+  }
+
+  AssistantUiController* GetAssistantUiController() override {
+    return &mock_assistant_ui_controller_;
+  }
+
+  AssistantWebController* GetAssistantWebController() override {
+    return &mock_assistant_web_controller_;
+  }
+
+  std::string Serialize(const google::protobuf::MessageLite& message) {
+    std::string output;
+    message.SerializeToString(&output);
+    return output;
+  }
+
+  AssistantScript script_;
+  StrictMock<MockAssistantService> mock_assistant_service_;
+  NiceMock<MockAssistantWebController> mock_assistant_web_controller_;
+  NiceMock<MockAssistantUiController> mock_assistant_ui_controller_;
+  std::unique_ptr<AssistantScriptExecutor> executor_;
+  StrictMock<base::MockCallback<AssistantScriptExecutor::RunScriptCallback>>
+      executor_callback_;
+};
+
+TEST_F(AssistantScriptExecutorTest, GetAssistantActionsFails) {
+  EXPECT_CALL(mock_assistant_service_, OnGetAssistantActions(_, _))
+      .WillOnce(RunOnceCallback<1>(false, ""));
+  EXPECT_CALL(executor_callback_, Run(false));
+  executor_->Run(executor_callback_.Get());
+}
+
+TEST_F(AssistantScriptExecutorTest, RunOneActionReportFailureAndStop) {
+  ActionsResponseProto actions_response;
+  actions_response.set_server_payload("payload");
+  actions_response.add_actions()
+      ->mutable_click()
+      ->mutable_element_to_click()
+      ->add_selectors("will fail");
+
+  EXPECT_CALL(mock_assistant_service_, OnGetAssistantActions(_, _))
+      .WillOnce(RunOnceCallback<1>(true, Serialize(actions_response)));
+
+  std::vector<ProcessedAssistantActionProto> processed_actions_capture;
+  EXPECT_CALL(mock_assistant_service_, OnGetNextAssistantActions(_, _, _))
+      .WillOnce(DoAll(SaveArg<1>(&processed_actions_capture),
+                      RunOnceCallback<2>(true, "")));
+  EXPECT_CALL(executor_callback_, Run(true));
+  executor_->Run(executor_callback_.Get());
+
+  ASSERT_EQ(1u, processed_actions_capture.size());
+  EXPECT_EQ(OTHER_ACTION_STATUS, processed_actions_capture[0].status());
+}
+
+TEST_F(AssistantScriptExecutorTest, RunMultipleActions) {
+  ActionsResponseProto initial_actions_response;
+  initial_actions_response.set_server_payload("payload1");
+  initial_actions_response.add_actions()->mutable_tell()->set_message("1");
+  initial_actions_response.add_actions()->mutable_tell()->set_message("2");
+  EXPECT_CALL(mock_assistant_service_,
+              OnGetAssistantActions(StrEq("script path"), _))
+      .WillOnce(RunOnceCallback<1>(true, Serialize(initial_actions_response)));
+
+  ActionsResponseProto next_actions_response;
+  next_actions_response.set_server_payload("payload2");
+  next_actions_response.add_actions()->mutable_tell()->set_message("3");
+  std::vector<ProcessedAssistantActionProto> processed_actions1_capture;
+  std::vector<ProcessedAssistantActionProto> processed_actions2_capture;
+  EXPECT_CALL(mock_assistant_service_, OnGetNextAssistantActions(_, _, _))
+      .WillOnce(
+          DoAll(SaveArg<1>(&processed_actions1_capture),
+                RunOnceCallback<2>(true, Serialize(next_actions_response))))
+      .WillOnce(DoAll(SaveArg<1>(&processed_actions2_capture),
+                      RunOnceCallback<2>(true, "")));
+  EXPECT_CALL(executor_callback_, Run(true));
+  executor_->Run(executor_callback_.Get());
+
+  EXPECT_EQ(2u, processed_actions1_capture.size());
+  EXPECT_EQ(1u, processed_actions2_capture.size());
+}
+
+TEST_F(AssistantScriptExecutorTest, InterruptActionListOnError) {
+  ActionsResponseProto initial_actions_response;
+  initial_actions_response.set_server_payload("payload");
+  initial_actions_response.add_actions()->mutable_tell()->set_message(
+      "will pass");
+  initial_actions_response.add_actions()
+      ->mutable_click()
+      ->mutable_element_to_click()
+      ->add_selectors("will fail");
+  initial_actions_response.add_actions()->mutable_tell()->set_message(
+      "never run");
+
+  EXPECT_CALL(mock_assistant_service_, OnGetAssistantActions(_, _))
+      .WillOnce(RunOnceCallback<1>(true, Serialize(initial_actions_response)));
+
+  ActionsResponseProto next_actions_response;
+  next_actions_response.set_server_payload("payload2");
+  next_actions_response.add_actions()->mutable_tell()->set_message(
+      "will run after error");
+  std::vector<ProcessedAssistantActionProto> processed_actions1_capture;
+  std::vector<ProcessedAssistantActionProto> processed_actions2_capture;
+  EXPECT_CALL(mock_assistant_service_, OnGetNextAssistantActions(_, _, _))
+      .WillOnce(
+          DoAll(SaveArg<1>(&processed_actions1_capture),
+                RunOnceCallback<2>(true, Serialize(next_actions_response))))
+      .WillOnce(DoAll(SaveArg<1>(&processed_actions2_capture),
+                      RunOnceCallback<2>(true, "")));
+  EXPECT_CALL(executor_callback_, Run(true));
+  executor_->Run(executor_callback_.Get());
+
+  ASSERT_EQ(2u, processed_actions1_capture.size());
+  EXPECT_EQ(ACTION_APPLIED, processed_actions1_capture[0].status());
+  EXPECT_EQ(OTHER_ACTION_STATUS, processed_actions1_capture[1].status());
+
+  ASSERT_EQ(1u, processed_actions2_capture.size());
+  EXPECT_EQ(ACTION_APPLIED, processed_actions2_capture[0].status());
+  // make sure "never run" wasn't the one that was run.
+  EXPECT_EQ("will run after error",
+            processed_actions2_capture[0].action().tell().message());
+}
+
+}  // namespace
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/assistant_service.cc b/components/autofill_assistant/browser/assistant_service.cc
index e33faef..65962d6 100644
--- a/components/autofill_assistant/browser/assistant_service.cc
+++ b/components/autofill_assistant/browser/assistant_service.cc
@@ -4,6 +4,10 @@
 
 #include "components/autofill_assistant/browser/assistant_service.h"
 
+#include <string>
+#include <utility>
+#include <vector>
+
 #include "base/strings/strcat.h"
 #include "components/autofill_assistant/browser/assistant_protocol_utils.h"
 #include "content/public/browser/browser_context.h"
@@ -92,6 +96,7 @@
 
 void AssistantService::GetNextAssistantActions(
     const std::string& previous_server_payload,
+    const std::vector<ProcessedAssistantActionProto>& processed_actions,
     ResponseCallback callback) {
   DCHECK(!previous_server_payload.empty());
 
@@ -101,7 +106,7 @@
   assistant_loader->loader = CreateAndStartLoader(
       assistant_script_action_server_url_,
       AssistantProtocolUtils::CreateNextScriptActionsRequest(
-          previous_server_payload),
+          previous_server_payload, processed_actions),
       assistant_loader.get());
   assistant_loaders_[assistant_loader.get()] = std::move(assistant_loader);
 }
diff --git a/components/autofill_assistant/browser/assistant_service.h b/components/autofill_assistant/browser/assistant_service.h
index 48edb44..8059a026 100644
--- a/components/autofill_assistant/browser/assistant_service.h
+++ b/components/autofill_assistant/browser/assistant_service.h
@@ -7,8 +7,11 @@
 
 #include <map>
 #include <memory>
+#include <string>
+#include <vector>
 
 #include "base/callback.h"
+#include "components/autofill_assistant/browser/assistant.pb.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 #include "url/gurl.h"
 
@@ -21,22 +24,25 @@
 // client actions.
 class AssistantService {
  public:
-  AssistantService(content::BrowserContext* context);
-  ~AssistantService();
+  explicit AssistantService(content::BrowserContext* context);
+  virtual ~AssistantService();
 
   using ResponseCallback =
       base::OnceCallback<void(bool result, const std::string&)>;
   // Get assistant scripts for a given |url|, which should be a valid URL.
-  void GetAssistantScriptsForUrl(const GURL& url, ResponseCallback callback);
+  virtual void GetAssistantScriptsForUrl(const GURL& url,
+                                         ResponseCallback callback);
 
   // Get assistant actions.
-  void GetAssistantActions(const std::string& script_path,
-                           ResponseCallback callback);
+  virtual void GetAssistantActions(const std::string& script_path,
+                                   ResponseCallback callback);
 
   // Get next sequence of assistant actions according to server payload in
   // previous reponse.
-  void GetNextAssistantActions(const std::string& previous_server_payload,
-                               ResponseCallback callback);
+  virtual void GetNextAssistantActions(
+      const std::string& previous_server_payload,
+      const std::vector<ProcessedAssistantActionProto>& processed_actions,
+      ResponseCallback callback);
 
  private:
   // Struct to store assistant scripts and actions request.
diff --git a/components/autofill_assistant/browser/assistant_ui_controller.h b/components/autofill_assistant/browser/assistant_ui_controller.h
index f8066a3..ed11132 100644
--- a/components/autofill_assistant/browser/assistant_ui_controller.h
+++ b/components/autofill_assistant/browser/assistant_ui_controller.h
@@ -9,6 +9,8 @@
 
 #include <string>
 
+#include "base/callback_forward.h"
+
 namespace autofill_assistant {
 // Controller to control autofill assistant UI.
 class AssistantUiController {
@@ -27,6 +29,18 @@
   // Hide the overlay.
   virtual void HideOverlay() = 0;
 
+  // Show UI to ask user to choose an address in personal data manager. GUID of
+  // the chosen address will be returned through callback if succeed, otherwise
+  // empty string is returned.
+  virtual void ChooseAddress(
+      base::OnceCallback<void(const std::string&)> callback) = 0;
+
+  // Show UI to ask user to choose a card in personal data manager. GUID of the
+  // chosen card will be returned through callback if succeed, otherwise empty
+  // string is returned.
+  virtual void ChooseCard(
+      base::OnceCallback<void(const std::string&)> callback) = 0;
+
  protected:
   AssistantUiController() = default;
 };
diff --git a/components/autofill_assistant/browser/assistant_web_controller.cc b/components/autofill_assistant/browser/assistant_web_controller.cc
index 3becf80e..f4f9d0ca 100644
--- a/components/autofill_assistant/browser/assistant_web_controller.cc
+++ b/components/autofill_assistant/browser/assistant_web_controller.cc
@@ -26,4 +26,20 @@
   std::move(callback).Run(true);
 }
 
+void AssistantWebController::FillAddressForm(
+    const std::string& guid,
+    const std::vector<std::string>& selectors,
+    base::OnceCallback<void(bool)> callback) {
+  // TODO(crbug.com/806868): Implement fill address form operation.
+  std::move(callback).Run(true);
+}
+
+void AssistantWebController::FillCardForm(
+    const std::string& guid,
+    const std::vector<std::string>& selectors,
+    base::OnceCallback<void(bool)> callback) {
+  // TODO(crbug.com/806868): Implement fill card form operation.
+  std::move(callback).Run(true);
+}
+
 }  // namespace autofill_assistant.
diff --git a/components/autofill_assistant/browser/assistant_web_controller.h b/components/autofill_assistant/browser/assistant_web_controller.h
index 2bc189da..e29457dd 100644
--- a/components/autofill_assistant/browser/assistant_web_controller.h
+++ b/components/autofill_assistant/browser/assistant_web_controller.h
@@ -16,18 +16,30 @@
 class AssistantWebController {
  public:
   AssistantWebController();
-  ~AssistantWebController();
+  virtual ~AssistantWebController();
 
   // Perform a moust left button click on the element given by |selectors| and
   // return the result through callback.
   // CSS selectors in |selectors| are ordered from top frame to the frame
   // contains the element and the element.
-  void ClickElement(const std::vector<std::string>& selectors,
-                    base::OnceCallback<void(bool)> callback);
+  virtual void ClickElement(const std::vector<std::string>& selectors,
+                            base::OnceCallback<void(bool)> callback);
 
   // Check whether the element given by |selectors| exists on the web page.
-  void ElementExists(const std::vector<std::string>& selectors,
-                     base::OnceCallback<void(bool)> callback);
+  virtual void ElementExists(const std::vector<std::string>& selectors,
+                             base::OnceCallback<void(bool)> callback);
+
+  // Fill the address form given by |selectors| with the given address |guid| in
+  // personal data manager.
+  virtual void FillAddressForm(const std::string& guid,
+                               const std::vector<std::string>& selectors,
+                               base::OnceCallback<void(bool)> callback);
+
+  // Fill the card form given by |selectors| with the given card |guid| in
+  // personal data manager.
+  virtual void FillCardForm(const std::string& guid,
+                            const std::vector<std::string>& selectors,
+                            base::OnceCallback<void(bool)> callback);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AssistantWebController);
diff --git a/components/autofill_assistant/browser/mock_assistant_service.cc b/components/autofill_assistant/browser/mock_assistant_service.cc
new file mode 100644
index 0000000..9674b6d
--- /dev/null
+++ b/components/autofill_assistant/browser/mock_assistant_service.cc
@@ -0,0 +1,12 @@
+// 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 "components/autofill_assistant/browser/mock_assistant_service.h"
+
+namespace autofill_assistant {
+
+MockAssistantService::MockAssistantService() : AssistantService(nullptr) {}
+MockAssistantService::~MockAssistantService() {}
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/mock_assistant_service.h b/components/autofill_assistant/browser/mock_assistant_service.h
new file mode 100644
index 0000000..47c0d42c
--- /dev/null
+++ b/components/autofill_assistant/browser/mock_assistant_service.h
@@ -0,0 +1,53 @@
+// 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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_ASSISTANT_SERVICE_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_ASSISTANT_SERVICE_H_
+
+#include <string>
+
+#include "components/autofill_assistant/browser/assistant_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+class MockAssistantService : public AssistantService {
+ public:
+  MockAssistantService();
+  ~MockAssistantService() override;
+
+  void GetAssistantScriptsForUrl(const GURL& url,
+                                 ResponseCallback callback) override {
+    // Transforming callback into a references allows using RunOnceCallback on
+    // the argument.
+    OnGetAssistantScriptsForUrl(url, callback);
+  }
+  MOCK_METHOD2(OnGetAssistantScriptsForUrl,
+               void(const GURL& url, ResponseCallback& callback));
+
+  void GetAssistantActions(const std::string& script_path,
+                           ResponseCallback callback) override {
+    OnGetAssistantActions(script_path, callback);
+  }
+  MOCK_METHOD2(OnGetAssistantActions,
+               void(const std::string& script_path,
+                    ResponseCallback& callback));
+
+  void GetNextAssistantActions(
+      const std::string& previous_server_payload,
+      const std::vector<ProcessedAssistantActionProto>& processed_actions,
+      ResponseCallback callback) override {
+    OnGetNextAssistantActions(previous_server_payload, processed_actions,
+                              callback);
+  }
+  MOCK_METHOD3(
+      OnGetNextAssistantActions,
+      void(const std::string& previous_server_payload,
+           const std::vector<ProcessedAssistantActionProto>& processed_actions,
+           ResponseCallback& callback));
+};
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_ASSISTANT_SERVICE_H_
diff --git a/components/autofill_assistant/browser/mock_assistant_ui_controller.cc b/components/autofill_assistant/browser/mock_assistant_ui_controller.cc
new file mode 100644
index 0000000..7cd9f30
--- /dev/null
+++ b/components/autofill_assistant/browser/mock_assistant_ui_controller.cc
@@ -0,0 +1,12 @@
+// 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 "components/autofill_assistant/browser/mock_assistant_ui_controller.h"
+
+namespace autofill_assistant {
+
+MockAssistantUiController::MockAssistantUiController() {}
+MockAssistantUiController::~MockAssistantUiController() {}
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/mock_assistant_ui_controller.h b/components/autofill_assistant/browser/mock_assistant_ui_controller.h
new file mode 100644
index 0000000..9680a20
--- /dev/null
+++ b/components/autofill_assistant/browser/mock_assistant_ui_controller.h
@@ -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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_ASSISTANT_UI_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_ASSISTANT_UI_CONTROLLER_H_
+
+#include "base/callback.h"
+#include "components/autofill_assistant/browser/assistant_ui_controller.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+class MockAssistantUiController : public AssistantUiController {
+ public:
+  MockAssistantUiController();
+  ~MockAssistantUiController() override;
+
+  MOCK_METHOD1(SetUiDelegate, void(AssistantUiDelegate* ui_delegate));
+  MOCK_METHOD1(ShowStatusMessage, void(const std::string& message));
+  MOCK_METHOD0(ShowOverlay, void());
+  MOCK_METHOD0(HideOverlay, void());
+
+  void ChooseAddress(
+      base::OnceCallback<void(const std::string&)> callback) override {
+    OnChooseAddress(callback);
+  }
+  MOCK_METHOD1(OnChooseAddress,
+               void(base::OnceCallback<void(const std::string&)>& callback));
+
+  void ChooseCard(
+      base::OnceCallback<void(const std::string&)> callback) override {
+    OnChooseCard(callback);
+  }
+  MOCK_METHOD1(OnChooseCard,
+               void(base::OnceCallback<void(const std::string&)>& callback));
+};
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_ASSISTANT_UI_CONTROLLER_H_
diff --git a/components/autofill_assistant/browser/mock_assistant_web_controller.cc b/components/autofill_assistant/browser/mock_assistant_web_controller.cc
new file mode 100644
index 0000000..a3d7022
--- /dev/null
+++ b/components/autofill_assistant/browser/mock_assistant_web_controller.cc
@@ -0,0 +1,12 @@
+// 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 "components/autofill_assistant/browser/mock_assistant_web_controller.h"
+
+namespace autofill_assistant {
+
+MockAssistantWebController::MockAssistantWebController() {}
+MockAssistantWebController::~MockAssistantWebController() {}
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/mock_assistant_web_controller.h b/components/autofill_assistant/browser/mock_assistant_web_controller.h
new file mode 100644
index 0000000..a560203
--- /dev/null
+++ b/components/autofill_assistant/browser/mock_assistant_web_controller.h
@@ -0,0 +1,43 @@
+// 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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_ASSISTANT_WEB_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_ASSISTANT_WEB_CONTROLLER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "components/autofill_assistant/browser/assistant_web_controller.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+class MockAssistantWebController : public AssistantWebController {
+ public:
+  MockAssistantWebController();
+  ~MockAssistantWebController() override;
+
+  void ClickElement(const std::vector<std::string>& selectors,
+                    base::OnceCallback<void(bool)> callback) override {
+    // Transforming callback into a references allows using RunOnceCallback on
+    // the argument.
+    OnClickElement(selectors, callback);
+  }
+  MOCK_METHOD2(OnClickElement,
+               void(const std::vector<std::string>& selectors,
+                    base::OnceCallback<void(bool)>& callback));
+
+  void ElementExists(const std::vector<std::string>& selectors,
+                     base::OnceCallback<void(bool)> callback) override {
+    OnElementExists(selectors, callback);
+  }
+  MOCK_METHOD2(OnElementExists,
+               void(const std::vector<std::string>& selectors,
+                    base::OnceCallback<void(bool)>& callback));
+};
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_ASSISTANT_WEB_CONTROLLER_H_
diff --git a/components/autofill_assistant/browser/mock_run_once_callback.h b/components/autofill_assistant/browser/mock_run_once_callback.h
new file mode 100644
index 0000000..97e3bf3a
--- /dev/null
+++ b/components/autofill_assistant/browser/mock_run_once_callback.h
@@ -0,0 +1,46 @@
+// 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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_RUN_ONCE_CALLBACK_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_RUN_ONCE_CALLBACK_H_
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+// Templates for calling base::OnceCallback from gmock actions.
+//
+// To work around the fact that OnceCallback can't be copied, the method
+// to be mocked needs to take the callback as a reference. To do it without
+// changing the original interface, follow this pattern:
+//
+//   void DoSomething(..., base::OnceCallback<void(bool)> callback) override {
+//     OnDoSomething(..., callback);
+//   }
+//   MOCK_METHOD2(OnDoSomething,
+//       void(..., base::OnceCallback<void(bool)>& callback));
+//
+//
+
+ACTION_TEMPLATE(RunOnceCallback,
+                HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_1_VALUE_PARAMS(p0)) {
+  return std::move(std::get<k>(args)).Run(p0);
+}
+
+ACTION_TEMPLATE(RunOnceCallback,
+                HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_2_VALUE_PARAMS(p0, p1)) {
+  return std::move(std::get<k>(args)).Run(p0, p1);
+}
+
+ACTION_TEMPLATE(RunOnceCallback,
+                HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_3_VALUE_PARAMS(p0, p1, p2)) {
+  return std::move(std::get<k>(args)).Run(p0, p1, p2);
+}
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_RUN_ONCE_CALLBACK_H_
diff --git a/components/browser_sync/profile_sync_test_util.cc b/components/browser_sync/profile_sync_test_util.cc
index 71421182..6605660 100644
--- a/components/browser_sync/profile_sync_test_util.cc
+++ b/components/browser_sync/profile_sync_test_util.cc
@@ -271,7 +271,7 @@
           base::ThreadTaskRunnerHandle::Get())) {
   RegisterPrefsForProfileSyncService(pref_service_.registry());
   auth_service_.set_auto_post_fetch_response_on_message_loop(true);
-  account_tracker_.Initialize(&signin_client_);
+  account_tracker_.Initialize(&pref_service_, base::FilePath());
   signin_manager_.Initialize(&pref_service_);
   local_session_event_router_ = std::make_unique<DummyRouter>();
   ON_CALL(sync_sessions_client_, GetLocalSessionEventRouter())
diff --git a/components/domain_reliability/OWNERS b/components/domain_reliability/OWNERS
index fdcdcec..1cfbdee 100644
--- a/components/domain_reliability/OWNERS
+++ b/components/domain_reliability/OWNERS
@@ -1,5 +1,3 @@
-davidben@chromium.org
-
 file://net/OWNERS
 
 per-file quic_error_mapping*=rch@chromium.org
diff --git a/components/guest_view/browser/guest_view_base.cc b/components/guest_view/browser/guest_view_base.cc
index 18cd29c..7951f7d6 100644
--- a/components/guest_view/browser/guest_view_base.cc
+++ b/components/guest_view/browser/guest_view_base.cc
@@ -683,7 +683,11 @@
 
 bool GuestViewBase::PreHandleGestureEvent(WebContents* source,
                                           const blink::WebGestureEvent& event) {
-  return blink::WebInputEvent::IsPinchGestureEventType(event.GetType());
+  // Pinch events which cause a scale change should not be routed to a guest.
+  // We still allow synthetic wheel events for touchpad pinch to go to the page.
+  DCHECK(!blink::WebInputEvent::IsPinchGestureEventType(event.GetType()) ||
+         event.NeedsWheelEvent());
+  return false;
 }
 
 void GuestViewBase::UpdatePreferredSize(WebContents* target_web_contents,
diff --git a/components/leveldb_proto/leveldb_database.cc b/components/leveldb_proto/leveldb_database.cc
index 16d891a..b514d5fd 100644
--- a/components/leveldb_proto/leveldb_database.cc
+++ b/components/leveldb_proto/leveldb_database.cc
@@ -168,13 +168,22 @@
 
 bool LevelDB::LoadWithFilter(const KeyFilter& filter,
                              std::vector<std::string>* entries) {
+  return LoadWithFilter(filter, entries, leveldb::ReadOptions(), std::string());
+}
+
+bool LevelDB::LoadWithFilter(const KeyFilter& filter,
+                             std::vector<std::string>* entries,
+                             const leveldb::ReadOptions& options,
+                             const std::string& target_prefix) {
   DFAKE_SCOPED_LOCK(thread_checker_);
   if (!db_)
     return false;
 
-  leveldb::ReadOptions options;
   std::unique_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
-  for (db_iterator->SeekToFirst(); db_iterator->Valid(); db_iterator->Next()) {
+  leveldb::Slice target(target_prefix);
+  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())))
diff --git a/components/leveldb_proto/leveldb_database.h b/components/leveldb_proto/leveldb_database.h
index b90f1f2..715ca62 100644
--- a/components/leveldb_proto/leveldb_database.h
+++ b/components/leveldb_proto/leveldb_database.h
@@ -58,6 +58,10 @@
   virtual bool Load(std::vector<std::string>* entries);
   virtual bool LoadWithFilter(const KeyFilter& filter,
                               std::vector<std::string>* entries);
+  virtual bool LoadWithFilter(const KeyFilter& filter,
+                              std::vector<std::string>* 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 d8adc5f..1d0e543 100644
--- a/components/leveldb_proto/proto_database.h
+++ b/components/leveldb_proto/proto_database.h
@@ -74,6 +74,10 @@
   // ProtoDatabase's taskrunner.
   virtual void LoadEntriesWithFilter(const LevelDB::KeyFilter& filter,
                                      LoadCallback callback) = 0;
+  virtual void LoadEntriesWithFilter(const LevelDB::KeyFilter& filter,
+                                     const leveldb::ReadOptions& options,
+                                     const std::string& target_prefix,
+                                     LoadCallback callback) = 0;
 
   // Asynchronously loads all keys from the database and invokes |callback| with
   // those keys when complete.
diff --git a/components/leveldb_proto/proto_database_impl.h b/components/leveldb_proto/proto_database_impl.h
index 4a60fe36..f7bc921 100644
--- a/components/leveldb_proto/proto_database_impl.h
+++ b/components/leveldb_proto/proto_database_impl.h
@@ -57,7 +57,12 @@
       typename ProtoDatabase<T>::UpdateCallback callback) override;
   void LoadEntries(typename ProtoDatabase<T>::LoadCallback callback) override;
   void LoadEntriesWithFilter(
-      const LevelDB::KeyFilter& key_filter,
+      const LevelDB::KeyFilter& filter,
+      typename ProtoDatabase<T>::LoadCallback callback) override;
+  void LoadEntriesWithFilter(
+      const LevelDB::KeyFilter& filter,
+      const leveldb::ReadOptions& options,
+      const std::string& target_prefix,
       typename ProtoDatabase<T>::LoadCallback callback) override;
   void LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) override;
   void GetEntry(const std::string& key,
@@ -181,6 +186,8 @@
 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);
@@ -189,7 +196,8 @@
   entries->clear();
 
   std::vector<std::string> loaded_entries;
-  *success = database->LoadWithFilter(filter, &loaded_entries);
+  *success =
+      database->LoadWithFilter(filter, &loaded_entries, options, target_prefix);
 
   for (const auto& serialized_entry : loaded_entries) {
     T entry;
@@ -339,6 +347,16 @@
 void ProtoDatabaseImpl<T>::LoadEntriesWithFilter(
     const LevelDB::KeyFilter& key_filter,
     typename ProtoDatabase<T>::LoadCallback callback) {
+  LoadEntriesWithFilter(key_filter, leveldb::ReadOptions(), std::string(),
+                        std::move(callback));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadEntriesWithFilter(
+    const LevelDB::KeyFilter& key_filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    typename ProtoDatabase<T>::LoadCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   bool* success = new bool(false);
 
@@ -349,7 +367,7 @@
   task_runner_->PostTaskAndReply(
       FROM_HERE,
       base::BindOnce(LoadEntriesFromTaskRunner<T>, base::Unretained(db_.get()),
-                     key_filter, entries_ptr, success),
+                     key_filter, options, target_prefix, entries_ptr, success),
       base::BindOnce(RunLoadCallback<T>, std::move(callback),
                      base::Owned(success), std::move(entries)));
 }
diff --git a/components/leveldb_proto/proto_database_impl_unittest.cc b/components/leveldb_proto/proto_database_impl_unittest.cc
index 9fd1a2eb..a49bb64 100644
--- a/components/leveldb_proto/proto_database_impl_unittest.cc
+++ b/components/leveldb_proto/proto_database_impl_unittest.cc
@@ -57,6 +57,11 @@
   MOCK_METHOD1(Load, bool(std::vector<std::string>*));
   MOCK_METHOD2(LoadWithFilter,
                bool(const KeyFilter&, std::vector<std::string>*));
+  MOCK_METHOD4(LoadWithFilter,
+               bool(const KeyFilter&,
+                    std::vector<std::string>*,
+                    const leveldb::ReadOptions&,
+                    const std::string&));
   MOCK_METHOD3(Get, bool(const std::string&, bool*, std::string*));
   MOCK_METHOD0(Destroy, bool());
 
@@ -282,7 +287,7 @@
                         base::BindOnce(&MockDatabaseCaller::InitCallback,
                                        base::Unretained(&caller)));
 
-  EXPECT_CALL(*mock_db, LoadWithFilter(_, _))
+  EXPECT_CALL(*mock_db, LoadWithFilter(_, _, _, _))
       .WillOnce(AppendLoadEntries(model));
   EXPECT_CALL(caller, LoadCallback1(true, _))
       .WillOnce(VerifyLoadEntries(testing::ByRef(model)));
@@ -304,7 +309,7 @@
                         base::BindOnce(&MockDatabaseCaller::InitCallback,
                                        base::Unretained(&caller)));
 
-  EXPECT_CALL(*mock_db, LoadWithFilter(_, _)).WillOnce(Return(false));
+  EXPECT_CALL(*mock_db, LoadWithFilter(_, _, _, _)).WillOnce(Return(false));
   EXPECT_CALL(caller, LoadCallback1(false, _));
   db_->LoadEntries(base::BindOnce(&MockDatabaseCaller::LoadCallback,
                                   base::Unretained(&caller)));
diff --git a/components/leveldb_proto/testing/fake_db.h b/components/leveldb_proto/testing/fake_db.h
index 234809d..bfce3cd 100644
--- a/components/leveldb_proto/testing/fake_db.h
+++ b/components/leveldb_proto/testing/fake_db.h
@@ -48,6 +48,11 @@
   void LoadEntriesWithFilter(
       const LevelDB::KeyFilter& key_filter,
       typename ProtoDatabase<T>::LoadCallback callback) override;
+  void LoadEntriesWithFilter(
+      const LevelDB::KeyFilter& filter,
+      const leveldb::ReadOptions& options,
+      const std::string& target_prefix,
+      typename ProtoDatabase<T>::LoadCallback callback) override;
   void LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) override;
   void GetEntry(const std::string& key,
                 typename ProtoDatabase<T>::GetCallback callback) override;
@@ -152,10 +157,22 @@
 void FakeDB<T>::LoadEntriesWithFilter(
     const LevelDB::KeyFilter& key_filter,
     typename ProtoDatabase<T>::LoadCallback callback) {
+  LoadEntriesWithFilter(key_filter, leveldb::ReadOptions(), std::string(),
+                        std::move(callback));
+}
+
+template <typename T>
+void FakeDB<T>::LoadEntriesWithFilter(
+    const LevelDB::KeyFilter& key_filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    typename ProtoDatabase<T>::LoadCallback callback) {
   std::unique_ptr<std::vector<T>> entries(new std::vector<T>());
   for (const auto& pair : *db_) {
-    if (key_filter.is_null() || key_filter.Run(pair.first))
-      entries->push_back(pair.second);
+    if (key_filter.is_null() || key_filter.Run(pair.first)) {
+      if (pair.first.compare(0, target_prefix.length(), target_prefix) == 0)
+        entries->push_back(pair.second);
+    }
   }
 
   load_callback_ =
diff --git a/components/password_manager/sync/browser/sync_username_test_base.cc b/components/password_manager/sync/browser/sync_username_test_base.cc
index 58ab04f..112a5ea 100644
--- a/components/password_manager/sync/browser/sync_username_test_base.cc
+++ b/components/password_manager/sync/browser/sync_username_test_base.cc
@@ -28,7 +28,7 @@
       signin_manager_(&signin_client_, &account_tracker_) {
   SigninManagerBase::RegisterProfilePrefs(prefs_.registry());
   AccountTrackerService::RegisterPrefs(prefs_.registry());
-  account_tracker_.Initialize(&signin_client_);
+  account_tracker_.Initialize(&prefs_, base::FilePath());
 }
 
 SyncUsernameTestBase::~SyncUsernameTestBase() {}
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc
index dbc6518..54fcb97 100644
--- a/components/payments/content/payment_request.cc
+++ b/components/payments/content/payment_request.cc
@@ -203,8 +203,10 @@
 void PaymentRequest::AreRequestedMethodsSupportedCallback(
     bool methods_supported) {
   if (methods_supported) {
-    if (SatisfiesSkipUIConstraints())
+    if (SatisfiesSkipUIConstraints()) {
+      skipped_payment_request_ui_ = true;
       Pay();
+    }
   } else {
     journey_logger_.SetNotShown(
         JourneyLogger::NOT_SHOWN_REASON_NO_SUPPORTED_PAYMENT_METHOD);
@@ -215,6 +217,19 @@
   }
 }
 
+bool PaymentRequest::SatisfiesSkipUIConstraints() const {
+  return base::FeatureList::IsEnabled(features::kWebPaymentsSingleAppUiSkip) &&
+         base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps) &&
+         is_show_user_gesture_ && state()->is_get_all_instruments_finished() &&
+         state()->available_instruments().size() == 1 &&
+         spec()->stringified_method_data().size() == 1 &&
+         !spec()->request_shipping() && !spec()->request_payer_name() &&
+         !spec()->request_payer_phone() &&
+         !spec()->request_payer_email()
+         // Only allowing URL base payment apps to skip the payment sheet.
+         && spec()->url_payment_method_identifiers().size() == 1;
+}
+
 void PaymentRequest::UpdateWith(mojom::PaymentDetailsPtr details) {
   std::string error;
   if (!ValidatePaymentDetails(ConvertPaymentDetails(details), &error)) {
@@ -394,19 +409,6 @@
   return delegate_->IsIncognito();
 }
 
-bool PaymentRequest::SatisfiesSkipUIConstraints() const {
-  return base::FeatureList::IsEnabled(features::kWebPaymentsSingleAppUiSkip) &&
-         base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps) &&
-         is_show_user_gesture_ && state()->is_get_all_instruments_finished() &&
-         state()->available_instruments().size() == 1 &&
-         spec()->stringified_method_data().size() == 1 &&
-         !spec()->request_shipping() && !spec()->request_payer_name() &&
-         !spec()->request_payer_phone() &&
-         !spec()->request_payer_email()
-         // Only allowing URL base payment apps to skip the payment sheet.
-         && spec()->url_payment_method_identifiers().size() == 1;
-}
-
 void PaymentRequest::RecordFirstAbortReason(
     JourneyLogger::AbortReason abort_reason) {
   if (!has_recorded_completion_) {
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h
index 25b15e9a7..9753d08e 100644
--- a/components/payments/content/payment_request.h
+++ b/components/payments/content/payment_request.h
@@ -107,13 +107,10 @@
 
   bool IsIncognito() const;
 
-  // Returns true if this payment request supports skipping the Payment Sheet.
-  // Typically, this means only one payment method is supported, it's a URL
-  // based method, and no other info is requested from the user.
-  bool SatisfiesSkipUIConstraints() const;
-
   content::WebContents* web_contents() { return web_contents_; }
 
+  bool skipped_payment_request_ui() { return skipped_payment_request_ui_; }
+
   PaymentRequestSpec* spec() { return spec_.get(); }
   PaymentRequestState* state() { return state_.get(); }
 
@@ -121,6 +118,11 @@
   PaymentRequestState* state() const { return state_.get(); }
 
  private:
+  // Returns true if this payment request supports skipping the Payment Sheet.
+  // Typically, this means only one payment method is supported, it's a URL
+  // based method, and no other info is requested from the user.
+  bool SatisfiesSkipUIConstraints() const;
+
   // Only records the abort reason if it's the first completion for this Payment
   // Request. This is necessary since the aborts cascade into one another with
   // the first one being the most precise.
@@ -172,6 +174,9 @@
   // Whether PaymentRequest.show() was invoked with a user gesture.
   bool is_show_user_gesture_ = false;
 
+  // Whether PaymentRequest.show() was invoked by skipping payment request UI.
+  bool skipped_payment_request_ui_ = false;
+
   base::WeakPtrFactory<PaymentRequest> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentRequest);
diff --git a/components/payments/content/payment_request_dialog.h b/components/payments/content/payment_request_dialog.h
index a08c1e64..3d23fcb 100644
--- a/components/payments/content/payment_request_dialog.h
+++ b/components/payments/content/payment_request_dialog.h
@@ -22,10 +22,6 @@
 
   virtual void ShowDialog() = 0;
 
-  virtual void ShowDialogAtPaymentHandlerSheet(
-      const GURL& url,
-      PaymentHandlerOpenWindowCallback callback) = 0;
-
   virtual void CloseDialog() = 0;
 
   virtual void ShowErrorMessage() = 0;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index f52b960..f6ccbb3 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -12819,6 +12819,46 @@
       When this policy is set to False, share discovery will not use the <ph name="NETBIOS_PROTOCOL">NetBIOS Name Query Request protocol</ph> protocol to discover shares.
       If the policy is left not set, the default is disabled for enterprise-managed users and enabled for non-managed users.''',
     },
+    {
+      'name': 'WebAppInstallForceList',
+      'type': 'dict',
+      'schema': {
+        'type': 'array',
+        'items': {
+          'type': 'object',
+          'properties': {
+            'url': { 'type': 'string' },
+            'launch_container': {
+              'type': 'string',
+              'enum': [
+                'tab',
+                'window'
+              ]
+            }
+          },
+          'required': ['url']
+        }
+      },
+      'supported_on': ['chrome.*:70-', 'chrome_os:70-'],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'example_value': [{
+        'url': 'https://www.google.com/maps',
+        'launch_container': 'window'
+      }, {
+        'url': 'https://docs.google.com',
+        'launch_container': 'tab'
+      }],
+      'id': 468,
+      'caption': '''Configure list of force-installed Web Apps''',
+      'tags': [],
+      'desc': '''Specifies a list of websites that are installed silently, without user interaction, and which cannot be uninstalled nor disabled by the user.
+
+      Each list item of the policy is an object with two members: "url" and "launch_container". "url" should be the URL of the web app to install and "launch_container" should be either "window" or "tab" to indicate how the Web App will be opened once installed. If "launch_container" is ommitted, the app will launch in a window if Chrome considers it a Progressive Web App and in a tab otherwise.''',
+      'label': '''URLs for Web Apps to be silently installed.''',
+    },
   ],
 
   'messages': {
@@ -12960,5 +13000,5 @@
   },
   'placeholders': [],
   'deleted_policy_ids': [412],
-  'highest_id_currently_used': 467
+  'highest_id_currently_used': 468
 }
diff --git a/components/previews/content/previews_content_util_unittest.cc b/components/previews/content/previews_content_util_unittest.cc
index a4aa11a..ff164e9 100644
--- a/components/previews/content/previews_content_util_unittest.cc
+++ b/components/previews/content/previews_content_util_unittest.cc
@@ -223,7 +223,8 @@
 TEST_F(PreviewsContentUtilTest,
        DetermineCommittedClientPreviewsStateNoScriptCheckIfStillAllowed) {
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine("Previews,ClientLoFi", std::string());
+  scoped_feature_list.InitFromCommandLine("Previews,ClientLoFi",
+                                          "NoScriptPreviews");
   // NoScript not allowed at commit time so Client LoFi chosen:
   EXPECT_EQ(content::PREVIEWS_OFF,
             previews::DetermineCommittedClientPreviewsState(
diff --git a/components/previews/content/previews_decider_impl_unittest.cc b/components/previews/content/previews_decider_impl_unittest.cc
index 0cb1b01..380914e 100644
--- a/components/previews/content/previews_decider_impl_unittest.cc
+++ b/components/previews/content/previews_decider_impl_unittest.cc
@@ -27,6 +27,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "components/blacklist/opt_out_blacklist/opt_out_blacklist_data.h"
 #include "components/blacklist/opt_out_blacklist/opt_out_blacklist_delegate.h"
 #include "components/blacklist/opt_out_blacklist/opt_out_blacklist_item.h"
@@ -836,7 +837,7 @@
   }
 }
 
-TEST_F(PreviewsDeciderImplTest, NoScriptDisallowedByDefault) {
+TEST_F(PreviewsDeciderImplTest, NoScriptFeatureDefaultBehavior) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(features::kPreviews);
   InitializeUIService();
@@ -850,13 +851,25 @@
       previews::params::GetECTThresholdForPreview(
           previews::PreviewsType::NOSCRIPT),
       std::vector<std::string>(), false));
+#if defined(OS_ANDROID)
+  // Enabled by default on Android but no server whitelist.
+  histogram_tester.ExpectTotalCount("Previews.EligibilityReason.NoScript", 1);
+  histogram_tester.ExpectUniqueSample(
+      "Previews.EligibilityReason.NoScript",
+      static_cast<int>(
+          PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER),
+      1);
+#else   // !defined(OS_ANDROID)
+  // Disabled by default on non-Android.
   histogram_tester.ExpectTotalCount("Previews.EligibilityReason.NoScript", 0);
+#endif  // defined(OS_ANDROID)
 }
 
 TEST_F(PreviewsDeciderImplTest, NoScriptAllowedByFeature) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kNoScriptPreviews}, {});
+      {features::kPreviews, features::kNoScriptPreviews},
+      {features::kOptimizationHints});
   InitializeUIService();
 
   const struct {
@@ -999,7 +1012,8 @@
        ResourceLoadingHintsDisallowedWithoutOptimizationHints) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kResourceLoadingHints}, {});
+      {features::kPreviews, features::kResourceLoadingHints},
+      {features::kOptimizationHints});
   InitializeUIService();
 
   network_quality_estimator()->set_effective_connection_type(
@@ -1314,7 +1328,8 @@
 TEST_F(PreviewsDeciderImplTest, IsURLAllowedForPreviewBlacklistStatuses) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kNoScriptPreviews}, {});
+      {features::kPreviews, features::kNoScriptPreviews},
+      {features::kOptimizationHints});
   InitializeUIService();
   auto expected_type = PreviewsType::NOSCRIPT;
 
diff --git a/components/previews/core/previews_features.cc b/components/previews/core/previews_features.cc
index 499b5141..5bad470c 100644
--- a/components/previews/core/previews_features.cc
+++ b/components/previews/core/previews_features.cc
@@ -37,8 +37,14 @@
 };
 
 // Enables the NoScript previews for Android.
-const base::Feature kNoScriptPreviews{"NoScriptPreviews",
-                                      base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kNoScriptPreviews {
+  "NoScriptPreviews",
+#if defined(OS_ANDROID)
+      base::FEATURE_ENABLED_BY_DEFAULT
+#else   // !defined(OS_ANDROID)
+      base::FEATURE_DISABLED_BY_DEFAULT
+#endif  // defined(OS_ANDROID)
+};
 
 // Enables the Stale Previews timestamp on Previews infobars.
 const base::Feature kStalePreviewsTimestamp{"StalePreviewsTimestamp",
@@ -46,8 +52,14 @@
 
 // Enables the syncing of the Optimization Hints component, which provides
 // hints for what Previews can be applied on a page load.
-const base::Feature kOptimizationHints{"OptimizationHints",
-                                       base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kOptimizationHints {
+  "OptimizationHints",
+#if defined(OS_ANDROID)
+      base::FEATURE_ENABLED_BY_DEFAULT
+#else   // !defined(OS_ANDROID)
+      base::FEATURE_DISABLED_BY_DEFAULT
+#endif  // defined(OS_ANDROID)
+};
 
 // Enables Optimization Hints that are marked as experimental. Optimizations are
 // marked experimental by setting an experiment name in the "experiment_name"
diff --git a/components/printing/common/print_messages.h b/components/printing/common/print_messages.h
index 0c311c9a..e3c11e1 100644
--- a/components/printing/common/print_messages.h
+++ b/components/printing/common/print_messages.h
@@ -26,7 +26,6 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/ipc/geometry/gfx_param_traits.h"
 #include "ui/gfx/ipc/skia/gfx_skia_param_traits.h"
-#include "ui/gfx/native_widget_types.h"
 
 #ifndef INTERNAL_COMPONENTS_PRINTING_COMMON_PRINT_MESSAGES_H_
 #define INTERNAL_COMPONENTS_PRINTING_COMMON_PRINT_MESSAGES_H_
@@ -316,9 +315,6 @@
 
   // Store the expected pages count.
   IPC_STRUCT_MEMBER(int, expected_pages_count)
-
-  // Whether the preview can be modified.
-  IPC_STRUCT_MEMBER(bool, modifiable)
 IPC_STRUCT_END()
 #endif  // BUILDFLAG(ENABLE_PRINT_PREVIEW)
 
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index efb0827..a212616 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -1346,7 +1346,6 @@
   preview_params.document_cookie = print_pages_params_->params.document_cookie;
   preview_params.expected_pages_count =
       print_preview_context_.total_page_count();
-  preview_params.modifiable = print_preview_context_.IsModifiable();
 
   PrintHostMsg_PreviewIds ids(print_pages_params_->params.preview_request_id,
                               print_pages_params_->params.preview_ui_id);
diff --git a/components/signin/core/browser/account_investigator_unittest.cc b/components/signin/core/browser/account_investigator_unittest.cc
index aef935b..a261bfa 100644
--- a/components/signin/core/browser/account_investigator_unittest.cc
+++ b/components/signin/core/browser/account_investigator_unittest.cc
@@ -49,7 +49,7 @@
     AccountTrackerService::RegisterPrefs(prefs_.registry());
     AccountInvestigator::RegisterPrefs(prefs_.registry());
     SigninManagerBase::RegisterProfilePrefs(prefs_.registry());
-    account_tracker_service_.Initialize(&signin_client_);
+    account_tracker_service_.Initialize(&prefs_, base::FilePath());
   }
 
   ~AccountInvestigatorTest() override { investigator_.Shutdown(); }
diff --git a/components/signin/core/browser/account_reconcilor_unittest.cc b/components/signin/core/browser/account_reconcilor_unittest.cc
index dd488d339..c49f7fe4 100644
--- a/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -323,7 +323,7 @@
       GaiaUrls::GetInstance()->GetCheckConnectionInfoURLWithSource(
           GaiaConstants::kChromeSource);
 
-  account_tracker_.Initialize(&test_signin_client_);
+  account_tracker_.Initialize(&pref_service_, base::FilePath());
   cookie_manager_service_.SetListAccountsResponseHttpNotFound();
   signin_manager_.Initialize(nullptr);
 
diff --git a/components/signin/core/browser/account_tracker_service.cc b/components/signin/core/browser/account_tracker_service.cc
index c0bb26a..fe4451e 100644
--- a/components/signin/core/browser/account_tracker_service.cc
+++ b/components/signin/core/browser/account_tracker_service.cc
@@ -21,7 +21,6 @@
 #include "build/build_config.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/scoped_user_pref_update.h"
-#include "components/signin/core/browser/signin_client.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_pref_names.h"
 
@@ -104,8 +103,7 @@
 const char AccountTrackerService::kAccountsFolder[] = "Accounts";
 const char AccountTrackerService::kAvatarImagesFolder[] = "Avatar Images";
 
-AccountTrackerService::AccountTrackerService()
-    : signin_client_(nullptr), weak_factory_(this) {}
+AccountTrackerService::AccountTrackerService() : weak_factory_(this) {}
 
 AccountTrackerService::~AccountTrackerService() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -119,13 +117,13 @@
                                 AccountTrackerService::MIGRATION_NOT_STARTED);
 }
 
-void AccountTrackerService::Initialize(SigninClient* signin_client,
-                                       const base::FilePath& user_data_dir) {
-  DCHECK(signin_client);
-  DCHECK(!signin_client_);
-  signin_client_ = signin_client;
+void AccountTrackerService::Initialize(PrefService* pref_service,
+                                       base::FilePath user_data_dir) {
+  DCHECK(pref_service);
+  DCHECK(!pref_service_);
+  pref_service_ = pref_service;
   LoadFromPrefs();
-  user_data_dir_ = user_data_dir;
+  user_data_dir_ = std::move(user_data_dir);
   if (!user_data_dir_.empty()) {
     // |image_storage_task_runner_| is a sequenced runner because we want to
     // avoid read and write operations to the same file at the same time.
@@ -137,7 +135,7 @@
 }
 
 void AccountTrackerService::Shutdown() {
-  signin_client_ = nullptr;
+  pref_service_ = nullptr;
   accounts_.clear();
 }
 
@@ -212,12 +210,11 @@
 
 AccountTrackerService::AccountIdMigrationState
 AccountTrackerService::GetMigrationState() const {
-  return GetMigrationState(signin_client_->GetPrefs());
+  return GetMigrationState(pref_service_);
 }
 
 void AccountTrackerService::SetMigrationState(AccountIdMigrationState state) {
-  signin_client_->GetPrefs()->SetInteger(prefs::kAccountIdMigrationState,
-                                         state);
+  pref_service_->SetInteger(prefs::kAccountIdMigrationState, state);
 }
 
 void AccountTrackerService::SetMigrationDone() {
@@ -450,8 +447,7 @@
 }
 
 void AccountTrackerService::LoadFromPrefs() {
-  const base::ListValue* list =
-      signin_client_->GetPrefs()->GetList(kAccountInfoPref);
+  const base::ListValue* list = pref_service_->GetList(kAccountInfoPref);
   std::set<std::string> to_remove;
   bool contains_deprecated_service_flags = false;
   for (size_t i = 0; i < list->GetSize(); ++i) {
@@ -518,7 +514,7 @@
   }
 
   if (contains_deprecated_service_flags)
-    RemoveDeprecatedServiceFlags(signin_client_->GetPrefs());
+    RemoveDeprecatedServiceFlags(pref_service_);
 
   // Remove any obsolete prefs.
   for (auto account_id : to_remove) {
@@ -541,12 +537,12 @@
 }
 
 void AccountTrackerService::SaveToPrefs(const AccountState& state) {
-  if (!signin_client_->GetPrefs())
+  if (!pref_service_)
     return;
 
   base::DictionaryValue* dict = nullptr;
   base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id);
-  ListPrefUpdate update(signin_client_->GetPrefs(), kAccountInfoPref);
+  ListPrefUpdate update(pref_service_, kAccountInfoPref);
   for (size_t i = 0; i < update->GetSize(); ++i, dict = nullptr) {
     if (update->GetDictionary(i, &dict)) {
       base::string16 value;
@@ -576,11 +572,11 @@
 }
 
 void AccountTrackerService::RemoveFromPrefs(const AccountState& state) {
-  if (!signin_client_->GetPrefs())
+  if (!pref_service_)
     return;
 
   base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id);
-  ListPrefUpdate update(signin_client_->GetPrefs(), kAccountInfoPref);
+  ListPrefUpdate update(pref_service_, kAccountInfoPref);
   for(size_t i = 0; i < update->GetSize(); ++i) {
     base::DictionaryValue* dict = nullptr;
     if (update->GetDictionary(i, &dict)) {
@@ -596,7 +592,7 @@
 std::string AccountTrackerService::PickAccountIdForAccount(
     const std::string& gaia,
     const std::string& email) const {
-  return PickAccountIdForAccount(signin_client_->GetPrefs(), gaia, email);
+  return PickAccountIdForAccount(pref_service_, gaia, email);
 }
 
 // static
diff --git a/components/signin/core/browser/account_tracker_service.h b/components/signin/core/browser/account_tracker_service.h
index c5dc4eea..739583dda 100644
--- a/components/signin/core/browser/account_tracker_service.h
+++ b/components/signin/core/browser/account_tracker_service.h
@@ -22,7 +22,6 @@
 #include "ui/gfx/image/image.h"
 
 class PrefService;
-class SigninClient;
 
 namespace base {
 class DictionaryValue;
@@ -89,13 +88,10 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
-  // Take a SigninClient rather than a PrefService and a URLRequestContextGetter
-  // since RequestContext cannot be created at startup.
-  // (see http://crbug.com/171406)
-  // If |user_data_dir| is empty, images will not be saved to or loaded from
-  // disk.
-  void Initialize(SigninClient* signin_client,
-                  const base::FilePath& user_data_dir = base::FilePath());
+  // Initializes the list of accounts from |pref_service| and load images from
+  // |user_data_dir|. If |user_data_dir| is empty, images will not be saved to
+  // nor loaded from disk.
+  void Initialize(PrefService* pref_service, base::FilePath user_data_dir);
 
   // Returns the list of known accounts and for which gaia IDs
   // have been fetched.
@@ -186,7 +182,7 @@
   void MigrateToGaiaId();
   void SetMigrationState(AccountIdMigrationState state);
 
-  SigninClient* signin_client_;  // Not owned.
+  PrefService* pref_service_ = nullptr;  // Not owned.
   std::map<std::string, AccountState> accounts_;
   base::ObserverList<Observer>::Unchecked observer_list_;
 
diff --git a/components/signin/core/browser/account_tracker_service_unittest.cc b/components/signin/core/browser/account_tracker_service_unittest.cc
index e1b623ff..fd4bc591 100644
--- a/components/signin/core/browser/account_tracker_service_unittest.cc
+++ b/components/signin/core/browser/account_tracker_service_unittest.cc
@@ -295,7 +295,7 @@
     signin_client_.reset(new TestSigninClient(&pref_service_));
 
     account_tracker_.reset(new AccountTrackerService());
-    account_tracker_->Initialize(signin_client_.get());
+    account_tracker_->Initialize(&pref_service_, base::FilePath());
 
     account_fetcher_.reset(new AccountFetcherService());
     account_fetcher_->Initialize(
@@ -354,6 +354,7 @@
     return fake_oauth2_token_service_.get();
   }
   SigninClient* signin_client() { return signin_client_.get(); }
+  PrefService* prefs() { return &pref_service_; }
 
   network::TestURLLoaderFactory* test_url_loader_factory() {
     return signin_client_->test_url_loader_factory();
@@ -520,7 +521,7 @@
   AccountFetcherService fetcher;
 
   tracker.AddObserver(&observer);
-  tracker.Initialize(signin_client());
+  tracker.Initialize(prefs(), base::FilePath());
 
   fetcher.Initialize(signin_client(), token_service(), &tracker,
                      std::make_unique<TestImageDecoder>());
@@ -602,7 +603,7 @@
   // Create an account tracker and an account fetcher service but do not enable
   // network fetches.
   AccountTrackerService tracker;
-  tracker.Initialize(signin_client());
+  tracker.Initialize(prefs(), base::FilePath());
 
   AccountFetcherService fetcher_service;
   fetcher_service.Initialize(signin_client(), token_service(), &tracker,
@@ -669,7 +670,7 @@
   // to be saved to persistence.
   {
     AccountTrackerService tracker;
-    tracker.Initialize(signin_client(), scoped_user_data_dir.GetPath());
+    tracker.Initialize(prefs(), scoped_user_data_dir.GetPath());
     SimulateTokenAvailable("alpha");
     ReturnAccountInfoFetchSuccess("alpha");
     ReturnAccountImageFetchSuccess("alpha");
@@ -685,7 +686,7 @@
     AccountTrackerService tracker;
     AccountTrackerObserver observer;
     tracker.AddObserver(&observer);
-    tracker.Initialize(signin_client(), scoped_user_data_dir.GetPath());
+    tracker.Initialize(prefs(), scoped_user_data_dir.GetPath());
     ASSERT_TRUE(observer.CheckEvents(TrackingEvent(UPDATED, "alpha"),
                                      TrackingEvent(UPDATED, "beta")));
     // Wait until all account images are loaded.
@@ -726,7 +727,7 @@
   // persistence. Also verify it is a child account.
   {
     AccountTrackerService tracker;
-    tracker.Initialize(signin_client());
+    tracker.Initialize(prefs(), base::FilePath());
 
     std::vector<AccountInfo> infos = tracker.GetAccounts();
     ASSERT_EQ(1u, infos.size());
@@ -807,7 +808,7 @@
   // prefs.
   {
     AccountTrackerService tracker;
-    tracker.Initialize(signin_client());
+    tracker.Initialize(prefs(), base::FilePath());
     AccountFetcherService fetcher;
     fetcher.Initialize(signin_client(), token_service(), &tracker,
                        std::make_unique<TestImageDecoder>());
@@ -820,7 +821,7 @@
 
   {
     AccountTrackerService tracker;
-    tracker.Initialize(signin_client());
+    tracker.Initialize(prefs(), base::FilePath());
     AccountFetcherService fetcher;
     fetcher.Initialize(signin_client(), token_service(), &tracker,
                        std::make_unique<TestImageDecoder>());
@@ -849,7 +850,7 @@
     AccountTrackerService tracker;
     AccountTrackerObserver observer;
     tracker.AddObserver(&observer);
-    tracker.Initialize(signin_client());
+    tracker.Initialize(prefs(), base::FilePath());
     AccountFetcherService fetcher;
     fetcher.Initialize(signin_client(), token_service(), &tracker,
                        std::make_unique<TestImageDecoder>());
@@ -876,7 +877,7 @@
   // prefs.
   {
     AccountTrackerService tracker;
-    tracker.Initialize(signin_client());
+    tracker.Initialize(prefs(), base::FilePath());
     AccountFetcherService fetcher;
     fetcher.Initialize(signin_client(), token_service(), &tracker,
                        std::make_unique<TestImageDecoder>());
@@ -900,7 +901,7 @@
   // and that no network fetches happen.
   {
     AccountTrackerService tracker;
-    tracker.Initialize(signin_client());
+    tracker.Initialize(prefs(), base::FilePath());
     AccountFetcherService fetcher;
     fetcher.Initialize(signin_client(), token_service(), &tracker,
                        std::make_unique<TestImageDecoder>());
@@ -927,7 +928,7 @@
   // are still valid, the network fetches are started.
   {
     AccountTrackerService tracker;
-    tracker.Initialize(signin_client());
+    tracker.Initialize(prefs(), base::FilePath());
     AccountFetcherService fetcher;
     fetcher.Initialize(signin_client(), token_service(), &tracker,
                        std::make_unique<TestImageDecoder>());
@@ -951,7 +952,7 @@
   // a correct non-dotted account id for the same account.
   {
     AccountTrackerService tracker;
-    tracker.Initialize(signin_client());
+    tracker.Initialize(prefs(), base::FilePath());
     AccountFetcherService fetcher;
     fetcher.Initialize(signin_client(), token_service(), &tracker,
                        std::make_unique<TestImageDecoder>());
@@ -972,7 +973,7 @@
   // it is the correct non dotted one.
   {
     AccountTrackerService tracker;
-    tracker.Initialize(signin_client());
+    tracker.Initialize(prefs(), base::FilePath());
     AccountFetcherService fetcher;
     fetcher.Initialize(signin_client(), token_service(), &tracker,
                        std::make_unique<TestImageDecoder>());
@@ -1017,9 +1018,7 @@
     dict->SetString("gaia", base::UTF8ToUTF16(gaia_beta));
     update->Append(std::move(dict));
 
-    std::unique_ptr<TestSigninClient> client;
-    client.reset(new TestSigninClient(&pref));
-    tracker.Initialize(client.get());
+    tracker.Initialize(&pref, base::FilePath());
 
     ASSERT_EQ(tracker.GetMigrationState(),
               AccountTrackerService::MIGRATION_IN_PROGRESS);
@@ -1069,9 +1068,7 @@
     dict->SetString("gaia", base::UTF8ToUTF16(std::string()));
     update->Append(std::move(dict));
 
-    std::unique_ptr<TestSigninClient> client;
-    client.reset(new TestSigninClient(&pref));
-    tracker.Initialize(client.get());
+    tracker.Initialize(&pref, base::FilePath());
 
     ASSERT_EQ(tracker.GetMigrationState(),
               AccountTrackerService::MIGRATION_NOT_STARTED);
@@ -1128,9 +1125,7 @@
     dict->SetString("gaia", base::UTF8ToUTF16(gaia_alpha));
     update->Append(std::move(dict));
 
-    std::unique_ptr<TestSigninClient> client;
-    client.reset(new TestSigninClient(&pref));
-    tracker.Initialize(client.get());
+    tracker.Initialize(&pref, base::FilePath());
 
     ASSERT_EQ(tracker.GetMigrationState(),
               AccountTrackerService::MIGRATION_IN_PROGRESS);
@@ -1150,7 +1145,7 @@
 
     tracker.SetMigrationDone();
     tracker.Shutdown();
-    tracker.Initialize(client.get());
+    tracker.Initialize(&pref, base::FilePath());
 
     ASSERT_EQ(tracker.GetMigrationState(),
               AccountTrackerService::MIGRATION_DONE);
@@ -1173,7 +1168,7 @@
 
 TEST_F(AccountTrackerServiceTest, ChildAccountBasic) {
   AccountTrackerService tracker;
-  tracker.Initialize(signin_client());
+  tracker.Initialize(prefs(), base::FilePath());
   FakeAccountFetcherService fetcher;
   fetcher.Initialize(signin_client(), token_service(), &tracker,
                      std::make_unique<TestImageDecoder>());
@@ -1203,7 +1198,7 @@
 
 TEST_F(AccountTrackerServiceTest, ChildAccountUpdatedAndRevoked) {
   AccountTrackerService tracker;
-  tracker.Initialize(signin_client());
+  tracker.Initialize(prefs(), base::FilePath());
   FakeAccountFetcherService fetcher;
   fetcher.Initialize(signin_client(), token_service(), &tracker,
                      std::make_unique<TestImageDecoder>());
@@ -1233,7 +1228,7 @@
 
 TEST_F(AccountTrackerServiceTest, ChildAccountUpdatedAndRevokedWithUpdate) {
   AccountTrackerService tracker;
-  tracker.Initialize(signin_client());
+  tracker.Initialize(prefs(), base::FilePath());
   FakeAccountFetcherService fetcher;
   fetcher.Initialize(signin_client(), token_service(), &tracker,
                      std::make_unique<TestImageDecoder>());
@@ -1269,7 +1264,7 @@
 
 TEST_F(AccountTrackerServiceTest, ChildAccountUpdatedTwiceThenRevoked) {
   AccountTrackerService tracker;
-  tracker.Initialize(signin_client());
+  tracker.Initialize(prefs(), base::FilePath());
   FakeAccountFetcherService fetcher;
   fetcher.Initialize(signin_client(), token_service(), &tracker,
                      std::make_unique<TestImageDecoder>());
@@ -1307,7 +1302,7 @@
 
 TEST_F(AccountTrackerServiceTest, ChildAccountGraduation) {
   AccountTrackerService tracker;
-  tracker.Initialize(signin_client());
+  tracker.Initialize(prefs(), base::FilePath());
   FakeAccountFetcherService fetcher;
   fetcher.Initialize(signin_client(), token_service(), &tracker,
                      std::make_unique<TestImageDecoder>());
@@ -1366,7 +1361,7 @@
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) && !defined(OS_IOS)
 TEST_F(AccountTrackerServiceTest, AdvancedProtectionAccountBasic) {
   AccountTrackerService tracker;
-  tracker.Initialize(signin_client());
+  tracker.Initialize(prefs(), base::FilePath());
   FakeAccountFetcherService fetcher;
   fetcher.Initialize(signin_client(), token_service(), &tracker,
                      std::make_unique<TestImageDecoder>());
diff --git a/components/signin/core/browser/signin_manager_unittest.cc b/components/signin/core/browser/signin_manager_unittest.cc
index e9daf4e4..e84be48d 100644
--- a/components/signin/core/browser/signin_manager_unittest.cc
+++ b/components/signin/core/browser/signin_manager_unittest.cc
@@ -90,7 +90,7 @@
     AccountTrackerService::RegisterPrefs(user_prefs_.registry());
     SigninManagerBase::RegisterProfilePrefs(user_prefs_.registry());
     SigninManagerBase::RegisterPrefs(local_state_.registry());
-    account_tracker_.Initialize(&test_signin_client_);
+    account_tracker_.Initialize(&user_prefs_, base::FilePath());
     account_fetcher_.Initialize(&test_signin_client_, &token_service_,
                                 &account_tracker_,
                                 std::make_unique<TestImageDecoder>());
@@ -112,6 +112,7 @@
 
   AccountTrackerService* account_tracker() { return &account_tracker_; }
   FakeAccountFetcherService* account_fetcher() { return &account_fetcher_; }
+  PrefService* prefs() { return &user_prefs_; }
 
   // Seed the account tracker with information from logged in user.  Normally
   // this is done by UI code before calling SigninManager.  Returns the string
@@ -513,7 +514,7 @@
     update->Append(std::move(dict));
 
     account_tracker()->Shutdown();
-    account_tracker()->Initialize(signin_client());
+    account_tracker()->Initialize(prefs(), base::FilePath());
 
     client_prefs->SetString(prefs::kGoogleServicesAccountId, email);
 
@@ -543,7 +544,7 @@
     update->Append(std::move(dict));
 
     account_tracker()->Shutdown();
-    account_tracker()->Initialize(signin_client());
+    account_tracker()->Initialize(prefs(), base::FilePath());
 
     client_prefs->ClearPref(prefs::kGoogleServicesAccountId);
     client_prefs->SetString(prefs::kGoogleServicesUsername, email);
@@ -573,7 +574,7 @@
     update->Append(std::move(dict));
 
     account_tracker()->Shutdown();
-    account_tracker()->Initialize(signin_client());
+    account_tracker()->Initialize(prefs(), base::FilePath());
 
     client_prefs->SetString(prefs::kGoogleServicesAccountId, gaia_id);
 
diff --git a/components/signin/ios/browser/account_consistency_service_unittest.mm b/components/signin/ios/browser/account_consistency_service_unittest.mm
index 2d37318..ab90643 100644
--- a/components/signin/ios/browser/account_consistency_service_unittest.mm
+++ b/components/signin/ios/browser/account_consistency_service_unittest.mm
@@ -149,7 +149,7 @@
     web_view_load_expection_count_ = 0;
     gaia_cookie_manager_service_.reset(new MockGaiaCookieManagerService());
     signin_client_.reset(new TestSigninClient(&prefs_));
-    account_tracker_service_.Initialize(signin_client_.get());
+    account_tracker_service_.Initialize(&prefs_, base::FilePath());
     signin_manager_.reset(new FakeSigninManager(
         signin_client_.get(), nullptr, &account_tracker_service_, nullptr));
     signin_manager_->Initialize(nullptr);
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
index f36924c..83f1ee4 100644
--- a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
+++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
@@ -53,7 +53,7 @@
     prefs_.registry()->RegisterIntegerPref(
         prefs::kAccountIdMigrationState,
         AccountTrackerService::MIGRATION_NOT_STARTED);
-    account_tracker_.Initialize(&client_);
+    account_tracker_.Initialize(&prefs_, base::FilePath());
 
     prefs_.registry()->RegisterBooleanPref(
         prefs::kTokenServiceExcludeAllSecondaryAccounts, false);
diff --git a/components/sync/test/fake_server/fake_server.cc b/components/sync/test/fake_server/fake_server.cc
index 944d7f69..1523e2b8 100644
--- a/components/sync/test/fake_server/fake_server.cc
+++ b/components/sync/test/fake_server/fake_server.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/guid.h"
+#include "base/hash.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -49,6 +50,70 @@
 
 FakeServer::~FakeServer() {}
 
+namespace {
+
+std::unique_ptr<sync_pb::DataTypeProgressMarker> RemoveWalletProgressMarker(
+    sync_pb::ClientToServerMessage* message) {
+  google::protobuf::RepeatedPtrField<sync_pb::DataTypeProgressMarker>*
+      progress_markers =
+          message->mutable_get_updates()->mutable_from_progress_marker();
+  for (int index = 0; index < progress_markers->size(); ++index) {
+    if (syncer::GetModelTypeFromSpecificsFieldNumber(
+            progress_markers->Get(index).data_type_id()) ==
+        syncer::AUTOFILL_WALLET_DATA) {
+      auto result = std::make_unique<sync_pb::DataTypeProgressMarker>(
+          progress_markers->Get(index));
+      progress_markers->erase(progress_markers->begin() + index);
+      return result;
+    }
+  }
+  return nullptr;
+}
+
+sync_pb::DataTypeProgressMarker* GetMutableWalletDataProgressMarker(
+    sync_pb::GetUpdatesResponse* gu_response) {
+  for (sync_pb::DataTypeProgressMarker& marker :
+       *gu_response->mutable_new_progress_marker()) {
+    if (syncer::GetModelTypeFromSpecificsFieldNumber(marker.data_type_id()) ==
+        syncer::AUTOFILL_WALLET_DATA) {
+      return &marker;
+    }
+  }
+  auto* new_marker = gu_response->add_new_progress_marker();
+  new_marker->set_data_type_id(
+      GetSpecificsFieldNumberFromModelType(syncer::AUTOFILL_WALLET_DATA));
+  return new_marker;
+}
+
+void PopulateWalletResults(const std::vector<sync_pb::SyncEntity>& entities,
+                           sync_pb::GetUpdatesResponse* gu_response) {
+  int64_t version =
+      (base::Time::Now() - base::Time::UnixEpoch()).InMilliseconds();
+  for (const auto& entity : entities) {
+    sync_pb::SyncEntity* response_entity = gu_response->add_entries();
+    *response_entity = entity;
+    response_entity->set_version(version);
+  }
+  sync_pb::DataTypeProgressMarker* response_marker =
+      GetMutableWalletDataProgressMarker(gu_response);
+  // Make sure to pick a token that will be consistent across clients when
+  // receiving the same data. We sum up the hashes which has the nice side
+  // effect of being independent of the order.
+  int64_t token = 0;
+  for (const auto& entity : entities) {
+    // PersistentHash returns 32-bit integers, so summing them up is defined
+    // behavior.
+    token += base::PersistentHash(entity.id_string());
+  }
+  response_marker->set_token(base::Int64ToString(token));
+  // Set the GC directive to implement non-incremental reads.
+  response_marker->mutable_gc_directive()->set_type(
+      sync_pb::GarbageCollectionDirective::VERSION_WATERMARK);
+  response_marker->mutable_gc_directive()->set_version_watermark(version - 1);
+}
+
+}  // namespace
+
 void FakeServer::HandleCommand(const std::string& request,
                                const base::Closure& completion_closure,
                                int* error_code,
@@ -98,8 +163,22 @@
         break;
         // Don't care.
     }
-    *response_code = SendToLoopbackServer(request, response);
+    // The loopback server does not know how to handle Wallet requests -- and
+    // should not. The FakeServer is handling those instead. The loopback server
+    // has a strong expectations about how progress tokens are structured. To
+    // not interfere with this, we remove wallet progress markers before passing
+    // the request to the loopback server and add them back again afterwards
+    // before handling those requests.
+    std::unique_ptr<sync_pb::DataTypeProgressMarker> wallet_marker =
+        RemoveWalletProgressMarker(&message);
+    *response_code =
+        SendToLoopbackServer(message.SerializeAsString(), response);
+    if (wallet_marker != nullptr) {
+      *message.mutable_get_updates()->add_from_progress_marker() =
+          *wallet_marker;
+    }
     if (*response_code == net::HTTP_OK) {
+      HandleWalletRequest(message, wallet_marker.get(), response);
       InjectClientCommand(response);
     }
     completion_closure.Run();
@@ -111,6 +190,21 @@
   completion_closure.Run();
 }
 
+void FakeServer::HandleWalletRequest(
+    const sync_pb::ClientToServerMessage& request,
+    sync_pb::DataTypeProgressMarker* wallet_marker,
+    std::string* response_string) {
+  if (request.message_contents() !=
+          sync_pb::ClientToServerMessage::GET_UPDATES ||
+      wallet_marker == nullptr) {
+    return;
+  }
+  sync_pb::ClientToServerResponse response_proto;
+  CHECK(response_proto.ParseFromString(*response_string));
+  PopulateWalletResults(wallet_entities_, response_proto.mutable_get_updates());
+  *response_string = response_proto.SerializeAsString();
+}
+
 int FakeServer::SendToLoopbackServer(const std::string& request,
                                      std::string* response) {
   int64_t response_code;
@@ -167,9 +261,23 @@
 
 void FakeServer::InjectEntity(std::unique_ptr<LoopbackServerEntity> entity) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(entity->GetModelType() != syncer::AUTOFILL_WALLET_DATA)
+      << "Wallet data must be injected via SetWalletData()";
   loopback_server_->SaveEntity(std::move(entity));
 }
 
+void FakeServer::SetWalletData(
+    const std::vector<sync_pb::SyncEntity>& wallet_entities) {
+  for (const auto& entity : wallet_entities) {
+    DCHECK_EQ(GetModelTypeFromSpecifics(entity.specifics()),
+              syncer::AUTOFILL_WALLET_DATA);
+    DCHECK(!entity.has_client_defined_unique_tag())
+        << "The sync server doesn not provide a client tag for wallet entries";
+    DCHECK(!entity.id_string().empty()) << "server id required!";
+  }
+  wallet_entities_ = wallet_entities;
+}
+
 bool FakeServer::ModifyEntitySpecifics(
     const std::string& id,
     const sync_pb::EntitySpecifics& updated_specifics) {
diff --git a/components/sync/test/fake_server/fake_server.h b/components/sync/test/fake_server/fake_server.h
index ab740d9d..1fe144cc 100644
--- a/components/sync/test/fake_server/fake_server.h
+++ b/components/sync/test/fake_server/fake_server.h
@@ -80,6 +80,10 @@
   // operations.
   void InjectEntity(std::unique_ptr<syncer::LoopbackServerEntity> entity);
 
+  // Sets the Wallet card and address data to be served in following GetUpdates
+  // requests.
+  void SetWalletData(const std::vector<sync_pb::SyncEntity>& wallet_entities);
+
   // Modifies the entity on the server with the given |id|. The entity's
   // EntitySpecifics are replaced with |updated_specifics| and its version is
   // updated. If the given |id| does not exist or the ModelType of
@@ -170,6 +174,9 @@
   bool ShouldSendTriggeredError() const;
   int SendToLoopbackServer(const std::string& request, std::string* response);
   void InjectClientCommand(std::string* response);
+  void HandleWalletRequest(const sync_pb::ClientToServerMessage& request,
+                           sync_pb::DataTypeProgressMarker* wallet_marker,
+                           std::string* response_string);
 
   // Whether the server should act as if incoming connections are properly
   // authenticated.
@@ -217,6 +224,10 @@
   std::unique_ptr<syncer::LoopbackServer> loopback_server_;
   std::unique_ptr<base::ScopedTempDir> loopback_server_storage_;
 
+  // The LoopbackServer does not know how to handle Wallet data properly, so
+  // the FakeServer handles those itself.
+  std::vector<sync_pb::SyncEntity> wallet_entities_;
+
   // Creates WeakPtr versions of the current FakeServer. This must be the last
   // data member!
   base::WeakPtrFactory<FakeServer> weak_ptr_factory_;
diff --git a/components/translate/core/browser/resources/translate.js b/components/translate/core/browser/resources/translate.js
index b2ece17..5b5ce6b4 100644
--- a/components/translate/core/browser/resources/translate.js
+++ b/components/translate/core/browser/resources/translate.js
@@ -152,6 +152,8 @@
   function invokeReadyCallback() {
     if (readyCallback) {
       readyCallback();
+      // Don't notify ready if already notified.
+      readyCallback = null;
     }
   }
 
diff --git a/components/variations/service/variations_service.cc b/components/variations/service/variations_service.cc
index 96705263..369b12ac 100644
--- a/components/variations/service/variations_service.cc
+++ b/components/variations/service/variations_service.cc
@@ -419,15 +419,12 @@
     PrefService* local_state,
     metrics::MetricsStateManager* state_manager,
     const char* disable_network_switch,
-    const UIStringOverrider& ui_string_overrider,
-    web_resource::ResourceRequestAllowedNotifier::NetworkConnectionTrackerGetter
-        network_connection_tracker_getter) {
+    const UIStringOverrider& ui_string_overrider) {
   std::unique_ptr<VariationsService> result;
   result.reset(new VariationsService(
       std::move(client),
       std::make_unique<web_resource::ResourceRequestAllowedNotifier>(
-          local_state, disable_network_switch,
-          std::move(network_connection_tracker_getter)),
+          local_state, disable_network_switch),
       local_state, state_manager, ui_string_overrider));
   return result;
 }
@@ -481,7 +478,8 @@
   // ResourceRequestAllowedNotifier does not install an observer if there is no
   // NetworkChangeNotifier, which results in never being notified of changes to
   // network status.
-  resource_request_allowed_notifier_->Init(this, false /* leaky */);
+  DCHECK(net::NetworkChangeNotifier::HasNetworkChangeNotifier());
+  resource_request_allowed_notifier_->Init(this);
 }
 
 bool VariationsService::DoFetchFromURL(const GURL& url, bool is_http_retry) {
diff --git a/components/variations/service/variations_service.h b/components/variations/service/variations_service.h
index f754c45..cb9ada3 100644
--- a/components/variations/service/variations_service.h
+++ b/components/variations/service/variations_service.h
@@ -147,9 +147,7 @@
       PrefService* local_state,
       metrics::MetricsStateManager* state_manager,
       const char* disable_network_switch,
-      const UIStringOverrider& ui_string_overrider,
-      web_resource::ResourceRequestAllowedNotifier::
-          NetworkConnectionTrackerGetter network_connection_tracker_getter);
+      const UIStringOverrider& ui_string_overrider);
 
   // Enables fetching the seed for testing, even for unofficial builds. This
   // should be used along with overriding |DoActualFetch| or using
diff --git a/components/variations/service/variations_service_unittest.cc b/components/variations/service/variations_service_unittest.cc
index 5826d50..2c10125 100644
--- a/components/variations/service/variations_service_unittest.cc
+++ b/components/variations/service/variations_service_unittest.cc
@@ -42,7 +42,6 @@
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_network_connection_tracker.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -280,9 +279,7 @@
 class VariationsServiceTest : public ::testing::Test {
  protected:
   VariationsServiceTest()
-      : network_tracker_(true,
-                         network::mojom::ConnectionType::CONNECTION_UNKNOWN),
-        enabled_state_provider_(
+      : enabled_state_provider_(
             new metrics::TestEnabledStateProvider(false, false)) {
     VariationsService::RegisterPrefs(prefs_.registry());
     metrics::CleanExitBeacon::RegisterPrefs(prefs_.registry());
@@ -302,7 +299,6 @@
 
  protected:
   TestingPrefServiceSimple prefs_;
-  network::TestNetworkConnectionTracker network_tracker_;
 
  private:
   base::test::ScopedTaskEnvironment scoped_task_environment_;
@@ -322,8 +318,7 @@
   TestVariationsServiceClient* raw_client = client.get();
   VariationsService service(
       std::move(client),
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), UIStringOverrider());
   GURL url = service.GetVariationsServerURL(&prefs_, std::string(),
                                             TestVariationsService::USE_HTTPS);
@@ -364,8 +359,7 @@
   TestVariationsServiceClient* raw_client = client.get();
   VariationsService service(
       std::move(client),
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), UIStringOverrider());
   raw_client->set_channel(version_info::Channel::UNKNOWN);
   GURL url = service.GetVariationsServerURL(&prefs_, std::string(),
@@ -396,8 +390,7 @@
   // Pass ownership to TestVariationsService, but keep a weak pointer to
   // manipulate it for this test.
   std::unique_ptr<web_resource::TestRequestAllowedNotifier> test_notifier =
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_);
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_);
   web_resource::TestRequestAllowedNotifier* raw_notifier = test_notifier.get();
   TestVariationsService test_service(std::move(test_notifier), &prefs_,
                                      GetMetricsStateManager(), true);
@@ -416,8 +409,7 @@
   // Pass ownership to TestVariationsService, but keep a weak pointer to
   // manipulate it for this test.
   std::unique_ptr<web_resource::TestRequestAllowedNotifier> test_notifier =
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_);
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_);
   web_resource::TestRequestAllowedNotifier* raw_notifier = test_notifier.get();
   TestVariationsService test_service(std::move(test_notifier), &prefs_,
                                      GetMetricsStateManager(), true);
@@ -431,8 +423,7 @@
   VariationsService::EnableFetchForTesting();
 
   TestVariationsService service(
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), true);
 
   EXPECT_FALSE(service.seed_stored());
@@ -455,8 +446,7 @@
   VariationsService::EnableFetchForTesting();
 
   TestVariationsService service(
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), true);
   service.set_intercepts_fetch(false);
   for (size_t i = 0; i < arraysize(non_ok_status_codes); ++i) {
@@ -476,8 +466,7 @@
   VariationsService::EnableFetchForTesting();
 
   TestVariationsService service(
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), true);
   service.set_intercepts_fetch(false);
   net::HttpRequestHeaders intercepted_headers;
@@ -514,8 +503,7 @@
   VariationsService::EnableFetchForTesting();
   for (size_t i = 0; i < arraysize(cases); ++i) {
     TestVariationsService service(
-        std::make_unique<web_resource::TestRequestAllowedNotifier>(
-            &prefs_, &network_tracker_),
+        std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
         &prefs_, GetMetricsStateManager(), true);
     service.set_intercepts_fetch(false);
 
@@ -543,8 +531,7 @@
   VariationsService::EnableFetchForTesting();
 
   TestVariationsService service(
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), true);
   EXPECT_FALSE(service.seed_stored());
   service.set_intercepts_fetch(false);
@@ -568,8 +555,7 @@
 TEST_F(VariationsServiceTest, Observer) {
   VariationsService service(
       std::make_unique<TestVariationsServiceClient>(),
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), UIStringOverrider());
 
   struct {
@@ -667,8 +653,7 @@
   for (const auto& test : test_cases) {
     VariationsService service(
         std::make_unique<TestVariationsServiceClient>(),
-        std::make_unique<web_resource::TestRequestAllowedNotifier>(
-            &prefs_, &network_tracker_),
+        std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
         &prefs_, GetMetricsStateManager(), UIStringOverrider());
 
     if (!test.pref_value_before) {
@@ -739,8 +724,7 @@
 
   for (const auto& test : test_cases) {
     TestVariationsService service(
-        std::make_unique<web_resource::TestRequestAllowedNotifier>(
-            &prefs_, &network_tracker_),
+        std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
         &prefs_, GetMetricsStateManager(), true);
 
     if (test.pref_value_before.empty()) {
@@ -782,8 +766,7 @@
 
   // Create a variations service and start the fetch.
   TestVariationsService service(
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), true);
   service.set_intercepts_fetch(false);
   service.DoActualFetch();
@@ -801,8 +784,7 @@
 
   // Create a variations service and perform a successful fetch.
   TestVariationsService service(
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), true);
   service.set_intercepts_fetch(false);
 
@@ -848,8 +830,7 @@
 
   // Create a variations service and perform a successful fetch.
   TestVariationsService service(
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), true);
   service.set_intercepts_fetch(false);
 
@@ -869,8 +850,7 @@
 
 TEST_F(VariationsServiceTest, FieldTrialCreatorInitializedCorrectly) {
   TestVariationsService service(
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), true);
 
   // Call will crash in service's VariationsFieldTrialCreator if not initialized
@@ -882,8 +862,7 @@
   std::string serialized_seed = SerializeSeed(CreateTestSeed());
   VariationsService::EnableFetchForTesting();
   TestVariationsService service(
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), false);
   service.set_intercepts_fetch(false);
   service.test_url_loader_factory()->AddResponse(
@@ -895,8 +874,7 @@
 TEST_F(VariationsServiceTest, InsecurelyFetchedNotSetWhenHTTPS) {
   std::string serialized_seed = SerializeSeed(CreateTestSeed());
   TestVariationsService service(
-      std::make_unique<web_resource::TestRequestAllowedNotifier>(
-          &prefs_, &network_tracker_),
+      std::make_unique<web_resource::TestRequestAllowedNotifier>(&prefs_),
       &prefs_, GetMetricsStateManager(), true);
   VariationsService::EnableFetchForTesting();
   service.set_intercepts_fetch(false);
diff --git a/components/viz/host/hit_test/hit_test_query.cc b/components/viz/host/hit_test/hit_test_query.cc
index a6128d3e..2d5a6170 100644
--- a/components/viz/host/hit_test/hit_test_query.cc
+++ b/components/viz/host/hit_test/hit_test_query.cc
@@ -110,6 +110,17 @@
     uint32_t region_index,
     Target* target) const {
   gfx::PointF location_transformed(location_in_parent);
+
+  // HasPerspective() is checked for the transform because the point will not
+  // be transformed correctly for a plane with a different normal.
+  // See https://crbug.com/854247.
+  if (hit_test_data_[region_index].transform().HasPerspective()) {
+    target->frame_sink_id = hit_test_data_[region_index].frame_sink_id;
+    target->location_in_target = gfx::PointF();
+    target->flags = HitTestRegionFlags::kHitTestAsk;
+    return true;
+  }
+
   hit_test_data_[region_index].transform().TransformPoint(
       &location_transformed);
   if (!gfx::RectF(hit_test_data_[region_index].rect)
diff --git a/components/viz/service/surfaces/surface_hittest.cc b/components/viz/service/surfaces/surface_hittest.cc
index 83d6b0b..6b630def 100644
--- a/components/viz/service/surfaces/surface_hittest.cc
+++ b/components/viz/service/surfaces/surface_hittest.cc
@@ -108,12 +108,17 @@
 
   // The |transform_to_root_target| matrix may have no back-projection if the
   // forward projection is degenerate.
+  // HasPerspective() is checked for the transform because the point will not
+  // be transformed correctly for a plane with a different normal.
+  // See https://crbug.com/854247.
   gfx::Transform transform_from_root_target;
   gfx::Transform transform_to_root_target =
       render_pass->transform_to_root_target;
   transform_to_root_target.FlattenTo2d();
-  if (!transform_to_root_target.GetInverse(&transform_from_root_target)) {
-    return false;
+  if (transform_to_root_target.HasPerspective() ||
+      !transform_to_root_target.GetInverse(&transform_from_root_target)) {
+    *out_query_renderer = true;
+    return true;
   }
 
   gfx::Point point_in_render_pass_space(point_in_root_target);
@@ -125,6 +130,10 @@
     gfx::Point point_in_quad_space;
     if (!PointInQuad(quad, point_in_render_pass_space,
                      &target_to_quad_transform, &point_in_quad_space)) {
+      if (target_to_quad_transform.HasPerspective()) {
+        *out_query_renderer = true;
+        return false;
+      }
       continue;
     }
 
@@ -335,7 +344,8 @@
   // rect.
   gfx::Transform transform = quad->shared_quad_state->quad_to_target_transform;
   transform.FlattenTo2d();
-  if (!transform.GetInverse(target_to_quad_transform)) {
+  if (!transform.GetInverse(target_to_quad_transform) ||
+      target_to_quad_transform->HasPerspective()) {
     return false;
   }
 
diff --git a/components/web_resource/BUILD.gn b/components/web_resource/BUILD.gn
index 6771f91..74863cc 100644
--- a/components/web_resource/BUILD.gn
+++ b/components/web_resource/BUILD.gn
@@ -36,7 +36,6 @@
   deps = [
     ":web_resource",
     "//base",
-    "//services/network/public/cpp",
   ]
 }
 
diff --git a/components/web_resource/resource_request_allowed_notifier.cc b/components/web_resource/resource_request_allowed_notifier.cc
index d7c0714..34d7bc7 100644
--- a/components/web_resource/resource_request_allowed_notifier.cc
+++ b/components/web_resource/resource_request_allowed_notifier.cc
@@ -10,39 +10,25 @@
 
 ResourceRequestAllowedNotifier::ResourceRequestAllowedNotifier(
     PrefService* local_state,
-    const char* disable_network_switch,
-    NetworkConnectionTrackerGetter network_connection_tracker_getter)
+    const char* disable_network_switch)
     : disable_network_switch_(disable_network_switch),
       local_state_(local_state),
       observer_requested_permission_(false),
       waiting_for_user_to_accept_eula_(false),
-      observer_(nullptr),
-      network_connection_tracker_getter_(
-          std::move(network_connection_tracker_getter)),
-      weak_factory_(this) {}
+      observer_(nullptr) {
+}
 
 ResourceRequestAllowedNotifier::~ResourceRequestAllowedNotifier() {
   if (observer_)
-    network_connection_tracker_->RemoveNetworkConnectionObserver(this);
+    net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
 }
 
-void ResourceRequestAllowedNotifier::Init(Observer* observer, bool leaky) {
+void ResourceRequestAllowedNotifier::Init(Observer* observer) {
   DCHECK(!observer_);
   DCHECK(observer);
   observer_ = observer;
 
-  DCHECK(network_connection_tracker_getter_);
-  network_connection_tracker_ =
-      std::move(network_connection_tracker_getter_).Run();
-
-  if (leaky)
-    network_connection_tracker_->AddLeakyNetworkConnectionObserver(this);
-  else
-    network_connection_tracker_->AddNetworkConnectionObserver(this);
-  network_connection_tracker_->GetConnectionType(
-      &connection_type_,
-      base::BindOnce(&ResourceRequestAllowedNotifier::SetConnectionType,
-                     weak_factory_.GetWeakPtr()));
+  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
 
   eula_notifier_.reset(CreateEulaNotifier());
   if (eula_notifier_) {
@@ -62,10 +48,8 @@
   // The observer requested permission. Return the current criteria state and
   // set a flag to remind this class to notify the observer once the criteria
   // is met.
-  observer_requested_permission_ =
-      waiting_for_user_to_accept_eula_ ||
-      connection_type_ == network::mojom::ConnectionType::CONNECTION_NONE ||
-      !connection_initialized_;
+  observer_requested_permission_ = waiting_for_user_to_accept_eula_ ||
+                                   net::NetworkChangeNotifier::IsOffline();
   if (!observer_requested_permission_)
     return ALLOWED;
   return waiting_for_user_to_accept_eula_ ? DISALLOWED_EULA_NOT_ACCEPTED :
@@ -85,11 +69,6 @@
   observer_requested_permission_ = requested;
 }
 
-void ResourceRequestAllowedNotifier::SetConnectionTypeForTesting(
-    network::mojom::ConnectionType type) {
-  SetConnectionType(type);
-}
-
 void ResourceRequestAllowedNotifier::MaybeNotifyObserver() {
   // Need to ensure that all criteria are met before notifying observers.
   if (observer_requested_permission_ && ResourceRequestsAllowed()) {
@@ -114,10 +93,9 @@
   MaybeNotifyObserver();
 }
 
-void ResourceRequestAllowedNotifier::OnConnectionChanged(
-    network::mojom::ConnectionType type) {
-  SetConnectionType(type);
-  if (type != network::mojom::ConnectionType::CONNECTION_NONE) {
+void ResourceRequestAllowedNotifier::OnNetworkChanged(
+    net::NetworkChangeNotifier::ConnectionType type) {
+  if (type != net::NetworkChangeNotifier::CONNECTION_NONE) {
     DVLOG(1) << "Network came online.";
     // MaybeNotifyObserver() internally guarantees that it will only notify the
     // observer if it's currently waiting for the network to come online.
@@ -125,10 +103,4 @@
   }
 }
 
-void ResourceRequestAllowedNotifier::SetConnectionType(
-    network::mojom::ConnectionType connection_type) {
-  connection_initialized_ = true;
-  connection_type_ = connection_type;
-}
-
 }  // namespace web_resource
diff --git a/components/web_resource/resource_request_allowed_notifier.h b/components/web_resource/resource_request_allowed_notifier.h
index f792dfa..695f60482 100644
--- a/components/web_resource/resource_request_allowed_notifier.h
+++ b/components/web_resource/resource_request_allowed_notifier.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "components/web_resource/eula_accepted_notifier.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
+#include "net/base/network_change_notifier.h"
 
 class PrefService;
 
@@ -37,7 +37,7 @@
 // global instance.
 class ResourceRequestAllowedNotifier
     : public EulaAcceptedNotifier::Observer,
-      public network::NetworkConnectionTracker::NetworkConnectionObserver {
+      public net::NetworkChangeNotifier::NetworkChangeObserver {
  public:
   // Observes resource request allowed state changes.
   class Observer {
@@ -54,26 +54,20 @@
     DISALLOWED_COMMAND_LINE_DISABLED,
   };
 
-  using NetworkConnectionTrackerGetter =
-      base::OnceCallback<network::NetworkConnectionTracker*()>;
-
   // Creates a new ResourceRequestAllowedNotifier.
   // |local_state| is the PrefService to observe.
   // |disable_network_switch| is the command line switch to disable network
   // activity. It is expected to outlive the ResourceRequestAllowedNotifier and
   // may be null.
-  ResourceRequestAllowedNotifier(
-      PrefService* local_state,
-      const char* disable_network_switch,
-      NetworkConnectionTrackerGetter network_connection_tracker_getter);
+  ResourceRequestAllowedNotifier(PrefService* local_state,
+                                 const char* disable_network_switch);
   ~ResourceRequestAllowedNotifier() override;
 
   // Sets |observer| as the service to be notified by this instance, and
   // performs initial checks on the criteria. |observer| may not be null.
   // This is to be called immediately after construction of an instance of
-  // ResourceRequestAllowedNotifier to pass it the interested service. Set
-  // |leaky| to true if this class will not be destructed before shutdown.
-  void Init(Observer* observer, bool leaky);
+  // ResourceRequestAllowedNotifier to pass it the interested service.
+  void Init(Observer* observer);
 
   // Returns whether resource requests are allowed, per the various criteria.
   // If not, this call will set some flags so it knows to notify the observer
@@ -88,8 +82,6 @@
 
   void SetWaitingForEulaForTesting(bool waiting);
   void SetObserverRequestedForTesting(bool requested);
-  void SetConnectionTypeForTesting(
-      network::mojom::ConnectionType connection_type);
 
  protected:
   // Notifies the observer if all criteria needed for resource requests are met.
@@ -104,10 +96,9 @@
   // EulaAcceptedNotifier::Observer overrides:
   void OnEulaAccepted() override;
 
-  // network::NetworkConnectionTracker::NetworkConnectionObserver overrides:
-  void OnConnectionChanged(network::mojom::ConnectionType type) override;
-
-  void SetConnectionType(network::mojom::ConnectionType connection_type);
+  // net::NetworkChangeNotifier::NetworkChangeObserver overrides:
+  void OnNetworkChanged(
+      net::NetworkChangeNotifier::ConnectionType type) override;
 
   // Name of the command line switch to disable the network activity.
   const char* disable_network_switch_;
@@ -129,14 +120,6 @@
   // Observing service interested in request permissions.
   Observer* observer_;
 
-  NetworkConnectionTrackerGetter network_connection_tracker_getter_;
-  network::NetworkConnectionTracker* network_connection_tracker_ = nullptr;
-  network::mojom::ConnectionType connection_type_ =
-      network::mojom::ConnectionType::CONNECTION_UNKNOWN;
-  bool connection_initialized_ = false;
-
-  base::WeakPtrFactory<ResourceRequestAllowedNotifier> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(ResourceRequestAllowedNotifier);
 };
 
diff --git a/components/web_resource/resource_request_allowed_notifier_test_util.cc b/components/web_resource/resource_request_allowed_notifier_test_util.cc
index 3c12718f..e297452 100644
--- a/components/web_resource/resource_request_allowed_notifier_test_util.cc
+++ b/components/web_resource/resource_request_allowed_notifier_test_util.cc
@@ -6,19 +6,11 @@
 
 namespace web_resource {
 
-TestRequestAllowedNotifier::TestRequestAllowedNotifier(
-    PrefService* local_state,
-    network::NetworkConnectionTracker* network_connection_tracker)
-    : ResourceRequestAllowedNotifier(
-          local_state,
-          nullptr,
-          base::BindOnce(
-              [](network::NetworkConnectionTracker* tracker) {
-                return tracker;
-              },
-              network_connection_tracker)),
+TestRequestAllowedNotifier::TestRequestAllowedNotifier(PrefService* local_state)
+    : ResourceRequestAllowedNotifier(local_state, nullptr),
       override_requests_allowed_(false),
-      requests_allowed_(true) {}
+      requests_allowed_(true) {
+}
 
 TestRequestAllowedNotifier::~TestRequestAllowedNotifier() {
 }
@@ -27,7 +19,7 @@
     Observer* observer,
     std::unique_ptr<EulaAcceptedNotifier> eula_notifier) {
   test_eula_notifier_.swap(eula_notifier);
-  Init(observer, false /* leaky */);
+  Init(observer);
 }
 
 void TestRequestAllowedNotifier::SetRequestsAllowedOverride(bool allowed) {
diff --git a/components/web_resource/resource_request_allowed_notifier_test_util.h b/components/web_resource/resource_request_allowed_notifier_test_util.h
index 9cd1c143..a9fadf1 100644
--- a/components/web_resource/resource_request_allowed_notifier_test_util.h
+++ b/components/web_resource/resource_request_allowed_notifier_test_util.h
@@ -25,9 +25,7 @@
 // it to return.
 class TestRequestAllowedNotifier : public ResourceRequestAllowedNotifier {
  public:
-  TestRequestAllowedNotifier(
-      PrefService* local_state,
-      network::NetworkConnectionTracker* network_connection_tracker);
+  explicit TestRequestAllowedNotifier(PrefService* local_state);
   ~TestRequestAllowedNotifier() override;
 
   // A version of |Init()| that accepts a custom EulaAcceptedNotifier.
diff --git a/components/web_resource/resource_request_allowed_notifier_unittest.cc b/components/web_resource/resource_request_allowed_notifier_unittest.cc
index 69b41ac..a2b1d58e 100644
--- a/components/web_resource/resource_request_allowed_notifier_unittest.cc
+++ b/components/web_resource/resource_request_allowed_notifier_unittest.cc
@@ -9,11 +9,38 @@
 #include "components/prefs/testing_pref_service.h"
 #include "components/web_resource/eula_accepted_notifier.h"
 #include "components/web_resource/resource_request_allowed_notifier_test_util.h"
-#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace web_resource {
 
+// Override NetworkChangeNotifier to simulate connection type changes for tests.
+class TestNetworkChangeNotifier : public net::NetworkChangeNotifier {
+ public:
+  TestNetworkChangeNotifier()
+      : connection_type_(net::NetworkChangeNotifier::CONNECTION_UNKNOWN) {}
+
+  // Simulates a change of the connection type to |type|. This will notify any
+  // objects that are NetworkChangeNotifiers.
+  void SimulateNetworkConnectionChange(
+      net::NetworkChangeNotifier::ConnectionType type) {
+    connection_type_ = type;
+    net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
+        connection_type_);
+    base::RunLoop().RunUntilIdle();
+  }
+
+ private:
+  ConnectionType GetCurrentConnectionType() const override {
+    return connection_type_;
+  }
+
+  // The currently simulated network connection type. If this is set to
+  // CONNECTION_NONE, then NetworkChangeNotifier::IsOffline will return true.
+  net::NetworkChangeNotifier::ConnectionType connection_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestNetworkChangeNotifier);
+};
+
 // EulaAcceptedNotifier test class that allows mocking the EULA accepted state
 // and issuing simulated notifications.
 class TestEulaAcceptedNotifier : public EulaAcceptedNotifier {
@@ -48,9 +75,7 @@
       public ResourceRequestAllowedNotifier::Observer {
  public:
   ResourceRequestAllowedNotifierTest()
-      : network_tracker_(true,
-                         network::mojom::ConnectionType::CONNECTION_UNKNOWN),
-        resource_request_allowed_notifier_(&prefs_, &network_tracker_),
+      : resource_request_allowed_notifier_(&prefs_),
         eula_notifier_(new TestEulaAcceptedNotifier),
         was_notified_(false) {
     resource_request_allowed_notifier_.InitWithEulaAcceptNotifier(
@@ -63,9 +88,9 @@
   // ResourceRequestAllowedNotifier::Observer override:
   void OnResourceRequestsAllowed() override { was_notified_ = true; }
 
-  void SimulateNetworkConnectionChange(network::mojom::ConnectionType type) {
-    network_tracker_.SetConnectionType(type);
-    base::RunLoop().RunUntilIdle();
+  void SimulateNetworkConnectionChange(
+      net::NetworkChangeNotifier::ConnectionType type) {
+    network_notifier.SimulateNetworkConnectionChange(type);
   }
 
   // Simulate a resource request from the test service. It returns true if
@@ -92,7 +117,7 @@
   // and the network.
   void DisableEulaAndNetwork() {
     SimulateNetworkConnectionChange(
-        network::mojom::ConnectionType::CONNECTION_NONE);
+        net::NetworkChangeNotifier::CONNECTION_NONE);
     SetWaitingForEula(true);
     SetNeedsEulaAcceptance(true);
   }
@@ -107,8 +132,8 @@
   }
 
  private:
-  base::MessageLoopForUI message_loop_;
-  network::TestNetworkConnectionTracker network_tracker_;
+  base::MessageLoopForUI message_loop;
+  TestNetworkChangeNotifier network_notifier;
   TestingPrefServiceSimple prefs_;
   TestRequestAllowedNotifier resource_request_allowed_notifier_;
   TestEulaAcceptedNotifier* eula_notifier_;  // Weak, owned by RRAN.
@@ -118,88 +143,71 @@
 };
 
 TEST_F(ResourceRequestAllowedNotifierTest, DoNotNotifyIfOffline) {
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_NONE);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_NONE);
   EXPECT_FALSE(SimulateResourceRequest());
 
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_NONE);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_NONE);
   EXPECT_FALSE(was_notified());
 }
 
 TEST_F(ResourceRequestAllowedNotifierTest, DoNotNotifyIfOnlineToOnline) {
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_TRUE(SimulateResourceRequest());
 
   SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_ETHERNET);
+      net::NetworkChangeNotifier::CONNECTION_ETHERNET);
   EXPECT_FALSE(was_notified());
 }
 
 TEST_F(ResourceRequestAllowedNotifierTest, NotifyOnReconnect) {
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_NONE);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_NONE);
   EXPECT_FALSE(SimulateResourceRequest());
 
   SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_ETHERNET);
+      net::NetworkChangeNotifier::CONNECTION_ETHERNET);
   EXPECT_TRUE(was_notified());
 }
 
 TEST_F(ResourceRequestAllowedNotifierTest, NoNotifyOnWardriving) {
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_TRUE(SimulateResourceRequest());
 
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_FALSE(was_notified());
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_3G);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_3G);
   EXPECT_FALSE(was_notified());
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_4G);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_4G);
   EXPECT_FALSE(was_notified());
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_FALSE(was_notified());
 }
 
 TEST_F(ResourceRequestAllowedNotifierTest, NoNotifyOnFlakyConnection) {
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_TRUE(SimulateResourceRequest());
 
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_FALSE(was_notified());
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_NONE);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_NONE);
   EXPECT_FALSE(was_notified());
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_FALSE(was_notified());
 }
 
 TEST_F(ResourceRequestAllowedNotifierTest, NotifyOnFlakyConnection) {
   // First, the observer queries the state while the network is connected.
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_TRUE(SimulateResourceRequest());
 
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_FALSE(was_notified());
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_NONE);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_NONE);
   EXPECT_FALSE(was_notified());
 
   // Now, the observer queries the state while the network is disconnected.
   EXPECT_FALSE(SimulateResourceRequest());
 
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_TRUE(was_notified());
 }
 
@@ -207,11 +215,9 @@
   DisableEulaAndNetwork();
   EXPECT_FALSE(SimulateResourceRequest());
 
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_FALSE(was_notified());
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_NONE);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_NONE);
   EXPECT_FALSE(was_notified());
   SimulateEulaAccepted();
   EXPECT_FALSE(was_notified());
@@ -221,10 +227,9 @@
   // Ensure that if the observing service does not request access, it does not
   // get notified, even if the criteria are met. Note that this is done by not
   // calling SimulateResourceRequest here.
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_NONE);
   SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_NONE);
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_ETHERNET);
+      net::NetworkChangeNotifier::CONNECTION_ETHERNET);
   EXPECT_FALSE(was_notified());
 }
 
@@ -243,8 +248,7 @@
   SimulateEulaAccepted();
   EXPECT_FALSE(was_notified());
 
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_TRUE(was_notified());
 }
 
@@ -252,8 +256,7 @@
   DisableEulaAndNetwork();
   EXPECT_FALSE(SimulateResourceRequest());
 
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_FALSE(was_notified());
 
   SimulateEulaAccepted();
@@ -266,8 +269,7 @@
   // calling SimulateResourceRequest here.
   DisableEulaAndNetwork();
 
-  SimulateNetworkConnectionChange(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
+  SimulateNetworkConnectionChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
   EXPECT_FALSE(was_notified());
 
   SimulateEulaAccepted();
diff --git a/components/web_resource/web_resource_service.cc b/components/web_resource/web_resource_service.cc
index c72c341..5680024 100644
--- a/components/web_resource/web_resource_service.cc
+++ b/components/web_resource/web_resource_service.cc
@@ -44,14 +44,10 @@
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const char* disable_network_switch,
     const ParseJSONCallback& parse_json_callback,
-    const net::NetworkTrafficAnnotationTag& traffic_annotation,
-    ResourceRequestAllowedNotifier::NetworkConnectionTrackerGetter
-        network_connection_tracker_getter)
+    const net::NetworkTrafficAnnotationTag& traffic_annotation)
     : prefs_(prefs),
-      resource_request_allowed_notifier_(new ResourceRequestAllowedNotifier(
-          prefs,
-          disable_network_switch,
-          std::move(network_connection_tracker_getter))),
+      resource_request_allowed_notifier_(
+          new ResourceRequestAllowedNotifier(prefs, disable_network_switch)),
       fetch_scheduled_(false),
       in_fetch_(false),
       web_resource_server_(web_resource_server),
@@ -63,7 +59,7 @@
       parse_json_callback_(parse_json_callback),
       traffic_annotation_(traffic_annotation),
       weak_ptr_factory_(this) {
-  resource_request_allowed_notifier_->Init(this, false /* leaky */);
+  resource_request_allowed_notifier_->Init(this);
   DCHECK(prefs);
 }
 
@@ -118,7 +114,7 @@
 void WebResourceService::SetResourceRequestAllowedNotifier(
     std::unique_ptr<ResourceRequestAllowedNotifier> notifier) {
   resource_request_allowed_notifier_ = std::move(notifier);
-  resource_request_allowed_notifier_->Init(this, false /* leaky */);
+  resource_request_allowed_notifier_->Init(this);
 }
 
 bool WebResourceService::GetFetchScheduled() const {
diff --git a/components/web_resource/web_resource_service.h b/components/web_resource/web_resource_service.h
index ba9d1407..279f793 100644
--- a/components/web_resource/web_resource_service.h
+++ b/components/web_resource/web_resource_service.h
@@ -55,9 +55,7 @@
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const char* disable_network_switch,
       const ParseJSONCallback& parse_json_callback,
-      const net::NetworkTrafficAnnotationTag& traffic_annotation,
-      ResourceRequestAllowedNotifier::NetworkConnectionTrackerGetter
-          network_connection_tracker_getter);
+      const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
   ~WebResourceService() override;
 
diff --git a/components/web_resource/web_resource_service_unittest.cc b/components/web_resource/web_resource_service_unittest.cc
index 0250013..b12caae5 100644
--- a/components/web_resource/web_resource_service_unittest.cc
+++ b/components/web_resource/web_resource_service_unittest.cc
@@ -15,7 +15,6 @@
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_network_connection_tracker.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -30,18 +29,9 @@
 class TestResourceRequestAllowedNotifier
     : public ResourceRequestAllowedNotifier {
  public:
-  TestResourceRequestAllowedNotifier(
-      PrefService* prefs,
-      const char* disable_network_switch,
-      network::NetworkConnectionTracker* network_connection_tracker)
-      : ResourceRequestAllowedNotifier(
-            prefs,
-            disable_network_switch,
-            base::BindOnce(
-                [](network::NetworkConnectionTracker* tracker) {
-                  return tracker;
-                },
-                network_connection_tracker)) {}
+  TestResourceRequestAllowedNotifier(PrefService* prefs,
+                                     const char* disable_network_switch)
+      : ResourceRequestAllowedNotifier(prefs, disable_network_switch) {}
 
   ResourceRequestAllowedNotifier::State GetResourceRequestsAllowedState()
       override {
@@ -71,8 +61,7 @@
       int cache_update_delay_ms,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const char* disable_network_switch,
-      const ParseJSONCallback& parse_json_callback,
-      network::NetworkConnectionTracker* network_connection_tracker)
+      const ParseJSONCallback& parse_json_callback)
       : WebResourceService(prefs,
                            web_resource_server,
                            application_locale,
@@ -82,21 +71,14 @@
                            url_loader_factory,
                            disable_network_switch,
                            parse_json_callback,
-                           TRAFFIC_ANNOTATION_FOR_TESTS,
-                           base::BindOnce(
-                               [](network::NetworkConnectionTracker* tracker) {
-                                 return tracker;
-                               },
-                               network_connection_tracker)){};
+                           TRAFFIC_ANNOTATION_FOR_TESTS){};
 
   void Unpack(const base::DictionaryValue& parsed_json) override {}
 };
 
 class WebResourceServiceTest : public testing::Test {
  public:
-  WebResourceServiceTest()
-      : network_tracker_(true,
-                         network::mojom::ConnectionType::CONNECTION_UNKNOWN) {}
+  WebResourceServiceTest() {}
 
   void SetUp() override {
     test_shared_loader_factory_ =
@@ -107,12 +89,10 @@
     test_web_resource_service_.reset(new TestWebResourceService(
         local_state_.get(), GURL(kTestUrl), "", kCacheUpdatePath.c_str(), 100,
         5000, test_shared_loader_factory_, nullptr,
-        base::BindRepeating(web_resource::WebResourceServiceTest::Parse),
-        &network_tracker_));
+        base::Bind(web_resource::WebResourceServiceTest::Parse)));
     error_message_ = "";
     TestResourceRequestAllowedNotifier* notifier =
-        new TestResourceRequestAllowedNotifier(local_state_.get(), nullptr,
-                                               &network_tracker_);
+        new TestResourceRequestAllowedNotifier(local_state_.get(), nullptr);
     notifier->SetState(ResourceRequestAllowedNotifier::ALLOWED);
     test_web_resource_service_->SetResourceRequestAllowedNotifier(
         std::unique_ptr<ResourceRequestAllowedNotifier>(notifier));
@@ -152,7 +132,6 @@
   network::TestURLLoaderFactory test_url_loader_factory_;
   scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
   std::unique_ptr<TestingPrefServiceSimple> local_state_;
-  network::TestNetworkConnectionTracker network_tracker_;
   std::unique_ptr<TestWebResourceService> test_web_resource_service_;
 };
 
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 752565f..be7c107 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1008,7 +1008,6 @@
     "loader/detachable_resource_handler.h",
     "loader/download_utils_impl.cc",
     "loader/download_utils_impl.h",
-    "loader/global_routing_id.h",
     "loader/intercepting_resource_handler.cc",
     "loader/intercepting_resource_handler.h",
     "loader/layered_resource_handler.cc",
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc
index 513f7cc..c874c05 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.cc
+++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -241,7 +241,7 @@
   if (!out_x || !out_y || !out_width || !out_height)
     return E_INVALIDARG;
 
-  const base::string16& text_str = GetText();
+  const base::string16& text_str = GetTextAsString16();
   HandleSpecialTextOffset(&offset);
   if (offset < 0 || offset > static_cast<LONG>(text_str.size()))
     return E_INVALIDARG;
@@ -289,7 +289,7 @@
   if (!text)
     return E_INVALIDARG;
 
-  const base::string16& text_str = GetText();
+  const base::string16& text_str = GetTextAsString16();
   HandleSpecialTextOffset(&start_offset);
   HandleSpecialTextOffset(&end_offset);
 
@@ -336,7 +336,7 @@
   if (offset < 0)
     return E_INVALIDARG;
 
-  const base::string16& text_str = GetText();
+  const base::string16& text_str = GetTextAsString16();
   LONG text_len = text_str.length();
   if (offset > text_len)
     return E_INVALIDARG;
@@ -380,7 +380,7 @@
   *end_offset = 0;
   *text = NULL;
 
-  const base::string16& text_str = GetText();
+  const base::string16& text_str = GetTextAsString16();
   LONG text_len = text_str.length();
   if (offset > text_len)
     return E_INVALIDARG;
@@ -414,7 +414,7 @@
   *end_offset = 0;
   *text = NULL;
 
-  const base::string16& text_str = GetText();
+  const base::string16& text_str = GetTextAsString16();
   LONG text_len = text_str.length();
   if (offset > text_len)
     return E_INVALIDARG;
@@ -447,7 +447,7 @@
   if (new_len == 0)
     return E_FAIL;
 
-  base::string16 substr = GetText().substr(start, new_len);
+  base::string16 substr = GetTextAsString16().substr(start, new_len);
   new_text->text = SysAllocString(substr.c_str());
   new_text->start = static_cast<LONG>(start);
   new_text->end = static_cast<LONG>(start + new_len);
@@ -584,7 +584,7 @@
   if (!owner())
     return E_FAIL;
 
-  const base::string16 text = GetText();
+  const base::string16 text = GetTextAsString16();
   HandleSpecialTextOffset(&offset);
   if (offset < 0 || offset > static_cast<LONG>(text.size()))
     return E_INVALIDARG;
@@ -660,7 +660,8 @@
   if (!hyperlink_index)
     return E_INVALIDARG;
 
-  if (char_index < 0 || char_index >= static_cast<LONG>(GetText().size())) {
+  if (char_index < 0 ||
+      char_index >= static_cast<LONG>(GetTextAsString16().size())) {
     return E_INVALIDARG;
   }
 
@@ -691,7 +692,7 @@
   if (index != 0 || !anchor)
     return E_INVALIDARG;
 
-  BSTR ia2_hypertext = SysAllocString(GetText().c_str());
+  BSTR ia2_hypertext = SysAllocString(GetTextAsString16().c_str());
   DCHECK(ia2_hypertext);
   anchor->vt = VT_BSTR;
   anchor->bstrVal = ia2_hypertext;
@@ -1454,7 +1455,8 @@
   if (!out_x || !out_y || !out_width || !out_height)
     return E_INVALIDARG;
 
-  unsigned int text_length = static_cast<unsigned int>(GetText().size());
+  unsigned int text_length =
+      static_cast<unsigned int>(GetTextAsString16().size());
   if (start_index > text_length || end_index > text_length ||
       start_index > end_index) {
     return E_INVALIDARG;
@@ -1482,7 +1484,8 @@
   if (!manager)
     return E_FAIL;
 
-  unsigned int text_length = static_cast<unsigned int>(GetText().size());
+  unsigned int text_length =
+      static_cast<unsigned int>(GetTextAsString16().size());
   if (start_index > text_length || end_index > text_length ||
       start_index > end_index) {
     return E_INVALIDARG;
@@ -1655,7 +1658,7 @@
           child->GetSpellingAttributes();
       MergeSpellingIntoTextAttributes(spelling_attributes, start_offset,
                                       &attributes_map);
-      start_offset += child->GetText().length();
+      start_offset += child->GetTextAsString16().length();
     } else {
       start_offset += 1;
     }
@@ -2075,7 +2078,8 @@
           spelling_attributes[start_offset + attribute.first] =
               std::move(attribute.second);
         }
-        start_offset += static_cast<int>(text_win->GetText().length());
+        start_offset +=
+            static_cast<int>(text_win->GetTextAsString16().length());
       }
     }
   }
@@ -2249,14 +2253,14 @@
   // TODO(nektar): |AXPosition| can handle other types of boundaries as well.
   ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
   return ui::FindAccessibleTextBoundary(
-      GetText(), owner()->GetLineStartOffsets(), boundary, start_offset,
-      direction, affinity);
+      GetTextAsString16(), owner()->GetLineStartOffsets(), boundary,
+      start_offset, direction, affinity);
 }
 
 LONG BrowserAccessibilityComWin::FindStartOfStyle(
     LONG start_offset,
     ui::TextBoundaryDirection direction) {
-  LONG text_length = static_cast<LONG>(GetText().length());
+  LONG text_length = static_cast<LONG>(GetTextAsString16().length());
   DCHECK_GE(start_offset, 0);
   DCHECK_LE(start_offset, text_length);
 
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
index 5b1585a..fbeb12c5 100644
--- a/content/browser/accessibility/browser_accessibility_win.cc
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -53,7 +53,7 @@
 }
 
 base::string16 BrowserAccessibilityWin::GetText() const {
-  return GetCOM()->AXPlatformNodeWin::GetText();
+  return GetCOM()->AXPlatformNodeWin::GetTextAsString16();
 }
 
 gfx::NativeViewAccessible BrowserAccessibilityWin::GetNativeViewAccessible() {
diff --git a/content/browser/appcache/appcache_service_impl.cc b/content/browser/appcache/appcache_service_impl.cc
index 4dca31e..513eef22 100644
--- a/content/browser/appcache/appcache_service_impl.cc
+++ b/content/browser/appcache/appcache_service_impl.cc
@@ -30,22 +30,13 @@
 
 namespace content {
 
-namespace {
+AppCacheInfoCollection::AppCacheInfoCollection() = default;
 
-void DeferredCallback(OnceCompletionCallback callback, int rv) {
-  std::move(callback).Run(rv);
-}
-
-}  // namespace
-
-AppCacheInfoCollection::AppCacheInfoCollection() {}
-
-AppCacheInfoCollection::~AppCacheInfoCollection() {}
+AppCacheInfoCollection::~AppCacheInfoCollection() = default;
 
 // AsyncHelper -------
 
-class AppCacheServiceImpl::AsyncHelper
-    : public AppCacheStorage::Delegate {
+class AppCacheServiceImpl::AsyncHelper : public AppCacheStorage::Delegate {
  public:
   AsyncHelper(AppCacheServiceImpl* service, OnceCompletionCallback callback)
       : service_(service), callback_(std::move(callback)) {
@@ -64,13 +55,12 @@
 
  protected:
   void CallCallback(int rv) {
-    if (!callback_.is_null()) {
+    if (callback_) {
       // Defer to guarantee async completion.
       base::SequencedTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::BindOnce(&DeferredCallback, std::move(callback_), rv));
+          FROM_HERE, base::BindOnce(std::move(callback_), rv));
     }
-    callback_.Reset();
+    DCHECK(!callback_);
   }
 
   AppCacheServiceImpl* service_;
@@ -442,9 +432,9 @@
   // leave the appcache disabled for an indefinite period of time. Some
   // users never shutdown the browser.
 
-  const base::TimeDelta kZeroDelta;
-  const base::TimeDelta kOneHour(base::TimeDelta::FromHours(1));
-  const base::TimeDelta k30Seconds(base::TimeDelta::FromSeconds(30));
+  constexpr base::TimeDelta kZeroDelta;
+  constexpr base::TimeDelta kOneHour = base::TimeDelta::FromHours(1);
+  constexpr base::TimeDelta kThirtySeconds = base::TimeDelta::FromSeconds(30);
 
   // If the system managed to stay up for long enough, reset the
   // delay so a new failure won't incur a long wait to get going again.
@@ -456,7 +446,7 @@
                       this, &AppCacheServiceImpl::Reinitialize);
 
   // Adjust the delay for next time.
-  base::TimeDelta increment = std::max(k30Seconds, next_reinit_delay_);
+  base::TimeDelta increment = std::max(kThirtySeconds, next_reinit_delay_);
   next_reinit_delay_ = std::min(next_reinit_delay_ + increment,  kOneHour);
 }
 
@@ -514,8 +504,7 @@
 void AppCacheServiceImpl::RegisterBackend(
     AppCacheBackendImpl* backend_impl) {
   DCHECK(backends_.find(backend_impl->process_id()) == backends_.end());
-  backends_.insert(
-      BackendMap::value_type(backend_impl->process_id(), backend_impl));
+  backends_.insert({backend_impl->process_id(), backend_impl});
 }
 
 void AppCacheServiceImpl::UnregisterBackend(
diff --git a/content/browser/appcache/appcache_service_impl.h b/content/browser/appcache/appcache_service_impl.h
index f9e5ed4a..d83fc409 100644
--- a/content/browser/appcache/appcache_service_impl.h
+++ b/content/browser/appcache/appcache_service_impl.h
@@ -65,8 +65,7 @@
 // Class that manages the application cache service. Sends notifications
 // to many frontends.  One instance per user-profile. Each instance has
 // exclusive access to its cache_directory on disk.
-class CONTENT_EXPORT AppCacheServiceImpl
-    : public AppCacheService {
+class CONTENT_EXPORT AppCacheServiceImpl : public AppCacheService {
  public:
 
   class CONTENT_EXPORT Observer {
@@ -154,8 +153,8 @@
   void RegisterBackend(AppCacheBackendImpl* backend_impl);
   virtual void UnregisterBackend(AppCacheBackendImpl* backend_impl);
   AppCacheBackendImpl* GetBackend(int id) const {
-    BackendMap::const_iterator it = backends_.find(id);
-    return (it != backends_.end()) ? it->second : NULL;
+    auto it = backends_.find(id);
+    return (it != backends_.end()) ? it->second : nullptr;
   }
 
   AppCacheStorage* storage() const { return storage_.get(); }
@@ -192,10 +191,6 @@
   class GetInfoHelper;
   class CheckResponseHelper;
 
-  using PendingAsyncHelpers =
-      std::map<AsyncHelper*, std::unique_ptr<AsyncHelper>>;
-  using BackendMap = std::map<int, AppCacheBackendImpl*>;
-
   void Reinitialize();
 
   base::FilePath cache_directory_;
@@ -205,8 +200,9 @@
   std::unique_ptr<AppCacheStorage> storage_;
   scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
   scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
-  PendingAsyncHelpers pending_helpers_;
-  BackendMap backends_;  // One 'backend' per child process.
+  std::map<AsyncHelper*, std::unique_ptr<AsyncHelper>> pending_helpers_;
+  // One 'backend' per child process.
+  std::map<int, AppCacheBackendImpl*> backends_;
   // Context for use during cache updates.
   net::URLRequestContext* request_context_;
   // If true, nothing (not even session-only data) should be deleted on exit.
diff --git a/content/browser/background_fetch/background_fetch.proto b/content/browser/background_fetch/background_fetch.proto
index 72ddf75..c14ad004 100644
--- a/content/browser/background_fetch/background_fetch.proto
+++ b/content/browser/background_fetch/background_fetch.proto
@@ -11,8 +11,13 @@
 // Stores per-registration (as opposed to per-request) data.
 // https://wicg.github.io/background-fetch/#background-fetch-registration
 //
-// Next Tag: 7
+// Next Tag: 8
 message BackgroundFetchRegistration {
+  enum BackgroundFetchState {
+    PENDING = 0;  // Default value.
+    FAILURE = 1;
+    SUCCESS = 2;
+  }
   // See definition of |unique_id| in BackgroundFetchRegistrationId.
   optional string unique_id = 1;
 
@@ -23,6 +28,7 @@
   optional uint64 uploaded = 4;
   optional uint64 download_total = 5;
   optional uint64 downloaded = 6;
+  optional BackgroundFetchState state = 7;
 }
 
 // Developer provided options.
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc
index 8fdf69d..6de73cb 100644
--- a/content/browser/background_fetch/background_fetch_context.cc
+++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -17,6 +17,8 @@
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/public/browser/background_fetch_delegate.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
@@ -131,6 +133,7 @@
     const std::vector<ServiceWorkerFetchRequest>& requests,
     const BackgroundFetchOptions& options,
     const SkBitmap& icon,
+    RenderFrameHost* render_frame_host,
     blink::mojom::BackgroundFetchService::FetchCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
@@ -141,10 +144,58 @@
   DCHECK_EQ(0u, fetch_callbacks_.count(registration_id));
   fetch_callbacks_[registration_id] = std::move(callback);
 
-  data_manager_->CreateRegistration(
-      registration_id, requests, options, icon,
+  // |data_manager| is guaranteed to outlive |this|. |create_registration| is
+  // passed to `DidGetPermission`, which is tied to |weak_factory_|. That means
+  // that if |create_registration| runs, |this| is still alive, as is
+  // |data_manager| (a pointer owned by |this|).
+  auto create_registration = base::BindOnce(
+      &BackgroundFetchDataManager::CreateRegistration,
+      base::Unretained(data_manager_.get()), registration_id, requests, options,
+      icon,
       base::BindOnce(&BackgroundFetchContext::DidCreateRegistration,
                      weak_factory_.GetWeakPtr(), registration_id));
+
+  GetPermissionForOrigin(
+      registration_id.origin(), render_frame_host,
+      base::BindOnce(&BackgroundFetchContext::DidGetPermission,
+                     weak_factory_.GetWeakPtr(), std::move(create_registration),
+                     registration_id));
+}
+
+void BackgroundFetchContext::GetPermissionForOrigin(
+    const url::Origin& origin,
+    RenderFrameHost* render_frame_host,
+    GetPermissionCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  ResourceRequestInfo::WebContentsGetter wc_getter = base::NullCallback();
+
+  // Permissions need to go through the DownloadRequestLimiter if the fetch
+  // is started from a top-level frame.
+  if (render_frame_host && !render_frame_host->GetParent()) {
+    wc_getter = base::BindRepeating(&WebContents::FromFrameTreeNodeId,
+                                    render_frame_host->GetFrameTreeNodeId());
+  }
+
+  delegate_proxy_.GetPermissionForOrigin(origin, std::move(wc_getter),
+                                         std::move(callback));
+}
+
+void BackgroundFetchContext::DidGetPermission(
+    base::OnceClosure permission_closure,
+    const BackgroundFetchRegistrationId& registration_id,
+    bool has_permission) {
+  if (has_permission) {
+    std::move(permission_closure).Run();
+    return;
+  }
+
+  // No permission, the fetch should be rejected.
+  background_fetch::RecordRegistrationCreatedError(
+      blink::mojom::BackgroundFetchError::PERMISSION_DENIED);
+  std::move(fetch_callbacks_[registration_id])
+      .Run(blink::mojom::BackgroundFetchError::PERMISSION_DENIED,
+           base::nullopt);
 }
 
 void BackgroundFetchContext::GetIconDisplaySize(
@@ -365,10 +416,14 @@
   if (error != blink::mojom::BackgroundFetchError::NONE)
     return;
 
+  auto controllers_iter = job_controllers_.find(registration_id.unique_id());
+
   if (reason_to_abort == BackgroundFetchReasonToAbort::ABORTED_BY_DEVELOPER) {
-    DCHECK(job_controllers_.count(registration_id.unique_id()));
-    job_controllers_[registration_id.unique_id()]->Abort(reason_to_abort);
+    DCHECK(controllers_iter != job_controllers_.end());
+    controllers_iter->second->Abort(reason_to_abort);
   }
+  auto registration = controllers_iter->second->NewRegistration(
+      blink::mojom::BackgroundFetchState::FAILURE);
 
   switch (reason_to_abort) {
     case BackgroundFetchReasonToAbort::ABORTED_BY_DEVELOPER:
@@ -376,8 +431,7 @@
       CleanupRegistration(registration_id, {},
                           blink::mojom::BackgroundFetchState::FAILURE);
       event_dispatcher_.DispatchBackgroundFetchAbortEvent(
-          registration_id, blink::mojom::BackgroundFetchState::FAILURE,
-          base::DoNothing());
+          registration_id, std::move(registration), base::DoNothing());
       return;
     case BackgroundFetchReasonToAbort::TOTAL_DOWNLOAD_SIZE_EXCEEDED:
     case BackgroundFetchReasonToAbort::SERVICE_WORKER_UNAVAILABLE:
@@ -390,13 +444,15 @@
           registration_id,
           std::make_unique<BackgroundFetchRequestMatchParams>(),
           base::BindOnce(&BackgroundFetchContext::DidGetSettledFetches,
-                         weak_factory_.GetWeakPtr(), registration_id));
+                         weak_factory_.GetWeakPtr(), registration_id,
+                         std::move(registration)));
       return;
   }
 }
 
 void BackgroundFetchContext::DidGetSettledFetches(
     const BackgroundFetchRegistrationId& registration_id,
+    std::unique_ptr<BackgroundFetchRegistration> registration,
     blink::mojom::BackgroundFetchError error,
     bool background_fetch_succeeded,
     std::vector<BackgroundFetchSettledFetch> settled_fetches,
@@ -410,13 +466,21 @@
     return;
   }
 
+  DCHECK(job_controllers_.count(registration_id.unique_id()));
+
+  if (job_controllers_[registration_id.unique_id()]->total_downloads() !=
+      static_cast<int>(settled_fetches.size())) {
+    // Something went wrong, and some information was lost.
+    background_fetch_succeeded = false;
+  }
+
   // The `backgroundfetchsuccess` event will be invoked when all requests in the
   // registration have completed successfully. In all other cases, the
   // `backgroundfetchfail` event will be invoked instead.
   if (background_fetch_succeeded) {
+    registration->state = blink::mojom::BackgroundFetchState::SUCCESS;
     event_dispatcher_.DispatchBackgroundFetchSuccessEvent(
-        registration_id, blink::mojom::BackgroundFetchState::SUCCESS,
-        std::move(settled_fetches),
+        registration_id, std::move(registration), std::move(settled_fetches),
         base::BindOnce(
             &BackgroundFetchContext::CleanupRegistration,
             weak_factory_.GetWeakPtr(), registration_id,
@@ -427,9 +491,9 @@
             blink::mojom::BackgroundFetchState::SUCCESS,
             true /* preserve_info_to_dispatch_click_event */));
   } else {
+    registration->state = blink::mojom::BackgroundFetchState::FAILURE;
     event_dispatcher_.DispatchBackgroundFetchFailEvent(
-        registration_id, blink::mojom::BackgroundFetchState::FAILURE,
-        std::move(settled_fetches),
+        registration_id, std::move(registration), std::move(settled_fetches),
         base::BindOnce(
             &BackgroundFetchContext::CleanupRegistration,
             weak_factory_.GetWeakPtr(), registration_id,
@@ -455,9 +519,12 @@
   // backgroundfetchsuccess/backgroundfetchfail event has been resolved. Store
   // the information we want to persist after the controller is gone, in
   // completed_fetches_.
+  auto controllers_iter = job_controllers_.find(registration_id.unique_id());
+  DCHECK(controllers_iter != job_controllers_.end());
   if (preserve_info_to_dispatch_click_event) {
-    completed_fetches_[registration_id.unique_id()] = {registration_id,
-                                                       background_fetch_state};
+    completed_fetches_[registration_id.unique_id()] = std::make_pair(
+        registration_id,
+        controllers_iter->second->NewRegistration(background_fetch_state));
   }
   job_controllers_.erase(registration_id.unique_id());
 
@@ -481,7 +548,7 @@
     // The fetch has succeeded or failed. (not aborted/cancelled).
     event_dispatcher_.DispatchBackgroundFetchClickEvent(
         iter->second.first /* registration_id */,
-        iter->second.second /* state */, base::DoNothing());
+        std::move(iter->second.second) /* registration */, base::DoNothing());
     completed_fetches_.erase(iter);
     return;
   }
@@ -492,9 +559,11 @@
     return;
   // TODO(crbug.com/873630): Implement a background fetch state manager to
   // keep track of states, and stop hard-coding it here.
+  auto registration = controllers_iter->second->NewRegistration(
+      blink::mojom::BackgroundFetchState::PENDING);
   event_dispatcher_.DispatchBackgroundFetchClickEvent(
-      controllers_iter->second->registration_id(),
-      blink::mojom::BackgroundFetchState::PENDING, base::DoNothing());
+      controllers_iter->second->registration_id(), std::move(registration),
+      base::DoNothing());
 }
 
 void BackgroundFetchContext::MatchRequests(
diff --git a/content/browser/background_fetch/background_fetch_context.h b/content/browser/background_fetch/background_fetch_context.h
index 9c40e87..e25b915 100644
--- a/content/browser/background_fetch/background_fetch_context.h
+++ b/content/browser/background_fetch/background_fetch_context.h
@@ -40,6 +40,7 @@
 class BackgroundFetchScheduler;
 class BrowserContext;
 class CacheStorageContextImpl;
+class RenderFrameHost;
 class ServiceWorkerContextWrapper;
 struct ServiceWorkerFetchRequest;
 
@@ -90,6 +91,7 @@
                   const std::vector<ServiceWorkerFetchRequest>& requests,
                   const BackgroundFetchOptions& options,
                   const SkBitmap& icon,
+                  RenderFrameHost* render_frame_host,
                   blink::mojom::BackgroundFetchService::FetchCallback callback);
 
   // Gets display size for the icon for Background Fetch UI.
@@ -148,6 +150,8 @@
   void OnStorageWiped() override;
 
  private:
+  using GetPermissionCallback = base::OnceCallback<void(bool)>;
+
   FRIEND_TEST_ALL_PREFIXES(BackgroundFetchServiceTest,
                            JobsInitializedOnBrowserRestart);
   friend class BackgroundFetchServiceTest;
@@ -204,6 +208,7 @@
   // retrieved from storage, and the Service Worker event can be invoked.
   void DidGetSettledFetches(
       const BackgroundFetchRegistrationId& registration_id,
+      std::unique_ptr<BackgroundFetchRegistration> registration,
       blink::mojom::BackgroundFetchError error,
       bool background_fetch_succeeded,
       std::vector<BackgroundFetchSettledFetch> settled_fetches,
@@ -259,6 +264,17 @@
   // blink::mojom::kInvalidServiceWorkerRegistrationId.
   void AbandonFetches(int64_t service_worker_registration_id);
 
+  // Check if |origin| has permission to start a fetch.
+  // virtual for testing.
+  void GetPermissionForOrigin(const url::Origin& origin,
+                              RenderFrameHost* render_frame_host,
+                              GetPermissionCallback callback);
+
+  // Callback for GetPermissionForOrigin.
+  void DidGetPermission(base::OnceClosure permission_closure,
+                        const BackgroundFetchRegistrationId& registration_id,
+                        bool has_permission);
+
   // |this| is owned, indirectly, by the BrowserContext.
   BrowserContext* browser_context_;
 
@@ -275,13 +291,13 @@
   std::map<std::string, std::unique_ptr<BackgroundFetchJobController>>
       job_controllers_;
 
-  // Map from |unique_id|s to {|registration_id|s, BackgroundFetchState}.
+  // Map from |unique_id|s to {|registration_id|, |registration|}.
   // An entry in here means the fetch has completed. This information is needed
   // after the fetch has completed to dispatch the backgroundfetchclick event.
   // TODO(crbug.com/857122): Clean this up when the UI is no longer showing.
   std::map<std::string,
            std::pair<BackgroundFetchRegistrationId,
-                     blink::mojom::BackgroundFetchState>>
+                     std::unique_ptr<BackgroundFetchRegistration>>>
       completed_fetches_;
   // Map from BackgroundFetchRegistrationIds to FetchCallbacks for active
   // fetches. Must be destroyed before |data_manager_| and
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.cc b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
index c698fe8..c8048fe 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
@@ -41,6 +41,29 @@
     return weak_ptr_factory_.GetWeakPtr();
   }
 
+  void ForwardGetPermissionForOriginCallbackToIO(
+      BackgroundFetchDelegate::GetPermissionForOriginCallback callback,
+      bool has_permission) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(std::move(callback), has_permission));
+  }
+
+  void GetPermissionForOrigin(
+      const url::Origin& origin,
+      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      BackgroundFetchDelegate::GetPermissionForOriginCallback callback) {
+    if (delegate_) {
+      delegate_->GetPermissionForOrigin(
+          origin, wc_getter,
+          base::BindOnce(&Core::ForwardGetPermissionForOriginCallbackToIO,
+                         weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+    } else {
+      std::move(callback).Run(false /* has_permission */);
+    }
+  }
+
   void ForwardGetIconDisplaySizeCallbackToIO(
       BackgroundFetchDelegate::GetIconDisplaySizeCallback callback,
       const gfx::Size& display_size) {
@@ -289,6 +312,17 @@
                                          ui_core_ptr_, std::move(callback)));
 }
 
+void BackgroundFetchDelegateProxy::GetPermissionForOrigin(
+    const url::Origin& origin,
+    const ResourceRequestInfo::WebContentsGetter& wc_getter,
+    BackgroundFetchDelegate::GetPermissionForOriginCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&Core::GetPermissionForOrigin, ui_core_ptr_, origin,
+                     wc_getter, std::move(callback)));
+}
+
 void BackgroundFetchDelegateProxy::CreateDownloadJob(
     base::WeakPtr<Controller> controller,
     std::unique_ptr<BackgroundFetchDescription> fetch_description,
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.h b/content/browser/background_fetch/background_fetch_delegate_proxy.h
index 8272ba6..d393db4 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy.h
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.h
@@ -66,6 +66,12 @@
   void GetIconDisplaySize(
       BackgroundFetchDelegate::GetIconDisplaySizeCallback callback);
 
+  // Checks if the provided origin has permission to start a Background Fetch.
+  void GetPermissionForOrigin(
+      const url::Origin& origin,
+      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      BackgroundFetchDelegate::GetPermissionForOriginCallback callback);
+
   // Creates a new download grouping described by |fetch_description|. Further
   // downloads started by StartRequest will also use
   // |fetch_description.job_unique_id| so that a notification can be updated
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
index 5bad5b7..8d14278 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
@@ -33,6 +33,12 @@
       BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) override {
     std::move(callback).Run(gfx::Size(kIconDisplaySize, kIconDisplaySize));
   }
+  void GetPermissionForOrigin(
+      const url::Origin& origin,
+      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      GetPermissionForOriginCallback callback) override {
+    std::move(callback).Run(true /* has_permission */);
+  }
   void CreateDownloadJob(
       std::unique_ptr<BackgroundFetchDescription> fetch_description) override {}
   void DownloadUrl(const std::string& job_unique_id,
diff --git a/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc b/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc
index c52f6b5..d280f1d 100644
--- a/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc
+++ b/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc
@@ -20,13 +20,11 @@
     ~BackgroundFetchEmbeddedWorkerTestHelper() = default;
 
 void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchAbortEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback) {
-  last_developer_id_ = developer_id;
-  last_unique_id_ = unique_id;
-  last_state_ = state;
+  last_developer_id_ = registration.developer_id;
+  last_unique_id_ = registration.unique_id;
+  last_state_ = registration.state;
 
   if (fail_abort_event_) {
     std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::REJECTED,
@@ -41,13 +39,11 @@
 }
 
 void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchClickEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback) {
-  last_developer_id_ = developer_id;
-  last_unique_id_ = unique_id;
-  last_state_ = state;
+  last_developer_id_ = registration.developer_id;
+  last_unique_id_ = registration.unique_id;
+  last_state_ = registration.state;
 
   if (fail_click_event_) {
     std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::REJECTED,
@@ -62,14 +58,12 @@
 }
 
 void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchFailEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback) {
-  last_developer_id_ = developer_id;
-  last_unique_id_ = unique_id;
-  last_state_ = state;
+  last_developer_id_ = registration.developer_id;
+  last_unique_id_ = registration.unique_id;
+  last_state_ = registration.state;
   last_fetches_ = fetches;
 
   if (fail_fetch_fail_event_) {
@@ -85,15 +79,13 @@
 }
 
 void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchSuccessEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
         callback) {
-  last_developer_id_ = developer_id;
-  last_unique_id_ = unique_id;
-  last_state_ = state;
+  last_developer_id_ = registration.developer_id;
+  last_unique_id_ = registration.unique_id;
+  last_state_ = registration.state;
   last_fetches_ = fetches;
 
   if (fail_fetched_event_) {
diff --git a/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h b/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h
index 5fcb21d..d6203654 100644
--- a/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h
+++ b/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h
@@ -63,28 +63,20 @@
  protected:
   // EmbeddedWorkerTestHelper overrides:
   void OnBackgroundFetchAbortEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback)
       override;
   void OnBackgroundFetchClickEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback)
       override;
   void OnBackgroundFetchFailEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback)
       override;
   void OnBackgroundFetchSuccessEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
           callback) override;
diff --git a/content/browser/background_fetch/background_fetch_event_dispatcher.cc b/content/browser/background_fetch/background_fetch_event_dispatcher.cc
index 8bf88edc..fcbfaae4 100644
--- a/content/browser/background_fetch/background_fetch_event_dispatcher.cc
+++ b/content/browser/background_fetch/background_fetch_event_dispatcher.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/stringprintf.h"
 #include "content/browser/background_fetch/background_fetch_registration_id.h"
@@ -76,84 +77,81 @@
 
 void BackgroundFetchEventDispatcher::DispatchBackgroundFetchAbortEvent(
     const BackgroundFetchRegistrationId& registration_id,
-    blink::mojom::BackgroundFetchState state,
+    std::unique_ptr<BackgroundFetchRegistration> registration,
     base::OnceClosure finished_closure) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   LoadServiceWorkerRegistrationForDispatch(
       registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_ABORT,
       std::move(finished_closure),
-      base::Bind(
+      base::AdaptCallbackForRepeating(base::BindOnce(
           &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchAbortEvent,
-          registration_id.developer_id(), registration_id.unique_id(), state));
+          std::move(registration))));
 }
 
 void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchAbortEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    std::unique_ptr<BackgroundFetchRegistration> registration,
     scoped_refptr<ServiceWorkerVersion> service_worker_version,
     int request_id) {
   DCHECK(service_worker_version);
+  DCHECK(registration);
   service_worker_version->endpoint()->DispatchBackgroundFetchAbortEvent(
-      developer_id, unique_id, state,
+      *registration,
       service_worker_version->CreateSimpleEventCallback(request_id));
 }
 
 void BackgroundFetchEventDispatcher::DispatchBackgroundFetchClickEvent(
     const BackgroundFetchRegistrationId& registration_id,
-    blink::mojom::BackgroundFetchState state,
+    std::unique_ptr<BackgroundFetchRegistration> registration,
     base::OnceClosure finished_closure) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   LoadServiceWorkerRegistrationForDispatch(
       registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_CLICK,
       std::move(finished_closure),
-      base::Bind(
+      base::AdaptCallbackForRepeating(base::BindOnce(
           &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchClickEvent,
-          registration_id, state));
+          std::move(registration))));
 }
 
 void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchClickEvent(
-    const BackgroundFetchRegistrationId& registration_id,
-    blink::mojom::BackgroundFetchState state,
+    std::unique_ptr<BackgroundFetchRegistration> registration,
     scoped_refptr<ServiceWorkerVersion> service_worker_version,
     int request_id) {
   DCHECK(service_worker_version);
+  DCHECK(registration);
   service_worker_version->endpoint()->DispatchBackgroundFetchClickEvent(
-      registration_id.developer_id(), registration_id.unique_id(), state,
+      *registration,
       service_worker_version->CreateSimpleEventCallback(request_id));
 }
 
 void BackgroundFetchEventDispatcher::DispatchBackgroundFetchFailEvent(
     const BackgroundFetchRegistrationId& registration_id,
-    blink::mojom::BackgroundFetchState state,
+    std::unique_ptr<BackgroundFetchRegistration> registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     base::OnceClosure finished_closure) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   LoadServiceWorkerRegistrationForDispatch(
       registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_FAIL,
       std::move(finished_closure),
-      base::Bind(
+      base::AdaptCallbackForRepeating(base::BindOnce(
           &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchFailEvent,
-          registration_id.developer_id(), registration_id.unique_id(), state,
-          fetches));
+          std::move(registration), fetches)));
 }
 
 void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchFailEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    std::unique_ptr<BackgroundFetchRegistration> registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     scoped_refptr<ServiceWorkerVersion> service_worker_version,
     int request_id) {
   DCHECK(service_worker_version);
+  DCHECK(registration);
   service_worker_version->endpoint()->DispatchBackgroundFetchFailEvent(
-      developer_id, unique_id, state, fetches,
+      *registration, fetches,
       service_worker_version->CreateSimpleEventCallback(request_id));
 }
 
 void BackgroundFetchEventDispatcher::DispatchBackgroundFetchSuccessEvent(
     const BackgroundFetchRegistrationId& registration_id,
-    blink::mojom::BackgroundFetchState state,
+    std::unique_ptr<BackgroundFetchRegistration> registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     base::OnceClosure finished_closure) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -161,22 +159,21 @@
       registration_id,
       ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_SUCCESS,
       std::move(finished_closure),
-      base::Bind(&BackgroundFetchEventDispatcher::
-                     DoDispatchBackgroundFetchSuccessEvent,
-                 registration_id.developer_id(), registration_id.unique_id(),
-                 state, fetches));
+      base::AdaptCallbackForRepeating(
+          base::BindOnce(&BackgroundFetchEventDispatcher::
+                             DoDispatchBackgroundFetchSuccessEvent,
+                         std::move(registration), fetches)));
 }
 
 void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchSuccessEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    std::unique_ptr<BackgroundFetchRegistration> registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     scoped_refptr<ServiceWorkerVersion> service_worker_version,
     int request_id) {
   DCHECK(service_worker_version);
+  DCHECK(registration);
   service_worker_version->endpoint()->DispatchBackgroundFetchSuccessEvent(
-      developer_id, unique_id, state, fetches,
+      *registration, fetches,
       service_worker_version->CreateSimpleEventCallback(request_id));
 }
 
diff --git a/content/browser/background_fetch/background_fetch_event_dispatcher.h b/content/browser/background_fetch/background_fetch_event_dispatcher.h
index 5fa5af8..19bdacb3 100644
--- a/content/browser/background_fetch/background_fetch_event_dispatcher.h
+++ b/content/browser/background_fetch/background_fetch_event_dispatcher.h
@@ -45,14 +45,14 @@
   // background fetch was aborted by the user or another external event.
   void DispatchBackgroundFetchAbortEvent(
       const BackgroundFetchRegistrationId& registration_id,
-      blink::mojom::BackgroundFetchState state,
+      std::unique_ptr<BackgroundFetchRegistration> registration,
       base::OnceClosure finished_closure);
 
   // Dispatches the `backgroundfetchclick` event, which indicates that the user
   // interface displayed for an active background fetch was activated.
   void DispatchBackgroundFetchClickEvent(
       const BackgroundFetchRegistrationId& registration_id,
-      blink::mojom::BackgroundFetchState state,
+      std::unique_ptr<BackgroundFetchRegistration> registration,
       base::OnceClosure finished_closure);
 
   // Dispatches the `backgroundfetchfail` event, which indicates that a
@@ -60,7 +60,7 @@
   // response pairs are included.
   void DispatchBackgroundFetchFailEvent(
       const BackgroundFetchRegistrationId& registration_id,
-      blink::mojom::BackgroundFetchState state,
+      std::unique_ptr<BackgroundFetchRegistration> registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       base::OnceClosure finished_closure);
 
@@ -69,7 +69,7 @@
   // included.
   void DispatchBackgroundFetchSuccessEvent(
       const BackgroundFetchRegistrationId& registration_id,
-      blink::mojom::BackgroundFetchState state,
+      std::unique_ptr<BackgroundFetchRegistration> registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       base::OnceClosure finished_closure);
 
@@ -117,27 +117,20 @@
 
   // Methods that actually invoke the event on an activated Service Worker.
   static void DoDispatchBackgroundFetchAbortEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      std::unique_ptr<BackgroundFetchRegistration> registration,
       scoped_refptr<ServiceWorkerVersion> service_worker_version,
       int request_id);
   static void DoDispatchBackgroundFetchClickEvent(
-      const BackgroundFetchRegistrationId& registration_id,
-      blink::mojom::BackgroundFetchState state,
+      std::unique_ptr<BackgroundFetchRegistration> registration,
       scoped_refptr<ServiceWorkerVersion> service_worker_version,
       int request_id);
   static void DoDispatchBackgroundFetchFailEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      std::unique_ptr<BackgroundFetchRegistration> registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       scoped_refptr<ServiceWorkerVersion> service_worker_version,
       int request_id);
   static void DoDispatchBackgroundFetchSuccessEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      std::unique_ptr<BackgroundFetchRegistration> registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       scoped_refptr<ServiceWorkerVersion> service_worker_version,
       int request_id);
diff --git a/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc b/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
index 3c34c478..ee26685 100644
--- a/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
@@ -45,9 +45,12 @@
       kExampleUniqueId);
 
   base::RunLoop run_loop;
+  auto registration = CreateBackgroundFetchRegistration(
+      invalid_registration_id.developer_id(),
+      invalid_registration_id.unique_id(),
+      blink::mojom::BackgroundFetchState::FAILURE);
   event_dispatcher_.DispatchBackgroundFetchAbortEvent(
-      invalid_registration_id, blink::mojom::BackgroundFetchState::FAILURE,
-      run_loop.QuitClosure());
+      invalid_registration_id, std::move(registration), run_loop.QuitClosure());
 
   run_loop.Run();
 
@@ -73,9 +76,11 @@
 
   {
     base::RunLoop run_loop;
+    auto registration = CreateBackgroundFetchRegistration(
+        kExampleDeveloperId, kExampleUniqueId,
+        blink::mojom::BackgroundFetchState::FAILURE);
     event_dispatcher_.DispatchBackgroundFetchAbortEvent(
-        registration_id, blink::mojom::BackgroundFetchState::FAILURE,
-        run_loop.QuitClosure());
+        registration_id, std::move(registration), run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -99,9 +104,12 @@
 
   {
     base::RunLoop run_loop;
-    event_dispatcher_.DispatchBackgroundFetchAbortEvent(
-        second_registration_id, blink::mojom::BackgroundFetchState::FAILURE,
-        run_loop.QuitClosure());
+    auto registration = CreateBackgroundFetchRegistration(
+        kExampleDeveloperId2, kExampleUniqueId2,
+        blink::mojom::BackgroundFetchState::FAILURE);
+    event_dispatcher_.DispatchBackgroundFetchAbortEvent(second_registration_id,
+                                                        std::move(registration),
+                                                        run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -135,9 +143,11 @@
 
   {
     base::RunLoop run_loop;
+    auto registration = CreateBackgroundFetchRegistration(
+        kExampleDeveloperId, kExampleUniqueId,
+        blink::mojom::BackgroundFetchState::PENDING);
     event_dispatcher_.DispatchBackgroundFetchClickEvent(
-        registration_id, blink::mojom::BackgroundFetchState::PENDING,
-        run_loop.QuitClosure());
+        registration_id, std::move(registration), run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -161,9 +171,12 @@
 
   {
     base::RunLoop run_loop;
-    event_dispatcher_.DispatchBackgroundFetchClickEvent(
-        second_registration_id, blink::mojom::BackgroundFetchState::FAILURE,
-        run_loop.QuitClosure());
+    auto registration = CreateBackgroundFetchRegistration(
+        kExampleDeveloperId2, kExampleUniqueId2,
+        blink::mojom::BackgroundFetchState::FAILURE);
+    event_dispatcher_.DispatchBackgroundFetchClickEvent(second_registration_id,
+                                                        std::move(registration),
+                                                        run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -200,8 +213,11 @@
 
   {
     base::RunLoop run_loop;
+    auto registration = CreateBackgroundFetchRegistration(
+        kExampleDeveloperId, kExampleUniqueId,
+        blink::mojom::BackgroundFetchState::FAILURE);
     event_dispatcher_.DispatchBackgroundFetchFailEvent(
-        registration_id, blink::mojom::BackgroundFetchState::FAILURE, fetches,
+        registration_id, std::move(registration), fetches,
         run_loop.QuitClosure());
 
     run_loop.Run();
@@ -229,9 +245,12 @@
 
   {
     base::RunLoop run_loop;
+    auto registration = CreateBackgroundFetchRegistration(
+        kExampleDeveloperId2, kExampleUniqueId2,
+        blink::mojom::BackgroundFetchState::FAILURE);
     event_dispatcher_.DispatchBackgroundFetchFailEvent(
-        second_registration_id, blink::mojom::BackgroundFetchState::FAILURE,
-        fetches, run_loop.QuitClosure());
+        second_registration_id, std::move(registration), fetches,
+        run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -269,8 +288,11 @@
 
   {
     base::RunLoop run_loop;
+    auto registration = CreateBackgroundFetchRegistration(
+        kExampleDeveloperId, kExampleUniqueId,
+        blink::mojom::BackgroundFetchState::SUCCESS);
     event_dispatcher_.DispatchBackgroundFetchSuccessEvent(
-        registration_id, blink::mojom::BackgroundFetchState::SUCCESS, fetches,
+        registration_id, std::move(registration), fetches,
         run_loop.QuitClosure());
 
     run_loop.Run();
@@ -302,9 +324,12 @@
 
   {
     base::RunLoop run_loop;
+    auto registration = CreateBackgroundFetchRegistration(
+        kExampleDeveloperId2, kExampleUniqueId2,
+        blink::mojom::BackgroundFetchState::SUCCESS);
     event_dispatcher_.DispatchBackgroundFetchSuccessEvent(
-        second_registration_id, blink::mojom::BackgroundFetchState::SUCCESS,
-        fetches, run_loop.QuitClosure());
+        second_registration_id, std::move(registration), fetches,
+        run_loop.QuitClosure());
 
     run_loop.Run();
   }
diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc
index f95b4be..ef07c1c 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -47,7 +47,7 @@
   total_downloads_ = total_downloads;
 
   // TODO(nator): Update this when we support uploads.
-  int total_downloads_size = options_.download_total;
+  total_downloads_size_ = options_.download_total;
 
   std::vector<std::string> active_guids;
   active_guids.reserve(active_fetch_requests.size());
@@ -57,7 +57,7 @@
   auto fetch_description = std::make_unique<BackgroundFetchDescription>(
       registration_id().unique_id(), ui_title, registration_id().origin(),
       icon_, completed_downloads, total_downloads,
-      complete_requests_downloaded_bytes_cache_, total_downloads_size,
+      complete_requests_downloaded_bytes_cache_, total_downloads_size_,
       std::move(active_guids));
 
   delegate_proxy_->CreateDownloadJob(GetWeakPtr(), std::move(fetch_description),
@@ -137,6 +137,15 @@
   delegate_proxy_->UpdateUI(registration_id().unique_id(), title, icon);
 }
 
+std::unique_ptr<BackgroundFetchRegistration>
+BackgroundFetchJobController::NewRegistration(
+    blink::mojom::BackgroundFetchState state) const {
+  return std::make_unique<BackgroundFetchRegistration>(
+      registration_id().developer_id(), registration_id().unique_id(),
+      0 /* upload_total */, 0 /* uploaded */, total_downloads_size_,
+      complete_requests_downloaded_bytes_cache_, state);
+}
+
 uint64_t BackgroundFetchJobController::GetInProgressDownloadedBytes() {
   return active_request_downloaded_bytes_;
 }
diff --git a/content/browser/background_fetch/background_fetch_job_controller.h b/content/browser/background_fetch/background_fetch_job_controller.h
index e57a219..a69f7a0 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.h
+++ b/content/browser/background_fetch/background_fetch_job_controller.h
@@ -76,9 +76,23 @@
   void UpdateUI(const base::Optional<std::string>& title,
                 const base::Optional<SkBitmap>& icon);
 
+  // Returns a unique_ptr to a BackgroundFetchRegistration object
+  // created with member fields.
+  std::unique_ptr<BackgroundFetchRegistration> NewRegistration(
+      blink::mojom::BackgroundFetchState state) const;
+
   // Returns the options with which this job is fetching data.
   const BackgroundFetchOptions& options() const { return options_; }
 
+  // Returns total downloaded bytes.
+  int downloaded() const { return complete_requests_downloaded_bytes_cache_; }
+
+  // Returns total size of downloads, as indicated by the developer.
+  int download_total() const { return total_downloads_size_; }
+
+  // Returns the number of requests that comprise the whole job.
+  int total_downloads() const { return total_downloads_; }
+
   base::WeakPtr<BackgroundFetchJobController> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
   }
@@ -116,6 +130,9 @@
   // delivering progress events without having to read from the database.
   uint64_t complete_requests_downloaded_bytes_cache_;
 
+  // Total downloads size, as indicated by the developer.
+  int total_downloads_size_ = 0;
+
   // Proxy for interacting with the BackgroundFetchDelegate across thread
   // boundaries. It is owned by the BackgroundFetchContext.
   BackgroundFetchDelegateProxy* delegate_proxy_;
diff --git a/content/browser/background_fetch/background_fetch_service_impl.cc b/content/browser/background_fetch/background_fetch_service_impl.cc
index 6bae7d6..f116ff5 100644
--- a/content/browser/background_fetch/background_fetch_service_impl.cc
+++ b/content/browser/background_fetch/background_fetch_service_impl.cc
@@ -16,7 +16,6 @@
 #include "content/browser/storage_partition_impl.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
@@ -91,7 +90,8 @@
     url::Origin origin,
     RenderFrameHost* render_frame_host)
     : background_fetch_context_(std::move(background_fetch_context)),
-      origin_(std::move(origin)) {
+      origin_(std::move(origin)),
+      render_frame_host_(render_frame_host) {
   DCHECK(background_fetch_context_);
 }
 
@@ -123,7 +123,8 @@
                                                 base::GenerateGUID());
 
   background_fetch_context_->StartFetch(registration_id, requests, options,
-                                        icon, std::move(callback));
+                                        icon, render_frame_host_,
+                                        std::move(callback));
 }
 
 void BackgroundFetchServiceImpl::GetIconDisplaySize(
diff --git a/content/browser/background_fetch/background_fetch_service_impl.h b/content/browser/background_fetch/background_fetch_service_impl.h
index 9eba08c9..5abcc9b 100644
--- a/content/browser/background_fetch/background_fetch_service_impl.h
+++ b/content/browser/background_fetch/background_fetch_service_impl.h
@@ -100,6 +100,8 @@
 
   const url::Origin origin_;
 
+  RenderFrameHost* render_frame_host_;
+
   DISALLOW_COPY_AND_ASSIGN(BackgroundFetchServiceImpl);
 };
 
diff --git a/content/browser/background_fetch/background_fetch_test_base.cc b/content/browser/background_fetch/background_fetch_test_base.cc
index fc5366e5..f8df776 100644
--- a/content/browser/background_fetch/background_fetch_test_base.cc
+++ b/content/browser/background_fetch/background_fetch_test_base.cc
@@ -163,4 +163,15 @@
                                    Referrer(), false /* is_reload */);
 }
 
+std::unique_ptr<BackgroundFetchRegistration>
+BackgroundFetchTestBase::CreateBackgroundFetchRegistration(
+    const std::string& developer_id,
+    const std::string& unique_id,
+    blink::mojom::BackgroundFetchState state) {
+  auto registration = std::make_unique<BackgroundFetchRegistration>(
+      developer_id, unique_id, 0 /* upload_total */, 0 /* uploaded */,
+      0 /* download_total */, 0 /* downloaded */, state);
+  return registration;
+}
+
 }  // namespace content
diff --git a/content/browser/background_fetch/background_fetch_test_base.h b/content/browser/background_fetch/background_fetch_test_base.h
index a2bcc73..50680da7 100644
--- a/content/browser/background_fetch/background_fetch_test_base.h
+++ b/content/browser/background_fetch/background_fetch_test_base.h
@@ -56,6 +56,12 @@
       const GURL& url,
       std::unique_ptr<TestResponse> response);
 
+  // Creates a BackgroundFetchRegistration object.
+  static std::unique_ptr<BackgroundFetchRegistration>
+  CreateBackgroundFetchRegistration(const std::string& developer_id,
+                                    const std::string& unique_id,
+                                    blink::mojom::BackgroundFetchState state);
+
   // Returns the embedded worker test helper instance, which can be used to
   // influence the behavior of the Service Worker events.
   BackgroundFetchEmbeddedWorkerTestHelper* embedded_worker_test_helper() {
diff --git a/content/browser/background_fetch/mock_background_fetch_delegate.cc b/content/browser/background_fetch/mock_background_fetch_delegate.cc
index c9934a8..3655aae7 100644
--- a/content/browser/background_fetch/mock_background_fetch_delegate.cc
+++ b/content/browser/background_fetch/mock_background_fetch_delegate.cc
@@ -6,6 +6,7 @@
 #include <vector>
 
 #include "base/files/file_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/background_fetch/mock_background_fetch_delegate.h"
 #include "content/public/browser/background_fetch_description.h"
@@ -56,6 +57,15 @@
 
 MockBackgroundFetchDelegate::~MockBackgroundFetchDelegate() {}
 
+void MockBackgroundFetchDelegate::GetPermissionForOrigin(
+    const url::Origin& origin,
+    const ResourceRequestInfo::WebContentsGetter& wc_getter,
+    GetPermissionForOriginCallback callback) {
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), true /* has_permission */));
+}
+
 void MockBackgroundFetchDelegate::GetIconDisplaySize(
     GetIconDisplaySizeCallback callback) {}
 
diff --git a/content/browser/background_fetch/mock_background_fetch_delegate.h b/content/browser/background_fetch/mock_background_fetch_delegate.h
index 6d12cd4..fc64bab 100644
--- a/content/browser/background_fetch/mock_background_fetch_delegate.h
+++ b/content/browser/background_fetch/mock_background_fetch_delegate.h
@@ -65,6 +65,10 @@
   ~MockBackgroundFetchDelegate() override;
 
   // BackgroundFetchDelegate implementation:
+  void GetPermissionForOrigin(
+      const url::Origin& origin,
+      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      GetPermissionForOriginCallback callback) override;
   void GetIconDisplaySize(
       BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) override;
   void CreateDownloadJob(
diff --git a/content/browser/background_fetch/storage/create_metadata_task.cc b/content/browser/background_fetch/storage/create_metadata_task.cc
index 5936af1..4604139 100644
--- a/content/browser/background_fetch/storage/create_metadata_task.cc
+++ b/content/browser/background_fetch/storage/create_metadata_task.cc
@@ -101,6 +101,8 @@
   registration_proto->set_unique_id(registration_id_.unique_id());
   registration_proto->set_developer_id(registration_id_.developer_id());
   registration_proto->set_download_total(options_.download_total);
+  registration_proto->set_state(
+      proto::BackgroundFetchRegistration_BackgroundFetchState_PENDING);
 
   // Set Options fields.
   auto* options_proto = metadata_proto_->mutable_options();
diff --git a/content/browser/background_fetch/storage/database_helpers.cc b/content/browser/background_fetch/storage/database_helpers.cc
index 7079357..6045198 100644
--- a/content/browser/background_fetch/storage/database_helpers.cc
+++ b/content/browser/background_fetch/storage/database_helpers.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "content/browser/background_fetch/background_fetch.pb.h"
+#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
 
 namespace content {
 
@@ -99,7 +100,19 @@
   registration.uploaded = registration_proto.uploaded();
   registration.download_total = registration_proto.download_total();
   registration.downloaded = registration_proto.downloaded();
-
+  switch (registration_proto.state()) {
+    case proto::BackgroundFetchRegistration_BackgroundFetchState_PENDING:
+      registration.state = blink::mojom::BackgroundFetchState::PENDING;
+      break;
+    case proto::BackgroundFetchRegistration_BackgroundFetchState_FAILURE:
+      registration.state = blink::mojom::BackgroundFetchState::FAILURE;
+      break;
+    case proto::BackgroundFetchRegistration_BackgroundFetchState_SUCCESS:
+      registration.state = blink::mojom::BackgroundFetchState::SUCCESS;
+      break;
+    default:
+      NOTREACHED();
+  }
   return registration;
 }
 
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc
index 2a67bcc..4fbe6ed 100644
--- a/content/browser/devtools/protocol/tracing_handler.cc
+++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -34,7 +34,6 @@
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/tracing/tracing_controller_impl.h"
 #include "content/public/browser/browser_thread.h"
@@ -405,28 +404,7 @@
                                                    options.fromMaybe(""));
   }
 
-  // GPU process id can only be retrieved on IO thread. Do some thread hopping.
-  BrowserThread::PostTaskAndReplyWithResult(
-      BrowserThread::IO, FROM_HERE, base::BindOnce([]() {
-        GpuProcessHost* gpu_process_host = GpuProcessHost::Get();
-        return gpu_process_host ? gpu_process_host->GetProcessId()
-                                : base::kNullProcessId;
-      }),
-      base::BindOnce(&TracingHandler::StartTracingWithGpuPid,
-                     weak_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void TracingHandler::StartTracingWithGpuPid(
-    std::unique_ptr<StartCallback> callback,
-    base::ProcessId gpu_pid) {
-  // Check if tracing was stopped in mid-air.
-  if (!did_initiate_recording_) {
-    callback->sendFailure(Response::Error(
-        "Tracing was stopped before start has been completed."));
-    return;
-  }
-
-  SetupProcessFilter(gpu_pid, nullptr);
+  SetupProcessFilter(nullptr);
 
   TracingController::GetInstance()->StartTracing(
       trace_config_, base::BindRepeating(&TracingHandler::OnRecordingEnabled,
@@ -435,20 +413,14 @@
 }
 
 void TracingHandler::SetupProcessFilter(
-    base::ProcessId gpu_pid,
     RenderFrameHost* new_render_frame_host) {
   if (!frame_tree_node_)
     return;
 
   base::ProcessId browser_pid = base::Process::Current().Pid();
   std::unordered_set<base::ProcessId> included_process_ids({browser_pid});
-
-  if (gpu_pid != base::kNullProcessId)
-    included_process_ids.insert(gpu_pid);
-
   if (new_render_frame_host)
     AppendProcessId(new_render_frame_host, &included_process_ids);
-
   for (FrameTreeNode* node :
        frame_tree_node_->frame_tree()->SubtreeNodes(frame_tree_node_)) {
     RenderFrameHost* frame_host = node->current_frame_host();
@@ -523,13 +495,8 @@
 
 void TracingHandler::OnRecordingEnabled(
     std::unique_ptr<StartCallback> callback) {
-  if (!did_initiate_recording_) {
-    callback->sendFailure(Response::Error(
-        "Tracing was stopped before start has been completed."));
-    return;
-  }
-
   EmitFrameTree();
+
   callback->sendSuccess();
 
   bool screenshot_enabled;
@@ -679,8 +646,7 @@
                        "FrameCommittedInBrowser", TRACE_EVENT_SCOPE_THREAD,
                        "data", std::move(data));
 
-  SetupProcessFilter(base::kNullProcessId,
-                     navigation_handle->GetRenderFrameHost());
+  SetupProcessFilter(navigation_handle->GetRenderFrameHost());
   TracingController::GetInstance()->StartTracing(
       trace_config_, base::RepeatingCallback<void()>());
 }
diff --git a/content/browser/devtools/protocol/tracing_handler.h b/content/browser/devtools/protocol/tracing_handler.h
index 97ba228..fc3336a 100644
--- a/content/browser/devtools/protocol/tracing_handler.h
+++ b/content/browser/devtools/protocol/tracing_handler.h
@@ -116,9 +116,7 @@
   CONTENT_EXPORT static base::trace_event::TraceConfig
       GetTraceConfigFromDevToolsConfig(
           const base::DictionaryValue& devtools_config);
-  void SetupProcessFilter(base::ProcessId gpu_pid, RenderFrameHost*);
-  void StartTracingWithGpuPid(std::unique_ptr<StartCallback>,
-                              base::ProcessId gpu_pid);
+  void SetupProcessFilter(RenderFrameHost*);
   void AppendProcessId(RenderFrameHost*,
                        std::unordered_set<base::ProcessId>* process_set);
   void OnProcessReady(RenderProcessHost*);
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 29f8d70..1e3da54 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -30,7 +30,6 @@
 #include "build/build_config.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/bad_message.h"
-#include "content/browser/loader/global_routing_id.h"
 #include "content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.h"
 #include "content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.h"
 #include "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h"
@@ -50,6 +49,7 @@
 #include "content/common/navigation_params.mojom.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/common/javascript_dialog_type.h"
 #include "content/public/common/previews_state.h"
@@ -850,6 +850,8 @@
                            SwapOutACKArrivesPriorToProcessShutdownRequest);
   FRIEND_TEST_ALL_PREFIXES(SecurityExploitBrowserTest,
                            AttemptDuplicateRenderViewHost);
+  FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
+                           FullscreenAfterFrameSwap);
 
   class DroppedInterfaceRequestLogger;
 
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 2484bfa..b793768 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -2163,6 +2163,13 @@
                            render_frame_host_->GetView() &&
                            render_frame_host_->GetView()->HasFocus();
 
+  // Remove the current frame and its descendants from the set of fullscreen
+  // frames immediately. They can stay in pending deletion for some time.
+  // Removing them when they are deleted is too late.
+  // This needs to be done before updating the frame tree structure, else it
+  // will have trouble removing the descendants.
+  render_frame_delegate_->FullscreenStateChanged(current_frame_host(), false);
+
   // While the old frame is still current, remove its children from the tree.
   frame_tree_node_->ResetForNewProcess();
 
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 11f7f15..0d8c115 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -677,10 +677,6 @@
   return nullptr;
 }
 
-base::ProcessId GpuProcessHost::GetProcessId() const {
-  return initialized_ ? process_->GetProcess().Pid() : base::kNullProcessId;
-}
-
 // static
 int GpuProcessHost::GetGpuCrashCount() {
   return static_cast<int>(base::subtle::NoBarrier_Load(&gpu_crash_count_));
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index c549b68..33ad6bd 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -118,7 +118,6 @@
   // null if the process no longer exists.
   static GpuProcessHost* FromID(int host_id);
   int host_id() const { return host_id_; }
-  base::ProcessId GetProcessId() const;
 
   // IPC::Sender implementation.
   bool Send(IPC::Message* msg) override;
diff --git a/content/browser/loader/global_routing_id.h b/content/browser/loader/global_routing_id.h
deleted file mode 100644
index 3f5aadf..0000000
--- a/content/browser/loader/global_routing_id.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_LOADER_GLOBAL_ROUTING_ID_H_
-#define CONTENT_BROWSER_LOADER_GLOBAL_ROUTING_ID_H_
-
-#include <tuple>
-
-#include "ipc/ipc_message.h"
-
-namespace content {
-
-// Uniquely identifies the route from which a net::URLRequest comes.
-struct GlobalRoutingID {
-  GlobalRoutingID() : child_id(-1), route_id(-1) {
-  }
-
-  GlobalRoutingID(int child_id, int route_id)
-      : child_id(child_id),
-        route_id(route_id) {
-  }
-
-  // The unique ID of the child process (different from OS's PID).
-  int child_id;
-
-  // The route ID (unique for each URLRequest source).
-  int route_id;
-
-  bool operator<(const GlobalRoutingID& other) const {
-    return std::tie(child_id, route_id) <
-           std::tie(other.child_id, other.route_id);
-  }
-  bool operator==(const GlobalRoutingID& other) const {
-    return child_id == other.child_id &&
-        route_id == other.route_id;
-  }
-  bool operator!=(const GlobalRoutingID& other) const {
-    return !(*this == other);
-  }
-};
-
-// Same as GlobalRoutingID except the route_id must be a RenderFrameHost routing
-// id.
-struct GlobalFrameRoutingId {
-  GlobalFrameRoutingId() : child_id(0), frame_routing_id(MSG_ROUTING_NONE) {}
-
-  GlobalFrameRoutingId(int child_id, int frame_routing_id)
-      : child_id(child_id), frame_routing_id(frame_routing_id) {}
-
-  // The unique ID of the child process (different from OS's PID).
-  int child_id;
-
-  // The route ID (unique for each URLRequest source).
-  int frame_routing_id;
-
-  bool operator<(const GlobalFrameRoutingId& other) const {
-    return std::tie(child_id, frame_routing_id) <
-           std::tie(other.child_id, other.frame_routing_id);
-  }
-  bool operator==(const GlobalFrameRoutingId& other) const {
-    return child_id == other.child_id &&
-           frame_routing_id == other.frame_routing_id;
-  }
-  bool operator!=(const GlobalFrameRoutingId& other) const {
-    return !(*this == other);
-  }
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_LOADER_GLOBAL_ROUTING_ID_H_
diff --git a/content/browser/loader/loader_io_thread_notifier.cc b/content/browser/loader/loader_io_thread_notifier.cc
index 47efe28..215e2f9 100644
--- a/content/browser/loader/loader_io_thread_notifier.cc
+++ b/content/browser/loader/loader_io_thread_notifier.cc
@@ -5,9 +5,9 @@
 #include "content/browser/loader/loader_io_thread_notifier.h"
 
 #include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/loader/global_routing_id.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_routing_id.h"
 
 namespace content {
 
diff --git a/content/browser/loader/prefetch_browsertest.cc b/content/browser/loader/prefetch_browsertest.cc
index fb0726e..0b6a19f8 100644
--- a/content/browser/loader/prefetch_browsertest.cc
+++ b/content/browser/loader/prefetch_browsertest.cc
@@ -110,12 +110,16 @@
     return nullptr;
   }
 
-  void WatchURLAndRunClosure(const std::string& relative_url,
-                             int* visit_count,
-                             base::OnceClosure closure,
-                             const net::test_server::HttpRequest& request) {
+  void WatchURLAndRunClosure(
+      const std::string& relative_url,
+      int* visit_count,
+      net::test_server::HttpRequest::HeaderMap* out_headers,
+      base::OnceClosure closure,
+      const net::test_server::HttpRequest& request) {
     if (request.relative_url == relative_url) {
       (*visit_count)++;
+      if (out_headers)
+        *out_headers = request.headers;
       if (closure)
         std::move(closure).Run();
     }
@@ -153,7 +157,7 @@
   base::RunLoop prefetch_waiter;
   embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
       &PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
-      target_url, &target_fetch_count, prefetch_waiter.QuitClosure()));
+      target_url, &target_fetch_count, nullptr, prefetch_waiter.QuitClosure()));
   embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
       &PrefetchBrowserTest::ServeResponses, base::Unretained(this)));
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -191,7 +195,7 @@
   base::RunLoop prefetch_waiter;
   embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
       &PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
-      target_url, &target_fetch_count, prefetch_waiter.QuitClosure()));
+      target_url, &target_fetch_count, nullptr, prefetch_waiter.QuitClosure()));
   embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
       &PrefetchBrowserTest::ServeResponses, base::Unretained(this)));
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -238,10 +242,12 @@
   base::RunLoop nostore_waiter;
   embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
       &PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
-      nocache_url, &nocache_fetch_count, nocache_waiter.QuitClosure()));
+      nocache_url, &nocache_fetch_count, nullptr,
+      nocache_waiter.QuitClosure()));
   embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
       &PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
-      nostore_url, &nostore_fetch_count, nostore_waiter.QuitClosure()));
+      nostore_url, &nostore_fetch_count, nullptr,
+      nostore_waiter.QuitClosure()));
   embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
       &PrefetchBrowserTest::ServeResponses, base::Unretained(this)));
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -298,10 +304,11 @@
   base::RunLoop preload_waiter;
   embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
       &PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
-      target_url, &target_fetch_count, base::RepeatingClosure()));
+      target_url, &target_fetch_count, nullptr, base::RepeatingClosure()));
   embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
       &PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
-      preload_url, &preload_fetch_count, preload_waiter.QuitClosure()));
+      preload_url, &preload_fetch_count, nullptr,
+      preload_waiter.QuitClosure()));
   embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
       &PrefetchBrowserTest::ServeResponses, base::Unretained(this)));
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -344,20 +351,23 @@
   RegisterResponse(
       target_sxg,
       // We mock the SignedExchangeHandler, so just return a HTML content
-      // as "application/signed-exchange;v=b0".
+      // as "application/signed-exchange;v=b1".
       ResponseEntry("<head><title>Prefetch Target (SXG)</title></head>",
-                    "application/signed-exchange;v=b0"));
+                    "application/signed-exchange;v=b1"));
   RegisterResponse(preload_url_in_sxg,
                    ResponseEntry("function foo() {}", "text/javascript"));
 
   base::RunLoop preload_waiter;
   base::RunLoop prefetch_waiter;
+  net::test_server::HttpRequest::HeaderMap prefetch_headers;
   embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
       &PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
-      target_sxg, &target_fetch_count, prefetch_waiter.QuitClosure()));
+      target_sxg, &target_fetch_count, &prefetch_headers,
+      prefetch_waiter.QuitClosure()));
   embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
       &PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
-      preload_url_in_sxg, &preload_fetch_count, preload_waiter.QuitClosure()));
+      preload_url_in_sxg, &preload_fetch_count, nullptr,
+      preload_waiter.QuitClosure()));
   embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
       &PrefetchBrowserTest::ServeResponses, base::Unretained(this)));
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -376,6 +386,11 @@
   prefetch_waiter.Run();
   EXPECT_EQ(1, target_fetch_count);
   EXPECT_TRUE(CheckPrefetchURLLoaderCountIfSupported(1));
+  if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange))
+    EXPECT_EQ(prefetch_headers["Accept"],
+              "application/signed-exchange;v=b1;q=0.9,*/*;q=0.8");
+  else
+    EXPECT_EQ(prefetch_headers["Accept"], "*/*");
 
   // Test after this point requires SignedHTTPExchange support, which is now
   // disabled when Network Service is enabled.
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index fe1365c..ec89329 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -29,10 +29,10 @@
 #include "base/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
-#include "content/browser/loader/global_routing_id.h"
 #include "content/browser/loader/resource_loader_delegate.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/global_request_id.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/stream_handle.h"
diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc
index d0caf30..7fe59fe 100644
--- a/content/browser/loader/resource_request_info_impl.cc
+++ b/content/browser/loader/resource_request_info_impl.cc
@@ -5,13 +5,13 @@
 #include "content/browser/loader/resource_request_info_impl.h"
 
 #include "content/browser/frame_host/frame_tree_node.h"
-#include "content/browser/loader/global_routing_id.h"
 #include "content/browser/loader/resource_message_filter.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/net/url_request_service_worker_data.h"
 #include "content/common/net/url_request_user_data.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/global_request_id.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/process_type.h"
 #include "net/url_request/url_request.h"
diff --git a/content/browser/media/capture/audio_mirroring_manager.cc b/content/browser/media/capture/audio_mirroring_manager.cc
index 1daaf6bf..32544941 100644
--- a/content/browser/media/capture/audio_mirroring_manager.cc
+++ b/content/browser/media/capture/audio_mirroring_manager.cc
@@ -36,12 +36,11 @@
   }
 #endif
   routes_.push_back(StreamRoutingState(
-      SourceFrameRef(render_process_id, render_frame_id),
-      diverter));
+      GlobalFrameRoutingId(render_process_id, render_frame_id), diverter));
 
   // Query existing destinations to see whether to immediately start diverting
   // the stream.
-  std::set<SourceFrameRef> candidates;
+  std::set<GlobalFrameRoutingId> candidates;
   candidates.insert(routes_.back().source_render_frame);
   InitiateQueriesToFindNewDestination(nullptr, candidates);
 }
@@ -79,7 +78,7 @@
     sessions_.push_back(destination);
   }
 
-  std::set<SourceFrameRef> candidates;
+  std::set<GlobalFrameRoutingId> candidates;
 
   // Query the MirroringDestination to see which of the audio streams should be
   // diverted.
@@ -103,7 +102,7 @@
   // Stop diverting each audio stream in the mirroring session being stopped.
   // Each stopped stream becomes a candidate to be diverted to another
   // destination.
-  std::set<SourceFrameRef> redivert_candidates;
+  std::set<GlobalFrameRoutingId> redivert_candidates;
   for (StreamRoutes::iterator it = routes_.begin(); it != routes_.end(); ++it) {
     if (it->destination == destination) {
       RouteDivertedFlow(&(*it), nullptr);
@@ -158,7 +157,7 @@
 
 void AudioMirroringManager::InitiateQueriesToFindNewDestination(
     MirroringDestination* old_destination,
-    const std::set<SourceFrameRef>& candidates) {
+    const std::set<GlobalFrameRoutingId>& candidates) {
   lock_.AssertAcquired();
 
   for (Destinations::const_iterator it = sessions_.begin();
@@ -176,7 +175,7 @@
 void AudioMirroringManager::UpdateRoutesToDestination(
     MirroringDestination* destination,
     bool add_only,
-    const std::set<SourceFrameRef>& matches,
+    const std::set<GlobalFrameRoutingId>& matches,
     bool is_duplicate) {
   base::AutoLock scoped_lock(lock_);
 
@@ -189,7 +188,7 @@
 void AudioMirroringManager::UpdateRoutesToDivertDestination(
     MirroringDestination* destination,
     bool add_only,
-    const std::set<SourceFrameRef>& matches) {
+    const std::set<GlobalFrameRoutingId>& matches) {
   lock_.AssertAcquired();
 
   if (std::find(sessions_.begin(), sessions_.end(), destination) ==
@@ -202,7 +201,7 @@
 
   // Start/stop diverting based on |matches|.  Any stopped stream becomes a
   // candidate to be diverted to another destination.
-  std::set<SourceFrameRef> redivert_candidates;
+  std::set<GlobalFrameRoutingId> redivert_candidates;
   for (StreamRoutes::iterator it = routes_.begin(); it != routes_.end(); ++it) {
     if (matches.find(it->source_render_frame) != matches.end()) {
       // Only change the route if the stream is not already being diverted.
@@ -223,7 +222,7 @@
 void AudioMirroringManager::UpdateRoutesToDuplicateDestination(
     MirroringDestination* destination,
     bool add_only,
-    const std::set<SourceFrameRef>& matches) {
+    const std::set<GlobalFrameRoutingId>& matches) {
   lock_.AssertAcquired();
 
   if (std::find(sessions_.begin(), sessions_.end(), destination) ==
@@ -267,18 +266,18 @@
 
   if (route->destination) {
     DVLOG(1) << "Stop diverting render_process_id:render_frame_id="
-             << route->source_render_frame.first << ':'
-             << route->source_render_frame.second
+             << route->source_render_frame.child_id << ':'
+             << route->source_render_frame.frame_routing_id
              << " --> MirroringDestination@" << route->destination;
     route->diverter->StopDiverting();
     route->destination = nullptr;
   }
 
   if (new_destination) {
-      DVLOG(1) << "Start diverting of render_process_id:render_frame_id="
-               << route->source_render_frame.first << ':'
-               << route->source_render_frame.second
-               << " --> MirroringDestination@" << new_destination;
+    DVLOG(1) << "Start diverting of render_process_id:render_frame_id="
+             << route->source_render_frame.child_id << ':'
+             << route->source_render_frame.frame_routing_id
+             << " --> MirroringDestination@" << new_destination;
     route->diverter->StartDiverting(
         new_destination->AddInput(route->diverter->GetAudioParameters()));
     route->destination = new_destination;
@@ -286,7 +285,7 @@
 }
 
 AudioMirroringManager::StreamRoutingState::StreamRoutingState(
-    const SourceFrameRef& source_frame,
+    const GlobalFrameRoutingId& source_frame,
     Diverter* stream_diverter)
     : source_render_frame(source_frame),
       diverter(stream_diverter),
diff --git a/content/browser/media/capture/audio_mirroring_manager.h b/content/browser/media/capture/audio_mirroring_manager.h
index 67ee6fb..f2c7739 100644
--- a/content/browser/media/capture/audio_mirroring_manager.h
+++ b/content/browser/media/capture/audio_mirroring_manager.h
@@ -41,6 +41,7 @@
 #include "base/synchronization/lock.h"
 #include "base/unguessable_token.h"
 #include "content/common/content_export.h"
+#include "content/public/browser/global_routing_id.h"
 #include "media/audio/audio_source_diverter.h"
 
 namespace media {
@@ -54,10 +55,6 @@
   // Interface for diverting audio data to an alternative AudioOutputStream.
   typedef media::AudioSourceDiverter Diverter;
 
-  // A SourceFrameRef is a RenderFrameHost identified by a <render_process_id,
-  // render_frame_id> pair.
-  typedef std::pair<int, int> SourceFrameRef;
-
   // Interface to be implemented by audio mirroring destinations.  See comments
   // for StartMirroring() and StopMirroring() below.
   class MirroringDestination {
@@ -70,11 +67,12 @@
     // access to a diverted audio flow versus 2) a duplicate copy of the audio
     // flow. |results_callback| must be run on the same thread as the one that
     // called QueryForMatches().
-    typedef base::Callback<void(const std::set<SourceFrameRef>&, bool)>
+    typedef base::OnceCallback<void(const std::set<GlobalFrameRoutingId>&,
+                                    bool)>
         MatchesCallback;
     virtual void QueryForMatches(
-        const std::set<SourceFrameRef>& candidates,
-        const MatchesCallback& results_callback) = 0;
+        const std::set<GlobalFrameRoutingId>& candidates,
+        MatchesCallback results_callback) = 0;
 
     // Create a consumer of audio data in the format specified by |params|, and
     // connect it as an input to mirroring.  This is used to provide
@@ -138,7 +136,7 @@
 
   struct StreamRoutingState {
     // The source render frame associated with the audio stream.
-    SourceFrameRef source_render_frame;
+    GlobalFrameRoutingId source_render_frame;
 
     // The diverter for re-routing the audio stream.
     Diverter* diverter;
@@ -152,7 +150,7 @@
     // StopDuplicating() is called to release them.
     std::map<MirroringDestination*, media::AudioPushSink*> duplications;
 
-    StreamRoutingState(const SourceFrameRef& source_frame,
+    StreamRoutingState(const GlobalFrameRoutingId& source_frame,
                        Diverter* stream_diverter);
     StreamRoutingState(const StreamRoutingState& other);
     ~StreamRoutingState();
@@ -165,7 +163,7 @@
   // |candidates| to be diverted to.
   void InitiateQueriesToFindNewDestination(
       MirroringDestination* old_destination,
-      const std::set<SourceFrameRef>& candidates);
+      const std::set<GlobalFrameRoutingId>& candidates);
 
   // MirroringDestination query callback.  |matches| contains all RenderFrame
   // sources that will be diverted or duplicated to |destination|.
@@ -175,15 +173,16 @@
   // destination instead of diverted.
   void UpdateRoutesToDestination(MirroringDestination* destination,
                                  bool add_only,
-                                 const std::set<SourceFrameRef>& matches,
+                                 const std::set<GlobalFrameRoutingId>& matches,
                                  bool is_duplicate);
 
   // |matches| contains all RenderFrame sources that will be diverted to
   // |destination|.  If |add_only| is false, then any Diverters currently routed
   // to |destination| but not found in |matches| will be stopped.
-  void UpdateRoutesToDivertDestination(MirroringDestination* destination,
-                                       bool add_only,
-                                       const std::set<SourceFrameRef>& matches);
+  void UpdateRoutesToDivertDestination(
+      MirroringDestination* destination,
+      bool add_only,
+      const std::set<GlobalFrameRoutingId>& matches);
 
   // |matches| contains all RenderFrame sources that will be duplicated to
   // |destination|.  If |add_only| is false, then any Diverters currently
@@ -191,7 +190,7 @@
   void UpdateRoutesToDuplicateDestination(
       MirroringDestination* destination,
       bool add_only,
-      const std::set<SourceFrameRef>& matches);
+      const std::set<GlobalFrameRoutingId>& matches);
 
   // Starts diverting audio to the |new_destination|, if not NULL.  Otherwise,
   // stops diverting audio.
diff --git a/content/browser/media/capture/audio_mirroring_manager_unittest.cc b/content/browser/media/capture/audio_mirroring_manager_unittest.cc
index a485e46..d128405 100644
--- a/content/browser/media/capture/audio_mirroring_manager_unittest.cc
+++ b/content/browser/media/capture/audio_mirroring_manager_unittest.cc
@@ -5,6 +5,7 @@
 #include "content/browser/media/capture/audio_mirroring_manager.h"
 
 #include <map>
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
@@ -44,8 +45,6 @@
 class MockMirroringDestination
     : public AudioMirroringManager::MirroringDestination {
  public:
-  typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
-
   MockMirroringDestination(int render_process_id,
                            int render_frame_id,
                            bool is_duplication)
@@ -54,27 +53,34 @@
         query_count_(0),
         is_duplication_(is_duplication) {}
 
-  MOCK_METHOD2(QueryForMatches,
-               void(const std::set<SourceFrameRef>& candidates,
-                    const MatchesCallback& results_callback));
+  void QueryForMatches(const std::set<GlobalFrameRoutingId>& candidates,
+                       MatchesCallback results_callback) override {
+    // The indirection is needed, because gmock has trouble with move-only
+    // parameters (like |results_callback|).
+    MockedQueryForMatches(candidates, &results_callback);
+  }
+  MOCK_METHOD2(MockedQueryForMatches,
+               void(const std::set<GlobalFrameRoutingId>& candidates,
+                    MatchesCallback* results_callback));
+
   MOCK_METHOD1(AddInput,
                media::AudioOutputStream*(const media::AudioParameters& params));
 
   MOCK_METHOD1(AddPushInput,
                media::AudioPushSink*(const media::AudioParameters& params));
 
-  void SimulateQuery(const std::set<SourceFrameRef>& candidates,
-                     const MatchesCallback& results_callback) {
+  void SimulateQuery(const std::set<GlobalFrameRoutingId>& candidates,
+                     MatchesCallback* results_callback) {
     ++query_count_;
 
-    std::set<SourceFrameRef> result;
-    if (candidates.find(SourceFrameRef(render_process_id_, render_frame_id_)) !=
-            candidates.end()) {
-      result.insert(SourceFrameRef(render_process_id_, render_frame_id_));
+    std::set<GlobalFrameRoutingId> result;
+    if (candidates.find(GlobalFrameRoutingId(
+            render_process_id_, render_frame_id_)) != candidates.end()) {
+      result.insert(GlobalFrameRoutingId(render_process_id_, render_frame_id_));
     }
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(results_callback, std::move(result), is_duplication_));
+    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+                            base::BindOnce(std::move(*results_callback),
+                                           std::move(result), is_duplication_));
   }
 
   media::AudioOutputStream* SimulateAddInput(
@@ -157,9 +163,9 @@
   void StartMirroringTo(const std::unique_ptr<MockMirroringDestination>& dest,
                         int expected_inputs_added,
                         int expected_push_inputs_added) {
-    EXPECT_CALL(*dest, QueryForMatches(_, _))
-        .WillRepeatedly(Invoke(dest.get(),
-                               &MockMirroringDestination::SimulateQuery));
+    EXPECT_CALL(*dest, MockedQueryForMatches(_, _))
+        .WillRepeatedly(
+            Invoke(dest.get(), &MockMirroringDestination::SimulateQuery));
     if (expected_inputs_added > 0) {
       EXPECT_CALL(*dest, AddInput(Ref(params_)))
           .Times(expected_inputs_added)
diff --git a/content/browser/media/capture/web_contents_audio_input_stream.cc b/content/browser/media/capture/web_contents_audio_input_stream.cc
index e1593cc..75d9bee 100644
--- a/content/browser/media/capture/web_contents_audio_input_stream.cc
+++ b/content/browser/media/capture/web_contents_audio_input_stream.cc
@@ -5,6 +5,7 @@
 #include "content/browser/media/capture/web_contents_audio_input_stream.h"
 
 #include <memory>
+#include <set>
 #include <string>
 
 #include "base/bind.h"
@@ -60,8 +61,6 @@
  private:
   friend class base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>;
 
-  typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
-
   enum State {
     CONSTRUCTED,
     OPENED,
@@ -88,10 +87,11 @@
   void UnmuteWebContentsAudio();
 
   // AudioMirroringManager::MirroringDestination implementation
-  void QueryForMatches(const std::set<SourceFrameRef>& candidates,
-                       const MatchesCallback& results_callback) override;
-  void QueryForMatchesOnUIThread(const std::set<SourceFrameRef>& candidates,
-                                 const MatchesCallback& results_callback);
+  void QueryForMatches(const std::set<GlobalFrameRoutingId>& candidates,
+                       MatchesCallback results_callback) override;
+  void QueryForMatchesOnUIThread(
+      const std::set<GlobalFrameRoutingId>& candidates,
+      MatchesCallback results_callback);
   media::AudioOutputStream* AddInput(
       const media::AudioParameters& params) override;
   media::AudioPushSink* AddPushInput(
@@ -297,35 +297,34 @@
 }
 
 void WebContentsAudioInputStream::Impl::QueryForMatches(
-    const std::set<SourceFrameRef>& candidates,
-    const MatchesCallback& results_callback) {
+    const std::set<GlobalFrameRoutingId>& candidates,
+    MatchesCallback results_callback) {
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::BindOnce(&Impl::QueryForMatchesOnUIThread, this, candidates,
-                     media::BindToCurrentLoop(results_callback)));
+                     media::BindToCurrentLoop(std::move(results_callback))));
 }
 
 void WebContentsAudioInputStream::Impl::QueryForMatchesOnUIThread(
-    const std::set<SourceFrameRef>& candidates,
-    const MatchesCallback& results_callback) {
+    const std::set<GlobalFrameRoutingId>& candidates,
+    MatchesCallback results_callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  std::set<SourceFrameRef> matches;
+  std::set<GlobalFrameRoutingId> matches;
   WebContents* const contents = tracker_->web_contents();
   if (contents) {
     // Add each ID to |matches| if it maps to a RenderFrameHost that maps to the
     // currently-tracked WebContents.
-    for (std::set<SourceFrameRef>::const_iterator i = candidates.begin();
-         i != candidates.end(); ++i) {
+    for (const auto& it : candidates) {
       WebContents* const contents_containing_frame =
           WebContents::FromRenderFrameHost(
-              RenderFrameHost::FromID(i->first, i->second));
+              RenderFrameHost::FromID(it.child_id, it.frame_routing_id));
       if (contents_containing_frame == contents)
-        matches.insert(*i);
+        matches.insert(it);
     }
   }
 
-  results_callback.Run(matches, is_duplication_);
+  std::move(results_callback).Run(matches, is_duplication_);
 }
 
 media::AudioOutputStream* WebContentsAudioInputStream::Impl::AddInput(
diff --git a/content/browser/media/capture/web_contents_audio_muter.cc b/content/browser/media/capture/web_contents_audio_muter.cc
index 59a30348..c10f522 100644
--- a/content/browser/media/capture/web_contents_audio_muter.cc
+++ b/content/browser/media/capture/web_contents_audio_muter.cc
@@ -80,33 +80,32 @@
  private:
   friend class base::RefCountedThreadSafe<MuteDestination>;
 
-  typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
-
   ~MuteDestination() override {}
 
-  void QueryForMatches(const std::set<SourceFrameRef>& candidates,
-                       const MatchesCallback& results_callback) override {
+  void QueryForMatches(const std::set<GlobalFrameRoutingId>& candidates,
+                       MatchesCallback results_callback) override {
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
         base::BindOnce(&MuteDestination::QueryForMatchesOnUIThread, this,
-                       candidates, media::BindToCurrentLoop(results_callback)));
+                       candidates,
+                       media::BindToCurrentLoop(std::move(results_callback))));
   }
 
-  void QueryForMatchesOnUIThread(const std::set<SourceFrameRef>& candidates,
-                                 const MatchesCallback& results_callback) {
+  void QueryForMatchesOnUIThread(
+      const std::set<GlobalFrameRoutingId>& candidates,
+      MatchesCallback results_callback) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    std::set<SourceFrameRef> matches;
+    std::set<GlobalFrameRoutingId> matches;
     // Add each ID to |matches| if it maps to a RenderFrameHost that maps to the
     // WebContents being muted.
-    for (std::set<SourceFrameRef>::const_iterator i = candidates.begin();
-         i != candidates.end(); ++i) {
+    for (const auto& it : candidates) {
       WebContents* const contents_containing_frame =
           WebContents::FromRenderFrameHost(
-              RenderFrameHost::FromID(i->first, i->second));
+              RenderFrameHost::FromID(it.child_id, it.frame_routing_id));
       if (contents_containing_frame == web_contents_)
-        matches.insert(*i);
+        matches.insert(it);
     }
-    results_callback.Run(matches, false);
+    std::move(results_callback).Run(matches, false);
   }
 
   media::AudioOutputStream* AddInput(
diff --git a/content/browser/payments/payment_app_info_fetcher.cc b/content/browser/payments/payment_app_info_fetcher.cc
index 5ba89bc..de760fb 100644
--- a/content/browser/payments/payment_app_info_fetcher.cc
+++ b/content/browser/payments/payment_app_info_fetcher.cc
@@ -4,12 +4,15 @@
 
 #include "content/browser/payments/payment_app_info_fetcher.h"
 
+#include <utility>
+
 #include "base/base64.h"
 #include "base/bind_helpers.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/manifest_icon_downloader.h"
 #include "content/public/common/console_message_level.h"
 #include "third_party/blink/public/common/manifest/manifest_icon_selector.h"
@@ -28,7 +31,7 @@
     PaymentAppInfoFetchCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  std::unique_ptr<std::vector<std::pair<int, int>>> provider_hosts =
+  std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_hosts =
       service_worker_context->GetProviderHostIds(context_url.GetOrigin());
 
   BrowserThread::PostTask(
@@ -39,7 +42,7 @@
 
 void PaymentAppInfoFetcher::StartOnUI(
     const GURL& context_url,
-    const std::unique_ptr<std::vector<std::pair<int, int>>>& provider_hosts,
+    const std::unique_ptr<std::vector<GlobalFrameRoutingId>>& provider_hosts,
     PaymentAppInfoFetchCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -70,7 +73,7 @@
 
 void PaymentAppInfoFetcher::SelfDeleteFetcher::Start(
     const GURL& context_url,
-    const std::unique_ptr<std::vector<std::pair<int, int>>>& provider_hosts) {
+    const std::unique_ptr<std::vector<GlobalFrameRoutingId>>& provider_hosts) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (provider_hosts->size() == 0U) {
@@ -81,7 +84,7 @@
   for (const auto& frame : *provider_hosts) {
     // Find out the render frame host registering the payment app.
     RenderFrameHostImpl* render_frame_host =
-        RenderFrameHostImpl::FromID(frame.first, frame.second);
+        RenderFrameHostImpl::FromID(frame.child_id, frame.frame_routing_id);
     if (!render_frame_host ||
         context_url.spec().compare(
             render_frame_host->GetLastCommittedURL().spec()) != 0) {
diff --git a/content/browser/payments/payment_app_info_fetcher.h b/content/browser/payments/payment_app_info_fetcher.h
index 73dd74fc..756622e 100644
--- a/content/browser/payments/payment_app_info_fetcher.h
+++ b/content/browser/payments/payment_app_info_fetcher.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/stored_payment_app.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
@@ -41,7 +42,7 @@
   // Only accessed on the UI thread.
   static void StartOnUI(
       const GURL& context_url,
-      const std::unique_ptr<std::vector<std::pair<int, int>>>& provider_hosts,
+      const std::unique_ptr<std::vector<GlobalFrameRoutingId>>& provider_hosts,
       PaymentAppInfoFetchCallback callback);
 
   // Keeps track of the web contents.
@@ -59,7 +60,7 @@
     ~SelfDeleteFetcher();
 
     void Start(const GURL& context_url,
-               const std::unique_ptr<std::vector<std::pair<int, int>>>&
+               const std::unique_ptr<std::vector<GlobalFrameRoutingId>>&
                    provider_hosts);
 
    private:
diff --git a/content/browser/payments/payment_instrument_icon_fetcher.cc b/content/browser/payments/payment_instrument_icon_fetcher.cc
index 8ef0de4e..3101c496 100644
--- a/content/browser/payments/payment_instrument_icon_fetcher.cc
+++ b/content/browser/payments/payment_instrument_icon_fetcher.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/payments/payment_instrument_icon_fetcher.h"
 
+#include <utility>
+
 #include "base/base64.h"
 #include "base/bind_helpers.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
@@ -99,12 +101,12 @@
 
 WebContents* GetWebContentsFromProviderHostIds(
     const GURL& scope,
-    std::unique_ptr<std::vector<std::pair<int, int>>> provider_hosts) {
+    std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_hosts) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   for (const auto& host : *provider_hosts) {
     RenderFrameHostImpl* render_frame_host =
-        RenderFrameHostImpl::FromID(host.first, host.second);
+        RenderFrameHostImpl::FromID(host.child_id, host.frame_routing_id);
     if (!render_frame_host)
       continue;
 
@@ -122,7 +124,7 @@
 
 void StartOnUI(
     const GURL& scope,
-    std::unique_ptr<std::vector<std::pair<int, int>>> provider_hosts,
+    std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_hosts,
     const std::vector<blink::Manifest::ImageResource>& icons,
     PaymentInstrumentIconFetcher::PaymentInstrumentIconFetcherCallback
         callback) {
@@ -138,7 +140,7 @@
 // static
 void PaymentInstrumentIconFetcher::Start(
     const GURL& scope,
-    std::unique_ptr<std::vector<std::pair<int, int>>> provider_hosts,
+    std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_hosts,
     const std::vector<blink::Manifest::ImageResource>& icons,
     PaymentInstrumentIconFetcherCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
diff --git a/content/browser/payments/payment_instrument_icon_fetcher.h b/content/browser/payments/payment_instrument_icon_fetcher.h
index c31d531..43ade57 100644
--- a/content/browser/payments/payment_instrument_icon_fetcher.h
+++ b/content/browser/payments/payment_instrument_icon_fetcher.h
@@ -5,12 +5,14 @@
 #ifndef CONTENT_BROWSER_PAYMENTS_PAYMENT_INSTRUMENT_ICON_FETCHER_H_
 #define CONTENT_BROWSER_PAYMENTS_PAYMENT_INSTRUMENT_ICON_FETCHER_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "content/public/browser/global_routing_id.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
 #include "third_party/blink/public/platform/modules/payments/payment_app.mojom.h"
 
@@ -24,7 +26,7 @@
   // Should be called on IO thread.
   static void Start(
       const GURL& scope,
-      std::unique_ptr<std::vector<std::pair<int, int>>> provider_hosts,
+      std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_hosts,
       const std::vector<blink::Manifest::ImageResource>& icons,
       PaymentInstrumentIconFetcherCallback callback);
 
diff --git a/content/browser/renderer_host/render_widget_targeter.cc b/content/browser/renderer_host/render_widget_targeter.cc
index 1239e5d..fce3e14a 100644
--- a/content/browser/renderer_host/render_widget_targeter.cc
+++ b/content/browser/renderer_host/render_widget_targeter.cc
@@ -245,7 +245,8 @@
     uint32_t request_id,
     const gfx::PointF& target_location,
     TracingUmaTracker tracker,
-    const viz::FrameSinkId& frame_sink_id) {
+    const viz::FrameSinkId& frame_sink_id,
+    const gfx::PointF& transformed_location) {
   tracker.Stop();
   if (request_id != last_request_id_ || !request_in_flight_) {
     // This is a response to a request that already timed out, so the event
@@ -267,10 +268,8 @@
       unresponsive_views_.find(view) != unresponsive_views_.end()) {
     FoundTarget(root_view.get(), view, *event, latency, target_location, false);
   } else {
-    gfx::PointF location = target_location;
-    target->TransformPointToCoordSpaceForView(location, view, &location);
-    QueryClient(root_view.get(), view, *event, latency, location, target.get(),
-                target_location);
+    QueryClient(root_view.get(), view, *event, latency, transformed_location,
+                target.get(), target_location);
   }
 }
 
diff --git a/content/browser/renderer_host/render_widget_targeter.h b/content/browser/renderer_host/render_widget_targeter.h
index 6399b2ad..5e6dda1d 100644
--- a/content/browser/renderer_host/render_widget_targeter.h
+++ b/content/browser/renderer_host/render_widget_targeter.h
@@ -117,6 +117,11 @@
 
   // |event| is in the coordinate space of |root_view|. |target_location|, if
   // set, is the location in |target|'s coordinate space.
+  // |target| is the current target that will be queried using its
+  // InputTargetClient interface.
+  // |frame_sink_id| is returned from the InputTargetClient to indicate where
+  // the event should be routed, and |transformed_location| is the point in
+  // that new target's coordinate space.
   void FoundFrameSinkId(base::WeakPtr<RenderWidgetHostViewBase> root_view,
                         base::WeakPtr<RenderWidgetHostViewBase> target,
                         ui::WebScopedInputEvent event,
@@ -124,7 +129,8 @@
                         uint32_t request_id,
                         const gfx::PointF& target_location,
                         TracingUmaTracker tracker,
-                        const viz::FrameSinkId& frame_sink_id);
+                        const viz::FrameSinkId& frame_sink_id,
+                        const gfx::PointF& transformed_location);
 
   // |event| is in the coordinate space of |root_view|. |target_location|, if
   // set, is the location in |target|'s coordinate space. If |latched_target| is
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index f432bee..191b0d1 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -213,49 +213,39 @@
   }
 
   void DispatchBackgroundFetchAbortEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       DispatchBackgroundFetchAbortEventCallback callback) override {
     if (!helper_)
       return;
-    helper_->OnBackgroundFetchAbortEventStub(developer_id, unique_id, state,
-                                             std::move(callback));
+    helper_->OnBackgroundFetchAbortEventStub(registration, std::move(callback));
   }
 
   void DispatchBackgroundFetchClickEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       DispatchBackgroundFetchClickEventCallback callback) override {
     if (!helper_)
       return;
-    helper_->OnBackgroundFetchClickEventStub(developer_id, unique_id, state,
-                                             std::move(callback));
+    helper_->OnBackgroundFetchClickEventStub(registration, std::move(callback));
   }
 
   void DispatchBackgroundFetchFailEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       DispatchBackgroundFetchFailEventCallback callback) override {
     if (!helper_)
       return;
-    helper_->OnBackgroundFetchFailEventStub(developer_id, unique_id, state,
-                                            fetches, std::move(callback));
+    helper_->OnBackgroundFetchFailEventStub(registration, fetches,
+                                            std::move(callback));
   }
 
   void DispatchBackgroundFetchSuccessEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       DispatchBackgroundFetchSuccessEventCallback callback) override {
     if (!helper_)
       return;
-    helper_->OnBackgroundFetchSuccessEventStub(developer_id, unique_id, state,
-                                               fetches, std::move(callback));
+    helper_->OnBackgroundFetchSuccessEventStub(registration, fetches,
+                                               std::move(callback));
   }
 
   void DispatchCookieChangeEvent(
@@ -599,27 +589,21 @@
 }
 
 void EmbeddedWorkerTestHelper::OnBackgroundFetchAbortEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
 }
 
 void EmbeddedWorkerTestHelper::OnBackgroundFetchClickEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
 }
 
 void EmbeddedWorkerTestHelper::OnBackgroundFetchFailEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
@@ -627,9 +611,7 @@
 }
 
 void EmbeddedWorkerTestHelper::OnBackgroundFetchSuccessEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
         callback) {
@@ -880,54 +862,42 @@
 }
 
 void EmbeddedWorkerTestHelper::OnBackgroundFetchAbortEventStub(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchAbortEvent,
-                     AsWeakPtr(), developer_id, unique_id, state,
-                     std::move(callback)));
+                     AsWeakPtr(), registration, std::move(callback)));
 }
 
 void EmbeddedWorkerTestHelper::OnBackgroundFetchClickEventStub(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchClickEvent,
-                     AsWeakPtr(), developer_id, unique_id, state,
-                     std::move(callback)));
+                     AsWeakPtr(), registration, std::move(callback)));
 }
 
 void EmbeddedWorkerTestHelper::OnBackgroundFetchFailEventStub(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchFailEvent,
-                     AsWeakPtr(), developer_id, unique_id, state, fetches,
-                     std::move(callback)));
+                     AsWeakPtr(), registration, fetches, std::move(callback)));
 }
 
 void EmbeddedWorkerTestHelper::OnBackgroundFetchSuccessEventStub(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
         callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchSuccessEvent,
-                     AsWeakPtr(), developer_id, unique_id, state, fetches,
-                     std::move(callback)));
+                     AsWeakPtr(), registration, fetches, std::move(callback)));
 }
 
 void EmbeddedWorkerTestHelper::OnCookieChangeEventStub(
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index e632de9..ac8cff0 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -35,6 +35,7 @@
 
 namespace content {
 
+struct BackgroundFetchRegistration;
 struct BackgroundFetchSettledFetch;
 class EmbeddedWorkerRegistry;
 class EmbeddedWorkerTestHelper;
@@ -167,25 +168,17 @@
   virtual void OnActivateEvent(
       mojom::ServiceWorker::DispatchActivateEventCallback callback);
   virtual void OnBackgroundFetchAbortEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback);
   virtual void OnBackgroundFetchClickEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback);
   virtual void OnBackgroundFetchFailEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback);
   virtual void OnBackgroundFetchSuccessEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
           callback);
@@ -271,25 +264,17 @@
   void OnActivateEventStub(
       mojom::ServiceWorker::DispatchActivateEventCallback callback);
   void OnBackgroundFetchAbortEventStub(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback);
   void OnBackgroundFetchClickEventStub(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback);
   void OnBackgroundFetchFailEventStub(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback);
   void OnBackgroundFetchSuccessEventStub(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
           callback);
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 e4b82677..3ba2c39c 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
@@ -4,9 +4,13 @@
 
 #include "content/browser/service_worker/service_worker_content_settings_proxy_impl.h"
 
+#include <utility>
+#include <vector>
+
 #include "base/threading/thread.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/common/content_client.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
@@ -40,7 +44,7 @@
   // content setting. However, service worker is not necessarily associated
   // with frames or making the request on behalf of frames,
   // so just pass an empty |render_frames|.
-  std::vector<std::pair<int, int>> render_frames;
+  std::vector<GlobalFrameRoutingId> render_frames;
   std::move(callback).Run(GetContentClient()->browser()->AllowWorkerIndexedDB(
       origin_.GetURL(), name, context_->wrapper()->resource_context(),
       render_frames));
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 513226c..ea8ec10 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -631,20 +631,20 @@
   context_core_->HasMainFrameProviderHost(origin, std::move(callback));
 }
 
-std::unique_ptr<std::vector<std::pair<int, int>>>
+std::unique_ptr<std::vector<GlobalFrameRoutingId>>
 ServiceWorkerContextWrapper::GetProviderHostIds(const GURL& origin) const {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  std::unique_ptr<std::vector<std::pair<int, int>>> provider_host_ids(
-      new std::vector<std::pair<int, int>>());
+  std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_host_ids(
+      new std::vector<GlobalFrameRoutingId>());
 
   for (std::unique_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
            context_core_->GetClientProviderHostIterator(
                origin, false /* include_reserved_clients */);
        !it->IsAtEnd(); it->Advance()) {
     ServiceWorkerProviderHost* provider_host = it->GetProviderHost();
-    provider_host_ids->push_back(
-        std::make_pair(provider_host->process_id(), provider_host->frame_id()));
+    provider_host_ids->push_back(GlobalFrameRoutingId(
+        provider_host->process_id(), provider_host->frame_id()));
   }
 
   return provider_host_ids;
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h
index f897d4f..7766bd23 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.h
+++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -19,6 +19,7 @@
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_context_core_observer.h"
 #include "content/common/content_export.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/service_worker_context.h"
 
 namespace base {
@@ -151,10 +152,9 @@
   void HasMainFrameProviderHost(const GURL& origin,
                                 BoolCallback callback) const;
 
-  // Returns all render process ids and frame ids for the given |origin|.
-  std::unique_ptr<
-      std::vector<std::pair<int /* render process id */, int /* frame id */>>>
-  GetProviderHostIds(const GURL& origin) const;
+  // Returns all frame ids for the given |origin|.
+  std::unique_ptr<std::vector<GlobalFrameRoutingId>> GetProviderHostIds(
+      const GURL& origin) const;
 
   // Returns the registration whose scope longest matches |document_url|. It is
   // guaranteed that the returned registration has the activated worker.
diff --git a/content/browser/shared_worker/shared_worker_host.cc b/content/browser/shared_worker/shared_worker_host.cc
index 993b59f..ba80bf1 100644
--- a/content/browser/shared_worker/shared_worker_host.cc
+++ b/content/browser/shared_worker/shared_worker_host.cc
@@ -41,7 +41,7 @@
 
 void AllowFileSystemOnIOThread(const GURL& url,
                                ResourceContext* resource_context,
-                               std::vector<std::pair<int, int>> render_frames,
+                               std::vector<GlobalFrameRoutingId> render_frames,
                                base::OnceCallback<void(bool)> callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   GetContentClient()->browser()->AllowWorkerFileSystem(
@@ -52,7 +52,7 @@
 bool AllowIndexedDBOnIOThread(const GURL& url,
                               const base::string16& name,
                               ResourceContext* resource_context,
-                              std::vector<std::pair<int, int>> render_frames) {
+                              std::vector<GlobalFrameRoutingId> render_frames) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   return GetContentClient()->browser()->AllowWorkerIndexedDB(
       url, name, resource_context, render_frames);
@@ -372,11 +372,12 @@
     info.client->OnFeatureUsed(feature);
 }
 
-std::vector<std::pair<int, int>>
+std::vector<GlobalFrameRoutingId>
 SharedWorkerHost::GetRenderFrameIDsForWorker() {
-  std::vector<std::pair<int, int>> result;
+  std::vector<GlobalFrameRoutingId> result;
+  result.reserve(clients_.size());
   for (const ClientInfo& info : clients_)
-    result.push_back(std::make_pair(info.process_id, info.frame_id));
+    result.push_back(GlobalFrameRoutingId(info.process_id, info.frame_id));
   return result;
 }
 
diff --git a/content/browser/shared_worker/shared_worker_host.h b/content/browser/shared_worker/shared_worker_host.h
index d8c7382..8947786 100644
--- a/content/browser/shared_worker/shared_worker_host.h
+++ b/content/browser/shared_worker/shared_worker_host.h
@@ -21,6 +21,7 @@
 #include "content/common/shared_worker/shared_worker_client.mojom.h"
 #include "content/common/shared_worker/shared_worker_factory.mojom.h"
 #include "content/common/shared_worker/shared_worker_host.mojom.h"
+#include "content/public/browser/global_routing_id.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "services/service_manager/public/mojom/interface_provider.mojom.h"
@@ -132,8 +133,8 @@
   void OnScriptLoadFailed() override;
   void OnFeatureUsed(blink::mojom::WebFeature feature) override;
 
-  // Return a vector of all the render process/render frame IDs.
-  std::vector<std::pair<int, int>> GetRenderFrameIDsForWorker();
+  // Returns the frame ids of this worker's clients.
+  std::vector<GlobalFrameRoutingId> GetRenderFrameIDsForWorker();
 
   void AllowFileSystemResponse(base::OnceCallback<void(bool)> callback,
                                bool allowed);
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 48bd9c4..1497e843 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -375,23 +375,6 @@
   focus_observer.Wait();
 }
 
-// A BrowserMessageFilter that drops SwapOut ACK messages.
-class SwapoutACKMessageFilter : public BrowserMessageFilter {
- public:
-  SwapoutACKMessageFilter() : BrowserMessageFilter(FrameMsgStart) {}
-
- protected:
-  ~SwapoutACKMessageFilter() override {}
-
- private:
-  // BrowserMessageFilter:
-  bool OnMessageReceived(const IPC::Message& message) override {
-    return message.type() == FrameHostMsg_SwapOut_ACK::ID;
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(SwapoutACKMessageFilter);
-};
-
 class RenderWidgetHostVisibilityObserver : public RenderWidgetHostObserver {
  public:
   explicit RenderWidgetHostVisibilityObserver(RenderWidgetHostImpl* rwhi,
@@ -7800,10 +7783,10 @@
   // At this point, we should have two pending WebContents.
   EXPECT_TRUE(base::ContainsKey(
       web_contents()->pending_contents_,
-      std::make_pair(process1->GetID(), filter1->routing_id())));
+      GlobalRoutingID(process1->GetID(), filter1->routing_id())));
   EXPECT_TRUE(base::ContainsKey(
       web_contents()->pending_contents_,
-      std::make_pair(process2->GetID(), filter2->routing_id())));
+      GlobalRoutingID(process2->GetID(), filter2->routing_id())));
 
   // Both subframes were set up in the same way, so the next routing ID for the
   // new popup windows should match up (this led to the collision in the
@@ -7878,10 +7861,10 @@
   // At this point, we should have two pending widgets.
   EXPECT_TRUE(base::ContainsKey(
       web_contents()->pending_widget_views_,
-      std::make_pair(process1->GetID(), filter1->routing_id())));
+      GlobalRoutingID(process1->GetID(), filter1->routing_id())));
   EXPECT_TRUE(base::ContainsKey(
       web_contents()->pending_widget_views_,
-      std::make_pair(process2->GetID(), filter2->routing_id())));
+      GlobalRoutingID(process2->GetID(), filter2->routing_id())));
 
   // Both subframes were set up in the same way, so the next routing ID for the
   // new popup widgets should match up (this led to the collision in the
@@ -7895,10 +7878,10 @@
                                     false, gfx::Rect());
   EXPECT_FALSE(base::ContainsKey(
       web_contents()->pending_widget_views_,
-      std::make_pair(process1->GetID(), filter1->routing_id())));
+      GlobalRoutingID(process1->GetID(), filter1->routing_id())));
   EXPECT_FALSE(base::ContainsKey(
       web_contents()->pending_widget_views_,
-      std::make_pair(process2->GetID(), filter2->routing_id())));
+      GlobalRoutingID(process2->GetID(), filter2->routing_id())));
 }
 #endif
 
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 06d9651..7e4cb96 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -217,7 +217,10 @@
   RouteMouseEventAndWaitUntilDispatch(router, root_view, expected_target,
                                       &down_event);
   EXPECT_TRUE(monitor.EventWasReceived());
-  EXPECT_NEAR(expected_location.x(), monitor.event().PositionInWidget().x, 2);
+  EXPECT_NEAR(expected_location.x(), monitor.event().PositionInWidget().x, 2)
+      << " & original location was " << location.x() << ", " << location.y()
+      << " & root_location was " << root_location.x() << ", "
+      << root_location.y();
   EXPECT_NEAR(expected_location.y(), monitor.event().PositionInWidget().y, 2);
 }
 
@@ -318,6 +321,44 @@
                                          gfx::PointF(5, 5));
 }
 
+void PerspectiveTransformedSurfaceHitTestHelper(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  GURL main_url(embedded_test_server->GetURL(
+      "/frame_tree/page_with_perspective_transformed_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell, main_url));
+  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
+
+  RenderFrameSubmissionObserver render_frame_submission_observer(web_contents);
+
+  FrameTreeNode* root = web_contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForHitTestDataOrChildSurfaceReady(child_node->current_frame_host());
+
+  // (90, 75) hit tests into the child frame that is positioned at (50, 50).
+  // Without other transformations this should result in a translated point
+  // of (40, 25), but the 45 degree 3-dimensional rotation of the frame about
+  // a vertical axis skews it.
+  // We can't allow DispatchMouseEventAndWaitUntilDispatch to compute the
+  // coordinates in the root space unless browser conversions with
+  // perspective transforms are first fixed. See https://crbug.com/854257.
+  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
+                                         gfx::PointF(90, 75), rwhv_child,
+                                         gfx::PointF(33, 23));
+}
+
 // Helper function that performs a surface hittest in nested frame.
 void NestedSurfaceHitTestTestHelper(
     Shell* shell,
@@ -1872,6 +1913,27 @@
   NonFlatTransformedSurfaceHitTestHelper(shell(), embedded_test_server());
 }
 
+// TODO(kenrb): Running this test on Android bots has slight discrepancies in
+// transformed event coordinates when we do manual calculation of expected
+// values. We can't rely on browser side transformation because it is broken
+// for perspective transforms. See https://crbug.com/854247.
+#if defined(OS_ANDROID)
+#define MAYBE_PerspectiveTransformedSurfaceHitTestTest \
+  DISABLED_PerspectiveTransformedSurfaceHitTestTest
+#else
+#define MAYBE_PerspectiveTransformedSurfaceHitTestTest \
+  PerspectiveTransformedSurfaceHitTestTest
+#endif
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
+                       MAYBE_PerspectiveTransformedSurfaceHitTestTest) {
+  PerspectiveTransformedSurfaceHitTestHelper(shell(), embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
+                       MAYBE_PerspectiveTransformedSurfaceHitTestTest) {
+  PerspectiveTransformedSurfaceHitTestHelper(shell(), embedded_test_server());
+}
+
 #if defined(OS_LINUX)
 // Flaky timeouts and failures: https://crbug.com/833380
 #define MAYBE_OverlapSurfaceHitTestTest DISABLED_OverlapSurfaceHitTestTest
@@ -4583,37 +4645,46 @@
   {
     base::RunLoop run_loop;
     viz::FrameSinkId received_frame_sink_id;
+    gfx::PointF returned_point;
     base::Closure quit_closure =
         content::GetDeferredQuitTaskForRunLoop(&run_loop);
     DCHECK_NE(child_node->current_frame_host()->GetInputTargetClient(),
               nullptr);
     child_node->current_frame_host()->GetInputTargetClient()->FrameSinkIdAt(
         point_in_child,
-        base::BindLambdaForTesting([&](const viz::FrameSinkId& id) {
-          received_frame_sink_id = id;
-          quit_closure.Run();
-        }));
+        base::BindLambdaForTesting(
+            [&](const viz::FrameSinkId& id, const gfx::PointF& point) {
+              received_frame_sink_id = id;
+              returned_point = point;
+              quit_closure.Run();
+            }));
     content::RunThisRunLoop(&run_loop);
     // |point_in_child| should hit test to the view for |child_node|.
     ASSERT_EQ(rwhv_child->GetFrameSinkId(), received_frame_sink_id);
+    ASSERT_EQ(gfx::PointF(1, 1), returned_point);
   }
 
   {
     base::RunLoop run_loop;
     viz::FrameSinkId received_frame_sink_id;
+    gfx::PointF returned_point;
     base::Closure quit_closure =
         content::GetDeferredQuitTaskForRunLoop(&run_loop);
     DCHECK_NE(child_node->current_frame_host()->GetInputTargetClient(),
               nullptr);
     child_node->current_frame_host()->GetInputTargetClient()->FrameSinkIdAt(
         gfx::ToCeiledPoint(point_in_nested_child),
-        base::BindLambdaForTesting([&](const viz::FrameSinkId& id) {
-          received_frame_sink_id = id;
-          quit_closure.Run();
-        }));
+        base::BindLambdaForTesting(
+            [&](const viz::FrameSinkId& id, const gfx::PointF& point) {
+              received_frame_sink_id = id;
+              returned_point = point;
+              quit_closure.Run();
+            }));
     content::RunThisRunLoop(&run_loop);
     // |point_in_nested_child| should hit test to |rwhv_grandchild|.
     ASSERT_EQ(rwhv_grandchild->GetFrameSinkId(), received_frame_sink_id);
+    EXPECT_NEAR(returned_point.x(), 5, 2);
+    EXPECT_NEAR(returned_point.y(), 5, 2);
   }
 }
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index f806c32..51d4ce1e 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2670,8 +2670,8 @@
     // FrameTreeNode id instead of the routing id of the Widget for the main
     // frame.  https://crbug.com/545684
     DCHECK_NE(MSG_ROUTING_NONE, main_frame_widget_route_id);
-    pending_contents_[std::make_pair(render_process_id,
-                                     main_frame_widget_route_id)] =
+    pending_contents_[GlobalRoutingID(render_process_id,
+                                      main_frame_widget_route_id)] =
         std::move(new_contents);
     AddDestructionObserver(raw_new_contents);
   }
@@ -2773,7 +2773,7 @@
     widget_view->SetPopupType(popup_type);
   }
   // Save the created widget associated with the route so we can show it later.
-  pending_widget_views_[std::make_pair(render_process_id, route_id)] =
+  pending_widget_views_[GlobalRoutingID(render_process_id, route_id)] =
       widget_view;
 }
 
@@ -2866,7 +2866,7 @@
 std::unique_ptr<WebContents> WebContentsImpl::GetCreatedWindow(
     int process_id,
     int main_frame_widget_route_id) {
-  auto key = std::make_pair(process_id, main_frame_widget_route_id);
+  auto key = GlobalRoutingID(process_id, main_frame_widget_route_id);
   auto iter = pending_contents_.find(key);
 
   // Certain systems can block the creation of new windows. If we didn't succeed
@@ -2894,14 +2894,14 @@
 
 RenderWidgetHostView* WebContentsImpl::GetCreatedWidget(int process_id,
                                                         int route_id) {
-  auto iter = pending_widget_views_.find(std::make_pair(process_id, route_id));
+  auto iter = pending_widget_views_.find(GlobalRoutingID(process_id, route_id));
   if (iter == pending_widget_views_.end()) {
     DCHECK(false);
     return nullptr;
   }
 
   RenderWidgetHostView* widget_host_view = iter->second;
-  pending_widget_views_.erase(std::make_pair(process_id, route_id));
+  pending_widget_views_.erase(GlobalRoutingID(process_id, route_id));
 
   RenderWidgetHost* widget_host = widget_host_view->GetRenderWidgetHost();
   if (!widget_host->GetProcess()->IsInitializedAndNotDead()) {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index dc1b991d..96a42c8 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -41,6 +41,7 @@
 #include "content/browser/wake_lock/wake_lock_context_host.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/color_chooser.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents.h"
@@ -1005,6 +1006,8 @@
                            NotifyFullscreenAcquired_Navigate);
   FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
                            NotifyFullscreenAcquired_SameOrigin);
+  FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
+                           FullscreenAfterFrameSwap);
   FRIEND_TEST_ALL_PREFIXES(FormStructureBrowserTest, HTMLFiles);
   FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest, HistoryNavigate);
   FRIEND_TEST_ALL_PREFIXES(RenderFrameHostManagerTest, PageDoesBackAndReload);
@@ -1410,13 +1413,11 @@
 
   // Tracks created WebContentsImpl objects that have not been shown yet. They
   // are identified by the process ID and routing ID passed to CreateNewWindow.
-  typedef std::pair<int, int> ProcessRoutingIdPair;
-  std::map<ProcessRoutingIdPair, std::unique_ptr<WebContents>>
-      pending_contents_;
+  std::map<GlobalRoutingID, std::unique_ptr<WebContents>> pending_contents_;
 
   // This map holds widgets that were created on behalf of the renderer but
   // haven't been shown yet.
-  std::map<ProcessRoutingIdPair, RenderWidgetHostView*> pending_widget_views_;
+  std::map<GlobalRoutingID, RenderWidgetHostView*> pending_widget_views_;
 
   std::map<WebContentsImpl*, std::unique_ptr<DestructionObserver>>
       destruction_observers_;
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 367e29c..f631913 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -2696,15 +2696,42 @@
   }
 }
 
-// TODO(beccahughes@): This test is flaking on Android. https://crbug.com/855018
-#if defined(OS_ANDROID)
-#define MAYBE_NotifyFullscreenAcquired_Navigate \
-    DISABLED_NotifyFullscreenAcquired_Navigate
-#else
-#define MAYBE_NotifyFullscreenAcquired_Navigate NotifyFullscreenAcquired_Navigate
-#endif
+// Regression test for https://crbug.com/855018.
+// RenderFrameHostImpls exit fullscreen as soon as they are swapped out.
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, FullscreenAfterFrameSwap) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  WebContentsImpl* web_contents =
+      static_cast<WebContentsImpl*>(shell()->web_contents());
+
+  GURL url_a = embedded_test_server()->GetURL("a.com", "/title1.html");
+  GURL url_b = embedded_test_server()->GetURL("b.com", "/title1.html");
+
+  // 1) Navigate. There is initially no fullscreen frame.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* main_frame =
+      static_cast<RenderFrameHostImpl*>(web_contents->GetMainFrame());
+  EXPECT_EQ(0u, web_contents->fullscreen_frame_tree_nodes_.size());
+
+  // 2) Make it fullscreen.
+  FullscreenWebContentsObserver observer(web_contents, main_frame);
+  EXPECT_TRUE(
+      ExecuteScript(main_frame, "document.body.webkitRequestFullscreen();"));
+  observer.Wait();
+  EXPECT_EQ(1u, web_contents->fullscreen_frame_tree_nodes_.size());
+
+  // 3) Navigate cross origin. Act as if the old frame was very slow delivering
+  //    the swapout ack and stayed in pending deletion for a while. Even if the
+  //    frame is still present, it must be removed from the list of frame in
+  //    fullscreen immediately.
+  auto filter = base::MakeRefCounted<SwapoutACKMessageFilter>();
+  main_frame->GetProcess()->AddFilter(filter.get());
+  main_frame->DisableSwapOutTimerForTesting();
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  EXPECT_EQ(0u, web_contents->fullscreen_frame_tree_nodes_.size());
+}
+
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
-                       MAYBE_NotifyFullscreenAcquired_Navigate) {
+                       NotifyFullscreenAcquired_Navigate) {
   ASSERT_TRUE(embedded_test_server()->Start());
   WebContentsImpl* web_contents =
       static_cast<WebContentsImpl*>(shell()->web_contents());
diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h
index 058f3e0..5c8f8a76 100644
--- a/content/browser/web_contents/web_contents_view_aura.h
+++ b/content/browser/web_contents/web_contents_view_aura.h
@@ -12,12 +12,12 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "content/browser/loader/global_routing_id.h"
 #include "content/browser/renderer_host/overscroll_controller_delegate.h"
 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
 #include "content/browser/web_contents/web_contents_view.h"
 #include "content/common/buildflags.h"
 #include "content/common/content_export.h"
+#include "content/public/browser/global_routing_id.h"
 #include "ui/aura/client/drag_drop_delegate.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
diff --git a/content/browser/web_contents/web_drag_dest_mac.h b/content/browser/web_contents/web_drag_dest_mac.h
index c81c2a89..6d6ae69 100644
--- a/content/browser/web_contents/web_drag_dest_mac.h
+++ b/content/browser/web_contents/web_drag_dest_mac.h
@@ -10,8 +10,8 @@
 #include <memory>
 
 #include "base/strings/string16.h"
-#include "content/browser/loader/global_routing_id.h"
 #include "content/common/content_export.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/common/drop_data.h"
 #include "ui/gfx/geometry/point_f.h"
 
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 9fbd8bb..65229dd8 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -444,9 +444,11 @@
   WebRuntimeFeatures::EnableIsolatedCodeCache(
       base::FeatureList::IsEnabled(features::kIsolatedCodeCache));
 
-  // Make srcset on link rel=preload work with SignedHTTPExchange flag too.
-  if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange))
+  if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange)) {
+    WebRuntimeFeatures::EnableSignedHTTPExchange(true);
+    // Make srcset on link rel=preload work with SignedHTTPExchange flag too.
     WebRuntimeFeatures::EnablePreloadImageSrcSetEnabled(true);
+  }
 
   WebRuntimeFeatures::EnableNestedWorkers(
       base::FeatureList::IsEnabled(blink::features::kNestedWorkers));
diff --git a/content/common/background_fetch/background_fetch_struct_traits.cc b/content/common/background_fetch/background_fetch_struct_traits.cc
index aa1d30fd..a8bde81 100644
--- a/content/common/background_fetch/background_fetch_struct_traits.cc
+++ b/content/common/background_fetch/background_fetch_struct_traits.cc
@@ -39,6 +39,7 @@
   registration->uploaded = data.uploaded();
   registration->download_total = data.download_total();
   registration->downloaded = data.downloaded();
+  registration->state = data.state();
   return true;
 }
 
diff --git a/content/common/background_fetch/background_fetch_struct_traits.h b/content/common/background_fetch/background_fetch_struct_traits.h
index 512f74b..3a3a6e1e 100644
--- a/content/common/background_fetch/background_fetch_struct_traits.h
+++ b/content/common/background_fetch/background_fetch_struct_traits.h
@@ -64,6 +64,10 @@
       const content::BackgroundFetchRegistration& registration) {
     return registration.downloaded;
   }
+  static blink::mojom::BackgroundFetchState state(
+      const content::BackgroundFetchRegistration& registration) {
+    return registration.state;
+  }
 
   static bool Read(blink::mojom::BackgroundFetchRegistrationDataView data,
                    content::BackgroundFetchRegistration* registration);
diff --git a/content/common/background_fetch/background_fetch_struct_traits_unittest.cc b/content/common/background_fetch/background_fetch_struct_traits_unittest.cc
index d990a54..615ec52 100644
--- a/content/common/background_fetch/background_fetch_struct_traits_unittest.cc
+++ b/content/common/background_fetch/background_fetch_struct_traits_unittest.cc
@@ -59,6 +59,7 @@
   registration.developer_id = "my_id";
   registration.unique_id = "7e57ab1e-c0de-a150-ca75-1e75f005ba11";
   registration.download_total = 9001;
+  registration.state = blink::mojom::BackgroundFetchState::FAILURE;
 
   BackgroundFetchRegistration roundtrip_registration;
   ASSERT_TRUE(blink::mojom::BackgroundFetchRegistration::Deserialize(
@@ -69,6 +70,7 @@
   EXPECT_EQ(roundtrip_registration.unique_id, registration.unique_id);
 
   EXPECT_EQ(roundtrip_registration.download_total, registration.download_total);
+  EXPECT_EQ(roundtrip_registration.state, registration.state);
 }
 
 TEST(BackgroundFetchStructTraitsTest, ImageResourceRoundtrip) {
diff --git a/content/common/background_fetch/background_fetch_types.cc b/content/common/background_fetch/background_fetch_types.cc
index a1e3ac23..e57a1a38 100644
--- a/content/common/background_fetch/background_fetch_types.cc
+++ b/content/common/background_fetch/background_fetch_types.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "content/common/background_fetch/background_fetch_types.h"
+#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
 
 namespace {
 
@@ -27,7 +28,24 @@
 
 BackgroundFetchOptions::~BackgroundFetchOptions() = default;
 
-BackgroundFetchRegistration::BackgroundFetchRegistration() = default;
+BackgroundFetchRegistration::BackgroundFetchRegistration()
+    : state(blink::mojom::BackgroundFetchState::PENDING) {}
+
+BackgroundFetchRegistration::BackgroundFetchRegistration(
+    const std::string& developer_id,
+    const std::string& unique_id,
+    uint64_t upload_total,
+    uint64_t uploaded,
+    uint64_t download_total,
+    uint64_t downloaded,
+    blink::mojom::BackgroundFetchState state)
+    : developer_id(developer_id),
+      unique_id(unique_id),
+      upload_total(upload_total),
+      uploaded(uploaded),
+      download_total(download_total),
+      downloaded(downloaded),
+      state(state) {}
 
 BackgroundFetchRegistration::BackgroundFetchRegistration(
     const BackgroundFetchRegistration& other) = default;
diff --git a/content/common/background_fetch/background_fetch_types.h b/content/common/background_fetch/background_fetch_types.h
index 193820e..7fd22c1b 100644
--- a/content/common/background_fetch/background_fetch_types.h
+++ b/content/common/background_fetch/background_fetch_types.h
@@ -14,6 +14,12 @@
 #include "third_party/blink/public/common/manifest/manifest.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom.h"
 
+namespace blink {
+namespace mojom {
+enum class BackgroundFetchState;
+}  // namespace mojom
+}  // namespace blink
+
 namespace content {
 
 // Represents the optional options a developer can provide when starting a new
@@ -34,6 +40,13 @@
 // https://wicg.github.io/background-fetch/#background-fetch-registration
 struct CONTENT_EXPORT BackgroundFetchRegistration {
   BackgroundFetchRegistration();
+  BackgroundFetchRegistration(const std::string& developer_id,
+                              const std::string& unique_id,
+                              uint64_t upload_total,
+                              uint64_t uploaded,
+                              uint64_t download_total,
+                              uint64_t downloaded,
+                              blink::mojom::BackgroundFetchState state);
   BackgroundFetchRegistration(const BackgroundFetchRegistration& other);
   ~BackgroundFetchRegistration();
 
@@ -49,7 +62,7 @@
   uint64_t uploaded = 0;
   uint64_t download_total = 0;
   uint64_t downloaded = 0;
-  // TODO(crbug.com/699957): Support the `activeFetches` member.
+  blink::mojom::BackgroundFetchState state;
 };
 
 // Represents a request/response pair for a settled Background Fetch fetch.
diff --git a/content/common/service_worker/service_worker.mojom b/content/common/service_worker/service_worker.mojom
index 21642ace..3f63a4a 100644
--- a/content/common/service_worker/service_worker.mojom
+++ b/content/common/service_worker/service_worker.mojom
@@ -20,6 +20,7 @@
 import "third_party/blink/public/mojom/service_worker/service_worker_fetch_response_callback.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_object.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom";
+import "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom";
 import "url/mojom/origin.mojom";
 import "url/mojom/url.mojom";
 
@@ -86,26 +87,21 @@
   // The callbacks are called once the event handler has run and waitUntil()
   // promise has settled. |developer_id| and |unique_id| are documented in
   // content::BackgroundFetchRegistrationId.
-  DispatchBackgroundFetchAbortEvent(string developer_id,
-                                    string unique_id,
-                                    blink.mojom.BackgroundFetchState state)
+  DispatchBackgroundFetchAbortEvent(
+      blink.mojom.BackgroundFetchRegistration registration)
       => (blink.mojom.ServiceWorkerEventStatus status,
           mojo_base.mojom.Time dispatch_event_time);
-  DispatchBackgroundFetchClickEvent(string developer_id,
-                                    string unique_id,
-                                    blink.mojom.BackgroundFetchState state)
+  DispatchBackgroundFetchClickEvent(
+      blink.mojom.BackgroundFetchRegistration registration)
       => (blink.mojom.ServiceWorkerEventStatus status,
           mojo_base.mojom.Time dispatch_event_time);
-  DispatchBackgroundFetchFailEvent(string developer_id,
-                                   string unique_id,
-                                   blink.mojom.BackgroundFetchState state,
-                                   array<blink.mojom.BackgroundFetchSettledFetch> fetches)
+ DispatchBackgroundFetchFailEvent(
+      blink.mojom.BackgroundFetchRegistration registration,
+      array<blink.mojom.BackgroundFetchSettledFetch> fetches)
       => (blink.mojom.ServiceWorkerEventStatus status,
           mojo_base.mojom.Time dispatch_event_time);
   DispatchBackgroundFetchSuccessEvent(
-      string developer_id,
-      string unique_id,
-      blink.mojom.BackgroundFetchState state,
+      blink.mojom.BackgroundFetchRegistration registration,
       array<blink.mojom.BackgroundFetchSettledFetch> fetches)
       => (blink.mojom.ServiceWorkerEventStatus status,
           mojo_base.mojom.Time dispatch_event_time);
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index d0f74db..09d5e0a 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -133,6 +133,7 @@
     "font_list_async.h",
     "frame_service_base.h",
     "global_request_id.h",
+    "global_routing_id.h",
     "gpu_client.h",
     "gpu_data_manager.h",
     "gpu_data_manager_observer.h",
diff --git a/content/public/browser/background_fetch_delegate.h b/content/public/browser/background_fetch_delegate.h
index 1113426..bff9eb6 100644
--- a/content/public/browser/background_fetch_delegate.h
+++ b/content/public/browser/background_fetch_delegate.h
@@ -15,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "content/common/content_export.h"
+#include "content/public/browser/resource_request_info.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
 class GURL;
@@ -28,6 +29,10 @@
 struct NetworkTrafficAnnotationTag;
 }  // namespace net
 
+namespace url {
+class Origin;
+}  // namespace url
+
 namespace content {
 struct BackgroundFetchResponse;
 struct BackgroundFetchResult;
@@ -50,6 +55,7 @@
 class CONTENT_EXPORT BackgroundFetchDelegate {
  public:
   using GetIconDisplaySizeCallback = base::OnceCallback<void(const gfx::Size&)>;
+  using GetPermissionForOriginCallback = base::OnceCallback<void(bool)>;
 
   // Client interface that a BackgroundFetchDelegate would use to signal the
   // progress of a background fetch.
@@ -98,6 +104,13 @@
   // Gets size of the icon to display with the Background Fetch UI.
   virtual void GetIconDisplaySize(GetIconDisplaySizeCallback callback) = 0;
 
+  // Checks whether |origin| has permission to start a Background Fetch.
+  // |wc_getter| can be null, which means this is running from a worker context.
+  virtual void GetPermissionForOrigin(
+      const url::Origin& origin,
+      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      GetPermissionForOriginCallback callback) = 0;
+
   // Creates a new download grouping identified by |job_unique_id|. Further
   // downloads started by DownloadUrl will also use this |job_unique_id| so that
   // a notification can be updated with the current status. If the download was
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index ba41da2..9098a79 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -327,7 +327,7 @@
 void ContentBrowserClient::AllowWorkerFileSystem(
     const GURL& url,
     ResourceContext* context,
-    const std::vector<std::pair<int, int> >& render_frames,
+    const std::vector<GlobalFrameRoutingId>& render_frames,
     base::Callback<void(bool)> callback) {
   std::move(callback).Run(true);
 }
@@ -336,7 +336,7 @@
     const GURL& url,
     const base::string16& name,
     ResourceContext* context,
-    const std::vector<std::pair<int, int> >& render_frames) {
+    const std::vector<GlobalFrameRoutingId>& render_frames) {
   return true;
 }
 
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index e9ce260..2c51c82 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -22,6 +22,7 @@
 #include "build/build_config.h"
 #include "content/public/browser/certificate_request_result_type.h"
 #include "content/public/browser/global_request_id.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/overlay_window.h"
 #include "content/public/browser/resource_request_info.h"
@@ -570,7 +571,7 @@
   virtual void AllowWorkerFileSystem(
       const GURL& url,
       ResourceContext* context,
-      const std::vector<std::pair<int, int> >& render_frames,
+      const std::vector<GlobalFrameRoutingId>& render_frames,
       base::Callback<void(bool)> callback);
 
   // Allow the embedder to control if access to IndexedDB by a shared worker
@@ -580,7 +581,7 @@
       const GURL& url,
       const base::string16& name,
       ResourceContext* context,
-      const std::vector<std::pair<int, int> >& render_frames);
+      const std::vector<GlobalFrameRoutingId>& render_frames);
 
   // Allow the embedder to control whether we can use Web Bluetooth.
   // TODO(crbug.com/589228): Replace this with a use of the permission system.
diff --git a/content/public/browser/global_routing_id.h b/content/public/browser/global_routing_id.h
new file mode 100644
index 0000000..bf6a9d8
--- /dev/null
+++ b/content/public/browser/global_routing_id.h
@@ -0,0 +1,82 @@
+// Copyright (c) 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 CONTENT_PUBLIC_BROWSER_GLOBAL_ROUTING_ID_H_
+#define CONTENT_PUBLIC_BROWSER_GLOBAL_ROUTING_ID_H_
+
+#include <tuple>
+
+#include "base/hash.h"
+#include "ipc/ipc_message.h"
+
+namespace content {
+
+// Uniquely identifies a target that legacy IPCs can be routed to.
+struct GlobalRoutingID {
+  GlobalRoutingID() : child_id(-1), route_id(-1) {}
+
+  GlobalRoutingID(int child_id, int route_id)
+      : child_id(child_id), route_id(route_id) {}
+
+  // The unique ID of the child process (this is different from OS's PID / this
+  // should come from RenderProcessHost::GetID()).
+  int child_id;
+
+  // The route ID.
+  int route_id;
+
+  bool operator<(const GlobalRoutingID& other) const {
+    return std::tie(child_id, route_id) <
+           std::tie(other.child_id, other.route_id);
+  }
+  bool operator==(const GlobalRoutingID& other) const {
+    return child_id == other.child_id && route_id == other.route_id;
+  }
+  bool operator!=(const GlobalRoutingID& other) const {
+    return !(*this == other);
+  }
+};
+
+// Same as GlobalRoutingID except the route_id must be a RenderFrameHost routing
+// id.
+struct GlobalFrameRoutingId {
+  GlobalFrameRoutingId() : child_id(0), frame_routing_id(MSG_ROUTING_NONE) {}
+
+  GlobalFrameRoutingId(int child_id, int frame_routing_id)
+      : child_id(child_id), frame_routing_id(frame_routing_id) {}
+
+  // GlobalFrameRoutingId is copyable.
+  GlobalFrameRoutingId(const GlobalFrameRoutingId&) = default;
+  GlobalFrameRoutingId& operator=(const GlobalFrameRoutingId&) = default;
+
+  // The unique ID of the child process (this is different from OS's PID / this
+  // should come from RenderProcessHost::GetID()).
+  int child_id;
+
+  // The route ID of a RenderFrame - should come from
+  // RenderFrameHost::GetRoutingID().
+  int frame_routing_id;
+
+  bool operator<(const GlobalFrameRoutingId& other) const {
+    return std::tie(child_id, frame_routing_id) <
+           std::tie(other.child_id, other.frame_routing_id);
+  }
+  bool operator==(const GlobalFrameRoutingId& other) const {
+    return child_id == other.child_id &&
+           frame_routing_id == other.frame_routing_id;
+  }
+  bool operator!=(const GlobalFrameRoutingId& other) const {
+    return !(*this == other);
+  }
+};
+
+struct GlobalFrameRoutingIdHasher {
+  std::size_t operator()(const GlobalFrameRoutingId& id) const {
+    return base::HashInts(id.child_id, id.frame_routing_id);
+  }
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_GLOBAL_ROUTING_ID_H_
diff --git a/content/public/browser/presentation_request.cc b/content/public/browser/presentation_request.cc
index d3a1dccd..b8df3bc 100644
--- a/content/public/browser/presentation_request.cc
+++ b/content/public/browser/presentation_request.cc
@@ -7,7 +7,7 @@
 namespace content {
 
 PresentationRequest::PresentationRequest(
-    const std::pair<int, int>& render_frame_host_id,
+    const GlobalFrameRoutingId& render_frame_host_id,
     const std::vector<GURL>& presentation_urls,
     const url::Origin& frame_origin)
     : render_frame_host_id(render_frame_host_id),
diff --git a/content/public/browser/presentation_request.h b/content/public/browser/presentation_request.h
index e2a1a5b1..224095a 100644
--- a/content/public/browser/presentation_request.h
+++ b/content/public/browser/presentation_request.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "content/common/content_export.h"
+#include "content/public/browser/global_routing_id.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -19,7 +20,7 @@
 // frame.
 struct CONTENT_EXPORT PresentationRequest {
  public:
-  PresentationRequest(const std::pair<int, int>& render_frame_host_id,
+  PresentationRequest(const GlobalFrameRoutingId& render_frame_host_id,
                       const std::vector<GURL>& presentation_urls,
                       const url::Origin& frame_origin);
   ~PresentationRequest();
@@ -28,7 +29,7 @@
   PresentationRequest& operator=(const PresentationRequest& other);
 
   // ID of RenderFrameHost that initiated the request.
-  std::pair<int, int> render_frame_host_id;
+  GlobalFrameRoutingId render_frame_host_id;
 
   // URLs of presentation.
   std::vector<GURL> presentation_urls;
diff --git a/content/renderer/input/input_target_client_impl.cc b/content/renderer/input/input_target_client_impl.cc
index db8a81e..b8ee18d5 100644
--- a/content/renderer/input/input_target_client_impl.cc
+++ b/content/renderer/input/input_target_client_impl.cc
@@ -24,8 +24,10 @@
 
 void InputTargetClientImpl::FrameSinkIdAt(const gfx::Point& point,
                                           FrameSinkIdAtCallback callback) {
-  std::move(callback).Run(
-      render_frame_->GetRenderWidget()->GetFrameSinkIdAtPoint(point));
+  gfx::PointF local_point;
+  viz::FrameSinkId id = render_frame_->GetRenderWidget()->GetFrameSinkIdAtPoint(
+      point, &local_point);
+  std::move(callback).Run(id, local_point);
 }
 
 }  // namespace content
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc
index e463640..3299f34 100644
--- a/content/renderer/input/render_widget_input_handler.cc
+++ b/content/renderer/input/render_widget_input_handler.cc
@@ -191,16 +191,18 @@
 RenderWidgetInputHandler::~RenderWidgetInputHandler() {}
 
 viz::FrameSinkId RenderWidgetInputHandler::GetFrameSinkIdAtPoint(
-    const gfx::Point& point) {
+    const gfx::Point& point,
+    gfx::PointF* local_point) {
   gfx::PointF point_in_pixel(point);
   if (widget_->compositor_deps()->IsUseZoomForDSFEnabled()) {
     point_in_pixel = gfx::ConvertPointToPixel(
         widget_->GetOriginalScreenInfo().device_scale_factor, point_in_pixel);
   }
-  blink::WebNode result_node = widget_->GetWebWidget()
-                                   ->HitTestResultAt(blink::WebPoint(
-                                       point_in_pixel.x(), point_in_pixel.y()))
-                                   .GetNode();
+  blink::WebHitTestResult result = widget_->GetWebWidget()->HitTestResultAt(
+      blink::WebPoint(point_in_pixel.x(), point_in_pixel.y()));
+
+  blink::WebNode result_node = result.GetNode();
+  *local_point = gfx::PointF(point);
 
   // TODO(crbug.com/797828): When the node is null the caller may
   // need to do extra checks. Like maybe update the layout and then
@@ -217,6 +219,11 @@
     viz::FrameSinkId frame_sink_id =
         RenderFrameProxy::FromWebFrame(result_frame->ToWebRemoteFrame())
             ->frame_sink_id();
+    *local_point = gfx::PointF(result.LocalPointWithoutContentBoxOffset());
+    if (widget_->compositor_deps()->IsUseZoomForDSFEnabled()) {
+      *local_point = gfx::ConvertPointToDIP(
+          widget_->GetOriginalScreenInfo().device_scale_factor, *local_point);
+    }
     if (frame_sink_id.is_valid())
       return frame_sink_id;
   }
diff --git a/content/renderer/input/render_widget_input_handler.h b/content/renderer/input/render_widget_input_handler.h
index 4ebdb4f..e3884c4 100644
--- a/content/renderer/input/render_widget_input_handler.h
+++ b/content/renderer/input/render_widget_input_handler.h
@@ -47,8 +47,10 @@
   virtual ~RenderWidgetInputHandler();
 
   // Hit test the given point to find out the frame underneath and
-  // returns the FrameSinkId for that frame.
-  viz::FrameSinkId GetFrameSinkIdAtPoint(const gfx::Point& point);
+  // returns the FrameSinkId for that frame. |local_point| returns the point
+  // in the coordinate space of the FrameSinkId that was hit.
+  viz::FrameSinkId GetFrameSinkIdAtPoint(const gfx::Point& point,
+                                         gfx::PointF* local_point);
 
   // Handle input events from the input event provider.
   virtual void HandleInputEvent(
diff --git a/content/renderer/media/webrtc/rtc_video_encoder.cc b/content/renderer/media/webrtc/rtc_video_encoder.cc
index 3ecf311..5df15b2 100644
--- a/content/renderer/media/webrtc/rtc_video_encoder.cc
+++ b/content/renderer/media/webrtc/rtc_video_encoder.cc
@@ -63,7 +63,7 @@
     return webrtc::kVideoCodecH264;
   }
   NOTREACHED() << "Invalid profile " << GetProfileName(profile);
-  return webrtc::kVideoCodecUnknown;
+  return webrtc::kVideoCodecGeneric;
 }
 
 // Populates struct webrtc::RTPFragmentationHeader for H264 codec.
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 3f35799..59e99c72 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -942,8 +942,9 @@
   Send(new ViewHostMsg_ForceRedrawComplete(routing_id(), snapshot_id));
 }
 
-viz::FrameSinkId RenderWidget::GetFrameSinkIdAtPoint(const gfx::Point& point) {
-  return input_handler_->GetFrameSinkIdAtPoint(point);
+viz::FrameSinkId RenderWidget::GetFrameSinkIdAtPoint(const gfx::Point& point,
+                                                     gfx::PointF* local_point) {
+  return input_handler_->GetFrameSinkIdAtPoint(point, local_point);
 }
 
 void RenderWidget::HandleInputEvent(
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index b1ff3bd8..4b3297ba 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -467,7 +467,8 @@
   // Requests a BeginMainFrame callback from the compositor.
   void SetNeedsMainFrame() override;
 
-  viz::FrameSinkId GetFrameSinkIdAtPoint(const gfx::Point& point);
+  viz::FrameSinkId GetFrameSinkIdAtPoint(const gfx::Point& point,
+                                         gfx::PointF* local_point);
 
   void HandleInputEvent(const blink::WebCoalescedInputEvent& input_event,
                         const ui::LatencyInfo& latency_info,
diff --git a/content/renderer/render_widget_browsertest.cc b/content/renderer/render_widget_browsertest.cc
index 56fcf0c..8082956 100644
--- a/content/renderer/render_widget_browsertest.cc
+++ b/content/renderer/render_widget_browsertest.cc
@@ -121,20 +121,23 @@
       "<iframe style='width: 200px; height: 100px;'"
       "srcdoc='<body style=\"margin: 0px; height: 100px; width: 200px;\">"
       "</body>'></iframe><div></body>");
+  gfx::PointF point;
   viz::FrameSinkId main_frame_sink_id =
-      widget()->GetFrameSinkIdAtPoint(gfx::Point(10, 10));
+      widget()->GetFrameSinkIdAtPoint(gfx::Point(10, 10), &point);
   EXPECT_EQ(static_cast<uint32_t>(widget()->routing_id()),
             main_frame_sink_id.sink_id());
   EXPECT_EQ(static_cast<uint32_t>(RenderThreadImpl::Get()->GetClientId()),
             main_frame_sink_id.client_id());
+  EXPECT_EQ(gfx::PointF(10, 10), point);
 
   // Targeting a child frame should also return the FrameSinkId for the main
   // widget.
   viz::FrameSinkId frame_sink_id =
-      widget()->GetFrameSinkIdAtPoint(gfx::Point(150, 150));
+      widget()->GetFrameSinkIdAtPoint(gfx::Point(150, 150), &point);
   EXPECT_EQ(static_cast<uint32_t>(widget()->routing_id()),
             frame_sink_id.sink_id());
   EXPECT_EQ(main_frame_sink_id.client_id(), frame_sink_id.client_id());
+  EXPECT_EQ(gfx::PointF(150, 150), point);
 }
 
 TEST_F(RenderWidgetTest, GetCompositionRangeValidComposition) {
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index a437bebd..67a5d18 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -65,6 +65,8 @@
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
 #include "third_party/blink/public/platform/interface_provider.h"
+#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
+#include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h"
 #include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_settled_fetch.h"
 #include "third_party/blink/public/platform/modules/notifications/web_notification_data.h"
 #include "third_party/blink/public/platform/modules/payments/web_payment_handler_response.h"
@@ -191,6 +193,17 @@
   return web_client_info;
 }
 
+// Converts a content::BackgroundFetchRegistration object to
+// a blink::WebBackgroundFetchRegistration object.
+blink::WebBackgroundFetchRegistration ToWebBackgroundFetchRegistration(
+    const BackgroundFetchRegistration& registration) {
+  return blink::WebBackgroundFetchRegistration(
+      blink::WebString::FromUTF8(registration.developer_id),
+      blink::WebString::FromUTF8(registration.unique_id),
+      registration.upload_total, registration.uploaded,
+      registration.download_total, registration.downloaded, registration.state);
+}
+
 // If |is_for_fetch_event| is true, some headers may be omitted according
 // to the embedder. It's always true now, but it might change with
 // more Onion Souping, and future callsites like Background Fetch probably don't
@@ -1594,9 +1607,7 @@
 }
 
 void ServiceWorkerContextClient::DispatchBackgroundFetchAbortEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     DispatchBackgroundFetchAbortEventCallback callback) {
   int request_id = context_->timeout_timer->StartEvent(
       CreateAbortCallback(&context_->background_fetch_abort_event_callbacks));
@@ -1610,14 +1621,11 @@
       TRACE_EVENT_FLAG_FLOW_OUT);
 
   proxy_->DispatchBackgroundFetchAbortEvent(
-      request_id, blink::WebString::FromUTF8(developer_id),
-      blink::WebString::FromUTF8(unique_id), state);
+      request_id, ToWebBackgroundFetchRegistration(registration));
 }
 
 void ServiceWorkerContextClient::DispatchBackgroundFetchClickEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     DispatchBackgroundFetchClickEventCallback callback) {
   int request_id = context_->timeout_timer->StartEvent(
       CreateAbortCallback(&context_->background_fetch_click_event_callbacks));
@@ -1631,14 +1639,11 @@
       TRACE_EVENT_FLAG_FLOW_OUT);
 
   proxy_->DispatchBackgroundFetchClickEvent(
-      request_id, blink::WebString::FromUTF8(developer_id),
-      blink::WebString::FromUTF8(unique_id), state);
+      request_id, ToWebBackgroundFetchRegistration(registration));
 }
 
 void ServiceWorkerContextClient::DispatchBackgroundFetchFailEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     DispatchBackgroundFetchFailEventCallback callback) {
   int request_id = context_->timeout_timer->StartEvent(
@@ -1661,14 +1666,11 @@
   }
 
   proxy_->DispatchBackgroundFetchFailEvent(
-      request_id, blink::WebString::FromUTF8(developer_id),
-      blink::WebString::FromUTF8(unique_id), state, web_fetches);
+      request_id, ToWebBackgroundFetchRegistration(registration), web_fetches);
 }
 
 void ServiceWorkerContextClient::DispatchBackgroundFetchSuccessEvent(
-    const std::string& developer_id,
-    const std::string& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const BackgroundFetchRegistration& registration,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     DispatchBackgroundFetchSuccessEventCallback callback) {
   int request_id = context_->timeout_timer->StartEvent(
@@ -1691,8 +1693,7 @@
   }
 
   proxy_->DispatchBackgroundFetchSuccessEvent(
-      request_id, blink::WebString::FromUTF8(developer_id),
-      blink::WebString::FromUTF8(unique_id), state, web_fetches);
+      request_id, ToWebBackgroundFetchRegistration(registration), web_fetches);
 }
 
 void ServiceWorkerContextClient::InitializeGlobalScope(
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 4d1688d9..fb9518d 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -284,25 +284,17 @@
       DispatchInstallEventCallback callback) override;
   void DispatchActivateEvent(DispatchActivateEventCallback callback) override;
   void DispatchBackgroundFetchAbortEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       DispatchBackgroundFetchAbortEventCallback callback) override;
   void DispatchBackgroundFetchClickEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       DispatchBackgroundFetchClickEventCallback callback) override;
   void DispatchBackgroundFetchFailEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       DispatchBackgroundFetchFailEventCallback callback) override;
   void DispatchBackgroundFetchSuccessEvent(
-      const std::string& developer_id,
-      const std::string& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const BackgroundFetchRegistration& registration,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       DispatchBackgroundFetchSuccessEventCallback callback) override;
   void DispatchExtendableMessageEvent(
diff --git a/content/renderer/service_worker/service_worker_context_client_unittest.cc b/content/renderer/service_worker/service_worker_context_client_unittest.cc
index 783f7f5..efd620e 100644
--- a/content/renderer/service_worker/service_worker_context_client_unittest.cc
+++ b/content/renderer/service_worker/service_worker_context_client_unittest.cc
@@ -83,32 +83,24 @@
   void DispatchActivateEvent(int event_id) override { NOTREACHED(); }
   void DispatchBackgroundFetchAbortEvent(
       int event_id,
-      const blink::WebString& developer_id,
-      const blink::WebString& unique_id,
-      blink::mojom::BackgroundFetchState state) override {
+      const blink::WebBackgroundFetchRegistration& registration) override {
     NOTREACHED();
   }
   void DispatchBackgroundFetchClickEvent(
       int event_id,
-      const blink::WebString& developer_id,
-      const blink::WebString& unique_id,
-      blink::mojom::BackgroundFetchState state) override {
+      const blink::WebBackgroundFetchRegistration& registration) override {
     NOTREACHED();
   }
   void DispatchBackgroundFetchFailEvent(
       int event_id,
-      const blink::WebString& developer_id,
-      const blink::WebString& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const blink::WebBackgroundFetchRegistration& registration,
       const blink::WebVector<blink::WebBackgroundFetchSettledFetch>& fetches)
       override {
     NOTREACHED();
   }
   void DispatchBackgroundFetchSuccessEvent(
       int event_id,
-      const blink::WebString& developer_id,
-      const blink::WebString& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const blink::WebBackgroundFetchRegistration& registration,
       const blink::WebVector<blink::WebBackgroundFetchSettledFetch>& fetches)
       override {
     NOTREACHED();
diff --git a/content/shell/browser/layout_test/blink_test_controller.cc b/content/shell/browser/layout_test/blink_test_controller.cc
index 3db1eb8..669d296 100644
--- a/content/shell/browser/layout_test/blink_test_controller.cc
+++ b/content/shell/browser/layout_test/blink_test_controller.cc
@@ -1261,8 +1261,7 @@
 
 mojom::LayoutTestControl* BlinkTestController::GetLayoutTestControlPtr(
     RenderFrameHost* frame) {
-  auto key = std::make_pair<int, int>(frame->GetProcess()->GetID(),
-                                      frame->GetRoutingID());
+  GlobalFrameRoutingId key(frame->GetProcess()->GetID(), frame->GetRoutingID());
   if (layout_test_control_map_.find(key) == layout_test_control_map_.end()) {
     mojom::LayoutTestControlAssociatedPtr& new_ptr =
         layout_test_control_map_[key];
@@ -1276,7 +1275,7 @@
 }
 
 void BlinkTestController::HandleLayoutTestControlError(
-    const std::pair<int, int>& key) {
+    const GlobalFrameRoutingId& key) {
   layout_test_control_map_.erase(key);
 }
 
diff --git a/content/shell/browser/layout_test/blink_test_controller.h b/content/shell/browser/layout_test/blink_test_controller.h
index be5df38..56f898b 100644
--- a/content/shell/browser/layout_test/blink_test_controller.h
+++ b/content/shell/browser/layout_test/blink_test_controller.h
@@ -11,6 +11,7 @@
 #include <set>
 #include <string>
 #include <utility>
+#include <vector>
 
 #include "base/cancelable_callback.h"
 #include "base/files/file_path.h"
@@ -22,6 +23,7 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "content/public/browser/bluetooth_chooser.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/gpu_data_manager_observer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -242,7 +244,7 @@
                                          const std::string& argument);
   void OnBlockThirdPartyCookies(bool block);
   mojom::LayoutTestControl* GetLayoutTestControlPtr(RenderFrameHost* frame);
-  void HandleLayoutTestControlError(const std::pair<int, int>& key);
+  void HandleLayoutTestControlError(const GlobalFrameRoutingId& key);
 
   void OnCleanupFinished();
   void OnCaptureDumpCompleted(mojom::LayoutTestDumpPtr dump);
@@ -328,11 +330,7 @@
   bool waiting_for_main_frame_dump_ = false;
 
   // Map from one frame to one mojo pipe.
-  //
-  // The key is a pair of (process id, frame routing id).
-  // TODO(lukasza): Use content::GlobalFrameRoutingID instead of std::pair<...>
-  // once it is exposed via content/public/browser API.
-  std::map<std::pair<int, int>, mojom::LayoutTestControlAssociatedPtr>
+  std::map<GlobalFrameRoutingId, mojom::LayoutTestControlAssociatedPtr>
       layout_test_control_map_;
 #if defined(OS_ANDROID)
   // Because of the nested message pump implementation, Android needs to allow
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 4aa72c2..1f4baf4 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
@@ -173,6 +173,14 @@
   std::move(callback).Run(gfx::Size(192, 192));
 }
 
+void LayoutTestBackgroundFetchDelegate::GetPermissionForOrigin(
+    const url::Origin& origin,
+    const ResourceRequestInfo::WebContentsGetter& wc_getter,
+    GetPermissionForOriginCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  std::move(callback).Run(true /* has_permission */);
+}
+
 void LayoutTestBackgroundFetchDelegate::CreateDownloadJob(
     std::unique_ptr<BackgroundFetchDescription> fetch_description) {}
 
diff --git a/content/shell/browser/layout_test/layout_test_background_fetch_delegate.h b/content/shell/browser/layout_test/layout_test_background_fetch_delegate.h
index a960a7f..6ed853f 100644
--- a/content/shell/browser/layout_test/layout_test_background_fetch_delegate.h
+++ b/content/shell/browser/layout_test/layout_test_background_fetch_delegate.h
@@ -27,6 +27,10 @@
 
   // BackgroundFetchDelegate implementation:
   void GetIconDisplaySize(GetIconDisplaySizeCallback callback) override;
+  void GetPermissionForOrigin(
+      const url::Origin& origin,
+      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      GetPermissionForOriginCallback callback) override;
   void CreateDownloadJob(
       std::unique_ptr<BackgroundFetchDescription> fetch_description) override;
   void DownloadUrl(const std::string& job_unique_id,
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc
index 3639a77..b02e0a5 100644
--- a/content/test/content_browser_test_utils_internal.cc
+++ b/content/test/content_browser_test_utils_internal.cc
@@ -456,4 +456,13 @@
   message_loop_runner_->Quit();
 }
 
+SwapoutACKMessageFilter::SwapoutACKMessageFilter()
+    : BrowserMessageFilter(FrameMsgStart) {}
+
+SwapoutACKMessageFilter::~SwapoutACKMessageFilter() {}
+
+bool SwapoutACKMessageFilter::OnMessageReceived(const IPC::Message& message) {
+  return message.type() == FrameHostMsg_SwapOut_ACK::ID;
+}
+
 }  // namespace content
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h
index 7834ba1..e6fe4c0 100644
--- a/content/test/content_browser_test_utils_internal.h
+++ b/content/test/content_browser_test_utils_internal.h
@@ -252,6 +252,20 @@
   DISALLOW_COPY_AND_ASSIGN(ShowWidgetMessageFilter);
 };
 
+// A BrowserMessageFilter that drops SwapOut ACK messages.
+class SwapoutACKMessageFilter : public BrowserMessageFilter {
+ public:
+  SwapoutACKMessageFilter();
+
+ protected:
+  ~SwapoutACKMessageFilter() override;
+
+ private:
+  // BrowserMessageFilter:
+  bool OnMessageReceived(const IPC::Message& message) override;
+  DISALLOW_COPY_AND_ASSIGN(SwapoutACKMessageFilter);
+};
+
 }  // namespace content
 
 #endif  // CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_
diff --git a/content/test/data/frame_tree/page_with_perspective_transformed_frame.html b/content/test/data/frame_tree/page_with_perspective_transformed_frame.html
new file mode 100644
index 0000000..1866a1d
--- /dev/null
+++ b/content/test/data/frame_tree/page_with_perspective_transformed_frame.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<style>
+iframe {
+  position:absolute;
+  top: 50px;
+  left: 50px;
+  width: 100px;
+  height: 100px;
+  transform: perspective(50em) rotateY(45deg);
+}
+
+</style>
+<html>
+<body>
+<iframe src="/cross-site/baz.com/title1.html"></iframe>
+This page contains a cross-origin iframe with 45 degree perspective.
+</body>
+</html>
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index ff1e41c..91c4afb 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -34,6 +34,9 @@
     # The multiview extension is only expected to be supported through ANGLE.
     self.Skip('WebglExtension_WEBGL_multiview',
         ['win', 'no_passthrough'], bug=864524)
+    # # ANGLE's OpenGL backend supports multiview only on NVIDIA.
+    self.Skip('WebglExtension_WEBGL_multiview',
+        ['win', 'passthrough', 'opengl', 'intel'], bug=864524)
     self.Skip('WebglExtension_EXT_disjoint_timer_query_webgl2',
         ['android'], bug=808744)
     self.Fail('WebglExtension_EXT_disjoint_timer_query_webgl2',
@@ -403,6 +406,27 @@
     self.Fail('conformance/renderbuffers/framebuffer-state-restoration.html',
         ['passthrough', 'opengl', 'intel'], bug=602688)
 
+    # Passthrough command decoder / Windows / OpenGL / Intel
+    self.Fail('conformance2/textures/misc/copy-texture-image-same-texture.html',
+        ['win', 'passthrough', 'opengl', 'intel'], bug=809594)
+    self.Fail('conformance2/renderbuffers/' +
+        'multisampled-depth-renderbuffer-initialization.html',
+        ['win', 'passthrough', 'opengl', 'intel'], bug=2760) # ANGLE bug
+    self.Fail('conformance/uniforms/' +
+        'no-over-optimization-on-uniform-array-16.html',
+        ['win', 'passthrough', 'opengl', 'intel'], bug=602688)
+    self.Fail('conformance/glsl/constructors/glsl-construct-mat2.html',
+        ['win', 'passthrough', 'opengl', 'intel'], bug=602688)
+    self.Fail('conformance2/textures/misc/texture-npot.html',
+        ['win', 'passthrough', 'opengl', 'intel'], bug=602688)
+    self.Fail('conformance2/textures/misc/npot-video-sizing.html',
+        ['win', 'passthrough', 'opengl', 'intel'], bug=602688)
+    self.Fail('conformance2/glsl3/' +
+        'vector-dynamic-indexing-swizzled-lvalue.html',
+        ['win', 'passthrough', 'opengl', 'intel'], bug=602688)
+    self.Fail('conformance2/glsl3/vector-dynamic-indexing.html',
+        ['win', 'passthrough', 'opengl', 'intel'], bug=602688)
+
     # Passthrough command decoder / Linux / OpenGL / NVIDIA
     self.Fail('conformance/textures/image_bitmap_from_video/' +
         'tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html',
@@ -968,9 +992,6 @@
         ['linux', ('nvidia', 0x1cb3), 'opengl'], bug=703779)
 
     # Linux Intel
-    self.Fail('conformance2/extensions/ext-color-buffer-float.html',
-        ['linux', 'intel'], bug=640389)
-
     # See https://bugs.freedesktop.org/show_bug.cgi?id=94477
     self.Skip('conformance/glsl/bugs/temp-expressions-should-not-crash.html',
         ['linux', 'intel'], bug=540543)  # GPU timeout
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index 92260a4..6511a0a 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -368,7 +368,7 @@
 void TestWebContents::AddPendingContents(
     std::unique_ptr<WebContents> contents) {
   // This is normally only done in WebContentsImpl::CreateNewWindow.
-  ProcessRoutingIdPair key(
+  GlobalRoutingID key(
       contents->GetRenderViewHost()->GetProcess()->GetID(),
       contents->GetRenderViewHost()->GetWidget()->GetRoutingID());
   WebContentsImpl* raw_contents = static_cast<WebContentsImpl*>(contents.get());
diff --git a/content/test/web_contents_observer_sanity_checker.h b/content/test/web_contents_observer_sanity_checker.h
index e9794e0d3..942396e2 100644
--- a/content/test/web_contents_observer_sanity_checker.h
+++ b/content/test/web_contents_observer_sanity_checker.h
@@ -5,12 +5,14 @@
 #ifndef CONTENT_TEST_WEB_CONTENTS_OBSERVER_SANITY_CHECKER_H_
 #define CONTENT_TEST_WEB_CONTENTS_OBSERVER_SANITY_CHECKER_H_
 
+#include <map>
 #include <set>
 #include <string>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/supports_user_data.h"
-#include "content/browser/loader/global_routing_id.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/web_contents_observer.h"
 
 namespace content {
diff --git a/docs/chromedriver_status.md b/docs/chromedriver_status.md
index dbfc1874..349568662 100644
--- a/docs/chromedriver_status.md
+++ b/docs/chromedriver_status.md
@@ -2,9 +2,12 @@
 
 Below is a list of all WebDriver commands and their current support in ChromeDriver based on what is in the [WebDriver Specification](https://w3c.github.io/webdriver/webdriver-spec.html).
 
+Notes:
+ - Currently some error strings returned by ChromeDriver are incorrect. This is tracked by bug [2552](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2552).
+
 | Method | URL | Command | Status | Bug
 | --- | --- | --- | --- | --- |
-| POST   | /session                                                       | New Session                | Partially Complete | [1997](https://bugs.chromium.org/p/chromedriver/issues/detail?id=1997)
+| POST   | /session                                                       | New Session                | Partially Complete | [1997](https://bugs.chromium.org/p/chromedriver/issues/detail?id=1997) [2537](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2537)
 | DELETE | /session/{session id}                                          | Delete Status              | Complete           |
 | GET    | /status                                                        | Status                     | Complete           |
 | GET    | /session/{session id}/timeouts                                 | Get Timeouts               | Complete           |
@@ -16,7 +19,7 @@
 | POST   | /session/{session id}/refresh                                  | Refresh                    | Partially Complete | [1988](https://bugs.chromium.org/p/chromedriver/issues/detail?id=1988)
 | GET    | /session/{session id}/title                                    | Get Title                  | Complete           |
 | GET    | /session/{session id}/window                                   | Get Window Handle          | Complete           |
-| DELETE | /session/{session id}/window                                   | Close Window               | Partially Complete | [1990](https://bugs.chromium.org/p/chromedriver/issues/detail?id=1990)
+| DELETE | /session/{session id}/window                                   | Close Window               | Complete           |
 | POST   | /session/{session id}/window                                   | Switch To Window           | Complete           |
 | GET    | /session/{session id}/window/handles                           | Get Window Handles         | Complete           |
 | POST   | /session/{session id}/frame                                    | Switch To Frame            | Partially Complete | [1992](https://bugs.chromium.org/p/chromedriver/issues/detail?id=1992)
@@ -43,8 +46,8 @@
 | POST   | /session/{session id}/element/{element id}/clear               | Element Clear              | Partially Complete | [1998](https://bugs.chromium.org/p/chromedriver/issues/detail?id=1998)
 | POST   | /session/{session id}/element/{element id}/value               | Element Send Keys          | Partially Complete | [1999](https://bugs.chromium.org/p/chromedriver/issues/detail?id=1999)
 | GET    | /session/{session id}/source                                   | Get Page Source            |                    |
-| POST   | /session/{session id}/execute/sync                             | Execute Script             | Partially Complete | [2000](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2000)
-| POST   | /session/{session id}/execute/async                            | Execute Async Script       | Partially Complete | [2001](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2001)
+| POST   | /session/{session id}/execute/sync                             | Execute Script             | Partially Complete | [2000](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2000) [2398](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2398) [2556](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2556)
+| POST   | /session/{session id}/execute/async                            | Execute Async Script       | Partially Complete | [2001](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2001) [2398](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2398) [2556](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2556)
 | GET    | /session/{session id}/cookie                                   | Get All Cookies            | Complete           |
 | GET    | /session/{session id}/cookie/{name}                            | Get Named Cookie           | Complete           |
 | POST   | /session/{session id}/cookie                                   | Add Cookie                 | Partially Complete | [2002](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2002)
@@ -52,8 +55,8 @@
 | DELETE | /session/{session id)/cookie                                   | Delete All Cookies         | Complete           |
 | POST   | /session/{session id}/actions                                  | Perform Actions            | Incomplete         | [1897](https://bugs.chromium.org/p/chromedriver/issues/detail?id=1897)
 | DELETE | /session/{session id}/actions                                  | Release Actions            | Incomplete         | [1897](https://bugs.chromium.org/p/chromedriver/issues/detail?id=1897)
-| POST   | /session/{session id}/alert/dismiss                            | Dismiss Alert              | Partially Complete | [1500](https://bugs.chromium.org/p/chromedriver/issues/detail?id=1500)
-| POST   | /session/{session id}/alert/accept                             | Accept Alert               | Partially Complete | [1500](https://bugs.chromium.org/p/chromedriver/issues/detail?id=1500)
+| POST   | /session/{session id}/alert/dismiss                            | Dismiss Alert              | Complete           |
+| POST   | /session/{session id}/alert/accept                             | Accept Alert               | Complete           |
 | GET    | /session/{session id}/alert/text                               | Get Alert Text             | Complete           |
 | POST   | /session/{session id}/alert/text                               | Send Alert Text            | Partially Complete | [2003](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2003)
 | GET    | /session/{session id}/screenshot                               | Take Screenshot            |                    |
diff --git a/extensions/browser/api/declarative_net_request/rules_monitor_service.cc b/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
index 6d2148ef..81304f8 100644
--- a/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
+++ b/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
@@ -104,6 +104,11 @@
   int expected_ruleset_checksum;
   URLPatternSet allowed_pages;
 
+  // True in case the checksum of the indexed ruleset changed. If true,
+  // |expected_ruleset_checksum| contains the updated checksum. This can only
+  // happen in case of an incorrect indexed ruleset format version.
+  bool checksum_updated_due_to_version_mismatch = false;
+
   DISALLOW_COPY_AND_ASSIGN(LoadRulesetInfo);
 };
 
@@ -179,23 +184,34 @@
     // be called on this sequence itself.
     IndexAndPersistRulesCallback ruleset_reindexed_callback = base::BindOnce(
         &FileSequenceState::OnRulesetReindexed, weak_factory_.GetWeakPtr(),
-        std::move(info), std::move(ui_callback));
+        std::move(info), result, std::move(ui_callback));
     IndexAndPersistRules(connector_.get(), nullptr /*identity*/, *extension,
                          std::move(ruleset_reindexed_callback));
   }
 
   // Callback invoked when the JSON ruleset is reindexed.
-  void OnRulesetReindexed(LoadRulesetInfo info,
-                          LoadRulesetUICallback ui_callback,
-                          IndexAndPersistRulesResult result) const {
+  void OnRulesetReindexed(
+      LoadRulesetInfo info,
+      RulesetMatcher::LoadRulesetResult initial_failure_reason,
+      LoadRulesetUICallback ui_callback,
+      IndexAndPersistRulesResult result) const {
     DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence());
 
+    // In case of updates to the ruleset version, the ruleset checksum can
+    // change.
+    if (result.success &&
+        initial_failure_reason ==
+            RulesetMatcher::LoadRulesetResult::kLoadErrorVersionMismatch) {
+      info.expected_ruleset_checksum = result.ruleset_checksum;
+      info.checksum_updated_due_to_version_mismatch = true;
+    }
+
     // The checksum of the reindexed ruleset should have been the same as the
-    // expected checksum obtained from prefs. If this is not the case, then
-    // there is some other issue (like the JSON rules file has been modified
-    // from the one used during installation or preferences are corrupted). But
-    // taking care of these is beyond our scope here, so simply signal a
-    // failure.
+    // expected checksum obtained from prefs, in all cases except when the
+    // ruleset version changes. If this is not the case, then there is some
+    // other issue (like the JSON rules file has been modified from the one used
+    // during installation or preferences are corrupted). But taking care of
+    // these is beyond our scope here, so simply signal a failure.
     bool reindexing_success =
         result.success &&
         info.expected_ruleset_checksum == result.ruleset_checksum;
@@ -325,6 +341,12 @@
 void RulesMonitorService::OnRulesetLoaded(
     LoadRulesetInfo info,
     std::unique_ptr<RulesetMatcher> matcher) {
+  // Update the ruleset checksum if needed.
+  if (info.checksum_updated_due_to_version_mismatch) {
+    prefs_->SetDNRRulesetChecksum(info.extension->id(),
+                                  info.expected_ruleset_checksum);
+  }
+
   if (!matcher) {
     // The ruleset failed to load. Notify the user.
     warning_service_->AddWarnings(
diff --git a/extensions/browser/api/declarative_net_request/rules_monitor_service.h b/extensions/browser/api/declarative_net_request/rules_monitor_service.h
index 5d018f1d..76196378 100644
--- a/extensions/browser/api/declarative_net_request/rules_monitor_service.h
+++ b/extensions/browser/api/declarative_net_request/rules_monitor_service.h
@@ -98,7 +98,7 @@
 
   // Guaranteed to be valid through-out the lifetime of this instance.
   InfoMap* const info_map_;
-  const ExtensionPrefs* const prefs_;
+  ExtensionPrefs* const prefs_;
   ExtensionRegistry* const extension_registry_;
   WarningService* const warning_service_;
 
diff --git a/extensions/browser/api/declarative_net_request/ruleset_matcher.cc b/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
index 414fe13..bab9700 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
@@ -47,6 +47,9 @@
   if (!base::ReadFileToString(indexed_ruleset_path, &ruleset_data))
     return kLoadErrorFileRead;
 
+  if (!StripVersionHeaderAndParseVersion(&ruleset_data))
+    return kLoadErrorVersionMismatch;
+
   // This guarantees that no memory access will end up outside the buffer.
   if (!IsValidRulesetData(
           base::make_span(reinterpret_cast<const uint8_t*>(ruleset_data.data()),
diff --git a/extensions/browser/api/declarative_net_request/ruleset_matcher.h b/extensions/browser/api/declarative_net_request/ruleset_matcher.h
index 9e3561a..e3b4838 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_matcher.h
+++ b/extensions/browser/api/declarative_net_request/ruleset_matcher.h
@@ -39,10 +39,22 @@
   // This is logged as part of UMA. Hence existing values should not be re-
   // numbered or deleted. New values should be added before kLoadRulesetMax.
   enum LoadRulesetResult {
+    // Ruleset loading succeeded.
     kLoadSuccess = 0,
+
+    // Ruleset loading failed since the provided path did not exist.
     kLoadErrorInvalidPath = 1,
+
+    // Ruleset loading failed due to a file read error.
     kLoadErrorFileRead = 2,
+
+    // Ruleset loading failed due to a checksum mismatch.
+    // TODO(karandeepb): Rename this to kLoadErrorChecksumMismatch.
     kLoadErrorRulesetVerification = 3,
+
+    // Ruleset loading failed due to version header mismatch.
+    kLoadErrorVersionMismatch = 4,
+
     kLoadResultMax
   };
 
diff --git a/extensions/browser/api/declarative_net_request/utils.cc b/extensions/browser/api/declarative_net_request/utils.cc
index 753b23b..fb838b3f 100644
--- a/extensions/browser/api/declarative_net_request/utils.cc
+++ b/extensions/browser/api/declarative_net_request/utils.cc
@@ -10,11 +10,13 @@
 
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/hash.h"
 #include "base/json/json_file_value_serializer.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/timer/elapsed_timer.h"
 #include "base/values.h"
@@ -39,7 +41,36 @@
 
 namespace dnr_api = extensions::api::declarative_net_request;
 
-// Returns the checksum of the given serialized |data|.
+// The ruleset format version of the flatbuffer schema. Increment this whenever
+// making an incompatible change to the schema at extension_ruleset.fbs or
+// url_pattern_index.fbs. Whenever an extension with an indexed ruleset format
+// version different from the one currently used by Chrome is loaded, the
+// extension ruleset will be reindexed.
+// TODO(crbug.com/755717): Add checks to ensure that we increment this when
+// necessary.
+constexpr int kIndexedRulesetFormatVersion = 1;
+
+constexpr int kInvalidIndexedRulesetFormatVersion = -1;
+
+int g_indexed_ruleset_format_version_for_testing =
+    kInvalidIndexedRulesetFormatVersion;
+
+int GetIndexedRulesetFormatVersion() {
+  return g_indexed_ruleset_format_version_for_testing ==
+                 kInvalidIndexedRulesetFormatVersion
+             ? kIndexedRulesetFormatVersion
+             : g_indexed_ruleset_format_version_for_testing;
+}
+
+// Returns the header to be used for indexed rulesets. This depends on the
+// current ruleset format version.
+std::string GetVersionHeader() {
+  return base::StringPrintf("---------Version=%d",
+                            GetIndexedRulesetFormatVersion());
+}
+
+// Returns the checksum of the given serialized |data|. |data| must not include
+// the version header.
 int GetChecksum(base::span<const uint8_t> data) {
   uint32_t hash = base::PersistentHash(data.data(), data.size());
 
@@ -48,7 +79,10 @@
   return static_cast<int>(hash & 0x7fffffff);
 }
 
-// Helper function to persist the indexed ruleset |data| for |extension|.
+// Helper function to persist the indexed ruleset |data| for |extension|. The
+// ruleset is composed of a version header corresponding to the current ruleset
+// format version, followed by the actual ruleset data. Note: The checksum only
+// corresponds to this ruleset data and does not include the version header.
 bool PersistRuleset(const Extension& extension,
                     base::span<const uint8_t> data,
                     int* ruleset_checksum) {
@@ -57,20 +91,34 @@
   const base::FilePath path =
       file_util::GetIndexedRulesetPath(extension.path());
 
-  // Create the directory corresponding to |path| if it does not exist and then
-  // persist the ruleset.
+  // Create the directory corresponding to |path| if it does not exist.
+  if (!base::CreateDirectory(path.DirName()))
+    return false;
+
+  base::File ruleset_file(
+      path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+  if (!ruleset_file.IsValid())
+    return false;
+
+  // Write the version header.
+  std::string version_header = GetVersionHeader();
+  int version_header_size = static_cast<int>(version_header.size());
+  if (ruleset_file.WriteAtCurrentPos(
+          version_header.data(), version_header_size) != version_header_size) {
+    return false;
+  }
+
+  // Write the flatbuffer ruleset.
   if (!base::IsValueInRangeForNumericType<int>(data.size()))
     return false;
-  const int data_size = static_cast<int>(data.size());
-  const bool success =
-      base::CreateDirectory(path.DirName()) &&
-      base::WriteFile(path, reinterpret_cast<const char*>(data.data()),
-                      data_size) == data_size;
+  int data_size = static_cast<int>(data.size());
+  if (ruleset_file.WriteAtCurrentPos(reinterpret_cast<const char*>(data.data()),
+                                     data_size) != data_size) {
+    return false;
+  }
 
-  if (success)
-    *ruleset_checksum = GetChecksum(data);
-
-  return success;
+  *ruleset_checksum = GetChecksum(data);
+  return true;
 }
 
 // Helper to retrieve the ruleset ExtensionResource for |extension|.
@@ -274,5 +322,28 @@
          flat::VerifyExtensionIndexedRulesetBuffer(verifier);
 }
 
+std::string GetVersionHeaderForTesting() {
+  return GetVersionHeader();
+}
+
+void SetIndexedRulesetFormatVersionForTesting(int version) {
+  DCHECK_NE(kInvalidIndexedRulesetFormatVersion, version);
+  g_indexed_ruleset_format_version_for_testing = version;
+}
+
+bool StripVersionHeaderAndParseVersion(std::string* ruleset_data) {
+  DCHECK(ruleset_data);
+  const std::string version_header = GetVersionHeader();
+
+  if (!base::StartsWith(*ruleset_data, version_header,
+                        base::CompareCase::SENSITIVE)) {
+    return false;
+  }
+
+  // Strip the header from |ruleset_data|.
+  ruleset_data->erase(0, version_header.size());
+  return true;
+}
+
 }  // namespace declarative_net_request
 }  // namespace extensions
diff --git a/extensions/browser/api/declarative_net_request/utils.h b/extensions/browser/api/declarative_net_request/utils.h
index 629d038..1a7650f 100644
--- a/extensions/browser/api/declarative_net_request/utils.h
+++ b/extensions/browser/api/declarative_net_request/utils.h
@@ -81,6 +81,17 @@
 // ruleset data with |expected_checksum|.
 bool IsValidRulesetData(base::span<const uint8_t> data, int expected_checksum);
 
+// Returns the version header used for indexed ruleset files. Only exposed for
+// testing.
+std::string GetVersionHeaderForTesting();
+
+// Override the ruleset format version for testing.
+void SetIndexedRulesetFormatVersionForTesting(int version);
+
+// Strips the version header from |ruleset_data|. Returns false on version
+// mismatch.
+bool StripVersionHeaderAndParseVersion(std::string* ruleset_data);
+
 }  // namespace declarative_net_request
 }  // namespace extensions
 
diff --git a/extensions/browser/app_window/app_web_contents_helper.cc b/extensions/browser/app_window/app_web_contents_helper.cc
index 21d676e9..158d1a2 100644
--- a/extensions/browser/app_window/app_web_contents_helper.cc
+++ b/extensions/browser/app_window/app_web_contents_helper.cc
@@ -32,8 +32,18 @@
 // static
 bool AppWebContentsHelper::ShouldSuppressGestureEvent(
     const blink::WebGestureEvent& event) {
+  // Disable "smart zoom" (double-tap with two fingers on Mac trackpad).
+  if (event.GetType() == blink::WebInputEvent::kGestureDoubleTap)
+    return true;
+
   // Disable pinch zooming in app windows.
-  return blink::WebInputEvent::IsPinchGestureEventType(event.GetType());
+  if (blink::WebInputEvent::IsPinchGestureEventType(event.GetType())) {
+    // Only suppress pinch events that cause a scale change. We still
+    // allow synthetic wheel events for touchpad pinch to go to the page.
+    return !event.NeedsWheelEvent();
+  }
+
+  return false;
 }
 
 content::WebContents* AppWebContentsHelper::OpenURLFromTab(
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index 42fec16..e6d8dd4 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -1740,9 +1740,8 @@
                            dnr_ruleset_checksum);
 }
 
-void ExtensionPrefs::SetDNRRulesetChecksumForTesting(
-    const ExtensionId& extension_id,
-    int dnr_ruleset_checksum) {
+void ExtensionPrefs::SetDNRRulesetChecksum(const ExtensionId& extension_id,
+                                           int dnr_ruleset_checksum) {
   UpdateExtensionPref(extension_id, kPrefDNRRulesetChecksum,
                       std::make_unique<base::Value>(dnr_ruleset_checksum));
 }
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h
index e55793d..9fbdcea 100644
--- a/extensions/browser/extension_prefs.h
+++ b/extensions/browser/extension_prefs.h
@@ -573,8 +573,8 @@
   // |dnr_ruleset_checksum|.
   bool GetDNRRulesetChecksum(const ExtensionId& extension_id,
                              int* dnr_ruleset_checksum) const;
-  void SetDNRRulesetChecksumForTesting(const ExtensionId& extension_id,
-                                       int dnr_ruleset_checksum);
+  void SetDNRRulesetChecksum(const ExtensionId& extension_id,
+                             int dnr_ruleset_checksum);
 
   // Sets the set of allowed pages for the given |extension_id|.
   void SetDNRAllowedPages(const ExtensionId& extension_id, URLPatternSet set);
diff --git a/extensions/browser/guest_view/web_view/web_view_renderer_state.cc b/extensions/browser/guest_view/web_view/web_view_renderer_state.cc
index c95fac9..e6a6e6b 100644
--- a/extensions/browser/guest_view/web_view/web_view_renderer_state.cc
+++ b/extensions/browser/guest_view/web_view/web_view_renderer_state.cc
@@ -95,7 +95,7 @@
   // TODO(fsamuel): Store per-process info in WebViewPartitionInfo instead of in
   // WebViewInfo.
   for (const auto& info : web_view_info_map_) {
-    if (info.first.first == guest_process_id) {
+    if (info.first.child_id == guest_process_id) {
       if (owner_process_id)
         *owner_process_id = info.second.embedder_process_id;
       if (owner_host)
diff --git a/extensions/browser/guest_view/web_view/web_view_renderer_state.h b/extensions/browser/guest_view/web_view/web_view_renderer_state.h
index c1c9242..28f4031 100644
--- a/extensions/browser/guest_view/web_view/web_view_renderer_state.h
+++ b/extensions/browser/guest_view/web_view/web_view_renderer_state.h
@@ -20,6 +20,7 @@
 
 #include "base/macros.h"
 #include "base/memory/singleton.h"
+#include "content/public/browser/global_routing_id.h"
 
 namespace extensions {
 
@@ -76,7 +77,7 @@
   friend class WebViewGuest;
   friend struct base::DefaultSingletonTraits<WebViewRendererState>;
 
-  using RenderId = std::pair<int, int>;
+  using RenderId = content::GlobalRoutingID;
   using WebViewInfoMap = std::map<RenderId, WebViewInfo>;
 
   struct WebViewPartitionInfo {
diff --git a/extensions/renderer/bindings/api_binding_test.cc b/extensions/renderer/bindings/api_binding_test.cc
index 38f0ec4..fb6d022 100644
--- a/extensions/renderer/bindings/api_binding_test.cc
+++ b/extensions/renderer/bindings/api_binding_test.cc
@@ -33,8 +33,9 @@
                                  gin::IsolateHolder::kStableV8Extras,
                                  gin::ArrayBufferAllocator::SharedInstance());
 
-  isolate_holder_ =
-      std::make_unique<gin::IsolateHolder>(base::ThreadTaskRunnerHandle::Get());
+  isolate_holder_ = std::make_unique<gin::IsolateHolder>(
+      base::ThreadTaskRunnerHandle::Get(),
+      gin::IsolateHolder::IsolateType::kTest);
   isolate()->Enter();
 
   v8::HandleScope handle_scope(isolate());
diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc
index e3a23cf3..4491b39 100644
--- a/gin/isolate_holder.cc
+++ b/gin/isolate_holder.cc
@@ -31,23 +31,29 @@
 }  // namespace
 
 IsolateHolder::IsolateHolder(
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-    : IsolateHolder(std::move(task_runner), AccessMode::kSingleThread) {}
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    IsolateType isolate_type)
+    : IsolateHolder(std::move(task_runner),
+                    AccessMode::kSingleThread,
+                    isolate_type) {}
 
 IsolateHolder::IsolateHolder(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    AccessMode access_mode)
+    AccessMode access_mode,
+    IsolateType isolate_type)
     : IsolateHolder(std::move(task_runner),
                     access_mode,
                     kAllowAtomicsWait,
+                    isolate_type,
                     IsolateCreationMode::kNormal) {}
 
 IsolateHolder::IsolateHolder(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     AccessMode access_mode,
     AllowAtomicsWaitMode atomics_wait_mode,
+    IsolateType isolate_type,
     IsolateCreationMode isolate_creation_mode)
-    : access_mode_(access_mode) {
+    : access_mode_(access_mode), isolate_type_(isolate_type) {
   DCHECK(task_runner);
   DCHECK(task_runner->BelongsToCurrentThread());
 
diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h
index a70ad1ce5..6945a601 100644
--- a/gin/public/isolate_holder.h
+++ b/gin/public/isolate_holder.h
@@ -58,14 +58,28 @@
     kCreateSnapshot,
   };
 
-  explicit IsolateHolder(
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+  // Isolate type used for UMA/UKM reporting:
+  // - kBlinkMainThread: the main isolate of Blink.
+  // - kBlinkWorkerThread: the isolate of a Blink worker.
+  // - kTest: used only in tests.
+  // - kUtility: the isolate of PDFium and ProxyResolver.
+  enum class IsolateType {
+    kBlinkMainThread,
+    kBlinkWorkerThread,
+    kTest,
+    kUtility
+  };
+
   IsolateHolder(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-                AccessMode access_mode);
+                IsolateType isolate_type);
+  IsolateHolder(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+                AccessMode access_mode,
+                IsolateType isolate_type);
   IsolateHolder(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
       AccessMode access_mode,
       AllowAtomicsWaitMode atomics_wait_mode,
+      IsolateType isolate_type,
       IsolateCreationMode isolate_creation_mode = IsolateCreationMode::kNormal);
   ~IsolateHolder();
 
@@ -90,6 +104,8 @@
   // This method returns if v8::Locker is needed to access isolate.
   AccessMode access_mode() const { return access_mode_; }
 
+  IsolateType isolate_type() const { return isolate_type_; }
+
   v8::SnapshotCreator* snapshot_creator() const {
     return snapshot_creator_.get();
   }
@@ -111,6 +127,7 @@
   std::unique_ptr<PerIsolateData> isolate_data_;
   std::unique_ptr<V8IsolateMemoryDumpProvider> isolate_memory_dump_provider_;
   AccessMode access_mode_;
+  IsolateType isolate_type_;
 
   DISALLOW_COPY_AND_ASSIGN(IsolateHolder);
 };
diff --git a/gin/shell/gin_main.cc b/gin/shell/gin_main.cc
index 304c9da..eb0c686 100644
--- a/gin/shell/gin_main.cc
+++ b/gin/shell/gin_main.cc
@@ -84,7 +84,9 @@
     gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
                                    gin::IsolateHolder::kStableV8Extras,
                                    gin::ArrayBufferAllocator::SharedInstance());
-    gin::IsolateHolder instance(base::ThreadTaskRunnerHandle::Get());
+    gin::IsolateHolder instance(
+        base::ThreadTaskRunnerHandle::Get(),
+        gin::IsolateHolder::IsolateType::kBlinkMainThread);
 
     gin::GinShellRunnerDelegate delegate;
     gin::ShellRunner runner(&delegate, instance.isolate());
diff --git a/gin/shell_runner_unittest.cc b/gin/shell_runner_unittest.cc
index 02e6835..1a5ad6b 100644
--- a/gin/shell_runner_unittest.cc
+++ b/gin/shell_runner_unittest.cc
@@ -36,7 +36,8 @@
   gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
                                  gin::IsolateHolder::kStableV8Extras,
                                  gin::ArrayBufferAllocator::SharedInstance());
-  gin::IsolateHolder instance(base::ThreadTaskRunnerHandle::Get());
+  gin::IsolateHolder instance(base::ThreadTaskRunnerHandle::Get(),
+                              gin::IsolateHolder::IsolateType::kTest);
 
   ShellRunnerDelegate delegate;
   Isolate* isolate = instance.isolate();
diff --git a/gin/test/v8_test.cc b/gin/test/v8_test.cc
index 88009dd..4a68091 100644
--- a/gin/test/v8_test.cc
+++ b/gin/test/v8_test.cc
@@ -28,7 +28,9 @@
                                  gin::IsolateHolder::kStableV8Extras,
                                  gin::ArrayBufferAllocator::SharedInstance());
 
-  instance_.reset(new gin::IsolateHolder(base::ThreadTaskRunnerHandle::Get()));
+  instance_.reset(new gin::IsolateHolder(
+      base::ThreadTaskRunnerHandle::Get(),
+      gin::IsolateHolder::IsolateType::kBlinkMainThread));
   instance_->isolate()->Enter();
   HandleScope handle_scope(instance_->isolate());
   context_.Reset(instance_->isolate(), Context::New(instance_->isolate()));
diff --git a/headless/lib/browser/headless_browser_context_impl.cc b/headless/lib/browser/headless_browser_context_impl.cc
index 565a640..0e59b9c 100644
--- a/headless/lib/browser/headless_browser_context_impl.cc
+++ b/headless/lib/browser/headless_browser_context_impl.cc
@@ -151,7 +151,7 @@
     const base::UnguessableToken& devtools_frame_token,
     int frame_tree_node_id) {
   base::AutoLock lock(devtools_frame_token_map_lock_);
-  devtools_frame_token_map_[std::make_pair(
+  devtools_frame_token_map_[content::GlobalFrameRoutingId(
       render_process_id, render_frame_routing_id)] = devtools_frame_token;
   frame_tree_node_id_to_devtools_frame_token_map_[frame_tree_node_id] =
       devtools_frame_token;
@@ -162,8 +162,8 @@
     int render_frame_routing_id,
     int frame_tree_node_id) {
   base::AutoLock lock(devtools_frame_token_map_lock_);
-  devtools_frame_token_map_.erase(
-      std::make_pair(render_process_id, render_frame_routing_id));
+  devtools_frame_token_map_.erase(content::GlobalFrameRoutingId(
+      render_process_id, render_frame_routing_id));
   frame_tree_node_id_to_devtools_frame_token_map_.erase(frame_tree_node_id);
 }
 
@@ -172,7 +172,7 @@
     int render_frame_id) const {
   base::AutoLock lock(devtools_frame_token_map_lock_);
   const auto& find_it = devtools_frame_token_map_.find(
-      std::make_pair(render_process_id, render_frame_id));
+      content::GlobalFrameRoutingId(render_process_id, render_frame_id));
   if (find_it == devtools_frame_token_map_.end())
     return nullptr;
   return &find_it->second;
diff --git a/headless/lib/browser/headless_browser_context_impl.h b/headless/lib/browser/headless_browser_context_impl.h
index b4b2f1a5..d192b10 100644
--- a/headless/lib/browser/headless_browser_context_impl.h
+++ b/headless/lib/browser/headless_browser_context_impl.h
@@ -13,6 +13,7 @@
 #include "base/files/file_path.h"
 #include "base/unguessable_token.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/resource_context.h"
 #include "headless/lib/browser/headless_browser_context_options.h"
 #include "headless/lib/browser/headless_network_conditions.h"
@@ -139,7 +140,7 @@
   // TODO(alexclarke): Remove if we can add DevTools frame token ID to
   // ResourceRequestInfo. See https://crbug.com/715541
   mutable base::Lock devtools_frame_token_map_lock_;
-  base::flat_map<std::pair<int, int>, base::UnguessableToken>
+  base::flat_map<content::GlobalFrameRoutingId, base::UnguessableToken>
       devtools_frame_token_map_;
   base::flat_map<int, base::UnguessableToken>
       frame_tree_node_id_to_devtools_frame_token_map_;
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index fe8c9032..e10ca3e3 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -777,6 +777,9 @@
       <message name="IDS_IOS_GOOGLE_SERVICES_SETTINGS_READING_LIST_TEXT" desc="Feature in the settings for the user to enable/disable, to sync reading list links between devices. [iOS only]">
         Reading List
       </message>
+      <message name="IDS_IOS_GOOGLE_SERVICES_SETTINGS_AUTOCOMPLETE_WALLET" desc="Label for the checkbox that controls the Autofill/Payments integration feature. 'Google Pay' should not be translated as it is the product name. [iOS only]">
+        Payment methods and addresses using Google Pay
+      </message>
       <message name="IDS_IOS_GOOGLE_SERVICES_SETTINGS_SETTINGS_TEXT" desc="Feature in the settings for the user to enable/disable, to sync settings data between devices. [iOS only]">
         Settings
       </message>
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 549c2e02..a906447c 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -210,7 +210,6 @@
     "//ios/web/public/app",
     "//net",
     "//rlz/buildflags",
-    "//services/network:network_service",
     "//ui/base",
   ]
 
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index c732355..6c856b1 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -106,7 +106,6 @@
   "+rlz/buildflags",
   "+services/identity/public",
   "+services/metrics/public",
-  "+services/network/network_change_manager.h",
   "+services/network/public/mojom",
   "+services/network/public/cpp",
   "+services/service_manager/public",
diff --git a/ios/chrome/browser/application_context.h b/ios/chrome/browser/application_context.h
index 37b4000..bfdcf5e 100644
--- a/ios/chrome/browser/application_context.h
+++ b/ios/chrome/browser/application_context.h
@@ -39,7 +39,6 @@
 }
 
 namespace network {
-class NetworkConnectionTracker;
 class SharedURLLoaderFactory;
 namespace mojom {
 class NetworkContext;
@@ -140,9 +139,6 @@
   virtual component_updater::ComponentUpdateService*
   GetComponentUpdateService() = 0;
 
-  // Returns the NetworkConnectionTracker instance for this ApplicationContext.
-  virtual network::NetworkConnectionTracker* GetNetworkConnectionTracker() = 0;
-
  protected:
   // Sets the global ApplicationContext instance.
   static void SetApplicationContext(ApplicationContext* context);
diff --git a/ios/chrome/browser/application_context_impl.cc b/ios/chrome/browser/application_context_impl.cc
index 359def6..b7db100 100644
--- a/ios/chrome/browser/application_context_impl.cc
+++ b/ios/chrome/browser/application_context_impl.cc
@@ -55,8 +55,6 @@
 #include "net/socket/client_socket_pool_manager.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
-#include "services/network/network_change_manager.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 
 namespace {
@@ -81,13 +79,6 @@
                                 app_context, std::move(request)));
 }
 
-// Passed to NetworkConnectionTracker to bind a NetworkChangeManagerRequest.
-void BindNetworkChangeManagerRequest(
-    network::NetworkChangeManager* network_change_manager,
-    network::mojom::NetworkChangeManagerRequest request) {
-  network_change_manager->AddRequest(std::move(request));
-}
-
 }  // namespace
 
 ApplicationContextImpl::ApplicationContextImpl(
@@ -354,21 +345,6 @@
   return component_updater_.get();
 }
 
-network::NetworkConnectionTracker*
-ApplicationContextImpl::GetNetworkConnectionTracker() {
-  if (!network_connection_tracker_) {
-    if (!network_change_manager_) {
-      network_change_manager_ =
-          std::make_unique<network::NetworkChangeManager>(nullptr);
-    }
-    network_connection_tracker_ =
-        std::make_unique<network::NetworkConnectionTracker>(base::BindRepeating(
-            &BindNetworkChangeManagerRequest,
-            base::Unretained(network_change_manager_.get())));
-  }
-  return network_connection_tracker_.get();
-}
-
 void ApplicationContextImpl::SetApplicationLocale(const std::string& locale) {
   DCHECK(thread_checker_.CalledOnValidThread());
   application_locale_ = locale;
diff --git a/ios/chrome/browser/application_context_impl.h b/ios/chrome/browser/application_context_impl.h
index 76bbed4..b868ba5 100644
--- a/ios/chrome/browser/application_context_impl.h
+++ b/ios/chrome/browser/application_context_impl.h
@@ -21,7 +21,6 @@
 }
 
 namespace network {
-class NetworkChangeManager;
 class WeakWrapperSharedURLLoaderFactory;
 }
 
@@ -69,7 +68,6 @@
   gcm::GCMDriver* GetGCMDriver() override;
   component_updater::ComponentUpdateService* GetComponentUpdateService()
       override;
-  network::NetworkConnectionTracker* GetNetworkConnectionTracker() override;
 
  private:
   // Sets the locale used by the application.
@@ -104,10 +102,6 @@
   // Created on the UI thread, destroyed on the IO thread.
   std::unique_ptr<web::NetworkContextOwner> network_context_owner_;
 
-  std::unique_ptr<network::NetworkChangeManager> network_change_manager_;
-  std::unique_ptr<network::NetworkConnectionTracker>
-      network_connection_tracker_;
-
   bool was_last_shutdown_clean_;
 
   DISALLOW_COPY_AND_ASSIGN(ApplicationContextImpl);
diff --git a/ios/chrome/browser/autofill/form_suggestion_view.mm b/ios/chrome/browser/autofill/form_suggestion_view.mm
index 9b22780..02abb037 100644
--- a/ios/chrome/browser/autofill/form_suggestion_view.mm
+++ b/ios/chrome/browser/autofill/form_suggestion_view.mm
@@ -69,7 +69,6 @@
 - (void)setupSubviews {
   self.showsVerticalScrollIndicator = NO;
   self.showsHorizontalScrollIndicator = NO;
-  self.bounces = NO;
   self.canCancelContentTouches = YES;
 
   UIStackView* stackView = [[UIStackView alloc] initWithArrangedSubviews:@[]];
diff --git a/ios/chrome/browser/google/BUILD.gn b/ios/chrome/browser/google/BUILD.gn
index b805688..b629ee4 100644
--- a/ios/chrome/browser/google/BUILD.gn
+++ b/ios/chrome/browser/google/BUILD.gn
@@ -17,7 +17,6 @@
     "//components/google/core/browser",
     "//components/keyed_service/ios",
     "//components/prefs",
-    "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/distribution",
diff --git a/ios/chrome/browser/google/google_url_tracker_factory.cc b/ios/chrome/browser/google/google_url_tracker_factory.cc
index f62da15..1f3081c 100644
--- a/ios/chrome/browser/google/google_url_tracker_factory.cc
+++ b/ios/chrome/browser/google/google_url_tracker_factory.cc
@@ -10,7 +10,6 @@
 #include "components/google/core/browser/google_url_tracker.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/prefs/pref_service.h"
-#include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/google/google_url_tracker_client_impl.h"
@@ -50,8 +49,7 @@
 
   return std::make_unique<GoogleURLTracker>(
       base::WrapUnique(new GoogleURLTrackerClientImpl(browser_state)),
-      GoogleURLTracker::NORMAL_MODE,
-      GetApplicationContext()->GetNetworkConnectionTracker());
+      GoogleURLTracker::NORMAL_MODE, context->GetNetworkConnectionTracker());
 }
 
 web::BrowserState* GoogleURLTrackerFactory::GetBrowserStateToUse(
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm b/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm
index bb9527b..ac381d9 100644
--- a/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm
@@ -76,9 +76,7 @@
   return variations::VariationsService::Create(
       std::make_unique<IOSChromeVariationsServiceClient>(), local_state_,
       GetMetricsStateManager(), "dummy-disable-background-switch",
-      ::CreateUIStringOverrider(),
-      base::BindOnce(&ApplicationContext::GetNetworkConnectionTracker,
-                     base::Unretained(GetApplicationContext())));
+      ::CreateUIStringOverrider());
 }
 
 std::unique_ptr<metrics::MetricsServiceClient>
diff --git a/ios/chrome/browser/signin/account_tracker_service_factory.cc b/ios/chrome/browser/signin/account_tracker_service_factory.cc
index a8ad4ea..cadccbbfa 100644
--- a/ios/chrome/browser/signin/account_tracker_service_factory.cc
+++ b/ios/chrome/browser/signin/account_tracker_service_factory.cc
@@ -10,7 +10,6 @@
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/signin/signin_client_factory.h"
 
 namespace ios {
 
@@ -18,7 +17,6 @@
     : BrowserStateKeyedServiceFactory(
           "AccountTrackerService",
           BrowserStateDependencyManager::GetInstance()) {
-  DependsOn(SigninClientFactory::GetInstance());
 }
 
 AccountTrackerServiceFactory::~AccountTrackerServiceFactory() {}
@@ -46,8 +44,7 @@
   ios::ChromeBrowserState* chrome_browser_state =
       ios::ChromeBrowserState::FromBrowserState(context);
   std::unique_ptr<AccountTrackerService> service(new AccountTrackerService());
-  service->Initialize(
-      SigninClientFactory::GetForBrowserState(chrome_browser_state));
+  service->Initialize(chrome_browser_state->GetPrefs(), base::FilePath());
   return service;
 }
 
diff --git a/ios/chrome/browser/signin/authentication_service_unittest.mm b/ios/chrome/browser/signin/authentication_service_unittest.mm
index 62cae6f..fa6fc8b09 100644
--- a/ios/chrome/browser/signin/authentication_service_unittest.mm
+++ b/ios/chrome/browser/signin/authentication_service_unittest.mm
@@ -565,8 +565,7 @@
   // Migrate the accounts (this actually requires a shutdown and re-initialize
   // of the account tracker).
   account_tracker->Shutdown();
-  account_tracker->Initialize(
-      SigninClientFactory::GetForBrowserState(browser_state_.get()));
+  account_tracker->Initialize(browser_state_->GetPrefs(), base::FilePath());
   account_tracker->SetMigrationDone();
 
   // Actually migrate the accounts in prefs.
diff --git a/ios/chrome/browser/translate/translate_service_ios.cc b/ios/chrome/browser/translate/translate_service_ios.cc
index 9a9c93f..2df8f01 100644
--- a/ios/chrome/browser/translate/translate_service_ios.cc
+++ b/ios/chrome/browser/translate/translate_service_ios.cc
@@ -19,10 +19,8 @@
 TranslateServiceIOS::TranslateServiceIOS()
     : resource_request_allowed_notifier_(
           GetApplicationContext()->GetLocalState(),
-          nullptr,
-          base::BindOnce(&ApplicationContext::GetNetworkConnectionTracker,
-                         base::Unretained(GetApplicationContext()))) {
-  resource_request_allowed_notifier_.Init(this, false /* leaky */);
+          nullptr) {
+  resource_request_allowed_notifier_.Init(this);
 }
 
 TranslateServiceIOS::~TranslateServiceIOS() {
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
index d282cf33..942fc82 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -459,8 +459,6 @@
        !content_suggestions::IsRegularXRegularSizeClass(self.view))) {
     [self.dispatcher onFakeboxBlur];
   }
-  self.fakeOmnibox.hidden = NO;
-
   [self.collectionSynchronizer shiftTilesDown];
 
   [self.commandHandler dismissModals];
@@ -476,7 +474,6 @@
          !content_suggestions::IsRegularXRegularSizeClass(self.view))) {
       [self.dispatcher onFakeboxAnimationComplete];
       [self.headerView fadeOutShadow];
-      [self.fakeOmnibox setHidden:YES];
     }
   };
   [self.collectionSynchronizer shiftTilesUpWithCompletionBlock:completionBlock];
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_consumer.h b/ios/chrome/browser/ui/settings/google_services_settings_consumer.h
index 9fb8ccc..def7367 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_consumer.h
+++ b/ios/chrome/browser/ui/settings/google_services_settings_consumer.h
@@ -19,6 +19,9 @@
 // Reloads |sections|.
 - (void)reloadSections:(NSIndexSet*)sections;
 
+// Reloads only a specific |item|.
+- (void)reloadItem:(CollectionViewItem*)item;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SETTINGS_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm b/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
index 3fb4be20..d32e3b4 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
@@ -6,6 +6,7 @@
 
 #include "base/auto_reset.h"
 #include "base/mac/foundation_util.h"
+#include "components/autofill/core/common/autofill_prefs.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/metrics/metrics_pref_names.h"
 #import "components/prefs/ios/pref_observer_bridge.h"
@@ -66,6 +67,7 @@
   SyncAutofillItemType,
   SyncSettingsItemType,
   SyncReadingListItemType,
+  AutocompleteWalletItemType,
   SyncActivityAndInteractionsItemType,
   SyncGoogleActivityControlsItemType,
   EncryptionItemType,
@@ -99,6 +101,9 @@
 @property(nonatomic, assign, readonly) BOOL isConsentGiven;
 // Sync setup service.
 @property(nonatomic, assign, readonly) SyncSetupService* syncSetupService;
+// Preference value for the autocomplete wallet feature.
+@property(nonatomic, strong, readonly)
+    PrefBackedBoolean* autocompleteWalletPreference;
 // Preference value for the "Autocomplete searches and URLs" feature.
 @property(nonatomic, strong, readonly)
     PrefBackedBoolean* autocompleteSearchPreference;
@@ -135,6 +140,8 @@
     SettingsCollapsibleItem* syncPersonalizationItem;
 // All the items for the personalized section.
 @property(nonatomic, strong, readonly) ItemArray personalizedItems;
+// Item for the autocomplete wallet feature.
+@property(nonatomic, strong, readonly) SyncSwitchItem* autocompleteWalletItem;
 // Collapsible item for the non-personalized section.
 @property(nonatomic, strong, readonly)
     SettingsCollapsibleItem* nonPersonalizedServicesItem;
@@ -149,6 +156,7 @@
 @synthesize consumer = _consumer;
 @synthesize authService = _authService;
 @synthesize syncSetupService = _syncSetupService;
+@synthesize autocompleteWalletPreference = _autocompleteWalletPreference;
 @synthesize autocompleteSearchPreference = _autocompleteSearchPreference;
 @synthesize preloadPagesPreference = _preloadPagesPreference;
 @synthesize preloadPagesWifiOnlyPreference = _preloadPagesWifiOnlyPreference;
@@ -163,6 +171,7 @@
 @synthesize syncEverythingItem = _syncEverythingItem;
 @synthesize syncPersonalizationItem = _syncPersonalizationItem;
 @synthesize personalizedItems = _personalizedItems;
+@synthesize autocompleteWalletItem = _autocompleteWalletItem;
 @synthesize nonPersonalizedServicesItem = _nonPersonalizedServicesItem;
 @synthesize nonPersonalizedItems = _nonPersonalizedItems;
 
@@ -189,21 +198,25 @@
     prefChangeRegistrar_.Init(userPrefService);
     prefObserverBridge_->ObserveChangesForPreference(kUnifiedConsentGiven,
                                                      &prefChangeRegistrar_);
+    _autocompleteWalletPreference = [[PrefBackedBoolean alloc]
+        initWithPrefService:userPrefService
+                   prefName:autofill::prefs::kAutofillWalletImportEnabled];
+    _autocompleteWalletPreference.observer = self;
     _autocompleteSearchPreference = [[PrefBackedBoolean alloc]
         initWithPrefService:userPrefService
                    prefName:prefs::kSearchSuggestEnabled];
-    [_autocompleteSearchPreference setObserver:self];
+    _autocompleteSearchPreference.observer = self;
     _preloadPagesPreference = [[PrefBackedBoolean alloc]
         initWithPrefService:userPrefService
                    prefName:prefs::kNetworkPredictionEnabled];
-    [_preloadPagesPreference setObserver:self];
+    _preloadPagesPreference.observer = self;
     _preloadPagesWifiOnlyPreference = [[PrefBackedBoolean alloc]
         initWithPrefService:userPrefService
                    prefName:prefs::kNetworkPredictionWifiOnly];
     _sendDataUsagePreference = [[PrefBackedBoolean alloc]
         initWithPrefService:localPrefService
                    prefName:metrics::prefs::kMetricsReportingEnabled];
-    [_sendDataUsagePreference setObserver:self];
+    _sendDataUsagePreference.observer = self;
     _sendDataUsageWifiOnlyPreference = [[PrefBackedBoolean alloc]
         initWithPrefService:localPrefService
                    prefName:prefs::kMetricsReportingWifiOnly];
@@ -211,7 +224,7 @@
         initWithPrefService:userPrefService
                    prefName:unified_consent::prefs::
                                 kUrlKeyedAnonymizedDataCollectionEnabled];
-    [_anonymizedDataCollectionPreference setObserver:self];
+    _anonymizedDataCollectionPreference.observer = self;
   }
   return self;
 }
@@ -379,13 +392,27 @@
     _personalizedItems = @[
       syncBookmarksItem, syncHistoryItem, syncPasswordsItem, syncOpenTabsItem,
       syncAutofillItem, syncSettingsItem, syncReadingListItem,
-      syncActivityAndInteractionsItem, syncGoogleActivityControlsItem,
-      encryptionItem, manageSyncedDataItem
+      self.autocompleteWalletItem, syncActivityAndInteractionsItem,
+      syncGoogleActivityControlsItem, encryptionItem, manageSyncedDataItem
     ];
   }
   return _personalizedItems;
 }
 
+- (SyncSwitchItem*)autocompleteWalletItem {
+  if (!_autocompleteWalletItem) {
+    _autocompleteWalletItem = [self
+        switchItemWithItemType:AutocompleteWalletItemType
+                  textStringID:
+                      IDS_IOS_GOOGLE_SERVICES_SETTINGS_AUTOCOMPLETE_WALLET
+                detailStringID:0
+                     commandID:
+                         GoogleServicesSettingsCommandIDAutocompleteWalletService
+                      dataType:0];
+  }
+  return _autocompleteWalletItem;
+}
+
 - (SettingsCollapsibleItem*)nonPersonalizedServicesItem {
   if (!_nonPersonalizedServicesItem) {
     _nonPersonalizedServicesItem = [self
@@ -497,6 +524,14 @@
   [self updateSectionWithCollapsibleItem:self.syncPersonalizationItem
                                    items:self.personalizedItems
                                  enabled:enabled];
+  syncer::ModelType autofillModelType =
+      _syncSetupService->GetModelType(SyncSetupService::kSyncAutofill);
+  BOOL isAutofillOn = _syncSetupService->IsDataTypePreferred(autofillModelType);
+  self.autocompleteWalletItem.enabled = enabled && isAutofillOn;
+  if (!isAutofillOn) {
+    // Autocomplete wallet item should be disabled when autofill is off.
+    self.autocompleteWalletItem.on = false;
+  }
 }
 
 // Updates the non-personalized section according to the user consent.
@@ -528,6 +563,9 @@
           switchItem.on = self.syncSetupService->IsDataTypePreferred(modelType);
           break;
         }
+        case GoogleServicesSettingsCommandIDAutocompleteWalletService:
+          switchItem.on = self.autocompleteWalletPreference.value;
+          break;
         case GoogleServicesSettingsCommandIDToggleAutocompleteSearchesService:
           switchItem.on = self.autocompleteSearchPreference.value;
           break;
@@ -588,6 +626,10 @@
   self.syncSetupService->SetDataTypeEnabled(modelType, value);
 }
 
+- (void)toggleAutocompleteWalletServiceWithValue:(BOOL)value {
+  self.autocompleteWalletPreference.value = value;
+}
+
 - (void)toggleAutocompleteSearchesServiceWithValue:(BOOL)value {
   self.autocompleteSearchPreference.value = value;
 }
@@ -653,10 +695,15 @@
 - (void)onSyncStateChanged {
   [self updatePersonalizedSection];
   if (!self.personalizedSectionBeingAnimated) {
+    CollectionViewModel* model = self.consumer.collectionViewModel;
     NSMutableIndexSet* sectionIndexToReload = [NSMutableIndexSet indexSet];
-    [sectionIndexToReload
-        addIndex:PersonalizedSectionIdentifier - kSectionIdentifierEnumZero];
+    [sectionIndexToReload addIndex:[model sectionForSectionIdentifier:
+                                              PersonalizedSectionIdentifier]];
     [self.consumer reloadSections:sectionIndexToReload];
+  } else {
+    // Needs to reload only the autocomplete wallet item (which is part of the
+    // personalized section), if the autofill feature changed state.
+    [self.consumer reloadItem:self.autocompleteWalletItem];
   }
 }
 
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_service_delegate.h b/ios/chrome/browser/ui/settings/google_services_settings_service_delegate.h
index fb7bcd16..e20b7448 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_service_delegate.h
+++ b/ios/chrome/browser/ui/settings/google_services_settings_service_delegate.h
@@ -15,6 +15,8 @@
   // Personalized section.
   // Enable/disabble bookmark sync.
   GoogleServicesSettingsCommandIDToggleDataTypeSync,
+  // Enable/disable autocomplete wallet for Google Pay.
+  GoogleServicesSettingsCommandIDAutocompleteWalletService,
   // Opens the Google activity controls dialog.
   GoogleServicesSettingsCommandIDOpenGoogleActivityControlsDialog,
   // Opens the encryption dialog.
@@ -42,6 +44,9 @@
 // Personalized section.
 // Called when GoogleServicesSettingsCommandIDToggleDataTypeSync is triggered.
 - (void)toggleSyncDataSync:(NSInteger)dataType withValue:(BOOL)value;
+// Called when GoogleServicesSettingsCommandIDAutocompleteWalletService is
+// triggered.
+- (void)toggleAutocompleteWalletServiceWithValue:(BOOL)value;
 
 // Non-personalized section.
 // Called when GoogleServicesSettingsCommandIDToggleAutocompleteSearchesService
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
index cef94c6..c6dee0a 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
@@ -110,6 +110,9 @@
       [self.serviceDelegate toggleSyncDataSync:syncSwitchItem.dataType
                                      withValue:isOn];
       break;
+    case GoogleServicesSettingsCommandIDAutocompleteWalletService:
+      [self.serviceDelegate toggleAutocompleteWalletServiceWithValue:isOn];
+      break;
     case GoogleServicesSettingsCommandIDToggleAutocompleteSearchesService:
       [self.serviceDelegate toggleAutocompleteSearchesServiceWithValue:isOn];
       break;
@@ -152,6 +155,11 @@
   [self.collectionView reloadSections:sections];
 }
 
+- (void)reloadItem:(CollectionViewItem*)item {
+  NSIndexPath* indexPath = [self.collectionViewModel indexPathForItem:item];
+  [self.collectionView reloadItemsAtIndexPaths:@[ indexPath ]];
+}
+
 #pragma mark - CollectionViewController
 
 - (void)loadModel {
@@ -235,6 +243,7 @@
     case GoogleServicesSettingsCommandIDNoOp:
     case GoogleServicesSettingsCommandIDToggleSyncEverything:
     case GoogleServicesSettingsCommandIDToggleDataTypeSync:
+    case GoogleServicesSettingsCommandIDAutocompleteWalletService:
     case GoogleServicesSettingsCommandIDToggleAutocompleteSearchesService:
     case GoogleServicesSettingsCommandIDTogglePreloadPagesService:
     case GoogleServicesSettingsCommandIDToggleImproveChromeService:
diff --git a/ios/chrome/test/testing_application_context.h b/ios/chrome/test/testing_application_context.h
index e9f99ec..ea8b4d2 100644
--- a/ios/chrome/test/testing_application_context.h
+++ b/ios/chrome/test/testing_application_context.h
@@ -59,7 +59,6 @@
   gcm::GCMDriver* GetGCMDriver() override;
   component_updater::ComponentUpdateService* GetComponentUpdateService()
       override;
-  network::NetworkConnectionTracker* GetNetworkConnectionTracker() override;
 
  private:
   base::ThreadChecker thread_checker_;
diff --git a/ios/chrome/test/testing_application_context.mm b/ios/chrome/test/testing_application_context.mm
index 9922836..85c7afd 100644
--- a/ios/chrome/test/testing_application_context.mm
+++ b/ios/chrome/test/testing_application_context.mm
@@ -179,9 +179,3 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   return nullptr;
 }
-
-network::NetworkConnectionTracker*
-TestingApplicationContext::GetNetworkConnectionTracker() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  return nullptr;
-}
diff --git a/ios/web/DEPS b/ios/web/DEPS
index 7f2767d7..375657e 100644
--- a/ios/web/DEPS
+++ b/ios/web/DEPS
@@ -5,6 +5,7 @@
   "+ios/web",
   "+mojo/public",
   "+net",
+  "+services/network/network_change_manager.h",
   "+services/network/network_context.h",
   "+services/network/public/cpp",
   "+services/network/public/mojom",
diff --git a/ios/web/browser_state.mm b/ios/web/browser_state.mm
index 37c8d2e..df3dcaf 100644
--- a/ios/web/browser_state.mm
+++ b/ios/web/browser_state.mm
@@ -23,7 +23,9 @@
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_context_getter_observer.h"
+#include "services/network/network_change_manager.h"
 #include "services/network/network_context.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
@@ -107,6 +109,13 @@
   DISALLOW_COPY_AND_ASSIGN(BrowserStateServiceManagerConnectionHolder);
 };
 
+// Passed to NetworkConnectionTracker to bind a NetworkChangeManagerRequest.
+void BindNetworkChangeManagerRequest(
+    network::NetworkChangeManager* network_change_manager,
+    network::mojom::NetworkChangeManagerRequest request) {
+  network_change_manager->AddRequest(std::move(request));
+}
+
 }  // namespace
 
 // static
@@ -189,6 +198,19 @@
   return cookie_manager_.get();
 }
 
+network::NetworkConnectionTracker* BrowserState::GetNetworkConnectionTracker() {
+  if (!network_connection_tracker_) {
+    DCHECK(!network_change_manager_);
+    network_change_manager_ =
+        std::make_unique<network::NetworkChangeManager>(nullptr);
+    network_connection_tracker_ =
+        std::make_unique<network::NetworkConnectionTracker>(base::BindRepeating(
+            &BindNetworkChangeManagerRequest,
+            base::Unretained(network_change_manager_.get())));
+  }
+  return network_connection_tracker_.get();
+}
+
 void BrowserState::GetProxyResolvingSocketFactory(
     network::mojom::ProxyResolvingSocketFactoryRequest request) {
   CreateNetworkContextIfNecessary();
diff --git a/ios/web/public/browser_state.h b/ios/web/public/browser_state.h
index 878d5507..535b5174 100644
--- a/ios/web/public/browser_state.h
+++ b/ios/web/public/browser_state.h
@@ -23,6 +23,8 @@
 }
 
 namespace network {
+class NetworkChangeManager;
+class NetworkConnectionTracker;
 class SharedURLLoaderFactory;
 class WeakWrapperSharedURLLoaderFactory;
 }  // namespace network
@@ -68,6 +70,9 @@
   // Returns a CookieManager that is backed by GetRequestContext.
   network::mojom::CookieManager* GetCookieManager();
 
+  // Returns the NetworkConnectionTracker instance for this BrowserState.
+  network::NetworkConnectionTracker* GetNetworkConnectionTracker();
+
   // Binds a ProxyResolvingSocketFactory request to NetworkContext.
   void GetProxyResolvingSocketFactory(
       network::mojom::ProxyResolvingSocketFactoryRequest request);
@@ -129,6 +134,12 @@
       shared_url_loader_factory_;
   network::mojom::NetworkContextPtr network_context_;
 
+  // Acts as a proxy between the NetworkChangeNotifier and
+  // NetworkConnectionTracker.
+  std::unique_ptr<network::NetworkChangeManager> network_change_manager_;
+  std::unique_ptr<network::NetworkConnectionTracker>
+      network_connection_tracker_;
+
   // Owns the network::NetworkContext that backs |url_loader_factory_|. Created
   // on the UI thread, destroyed on the IO thread.
   std::unique_ptr<NetworkContextOwner> network_context_owner_;
diff --git a/ios/web/public/web_state/web_frames_manager.h b/ios/web/public/web_state/web_frames_manager.h
index 441a385..770cbbb 100644
--- a/ios/web/public/web_state/web_frames_manager.h
+++ b/ios/web/public/web_state/web_frames_manager.h
@@ -5,10 +5,11 @@
 #ifndef IOS_WEB_PUBLIC_WEB_STATE_WEB_FRAMES_MANAGER_H_
 #define IOS_WEB_PUBLIC_WEB_STATE_WEB_FRAMES_MANAGER_H_
 
+#include <set>
 #include <string>
-#include <vector>
 
 #include "base/macros.h"
+#import "ios/web/public/web_state/web_state_user_data.h"
 
 namespace web {
 
@@ -19,19 +20,24 @@
 // NOTE: WebFrame objects should be used directly from this manager and not
 // stored elsewhere for later use becase WebFrames are frequently replaced.
 // For example, a navigation will invalidate the WebFrame object for that frame.
-class WebFramesManager {
+class WebFramesManager : public web::WebStateUserData<WebFramesManager> {
  public:
   // Returns a list of all the web frames associated with WebState.
   // NOTE: Due to the asynchronous nature of renderer, this list may be
   // outdated.
-  virtual const std::vector<WebFrame*>& GetAllWebFrames() = 0;
+  virtual std::set<WebFrame*> GetAllWebFrames() = 0;
   // Returns the web frame for the main frame associated with WebState or null
   // if unknown.
   // NOTE: Due to the asynchronous nature of JavaScript to native messsaging,
   // this object may be outdated.
   virtual WebFrame* GetMainWebFrame() = 0;
+  // Returns the web frame with |frame_id|, if one exists.
+  // NOTE: Due to the asynchronous nature of JavaScript to native messsaging,
+  // this object may be outdated and the WebFrame returned by this method may
+  // not back a real frame in the web page.
+  virtual WebFrame* GetFrameWithId(const std::string& frame_id) = 0;
 
-  virtual ~WebFramesManager() {}
+  ~WebFramesManager() override {}
 
  protected:
   WebFramesManager() {}
diff --git a/ios/web/web_state/web_frames_manager_impl.h b/ios/web/web_state/web_frames_manager_impl.h
index bef7fe3..0f316a1 100644
--- a/ios/web/web_state/web_frames_manager_impl.h
+++ b/ios/web/web_state/web_frames_manager_impl.h
@@ -6,19 +6,19 @@
 #define IOS_WEB_WEB_STATE_WEB_FRAMES_MANAGER_IMPL_H_
 
 #include "ios/web/public/web_state/web_frames_manager.h"
-#include "ios/web/public/web_state/web_state_user_data.h"
 
 namespace web {
 
 class WebFrame;
 
-class WebFramesManagerImpl
-    : public WebFramesManager,
-      public web::WebStateUserData<WebFramesManagerImpl> {
+class WebFramesManagerImpl : public WebFramesManager {
  public:
   ~WebFramesManagerImpl() override;
   explicit WebFramesManagerImpl(web::WebState* web_state);
 
+  static void CreateForWebState(WebState* web_state);
+  static WebFramesManagerImpl* FromWebState(WebState* web_state);
+
   // Adds |frame| to the list of web frames associated with WebState.
   void AddFrame(std::unique_ptr<WebFrame> frame);
   // Removes the web frame with |frame_id|, if one exists, from the list of
@@ -30,21 +30,16 @@
   // and keys of existing frames.
   void RegisterExistingFrames();
 
-  // Returns the web frame with |frame_id|, if one exisits, from the list of
-  // associated web frames.
-  WebFrame* GetFrameWithId(const std::string& frame_id);
-
   // WebFramesManager overrides
-  const std::vector<WebFrame*>& GetAllWebFrames() override;
+  std::set<WebFrame*> GetAllWebFrames() override;
   WebFrame* GetMainWebFrame() override;
+  WebFrame* GetFrameWithId(const std::string& frame_id) override;
 
  private:
   friend class web::WebStateUserData<WebFramesManagerImpl>;
 
-  // List of all web frames associated with WebState.
-  std::vector<std::unique_ptr<WebFrame>> web_frames_;
   // List of pointers to all web frames associated with WebState.
-  std::vector<WebFrame*> web_frame_ptrs_;
+  std::map<std::string, std::unique_ptr<WebFrame>> web_frames_;
 
   // Reference to the current main web frame.
   WebFrame* main_web_frame_ = nullptr;
diff --git a/ios/web/web_state/web_frames_manager_impl.mm b/ios/web/web_state/web_frames_manager_impl.mm
index 0d83ba1..5b902e5 100644
--- a/ios/web/web_state/web_frames_manager_impl.mm
+++ b/ios/web/web_state/web_frames_manager_impl.mm
@@ -31,7 +31,19 @@
 
 namespace web {
 
-DEFINE_WEB_STATE_USER_DATA_KEY(WebFramesManagerImpl);
+// static
+void WebFramesManagerImpl::CreateForWebState(WebState* web_state) {
+  DCHECK(web_state);
+  if (!FromWebState(web_state))
+    web_state->SetUserData(
+        UserDataKey(), base::WrapUnique(new WebFramesManagerImpl(web_state)));
+}
+
+// static
+WebFramesManagerImpl* WebFramesManagerImpl::FromWebState(WebState* web_state) {
+  return static_cast<WebFramesManagerImpl*>(
+      WebFramesManager::FromWebState(web_state));
+}
 
 WebFramesManagerImpl::~WebFramesManagerImpl() = default;
 
@@ -42,39 +54,35 @@
   if (frame->IsMainFrame()) {
     main_web_frame_ = frame.get();
   }
-  web_frame_ptrs_.push_back(frame.get());
-  web_frames_.push_back(std::move(frame));
+  DCHECK(web_frames_.count(frame->GetFrameId()) == 0);
+  web_frames_[frame->GetFrameId()] = std::move(frame);
 }
 
 void WebFramesManagerImpl::RemoveFrameWithId(const std::string& frame_id) {
   if (main_web_frame_ && main_web_frame_->GetFrameId() == frame_id) {
     main_web_frame_ = nullptr;
   }
-
-  auto web_frame_ptrs_it = std::find_if(
-      web_frame_ptrs_.begin(), web_frame_ptrs_.end(), FrameIdMatcher(frame_id));
-  if (web_frame_ptrs_it != web_frame_ptrs_.end()) {
-    web_frame_ptrs_.erase(web_frame_ptrs_it);
-    web_frames_.erase(web_frames_.begin() +
-                      (web_frame_ptrs_it - web_frame_ptrs_.begin()));
-  }
+  web_frames_.erase(frame_id);
 }
 
 void WebFramesManagerImpl::RemoveAllWebFrames() {
   main_web_frame_ = nullptr;
   web_frames_.clear();
-  web_frame_ptrs_.clear();
 }
 
 WebFrame* WebFramesManagerImpl::GetFrameWithId(const std::string& frame_id) {
-  auto web_frame_ptrs_it = std::find_if(
-      web_frame_ptrs_.begin(), web_frame_ptrs_.end(), FrameIdMatcher(frame_id));
-  return web_frame_ptrs_it == web_frame_ptrs_.end() ? nullptr
-                                                    : *web_frame_ptrs_it;
+  DCHECK(!frame_id.empty());
+  auto web_frames_it = web_frames_.find(frame_id);
+  return web_frames_it == web_frames_.end() ? nullptr
+                                            : web_frames_it->second.get();
 }
 
-const std::vector<WebFrame*>& WebFramesManagerImpl::GetAllWebFrames() {
-  return web_frame_ptrs_;
+std::set<WebFrame*> WebFramesManagerImpl::GetAllWebFrames() {
+  std::set<WebFrame*> frames;
+  for (const auto& it : web_frames_) {
+    frames.insert(it.second.get());
+  }
+  return frames;
 }
 
 WebFrame* WebFramesManagerImpl::GetMainWebFrame() {
diff --git a/ios/web/web_state/web_frames_manager_impl_unittest.mm b/ios/web/web_state/web_frames_manager_impl_unittest.mm
index 6baf7af..ccd0fbe 100644
--- a/ios/web/web_state/web_frames_manager_impl_unittest.mm
+++ b/ios/web/web_state/web_frames_manager_impl_unittest.mm
@@ -22,7 +22,7 @@
 const char kFrameKey[] = "d1uJzdvOFIUT5kEpK4o+x5JCaSlYT/a45ISU7S9EzTo=";
 
 // Returns true if |web_frame| is contained in |frames|.
-bool ContainsWebFrame(std::vector<web::WebFrame*> frames,
+bool ContainsWebFrame(std::set<web::WebFrame*> frames,
                       web::WebFrame* web_frame) {
   return frames.end() != std::find(frames.begin(), frames.end(), web_frame);
 }
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 90f015b..5bf710c 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -246,7 +246,6 @@
   "//components/language/core/browser",
   "//components/language/core/common",
   "//components/net_log",
-  "//services/network:network_service",
   "//components/password_manager/core/browser",
   "//components/password_manager/core/browser/form_parsing:form_parsing",
   "//components/password_manager/core/common",
diff --git a/ios/web_view/internal/DEPS b/ios/web_view/internal/DEPS
index 57946d6..560a264 100644
--- a/ios/web_view/internal/DEPS
+++ b/ios/web_view/internal/DEPS
@@ -34,7 +34,6 @@
   "+ios/web_view",
   "+net",
   "+services/identity/public/cpp",
-  "+services/network/network_change_manager.h",
   "+services/network/public/cpp",
   "+services/network/public/mojom",
   "+third_party/ocmock",
diff --git a/ios/web_view/internal/app/application_context.cc b/ios/web_view/internal/app/application_context.cc
index ca0468b..593402e32 100644
--- a/ios/web_view/internal/app/application_context.cc
+++ b/ios/web_view/internal/app/application_context.cc
@@ -20,22 +20,10 @@
 #include "ios/web_view/cwv_web_view_features.h"
 #include "ios/web_view/internal/app/web_view_io_thread.h"
 #include "net/socket/client_socket_pool_manager.h"
-#include "services/network/network_change_manager.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 namespace ios_web_view {
-namespace {
-
-// Passed to NetworkConnectionTracker to bind a NetworkChangeManagerRequest.
-void BindNetworkChangeManagerRequest(
-    network::NetworkChangeManager* network_change_manager,
-    network::mojom::NetworkChangeManagerRequest request) {
-  network_change_manager->AddRequest(std::move(request));
-}
-
-}  // namespace
 
 ApplicationContext* ApplicationContext::GetInstance() {
   return base::Singleton<ApplicationContext>::get();
@@ -149,21 +137,6 @@
   return network_context_.get();
 }
 
-network::NetworkConnectionTracker*
-ApplicationContext::GetNetworkConnectionTracker() {
-  if (!network_connection_tracker_) {
-    if (!network_change_manager_) {
-      network_change_manager_ =
-          std::make_unique<network::NetworkChangeManager>(nullptr);
-    }
-    network_connection_tracker_ =
-        std::make_unique<network::NetworkConnectionTracker>(base::BindRepeating(
-            &BindNetworkChangeManagerRequest,
-            base::Unretained(network_change_manager_.get())));
-  }
-  return network_connection_tracker_.get();
-}
-
 const std::string& ApplicationContext::GetApplicationLocale() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!application_locale_.empty());
diff --git a/ios/web_view/internal/app/application_context.h b/ios/web_view/internal/app/application_context.h
index 19f242d..5e94d37 100644
--- a/ios/web_view/internal/app/application_context.h
+++ b/ios/web_view/internal/app/application_context.h
@@ -23,8 +23,6 @@
 }
 
 namespace network {
-class NetworkChangeManager;
-class NetworkConnectionTracker;
 class SharedURLLoaderFactory;
 class WeakWrapperSharedURLLoaderFactory;
 namespace mojom {
@@ -56,9 +54,6 @@
   scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory();
   network::mojom::NetworkContext* GetSystemNetworkContext();
 
-  // Returns the NetworkConnectionTracker instance for this ApplicationContext.
-  network::NetworkConnectionTracker* GetNetworkConnectionTracker();
-
   // Gets the locale used by the application.
   const std::string& GetApplicationLocale();
 
@@ -103,10 +98,6 @@
   // Created on the UI thread, destroyed on the IO thread.
   std::unique_ptr<web::NetworkContextOwner> network_context_owner_;
 
-  std::unique_ptr<network::NetworkChangeManager> network_change_manager_;
-  std::unique_ptr<network::NetworkConnectionTracker>
-      network_connection_tracker_;
-
   DISALLOW_COPY_AND_ASSIGN(ApplicationContext);
 };
 
diff --git a/ios/web_view/internal/signin/web_view_account_tracker_service_factory.mm b/ios/web_view/internal/signin/web_view_account_tracker_service_factory.mm
index 1ec93fdc9..27b3e5d 100644
--- a/ios/web_view/internal/signin/web_view_account_tracker_service_factory.mm
+++ b/ios/web_view/internal/signin/web_view_account_tracker_service_factory.mm
@@ -9,8 +9,6 @@
 #include "base/memory/singleton.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/signin/core/browser/account_tracker_service.h"
-#include "ios/web_view/internal/signin/ios_web_view_signin_client.h"
-#include "ios/web_view/internal/signin/web_view_signin_client_factory.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -23,7 +21,6 @@
     : BrowserStateKeyedServiceFactory(
           "AccountTrackerService",
           BrowserStateDependencyManager::GetInstance()) {
-  DependsOn(WebViewSigninClientFactory::GetInstance());
 }
 
 // static
@@ -51,8 +48,7 @@
       WebViewBrowserState::FromBrowserState(context);
   std::unique_ptr<AccountTrackerService> service =
       std::make_unique<AccountTrackerService>();
-  service->Initialize(
-      WebViewSigninClientFactory::GetForBrowserState(browser_state));
+  service->Initialize(browser_state->GetPrefs(), base::FilePath());
   return service;
 }
 
diff --git a/ios/web_view/internal/translate/web_view_translate_service.cc b/ios/web_view/internal/translate/web_view_translate_service.cc
index fbe15c8..f9e06a7 100644
--- a/ios/web_view/internal/translate/web_view_translate_service.cc
+++ b/ios/web_view/internal/translate/web_view_translate_service.cc
@@ -15,10 +15,8 @@
     TranslateRequestsAllowedListener()
     : resource_request_allowed_notifier_(
           ios_web_view::ApplicationContext::GetInstance()->GetLocalState(),
-          /*disable_network_switch=*/nullptr,
-          base::BindOnce(&ApplicationContext::GetNetworkConnectionTracker,
-                         base::Unretained(ApplicationContext::GetInstance()))) {
-  resource_request_allowed_notifier_.Init(this, /*leaky=*/false);
+          /*disable_network_switch=*/nullptr) {
+  resource_request_allowed_notifier_.Init(this);
 }
 
 WebViewTranslateService::TranslateRequestsAllowedListener::
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index 9617a472..786ad95 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -424,8 +424,7 @@
 // received before any data is returned from the socket. The request should be
 // retried with early data disabled.
 //
-// See https://tools.ietf.org/html/draft-ietf-tls-tls13-28#appendix-D.3 for
-// details.
+// See https://tools.ietf.org/html/rfc8446#appendix-D.3 for details.
 NET_ERROR(WRONG_VERSION_ON_EARLY_DATA, -179)
 
 // Certificate error codes
diff --git a/net/cert/nss_cert_database.cc b/net/cert/nss_cert_database.cc
index ef6d740..a6f3aabb 100644
--- a/net/cert/nss_cert_database.cc
+++ b/net/cert/nss_cert_database.cc
@@ -347,6 +347,26 @@
   return false;
 }
 
+bool NSSCertDatabase::IsWebTrustAnchor(const CERTCertificate* cert) const {
+  CERTCertTrust nsstrust;
+  SECStatus rv = CERT_GetCertTrust(cert, &nsstrust);
+  if (rv != SECSuccess) {
+    LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError();
+    return false;
+  }
+
+  // Note: This should return true iff a net::TrustStoreNSS instantiated with
+  // SECTrustType trustSSL would classify |cert| as a trust anchor.
+  const unsigned int ssl_trust_flags = nsstrust.sslFlags;
+
+  // Determine if the certificate is a trust anchor.
+  if ((ssl_trust_flags & CERTDB_TRUSTED_CA) == CERTDB_TRUSTED_CA) {
+    return true;
+  }
+
+  return false;
+}
+
 bool NSSCertDatabase::SetCertTrust(CERTCertificate* cert,
                                    CertType type,
                                    TrustBits trust_bits) {
diff --git a/net/cert/nss_cert_database.h b/net/cert/nss_cert_database.h
index d2baedd..b2fe081c 100644
--- a/net/cert/nss_cert_database.h
+++ b/net/cert/nss_cert_database.h
@@ -211,6 +211,10 @@
   // rejecting them.
   bool IsUntrusted(const CERTCertificate* cert) const;
 
+  // IsWebTrustAnchor returns true if |cert| is explicitly trusted for web
+  // navigations according to the trust bits stored in the database.
+  bool IsWebTrustAnchor(const CERTCertificate* cert) const;
+
   // Set trust values for certificate.
   // Returns true on success or false on failure.
   bool SetCertTrust(CERTCertificate* cert, CertType type, TrustBits trust_bits);
diff --git a/net/proxy_resolution/proxy_resolver_v8.cc b/net/proxy_resolution/proxy_resolver_v8.cc
index 5b46b99..c77fcc8 100644
--- a/net/proxy_resolution/proxy_resolver_v8.cc
+++ b/net/proxy_resolution/proxy_resolver_v8.cc
@@ -393,8 +393,9 @@
         has_initialized_v8_ = true;
       }
 
-      holder_.reset(new gin::IsolateHolder(base::ThreadTaskRunnerHandle::Get(),
-                                           gin::IsolateHolder::kUseLocker));
+      holder_.reset(new gin::IsolateHolder(
+          base::ThreadTaskRunnerHandle::Get(), gin::IsolateHolder::kUseLocker,
+          gin::IsolateHolder::IsolateType::kUtility));
     }
 
     return holder_->isolate();
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index c87110e..5e47623b 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -542,8 +542,9 @@
                                  gin::IsolateHolder::kStableV8Extras,
                                  gin::ArrayBufferAllocator::SharedInstance());
   DCHECK(!g_isolate_holder);
-  g_isolate_holder = new gin::IsolateHolder(base::ThreadTaskRunnerHandle::Get(),
-                                            gin::IsolateHolder::kSingleThread);
+  g_isolate_holder = new gin::IsolateHolder(
+      base::ThreadTaskRunnerHandle::Get(), gin::IsolateHolder::kSingleThread,
+      gin::IsolateHolder::IsolateType::kUtility);
   g_isolate_holder->isolate()->Enter();
 }
 
diff --git a/services/identity/identity_manager_impl_unittest.cc b/services/identity/identity_manager_impl_unittest.cc
index 7ffbb7d4..0e9bb8923 100644
--- a/services/identity/identity_manager_impl_unittest.cc
+++ b/services/identity/identity_manager_impl_unittest.cc
@@ -104,7 +104,7 @@
     SigninManagerBase::RegisterProfilePrefs(pref_service_.registry());
     SigninManagerBase::RegisterPrefs(pref_service_.registry());
 
-    account_tracker_.Initialize(&signin_client_);
+    account_tracker_.Initialize(&pref_service_, base::FilePath());
   }
 
   void TearDown() override {
diff --git a/services/identity/public/cpp/access_token_fetcher_unittest.cc b/services/identity/public/cpp/access_token_fetcher_unittest.cc
index 095255f..9862f533 100644
--- a/services/identity/public/cpp/access_token_fetcher_unittest.cc
+++ b/services/identity/public/cpp/access_token_fetcher_unittest.cc
@@ -49,7 +49,7 @@
     AccountTrackerService::RegisterPrefs(pref_service_.registry());
 
     account_tracker_ = std::make_unique<AccountTrackerService>();
-    account_tracker_->Initialize(&signin_client_);
+    account_tracker_->Initialize(&pref_service_, base::FilePath());
 
     token_service_.AddDiagnosticsObserver(this);
   }
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc
index 67540ea9..256a2dd9 100644
--- a/services/identity/public/cpp/identity_manager_unittest.cc
+++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -360,7 +360,7 @@
     SigninManagerBase::RegisterProfilePrefs(pref_service_.registry());
     SigninManagerBase::RegisterPrefs(pref_service_.registry());
 
-    account_tracker_.Initialize(&signin_client_);
+    account_tracker_.Initialize(&pref_service_, base::FilePath());
 
     RecreateSigninAndIdentityManager(
         signin::AccountConsistencyMethod::kDisabled,
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc
index b878334..bcb23901 100644
--- a/services/identity/public/cpp/identity_test_environment.cc
+++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -79,7 +79,7 @@
   SigninManagerBase::RegisterProfilePrefs(pref_service_.registry());
   SigninManagerBase::RegisterPrefs(pref_service_.registry());
 
-  account_tracker_.Initialize(&signin_client_);
+  account_tracker_.Initialize(&pref_service_, base::FilePath());
 
   identity_manager_.reset(new IdentityManager(&signin_manager_, &token_service_,
                                               &account_tracker_,
diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn
index ccf815a..7ff247f 100644
--- a/services/network/public/cpp/BUILD.gn
+++ b/services/network/public/cpp/BUILD.gn
@@ -10,6 +10,8 @@
   sources = [
     "cors/cors.cc",
     "cors/cors.h",
+    "cors/origin_access_entry.cc",
+    "cors/origin_access_entry.h",
     "cors/preflight_cache.cc",
     "cors/preflight_cache.h",
     "cors/preflight_result.cc",
@@ -140,6 +142,7 @@
 
   sources = [
     "cors/cors_unittest.cc",
+    "cors/origin_access_entry_unittest.cc",
     "cors/preflight_cache_unittest.cc",
     "cors/preflight_result_unittest.cc",
     "cross_thread_shared_url_loader_factory_info_unittest.cc",
diff --git a/services/network/public/cpp/cors/origin_access_entry.cc b/services/network/public/cpp/cors/origin_access_entry.cc
new file mode 100644
index 0000000..6b7400d
--- /dev/null
+++ b/services/network/public/cpp/cors/origin_access_entry.cc
@@ -0,0 +1,124 @@
+// 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 "services/network/public/cpp/cors/origin_access_entry.h"
+
+#include "base/strings/string_util.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "url/origin.h"
+#include "url/url_util.h"
+
+namespace network {
+
+namespace cors {
+
+namespace {
+
+bool IsSubdomainOfHost(const std::string& subdomain, const std::string& host) {
+  if (subdomain.length() <= host.length())
+    return false;
+
+  if (subdomain[subdomain.length() - host.length() - 1] != '.')
+    return false;
+
+  if (!base::EndsWith(subdomain, host, base::CompareCase::SENSITIVE))
+    return false;
+
+  return true;
+}
+
+}  // namespace
+
+OriginAccessEntry::OriginAccessEntry(const std::string& protocol,
+                                     const std::string& host,
+                                     MatchMode match_mode)
+    : protocol_(protocol),
+      host_(host),
+      match_mode_(match_mode),
+      host_is_ip_address_(url::HostIsIPAddress(host)),
+      host_is_public_suffix_(false) {
+  if (host_is_ip_address_)
+    return;
+
+  // Look for top-level domains, either with or without an additional dot.
+  // Call sites in Blink passes some things that aren't technically hosts like
+  // "*.foo", so use the permissive variant.
+  size_t public_suffix_length =
+      net::registry_controlled_domains::PermissiveGetHostRegistryLength(
+          host_, net::registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES,
+          net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+  if (public_suffix_length == 0)
+    public_suffix_length = host_.length();
+
+  if (host_.length() <= public_suffix_length + 1) {
+    host_is_public_suffix_ = true;
+  } else if (match_mode_ == kAllowRegisterableDomains && public_suffix_length) {
+    // The "2" in the next line is 1 for the '.', plus a 1-char minimum label
+    // length.
+    const size_t dot =
+        host_.rfind('.', host_.length() - public_suffix_length - 2);
+    if (dot == std::string::npos)
+      registerable_domain_ = host_;
+    else
+      registerable_domain_ = host_.substr(dot + 1);
+  }
+}
+
+OriginAccessEntry::OriginAccessEntry(OriginAccessEntry&& from) = default;
+
+OriginAccessEntry::MatchResult OriginAccessEntry::MatchesOrigin(
+    const url::Origin& origin) const {
+  if (protocol_ != origin.scheme())
+    return kDoesNotMatchOrigin;
+
+  return MatchesDomain(origin);
+}
+
+OriginAccessEntry::MatchResult OriginAccessEntry::MatchesDomain(
+    const url::Origin& origin) const {
+  // Special case: Include subdomains and empty host means "all hosts, including
+  // ip addresses".
+  if (match_mode_ != kDisallowSubdomains && host_.empty())
+    return kMatchesOrigin;
+
+  // Exact match.
+  if (host_ == origin.host())
+    return kMatchesOrigin;
+
+  // Don't try to do subdomain matching on IP addresses.
+  if (host_is_ip_address_)
+    return kDoesNotMatchOrigin;
+
+  // Match subdomains.
+  switch (match_mode_) {
+    case kDisallowSubdomains:
+      return kDoesNotMatchOrigin;
+
+    case kAllowSubdomains:
+      if (!IsSubdomainOfHost(origin.host(), host_))
+        return kDoesNotMatchOrigin;
+      break;
+
+    case kAllowRegisterableDomains:
+      // Fall back to a simple subdomain check if no registerable domain could
+      // be found:
+      if (registerable_domain_.empty()) {
+        if (!IsSubdomainOfHost(origin.host(), host_))
+          return kDoesNotMatchOrigin;
+      } else if (registerable_domain_ != origin.host() &&
+                 !IsSubdomainOfHost(origin.host(), registerable_domain_)) {
+        return kDoesNotMatchOrigin;
+      }
+      break;
+  };
+
+  if (host_is_public_suffix_)
+    return kMatchesOriginButIsPublicSuffix;
+
+  return kMatchesOrigin;
+}
+
+}  // namespace cors
+
+}  // namespace network
diff --git a/services/network/public/cpp/cors/origin_access_entry.h b/services/network/public/cpp/cors/origin_access_entry.h
new file mode 100644
index 0000000..46a35c2
--- /dev/null
+++ b/services/network/public/cpp/cors/origin_access_entry.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 SERVICES_NETWORK_PUBLIC_CPP_CORS_ORIGIN_ACCESS_ENTRY_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_CORS_ORIGIN_ACCESS_ENTRY_H_
+
+#include <string>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+
+namespace url {
+class Origin;
+}  // namespace url
+
+namespace network {
+
+namespace cors {
+
+// A class to hold a protocol and host pair and to provide methods to determine
+// if a given origin or domain matches to the pair. The class can have a setting
+// to control if the matching methods accept a partial match.
+class COMPONENT_EXPORT(NETWORK_CPP) OriginAccessEntry final {
+ public:
+  // A enum to represent a mode if matching functions can accept a partial match
+  // for sub-domains, or for registerable domains.
+  enum MatchMode {
+    // 'www.example.com' matches an OriginAccessEntry for 'example.com'
+    kAllowSubdomains,
+
+    // 'www.example.com' matches an OriginAccessEntry for 'not-www.example.com'
+    kAllowRegisterableDomains,
+
+    // 'www.example.com' does not match an OriginAccessEntry for 'example.com'
+    kDisallowSubdomains,
+  };
+
+  enum MatchResult {
+    kMatchesOrigin,
+    kMatchesOriginButIsPublicSuffix,
+    kDoesNotMatchOrigin
+  };
+
+  // If host is empty string and MatchMode is not DisallowSubdomains, the entry
+  // will match all domains in the specified protocol.
+  // IPv6 addresses must include brackets (e.g.
+  // '[2001:db8:85a3::8a2e:370:7334]', not '2001:db8:85a3::8a2e:370:7334').
+  OriginAccessEntry(const std::string& protocol,
+                    const std::string& host,
+                    MatchMode match_mode);
+  OriginAccessEntry(OriginAccessEntry&& from);
+
+  // 'matchesOrigin' requires a protocol match (e.g. 'http' != 'https').
+  // 'matchesDomain' relaxes this constraint.
+  MatchResult MatchesOrigin(const url::Origin& origin) const;
+  MatchResult MatchesDomain(const url::Origin& domain) const;
+
+  bool host_is_ip_address() const { return host_is_ip_address_; }
+  const std::string& registerable_domain() const {
+    return registerable_domain_;
+  }
+
+ private:
+  const std::string protocol_;
+  const std::string host_;
+  const MatchMode match_mode_;
+  const bool host_is_ip_address_;
+
+  std::string registerable_domain_;
+  bool host_is_public_suffix_;
+
+  DISALLOW_COPY_AND_ASSIGN(OriginAccessEntry);
+};
+
+}  // namespace cors
+
+}  // namespace network
+
+#endif  // SERVICES_NETWORK_PUBLIC_CPP_CORS_ORIGIN_ACCESS_ENTRY_H_
diff --git a/third_party/blink/renderer/platform/weborigin/origin_access_entry_test.cc b/services/network/public/cpp/cors/origin_access_entry_unittest.cc
similarity index 73%
rename from third_party/blink/renderer/platform/weborigin/origin_access_entry_test.cc
rename to services/network/public/cpp/cors/origin_access_entry_unittest.cc
index 9bfe180..d814028c 100644
--- a/third_party/blink/renderer/platform/weborigin/origin_access_entry_test.cc
+++ b/services/network/public/cpp/cors/origin_access_entry_unittest.cc
@@ -1,63 +1,38 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+// 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/platform/weborigin/origin_access_entry.h"
+#include "services/network/public/cpp/cors/origin_access_entry.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+#include "url/gurl.h"
+#include "url/origin.h"
 
-namespace blink {
+namespace network {
+
+namespace cors {
+
+namespace {
 
 TEST(OriginAccessEntryTest, PublicSuffixListTest) {
-  scoped_refptr<const SecurityOrigin> origin =
-      SecurityOrigin::CreateFromString("http://www.google.com");
+  url::Origin origin = url::Origin::Create(GURL("http://www.google.com"));
   OriginAccessEntry entry1("http", "google.com",
                            OriginAccessEntry::kAllowSubdomains);
   OriginAccessEntry entry2("http", "hamster.com",
                            OriginAccessEntry::kAllowSubdomains);
   OriginAccessEntry entry3("http", "com", OriginAccessEntry::kAllowSubdomains);
-  EXPECT_EQ(OriginAccessEntry::kMatchesOrigin, entry1.MatchesOrigin(*origin));
+  EXPECT_EQ(OriginAccessEntry::kMatchesOrigin, entry1.MatchesOrigin(origin));
   EXPECT_EQ(OriginAccessEntry::kDoesNotMatchOrigin,
-            entry2.MatchesOrigin(*origin));
+            entry2.MatchesOrigin(origin));
   EXPECT_EQ(OriginAccessEntry::kMatchesOriginButIsPublicSuffix,
-            entry3.MatchesOrigin(*origin));
+            entry3.MatchesOrigin(origin));
 }
 
 TEST(OriginAccessEntryTest, AllowSubdomainsTest) {
   struct TestCase {
-    const char* protocol;
-    const char* host;
-    const char* origin;
+    const std::string protocol;
+    const std::string host;
+    const std::string origin;
     OriginAccessEntry::MatchResult expected_origin;
     OriginAccessEntry::MatchResult expected_domain;
   } inputs[] = {
@@ -110,20 +85,19 @@
   for (const auto& test : inputs) {
     SCOPED_TRACE(testing::Message()
                  << "Host: " << test.host << ", Origin: " << test.origin);
-    scoped_refptr<const SecurityOrigin> origin_to_test =
-        SecurityOrigin::CreateFromString(test.origin);
+    url::Origin origin_to_test = url::Origin::Create(GURL(test.origin));
     OriginAccessEntry entry1(test.protocol, test.host,
                              OriginAccessEntry::kAllowSubdomains);
-    EXPECT_EQ(test.expected_origin, entry1.MatchesOrigin(*origin_to_test));
-    EXPECT_EQ(test.expected_domain, entry1.MatchesDomain(*origin_to_test));
+    EXPECT_EQ(test.expected_origin, entry1.MatchesOrigin(origin_to_test));
+    EXPECT_EQ(test.expected_domain, entry1.MatchesDomain(origin_to_test));
   }
 }
 
 TEST(OriginAccessEntryTest, AllowRegisterableDomainsTest) {
   struct TestCase {
-    const char* protocol;
-    const char* host;
-    const char* origin;
+    const std::string protocol;
+    const std::string host;
+    const std::string origin;
     OriginAccessEntry::MatchResult expected;
   } inputs[] = {
       {"http", "example.com", "http://example.com/",
@@ -159,23 +133,22 @@
   };
 
   for (const auto& test : inputs) {
-    scoped_refptr<const SecurityOrigin> origin_to_test =
-        SecurityOrigin::CreateFromString(test.origin);
+    url::Origin origin_to_test = url::Origin::Create(GURL(test.origin));
     OriginAccessEntry entry1(test.protocol, test.host,
                              OriginAccessEntry::kAllowRegisterableDomains);
 
     SCOPED_TRACE(testing::Message()
                  << "Host: " << test.host << ", Origin: " << test.origin
-                 << ", Domain: " << entry1.Registerable().Utf8().data());
-    EXPECT_EQ(test.expected, entry1.MatchesOrigin(*origin_to_test));
+                 << ", Domain: " << entry1.registerable_domain());
+    EXPECT_EQ(test.expected, entry1.MatchesOrigin(origin_to_test));
   }
 }
 
 TEST(OriginAccessEntryTest, AllowRegisterableDomainsTestWithDottedSuffix) {
   struct TestCase {
-    const char* protocol;
-    const char* host;
-    const char* origin;
+    const std::string protocol;
+    const std::string host;
+    const std::string origin;
     OriginAccessEntry::MatchResult expected;
   } inputs[] = {
       {"http", "example.appspot.com", "http://example.appspot.com/",
@@ -212,23 +185,22 @@
   };
 
   for (const auto& test : inputs) {
-    scoped_refptr<const SecurityOrigin> origin_to_test =
-        SecurityOrigin::CreateFromString(test.origin);
+    url::Origin origin_to_test = url::Origin::Create(GURL(test.origin));
     OriginAccessEntry entry1(test.protocol, test.host,
                              OriginAccessEntry::kAllowRegisterableDomains);
 
     SCOPED_TRACE(testing::Message()
                  << "Host: " << test.host << ", Origin: " << test.origin
-                 << ", Domain: " << entry1.Registerable().Utf8().data());
-    EXPECT_EQ(test.expected, entry1.MatchesOrigin(*origin_to_test));
+                 << ", Domain: " << entry1.registerable_domain());
+    EXPECT_EQ(test.expected, entry1.MatchesOrigin(origin_to_test));
   }
 }
 
 TEST(OriginAccessEntryTest, DisallowSubdomainsTest) {
   struct TestCase {
-    const char* protocol;
-    const char* host;
-    const char* origin;
+    const std::string protocol;
+    const std::string host;
+    const std::string origin;
     OriginAccessEntry::MatchResult expected;
   } inputs[] = {
       {"http", "example.com", "http://example.com/",
@@ -262,18 +234,17 @@
   for (const auto& test : inputs) {
     SCOPED_TRACE(testing::Message()
                  << "Host: " << test.host << ", Origin: " << test.origin);
-    scoped_refptr<const SecurityOrigin> origin_to_test =
-        SecurityOrigin::CreateFromString(test.origin);
+    url::Origin origin_to_test = url::Origin::Create(GURL(test.origin));
     OriginAccessEntry entry1(test.protocol, test.host,
                              OriginAccessEntry::kDisallowSubdomains);
-    EXPECT_EQ(test.expected, entry1.MatchesOrigin(*origin_to_test));
+    EXPECT_EQ(test.expected, entry1.MatchesOrigin(origin_to_test));
   }
 }
 
 TEST(OriginAccessEntryTest, IPAddressTest) {
   struct TestCase {
-    const char* protocol;
-    const char* host;
+    const std::string protocol;
+    const std::string host;
     bool is_ip_address;
   } inputs[] = {
       {"http", "1.1.1.1", true},
@@ -291,15 +262,15 @@
     SCOPED_TRACE(testing::Message() << "Host: " << test.host);
     OriginAccessEntry entry(test.protocol, test.host,
                             OriginAccessEntry::kDisallowSubdomains);
-    EXPECT_EQ(test.is_ip_address, entry.HostIsIPAddress()) << test.host;
+    EXPECT_EQ(test.is_ip_address, entry.host_is_ip_address()) << test.host;
   }
 }
 
 TEST(OriginAccessEntryTest, IPAddressMatchingTest) {
   struct TestCase {
-    const char* protocol;
-    const char* host;
-    const char* origin;
+    const std::string protocol;
+    const std::string host;
+    const std::string origin;
     OriginAccessEntry::MatchResult expected;
   } inputs[] = {
       {"http", "192.0.0.123", "http://192.0.0.123/",
@@ -315,16 +286,19 @@
   for (const auto& test : inputs) {
     SCOPED_TRACE(testing::Message()
                  << "Host: " << test.host << ", Origin: " << test.origin);
-    scoped_refptr<const SecurityOrigin> origin_to_test =
-        SecurityOrigin::CreateFromString(test.origin);
+    url::Origin origin_to_test = url::Origin::Create(GURL(test.origin));
     OriginAccessEntry entry1(test.protocol, test.host,
                              OriginAccessEntry::kAllowSubdomains);
-    EXPECT_EQ(test.expected, entry1.MatchesOrigin(*origin_to_test));
+    EXPECT_EQ(test.expected, entry1.MatchesOrigin(origin_to_test));
 
     OriginAccessEntry entry2(test.protocol, test.host,
                              OriginAccessEntry::kDisallowSubdomains);
-    EXPECT_EQ(test.expected, entry2.MatchesOrigin(*origin_to_test));
+    EXPECT_EQ(test.expected, entry2.MatchesOrigin(origin_to_test));
   }
 }
 
-}  // namespace blink
+}  // namespace
+
+}  // namespace cors
+
+}  // namespace network
diff --git a/services/network/public/cpp/simple_url_loader.cc b/services/network/public/cpp/simple_url_loader.cc
index 668b0f0..10a89108 100644
--- a/services/network/public/cpp/simple_url_loader.cc
+++ b/services/network/public/cpp/simple_url_loader.cc
@@ -9,6 +9,7 @@
 #include <algorithm>
 
 #include "base/bind.h"
+#include "base/debug/alias.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
@@ -489,6 +490,19 @@
       mojo::ScopedDataPipeConsumerHandle body_data_pipe =
           std::move(body_data_pipe_);
 
+      // TODO(mmenke): Remove this once https://crbug.com/875253 is understood
+      // and fixed.
+      int total_bytes_read = total_bytes_read_;
+      int max_body_size = max_body_size_;
+      base::debug::Alias(&body_data);
+      base::debug::Alias(&max_body_size);
+      base::debug::Alias(&total_bytes_read);
+      base::debug::Alias(&read_size);
+      base::debug::Alias(&copy_size);
+      // This is just to make sure the first byte of body_data is accessible.
+      char first_read_byte = static_cast<const char*>(body_data)[0];
+      base::debug::Alias(&first_read_byte);
+
       // This call may delete the BodyReader.
       net::Error error =
           delegate_->OnDataRead(copy_size, static_cast<const char*>(body_data));
@@ -632,6 +646,11 @@
   // BodyReader::Delegate implementation.
 
   net::Error OnDataRead(uint32_t length, const char* data) override {
+    // TODO(mmenke): Remove this once https://crbug.com/875253 is understood and
+    // fixed.
+    std::string* body = body_.get();
+    base::debug::Alias(&body);
+
     body_->append(data, length);
     ReportProgress(body_reader_->total_bytes_read());
     return net::OK;
diff --git a/services/ui/ime/test_ime_driver/test_ime_driver.cc b/services/ui/ime/test_ime_driver/test_ime_driver.cc
index d7c83d3..59250e6 100644
--- a/services/ui/ime/test_ime_driver/test_ime_driver.cc
+++ b/services/ui/ime/test_ime_driver/test_ime_driver.cc
@@ -20,8 +20,12 @@
 
  private:
   // mojom::InputMethod:
-  void OnTextInputTypeChanged(TextInputType text_input_type) override {}
-  void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) override {}
+  void OnTextInputTypeChanged(TextInputType text_input_type) override {
+    NOTIMPLEMENTED();
+  }
+  void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) override {
+    NOTIMPLEMENTED();
+  }
   void ProcessKeyEvent(std::unique_ptr<Event> key_event,
                        ProcessKeyEventCallback callback) override {
     DCHECK(key_event->IsKeyEvent());
@@ -35,7 +39,8 @@
                        base::Unretained(this), std::move(cloned_event),
                        std::move(callback)));
   }
-  void CancelComposition() override {}
+  void CancelComposition() override { NOTIMPLEMENTED(); }
+  void ShowVirtualKeyboardIfEnabled() override { NOTIMPLEMENTED(); }
 
   void PostProcssKeyEvent(std::unique_ptr<Event> key_event,
                           ProcessKeyEventCallback callback,
diff --git a/services/ui/public/interfaces/ime/ime.mojom b/services/ui/public/interfaces/ime/ime.mojom
index 0157f71..8dfa142 100644
--- a/services/ui/public/interfaces/ime/ime.mojom
+++ b/services/ui/public/interfaces/ime/ime.mojom
@@ -155,6 +155,9 @@
   ProcessKeyEvent(ui.mojom.Event key_event) => (bool handled);
 
   CancelComposition();
+
+  // Plumbs requests to show the virtual keyboard.
+  ShowVirtualKeyboardIfEnabled();
 };
 
 // IME drivers send updates to clients using the TextInputClient interface.
diff --git a/services/viz/public/interfaces/hit_test/input_target_client.mojom b/services/viz/public/interfaces/hit_test/input_target_client.mojom
index 32d4b2c..1ec376a 100644
--- a/services/viz/public/interfaces/hit_test/input_target_client.mojom
+++ b/services/viz/public/interfaces/hit_test/input_target_client.mojom
@@ -1,3 +1,7 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
 module viz.mojom;
 
 import "services/viz/public/interfaces/compositing/frame_sink_id.mojom";
@@ -12,5 +16,8 @@
   // RenderWidget containing the point, which is either the widget that was
   // asked to perform the hit test or an immediately embedded widget (i.e. an
   // out-of-process iframe).
-  FrameSinkIdAt(gfx.mojom.Point point) => (FrameSinkId id);
+  // |local_point| is the point in the coordinate space of the RenderWidget
+  // indicated by the FrameSinkId.
+  FrameSinkIdAt(gfx.mojom.Point point) => (FrameSinkId id,
+                                           gfx.mojom.PointF local_point);
 };
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 154e3e12..aaf70a7 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -365,8 +365,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/floats-do-not-overhang-from-block-formatting-context.html [ Failure ]
 crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/intruding-painted-twice.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/line-break-after-white-space-crash.html [ Pass Crash Timeout ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/negative-margin-on-element-avoiding-floats-with-margin-on-parent.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/negative-margin-on-element-avoiding-floats.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/nopaint-after-layer-destruction.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/nopaint-after-layer-destruction2.html [ Failure ]
 crbug.com/810370 virtual/layout_ng/fast/block/float/overhanging-float-remove-from-fixed-position-block.html [ Failure ]
@@ -401,9 +399,6 @@
 # Maybe a Mac-specific rebaselining issue.
 crbug.com/846557 [ Mac ] virtual/layout_ng_experimental/css3/flexbox/button.html [ Skip ]
 
-### Crash site: ContainerNode.cpp
-crbug.com/714962 virtual/layout_ng/fast/inline/inline-with-empty-inline-children.html [ Crash Failure ]
-
 ### Crash site: layout_ng_block_flow.cc
 crbug.com/714962 virtual/layout_ng/fast/inline/inline-offsetLeft-relpos.html [ Crash Failure ]
 
@@ -414,9 +409,7 @@
 
 ### Image/text failures
 #crbug.com/714962 virtual/layout_ng/fast/inline/001.html [ Failure ]
-crbug.com/714962 virtual/layout_ng/fast/inline/absolute-positioned-block-in-centred-block.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/continuation-outlines-with-layers-2.html [ Failure ]
-crbug.com/714962 virtual/layout_ng/fast/inline/drawStyledEmptyInlinesWithWS.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/emptyInlinesWithinLists.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/inline-box-background-long-image.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/inline-box-background-repeat-x.html [ Failure ]
@@ -427,6 +420,8 @@
 crbug.com/714962 virtual/layout_ng/fast/inline/outline-offset.html [ Failure ]
 crbug.com/714962 [ Mac ] virtual/layout_ng/fast/inline/br-text-decoration.html [ Failure ]
 crbug.com/714962 [ Mac ] virtual/layout_ng/fast/inline/drawStyledEmptyInlines.html [ Failure ]
+crbug.com/714962 [ Mac ] virtual/layout_ng/fast/inline/drawStyledEmptyInlinesWithWS.html [ Failure ]
+
 ### Image/text failures also on LayoutNG
 crbug.com/714962 virtual/layout_ng/fast/inline/absolute-positioned-inline-in-centred-block.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/continuation-outlines-with-layers.html [ Failure ]
@@ -454,13 +449,10 @@
 ### virtual/layout_ng/fast/writing-mode/
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/auto-sizing-orthogonal-flows.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/background-vertical-lr.html [ Failure ]
-crbug.com/714962 virtual/layout_ng/fast/writing-mode/background-vertical-rl.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/basic-vertical-line.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/border-image-vertical-lr.html [ Failure ]
-crbug.com/714962 virtual/layout_ng/fast/writing-mode/border-image-vertical-rl.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/border-radius-clipping-vertical-lr.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/border-styles-vertical-lr.html [ Failure ]
-crbug.com/714962 virtual/layout_ng/fast/writing-mode/border-styles-vertical-rl.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/box-shadow-vertical-lr.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/box-shadow-vertical-rl.html [ Failure ]
 crbug.com/714962 [ Mac ] virtual/layout_ng/fast/writing-mode/broken-ideograph-small-caps.html [ Failure ]
@@ -474,9 +466,6 @@
 crbug.com/714962 [ Mac ] virtual/layout_ng/fast/writing-mode/orthogonal-inline-block.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/orthogonal-writing-modes-available-width-absolute-crash.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/percentage-height-orthogonal-writing-modes.html [ Failure ]
-crbug.com/714962 virtual/layout_ng/fast/writing-mode/text-combine-justify.html [ Failure ]
-crbug.com/714962 virtual/layout_ng/fast/writing-mode/text-combine-line-break.html [ Failure ]
-crbug.com/714962 virtual/layout_ng/fast/writing-mode/text-combine-various-fonts.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/vertical-align-table-baseline.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/vertical-baseline-alignment.html [ Failure ]
 crbug.com/714962 [ Mac ] virtual/layout_ng/fast/writing-mode/vertical-font-fallback.html [ Failure ]
@@ -1930,7 +1919,6 @@
 crbug.com/652964 [ Linux Win ] fast/text/hyphens/midword-break-priority.html [ Skip ]
 
 crbug.com/405389 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-017.html [ Failure ]
-crbug.com/424365 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-010.html [ Failure ]
 crbug.com/424365 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-024.html [ Failure ]
 crbug.com/441840 [ Win ] external/wpt/css/css-shapes/shape-outside/values/shape-margin-001.html [ Failure ]
 crbug.com/441840 external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-004.html [ Failure ]
@@ -2880,7 +2868,6 @@
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-024.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-048.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-026.html [ Failure ]
-crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-020.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-055.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-051.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-037.html [ Failure ]
@@ -2889,7 +2876,6 @@
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-003.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-border-box-border-radius-009.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-008.html [ Failure ]
-crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-021.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-050.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-050.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-border-box-border-radius-012.html [ Failure ]
@@ -2905,8 +2891,6 @@
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-021.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-025.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-027.html [ Failure ]
-crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-022.html [ Failure ]
-crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-020.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-046.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-042.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-039.html [ Failure ]
@@ -2917,7 +2901,6 @@
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-border-box-border-radius-008.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-054.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-border-box-border-radius-004.html [ Failure ]
-crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-048.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-022.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-025.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-border-box-border-radius-007.html [ Failure ]
@@ -3203,7 +3186,6 @@
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/descriptor-symbols.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/system-extends-invalid.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/redefine-builtin.html [ Failure ]
-crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-003v.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-006v.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-fonts/font-variant-06.xht [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-001v.html [ Failure ]
@@ -4983,9 +4965,6 @@
 # Test frequently times out on Mac CQ bots.
 crbug.com/874703 [ Mac ] http/tests/devtools/extensions/extensions-panel.js [ Timeout Pass ]
 
-# This won't pass until the bug fixed.
-crbug.com/875287 fast/frames/crash-frameset-CSS-content-property.html [ Crash ]
-
 # Wake Lock api test timeouts
 crbug.com/872530 external/wpt/wake-lock/wakelock-applicability-manual.https.html [ Pass Timeout ]
 crbug.com/872530 external/wpt/wake-lock/wakelock-document-hidden.https.html [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed.html b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed.html
index 80d0e394..ad49d6f 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed.html
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed.html
@@ -16,7 +16,7 @@
     if (e.type == removalEventType) {
         debug('Removing iframe');
         target.parentNode.removeChild(target);
-        internals.gc();
+        gc();
     }
 }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-gpu-tasks-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-gpu-tasks-expected.txt
deleted file mode 100644
index c4d9058..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-gpu-tasks-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Tests the Timeline events for GPUTask
-
-Found GPUTask events: true
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-gpu-tasks.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-gpu-tasks.js
deleted file mode 100644
index 7b2a7aa..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-gpu-tasks.js
+++ /dev/null
@@ -1,24 +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.
-
-(async function() {
-  TestRunner.addResult(`Tests the Timeline events for GPUTask\n`);
-  await TestRunner.loadModule('performance_test_runner');
-  await TestRunner.showPanel('timeline');
-  await TestRunner.evaluateInPagePromise(`
-      async function performActions() {
-        const gl = document.createElement('canvas').getContext('webgl');
-        return gl.getParameter(gl.MAX_VIEWPORT_DIMS);
-      }
-  `);
-
-  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
-
-  const tracingModel = PerformanceTestRunner.tracingModel();
-  const hasGPUTasks = tracingModel.sortedProcesses().some(p => p.sortedThreads().some(t => t.events().some(
-      event => event.name === TimelineModel.TimelineModel.RecordType.GPUTask)));
-  TestRunner.addResult(`Found GPUTask events: ${hasGPUTasks}`);
-
-  TestRunner.completeTest();
-})();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/tracing-process-filter-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/tracing-process-filter-expected.txt
index 76ab560..6f0712c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/tracing-process-filter-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/tracing-process-filter-expected.txt
@@ -2,5 +2,5 @@
 Recording started
 Another page
 Tracing complete
-There should be just 3 processes (browser, GPU, and renderer): 3
+There should be just 2 processes (browser and renderer): 2
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/tracing-process-filter.js b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/tracing-process-filter.js
index c43f871..f81444e 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/tracing-process-filter.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/tracing-process-filter.js
@@ -16,7 +16,7 @@
   const pids = new Set();
   for (const event of events)
     pids.add(event.pid);
-  testRunner.log(`There should be just 3 processes (browser, GPU, and renderer): ${pids.size}`);
+  testRunner.log(`There should be just 2 processes (browser and renderer): ${pids.size}`);
 
   testRunner.completeTest();
 })
diff --git a/third_party/WebKit/LayoutTests/reporting-observer/intervention.html b/third_party/WebKit/LayoutTests/reporting-observer/intervention.html
index d71074a..8e12d888 100644
--- a/third_party/WebKit/LayoutTests/reporting-observer/intervention.html
+++ b/third_party/WebKit/LayoutTests/reporting-observer/intervention.html
@@ -9,9 +9,12 @@
 
 <script>
 async_test(function(test) {
+  var kInterventionReport = 2531; // From web_feature.mojom.
+
   var observer = new ReportingObserver(function(reports, observer) {
     test.step(function() {
       assert_equals(reports.length, 1);
+      assert_true(internals.isUseCounted(document, kInterventionReport));
 
       // Ensure that the contents of the report are valid.
       assert_equals(reports[0].type, "intervention");
@@ -29,6 +32,7 @@
   });
   observer.observe();
 
+  assert_false(internals.isUseCounted(document, kInterventionReport));
   causeIntervention();
 }, "Intervention report");
 </script>
diff --git a/third_party/WebKit/LayoutTests/reporting-observer/resources/deprecation.js b/third_party/WebKit/LayoutTests/reporting-observer/resources/deprecation.js
index e86b736f..5078e75 100644
--- a/third_party/WebKit/LayoutTests/reporting-observer/resources/deprecation.js
+++ b/third_party/WebKit/LayoutTests/reporting-observer/resources/deprecation.js
@@ -1,7 +1,12 @@
 async_test(function(test) {
+  // UseCounter feature IDs, from web_feature.mojom.
+  var kReportingObserver = 2529;
+  var kDeprecationReport = 2530;
+
   var observer = new ReportingObserver(function(reports, observer) {
     test.step(function() {
       assert_equals(reports.length, 2);
+      assert_true(internals.isUseCounted(document, kDeprecationReport));
 
       // Ensure that the contents of the reports are valid.
       for(let report of reports) {
@@ -21,7 +26,11 @@
 
     test.done();
   });
+  assert_false(internals.isUseCounted(document, kReportingObserver));
   observer.observe();
+  assert_true(internals.isUseCounted(document, kReportingObserver));
+
+  assert_false(internals.isUseCounted(document, kDeprecationReport));
 
   // This ensures that ReportingObserver is traced properly. This will cause the
   // test to fail otherwise.
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/crashes/imperative-api.html b/third_party/WebKit/LayoutTests/shadow-dom/crashes/imperative-api.html
new file mode 100644
index 0000000..3b44667
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/shadow-dom/crashes/imperative-api.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!--
+CrashTests for Imperative Shadow DOM Distribution API.
+See https://crbug.com/869308
+-->
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<div id="host">
+  <div id="child1"></div>
+</div>
+
+<script>
+const host = document.querySelector("#host");
+const child1 = document.querySelector("#child1");
+const shadow_root = host.attachShadow({ mode: "open", slotting: "manual" });
+const slot1 = document.createElement("slot");
+const slot2 = document.createElement("slot");
+shadow_root.appendChild(slot1);
+shadow_root.appendChild(slot2);
+
+test(() => {
+  slot2.assign([child1]);
+  slot1.assign([child1]);
+
+  slot1.remove();
+  slot2.remove();
+}, "slot.remove after slot\'s removal should not crash");
+</script>
diff --git a/third_party/android_async_task/java/src/org/chromium/base/AsyncTask.java b/third_party/android_async_task/java/src/org/chromium/base/AsyncTask.java
index b977e20..31c3601f4 100644
--- a/third_party/android_async_task/java/src/org/chromium/base/AsyncTask.java
+++ b/third_party/android_async_task/java/src/org/chromium/base/AsyncTask.java
@@ -143,7 +143,7 @@
  *     <li>The AsyncTask class must be loaded on the UI thread. This is done
  *     automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li>
  *     <li>The task instance must be created on the UI thread.</li>
- *     <li>{@link #execute} must be invoked on the UI thread.</li>
+ *     <li>{@link #executeOnExecutor(Executor)} must be invoked on the UI thread.</li>
  *     <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
  *     {@link #doInBackground} manually.</li>
  *     <li>The task can be executed only once (an exception will be thrown if
@@ -207,8 +207,6 @@
     private static final int MESSAGE_POST_RESULT = 0x1;
     private static final int MESSAGE_POST_PROGRESS = 0x2;
 
-    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
-
     private static final StealRunnableHandler STEAL_RUNNABLE_HANDLER = new StealRunnableHandler();
 
     private final Callable<Result> mWorker;
@@ -409,9 +407,7 @@
     }
 
     /**
-     * Override this method to perform a computation on a background thread. The
-     * specified parameters are the parameters passed to {@link #execute}
-     * by the caller of this task.
+     * Override this method to perform a computation on a background thread.
      *
      * @return A result, defined by the subclass of this task.
      *
@@ -568,37 +564,6 @@
      * Executes the task with the specified parameters. The task returns
      * itself (this) so that the caller can keep a reference to it.
      *
-     * <p>Note: this function schedules the task on a queue for a single background
-     * thread or pool of threads depending on the platform version.  When first
-     * introduced, AsyncTasks were executed serially on a single background thread.
-     * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
-     * to a pool of threads allowing multiple tasks to operate in parallel. Starting
-     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
-     * executed on a single thread to avoid common application errors caused
-     * by parallel execution.  If you truly want parallel execution, you can use
-     * the {@link #executeOnExecutor} version of this method
-     * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
-     * on its use.
-     *
-     * <p>This method must be invoked on the UI thread.
-     *
-     * @return This instance of AsyncTask.
-     *
-     * @throws IllegalStateException If {@link #getStatus()} returns either
-     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
-     *
-     * @see #executeOnExecutor(java.util.concurrent.Executor)
-     * @see #execute(Runnable)
-     */
-    @MainThread
-    public final AsyncTask<Result> execute() {
-        return executeOnExecutor(sDefaultExecutor);
-    }
-
-    /**
-     * Executes the task with the specified parameters. The task returns
-     * itself (this) so that the caller can keep a reference to it.
-     *
      * <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
      * allow multiple tasks to run in parallel on a pool of threads managed by
      * AsyncTask, however you can also use your own {@link Executor} for custom
@@ -624,8 +589,6 @@
      *
      * @throws IllegalStateException If {@link #getStatus()} returns either
      *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
-     *
-     * @see #execute()
      */
     @SuppressWarnings({"MissingCasesInEnumSwitch"})
     @MainThread
@@ -651,19 +614,6 @@
         return this;
     }
 
-    /**
-     * Convenience version of {@link #execute()} for use with
-     * a simple Runnable object. See {@link #execute()} for more
-     * information on the order of execution.
-     *
-     * @see #execute()
-     * @see #executeOnExecutor(java.util.concurrent.Executor)
-     */
-    @MainThread
-    public static void execute(Runnable runnable) {
-        sDefaultExecutor.execute(runnable);
-    }
-
     private void finish(Result result) {
         if (isCancelled()) {
             onCancelled(result);
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 50d29a0..df91be1c 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -126,6 +126,7 @@
     "platform/linux/web_sandbox_support.h",
     "platform/mac/web_sandbox_support.h",
     "platform/mac/web_scrollbar_theme.h",
+    "platform/modules/background_fetch/web_background_fetch_registration.h",
     "platform/modules/background_fetch/web_background_fetch_settled_fetch.h",
     "platform/modules/indexeddb/web_idb_callbacks.h",
     "platform/modules/indexeddb/web_idb_cursor.h",
diff --git a/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom b/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom
index 550260d..3a4b0b9 100644
--- a/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom
+++ b/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom
@@ -18,7 +18,8 @@
   INVALID_ID,
   STORAGE_ERROR,
   SERVICE_WORKER_UNAVAILABLE,
-  QUOTA_EXCEEDED
+  QUOTA_EXCEEDED,
+  PERMISSION_DENIED
 };
 
 // Struct representing completed Background Fetch requests, along with their
@@ -59,6 +60,7 @@
   uint64 uploaded;
   uint64 download_total;
   uint64 downloaded;
+  BackgroundFetchState state;
 };
 
 interface BackgroundFetchRegistrationObserver {
diff --git a/third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h b/third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h
new file mode 100644
index 0000000..fb8a54d
--- /dev/null
+++ b/third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h
@@ -0,0 +1,46 @@
+// 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_PUBLIC_PLATFORM_MODULES_BACKGROUND_FETCH_WEB_BACKGROUND_FETCH_REGISTRATION_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_BACKGROUND_FETCH_WEB_BACKGROUND_FETCH_REGISTRATION_H_
+
+#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-shared.h"
+#include "third_party/blink/public/platform/web_common.h"
+#include "third_party/blink/public/platform/web_string.h"
+
+namespace blink {
+
+// Represents a BackgroundFetchRegistration object, added mainly for layering.
+// Analogous to the following structure in the spec:
+// https://wicg.github.io/background-fetch/#background-fetch-registration
+struct WebBackgroundFetchRegistration {
+  WebBackgroundFetchRegistration(const WebString& developer_id,
+                                 const WebString& unique_id,
+                                 uint64_t upload_total,
+                                 uint64_t uploaded,
+                                 uint64_t download_total,
+                                 uint64_t downloaded,
+                                 mojom::BackgroundFetchState state)
+      : developer_id(developer_id),
+        unique_id(unique_id),
+        upload_total(upload_total),
+        uploaded(uploaded),
+        download_total(download_total),
+        downloaded(downloaded),
+        state(state) {}
+
+  ~WebBackgroundFetchRegistration() = default;
+
+  WebString developer_id;
+  WebString unique_id;
+  uint64_t upload_total;
+  uint64_t uploaded;
+  uint64_t download_total;
+  uint64_t downloaded;
+  mojom::BackgroundFetchState state;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_BACKGROUND_FETCH_WEB_BACKGROUND_FETCH_REGISTRATION_H_
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index 1beafa7..4f1beb4 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1981,6 +1981,10 @@
   kV8MediaStreamTrack_ContentHint_AttributeGetter = 2525,
   kV8MediaStreamTrack_ContentHint_AttributeSetter = 2526,
   kV8IDBFactory_Open_Method = 2527,
+  kEvaluateScriptMovedBetweenDocuments = 2528,
+  kReportingObserver = 2529,
+  kDeprecationReport = 2530,
+  kInterventionReport = 2531,
 
   // 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/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index e78a4d4..23c12c8 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -150,6 +150,7 @@
       bool);
   BLINK_PLATFORM_EXPORT static void EnableSharedArrayBuffer(bool);
   BLINK_PLATFORM_EXPORT static void EnableSharedWorker(bool);
+  BLINK_PLATFORM_EXPORT static void EnableSignedHTTPExchange(bool);
   BLINK_PLATFORM_EXPORT static void EnableSlimmingPaintV2(bool);
   BLINK_PLATFORM_EXPORT static void EnableTouchEventFeatureDetection(bool);
   BLINK_PLATFORM_EXPORT static void EnableUserActivationV2(bool);
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
index 0d21f81..923f0a2 100644
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
@@ -34,6 +34,7 @@
 #include "base/time/time.h"
 #include "third_party/blink/public/common/message_port/transferable_message.h"
 #include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-shared.h"
+#include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_registration.h"
 #include "third_party/blink/public/platform/web_canonical_cookie.h"
@@ -70,25 +71,17 @@
 
   virtual void DispatchBackgroundFetchAbortEvent(
       int event_id,
-      const WebString& developer_id,
-      const WebString& unique_id,
-      blink::mojom::BackgroundFetchState state) = 0;
+      const WebBackgroundFetchRegistration& registration) = 0;
   virtual void DispatchBackgroundFetchClickEvent(
       int event_id,
-      const WebString& developer_id,
-      const WebString& unique_id,
-      blink::mojom::BackgroundFetchState state) = 0;
+      const WebBackgroundFetchRegistration& registration) = 0;
   virtual void DispatchBackgroundFetchFailEvent(
       int event_id,
-      const WebString& developer_id,
-      const WebString& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const WebBackgroundFetchRegistration& registration,
       const WebVector<WebBackgroundFetchSettledFetch>& fetches) = 0;
   virtual void DispatchBackgroundFetchSuccessEvent(
       int event_id,
-      const WebString& developer_id,
-      const WebString& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const WebBackgroundFetchRegistration& registration,
       const WebVector<WebBackgroundFetchSettledFetch>& fetches) = 0;
   virtual void DispatchCookieChangeEvent(
       int event_id,
diff --git a/third_party/blink/public/web/web_hit_test_result.h b/third_party/blink/public/web/web_hit_test_result.h
index c88ba06..72645e2c 100644
--- a/third_party/blink/public/web/web_hit_test_result.h
+++ b/third_party/blink/public/web/web_hit_test_result.h
@@ -56,6 +56,10 @@
   // Coordinates of the point that was hit. Relative to the node.
   BLINK_EXPORT WebPoint LocalPoint() const;
 
+  // Coordinates of the point that was hit. Relative to the node, but with
+  // ContentBoxOffset removed if the node has box layout.
+  BLINK_EXPORT WebPoint LocalPointWithoutContentBoxOffset() const;
+
   // If a link (eg. anchor or area tag) is hit, return the element.
   // Return null otheriwse.
   BLINK_EXPORT WebElement UrlElement() const;
diff --git a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
index 55f9850..ead42a8 100644
--- a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
+++ b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
@@ -58,10 +58,14 @@
   // the incumbent context which originally schedules the currently-running
   // callback to see whether the script setting is disabled before invoking
   // the callback.
+  // TODO(crbug.com/608641): move IsMainWorld check into
+  // ExecutionContext::CanExecuteScripts()
   return incumbent_execution_context &&
          !incumbent_execution_context->IsContextPaused() &&
          !incumbent_execution_context->IsContextDestroyed() &&
-         incumbent_execution_context->CanExecuteScripts(kAboutToExecuteScript);
+         (!incumbent_script_state->World().IsMainWorld() ||
+          incumbent_execution_context->CanExecuteScripts(
+              kAboutToExecuteScript));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/templates/interface.cpp.tmpl b/third_party/blink/renderer/bindings/templates/interface.cpp.tmpl
index 00aa053..a6844bb 100644
--- a/third_party/blink/renderer/bindings/templates/interface.cpp.tmpl
+++ b/third_party/blink/renderer/bindings/templates/interface.cpp.tmpl
@@ -1045,12 +1045,16 @@
     default:
       NOTREACHED();
   };
+  // TODO(v8:8073): Use specific deallocator per mode once v8 provides information.
   WTF::ArrayBufferContents::DataHandle data(v8Contents.AllocationBase(),
                                             v8Contents.AllocationLength(),
                                             v8Contents.Data(),
                                             v8Contents.ByteLength(),
                                             kind,
-                                            WTF::ArrayBufferContents::FreeMemory);
+                                            [](void* buffer, size_t length, void* alloc_data) {
+                                              WTF::ArrayBufferContents::FreeMemory(buffer);
+                                            },
+                                            nullptr);
   WTF::ArrayBufferContents contents(std::move(data), WTF::ArrayBufferContents::k{% if interface_name == 'ArrayBuffer' %}Not{% endif %}Shared);
   {{cpp_class}}* buffer = {{cpp_class}}::Create(contents);
   v8::Local<v8::Object> associatedWrapper = buffer->AssociateWithWrapper(v8::Isolate::GetCurrent(), buffer->GetWrapperTypeInfo(), object);
diff --git a/third_party/blink/renderer/bindings/templates/methods.cpp.tmpl b/third_party/blink/renderer/bindings/templates/methods.cpp.tmpl
index 8b8f8929..ec8eaaa 100644
--- a/third_party/blink/renderer/bindings/templates/methods.cpp.tmpl
+++ b/third_party/blink/renderer/bindings/templates/methods.cpp.tmpl
@@ -212,6 +212,20 @@
 if (!info[{{argument.index}}]->IsNullOrUndefined()) {
   {{v8_value_to_local_cpp_value(argument) | trim | indent(2)}}
 }
+{% elif argument.idl_type == 'object' %}
+if (info[{{argument.index}}]->IsObject()) {
+  {{v8_value_to_local_cpp_value(argument)}}
+{% if argument.is_nullable %}
+} else if (info[{{argument.index}}]->IsNullOrUndefined()) {
+  {{argument.name}} = ScriptValue(ScriptState::Current(info.GetIsolate()), v8::Null(info.GetIsolate()));
+{% elif argument.is_optional %}
+} else if (info[{{argument.index}}]->IsUndefined()) {
+  {{argument.name}} = ScriptValue(ScriptState::Current(info.GetIsolate()), v8::Undefined(info.GetIsolate()));
+{% endif %}
+} else {
+  {{throw_argument_error(method, argument, "parameter %(index)d ('%(name)s') is not an object.")}}
+  return;
+}
 {% else %}{# argument is something else #}
 {{v8_value_to_local_cpp_value(argument)}}
 {% endif %}{# end of the dispatch by the argument type #}
diff --git a/third_party/blink/renderer/bindings/tests/idls/core/test_interface.idl b/third_party/blink/renderer/bindings/tests/idls/core/test_interface.idl
index 747e0e9..b3262e53 100644
--- a/third_party/blink/renderer/bindings/tests/idls/core/test_interface.idl
+++ b/third_party/blink/renderer/bindings/tests/idls/core/test_interface.idl
@@ -72,6 +72,7 @@
 
     void voidMethodTestInterfaceEmptyArg(TestInterfaceEmpty testInterfaceEmptyArg);
     void voidMethodDoubleArgFloatArg(double doubleArg, float floatArg);
+    void voidMethodNullableAndOptionalObjectArgs(object objectArg, optional object optionalObjectArg, object? nullableObjectArg);
     void voidMethodUnrestrictedDoubleArgUnrestrictedFloatArg(unrestricted double unrestrictedDoubleArg, unrestricted float unrestrictedFloatArg);
     void voidMethodTestEnumArg(TestEnum testEnumArg);
     [PerWorldBindings] void voidMethod();
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_array_buffer.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_array_buffer.cc
index f9eab4d..aeec0af 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_array_buffer.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_array_buffer.cc
@@ -87,12 +87,16 @@
     default:
       NOTREACHED();
   };
+  // TODO(v8:8073): Use specific deallocator per mode once v8 provides information.
   WTF::ArrayBufferContents::DataHandle data(v8Contents.AllocationBase(),
                                             v8Contents.AllocationLength(),
                                             v8Contents.Data(),
                                             v8Contents.ByteLength(),
                                             kind,
-                                            WTF::ArrayBufferContents::FreeMemory);
+                                            [](void* buffer, size_t length, void* alloc_data) {
+                                              WTF::ArrayBufferContents::FreeMemory(buffer);
+                                            },
+                                            nullptr);
   WTF::ArrayBufferContents contents(std::move(data), WTF::ArrayBufferContents::kNotShared);
   TestArrayBuffer* buffer = TestArrayBuffer::Create(contents);
   v8::Local<v8::Object> associatedWrapper = buffer->AssociateWithWrapper(v8::Isolate::GetCurrent(), buffer->GetWrapperTypeInfo(), object);
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.cc
index e1b3c85..67da698 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.cc
@@ -1555,6 +1555,55 @@
   impl->voidMethodDoubleArgFloatArg(doubleArg, floatArg);
 }
 
+static void voidMethodNullableAndOptionalObjectArgsMethod(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  TestInterfaceImplementation* impl = V8TestInterface::ToImpl(info.Holder());
+
+  if (UNLIKELY(info.Length() < 2)) {
+    V8ThrowException::ThrowTypeError(info.GetIsolate(), ExceptionMessages::FailedToExecute("voidMethodNullableAndOptionalObjectArgs", "TestInterface", ExceptionMessages::NotEnoughArguments(2, info.Length())));
+    return;
+  }
+
+  ScriptValue objectArg;
+  ScriptValue optionalObjectArg;
+  ScriptValue nullableObjectArg;
+  int numArgsPassed = info.Length();
+  while (numArgsPassed > 0) {
+    if (!info[numArgsPassed - 1]->IsUndefined())
+      break;
+    --numArgsPassed;
+  }
+  if (info[0]->IsObject()) {
+    objectArg = ScriptValue(ScriptState::Current(info.GetIsolate()), info[0]);
+  } else {
+    V8ThrowException::ThrowTypeError(info.GetIsolate(), ExceptionMessages::FailedToExecute("voidMethodNullableAndOptionalObjectArgs", "TestInterface", "parameter 1 ('objectArg') is not an object."));
+    return;
+  }
+
+  if (UNLIKELY(numArgsPassed <= 1)) {
+    impl->voidMethodNullableAndOptionalObjectArgs(objectArg);
+    return;
+  }
+  if (info[1]->IsObject()) {
+    optionalObjectArg = ScriptValue(ScriptState::Current(info.GetIsolate()), info[1]);
+  } else if (info[1]->IsUndefined()) {
+    optionalObjectArg = ScriptValue(ScriptState::Current(info.GetIsolate()), v8::Undefined(info.GetIsolate()));
+  } else {
+    V8ThrowException::ThrowTypeError(info.GetIsolate(), ExceptionMessages::FailedToExecute("voidMethodNullableAndOptionalObjectArgs", "TestInterface", "parameter 2 ('optionalObjectArg') is not an object."));
+    return;
+  }
+
+  if (info[2]->IsObject()) {
+    nullableObjectArg = ScriptValue(ScriptState::Current(info.GetIsolate()), info[2]);
+  } else if (info[2]->IsNullOrUndefined()) {
+    nullableObjectArg = ScriptValue(ScriptState::Current(info.GetIsolate()), v8::Null(info.GetIsolate()));
+  } else {
+    V8ThrowException::ThrowTypeError(info.GetIsolate(), ExceptionMessages::FailedToExecute("voidMethodNullableAndOptionalObjectArgs", "TestInterface", "parameter 3 ('nullableObjectArg') is not an object."));
+    return;
+  }
+
+  impl->voidMethodNullableAndOptionalObjectArgs(objectArg, optionalObjectArg, nullableObjectArg);
+}
+
 static void voidMethodUnrestrictedDoubleArgUnrestrictedFloatArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) {
   ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext, "TestInterface", "voidMethodUnrestrictedDoubleArgUnrestrictedFloatArg");
 
@@ -3202,6 +3251,12 @@
   TestInterfaceImplementationV8Internal::voidMethodDoubleArgFloatArgMethod(info);
 }
 
+void V8TestInterface::voidMethodNullableAndOptionalObjectArgsMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestInterfaceImplementation_voidMethodNullableAndOptionalObjectArgs");
+
+  TestInterfaceImplementationV8Internal::voidMethodNullableAndOptionalObjectArgsMethod(info);
+}
+
 void V8TestInterface::voidMethodUnrestrictedDoubleArgUnrestrictedFloatArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
   RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestInterfaceImplementation_voidMethodUnrestrictedDoubleArgUnrestrictedFloatArg");
 
@@ -3677,6 +3732,7 @@
 static const V8DOMConfiguration::MethodConfiguration V8TestInterfaceMethods[] = {
     {"voidMethodTestInterfaceEmptyArg", V8TestInterface::voidMethodTestInterfaceEmptyArgMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds},
     {"voidMethodDoubleArgFloatArg", V8TestInterface::voidMethodDoubleArgFloatArgMethodCallback, 2, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds},
+    {"voidMethodNullableAndOptionalObjectArgs", V8TestInterface::voidMethodNullableAndOptionalObjectArgsMethodCallback, 2, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds},
     {"voidMethodUnrestrictedDoubleArgUnrestrictedFloatArg", V8TestInterface::voidMethodUnrestrictedDoubleArgUnrestrictedFloatArgMethodCallback, 2, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds},
     {"voidMethodTestEnumArg", V8TestInterface::voidMethodTestEnumArgMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds},
     {"voidMethod", V8TestInterface::voidMethodMethodCallbackForMainWorld, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kMainWorld},
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.h b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.h
index e3ac903..4d87362 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.h
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.h
@@ -179,6 +179,7 @@
 
   CORE_EXPORT static void voidMethodTestInterfaceEmptyArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
   CORE_EXPORT static void voidMethodDoubleArgFloatArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
+  CORE_EXPORT static void voidMethodNullableAndOptionalObjectArgsMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
   CORE_EXPORT static void voidMethodUnrestrictedDoubleArgUnrestrictedFloatArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
   CORE_EXPORT static void voidMethodTestEnumArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
   CORE_EXPORT static void voidMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 5913d45..40226dd 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -32,6 +32,7 @@
 #include <memory>
 
 #include "base/auto_reset.h"
+#include "base/optional.h"
 #include "services/metrics/public/cpp/mojo_ukm_recorder.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
@@ -5059,7 +5060,7 @@
   if (!access_entry_from_url_) {
     access_entry_from_url_ = std::make_unique<OriginAccessEntry>(
         Url().Protocol(), Url().Host(),
-        OriginAccessEntry::kAllowRegisterableDomains);
+        network::cors::OriginAccessEntry::kAllowRegisterableDomains);
   }
   return *access_entry_from_url_;
 }
@@ -5347,17 +5348,19 @@
   // string "null". https://crbug.com/733150
   if (!RuntimeEnabledFeatures::NullableDocumentDomainEnabled() ||
       new_domain != "null") {
-    OriginAccessEntry access_entry(GetSecurityOrigin()->Protocol(), new_domain,
-                                   OriginAccessEntry::kAllowSubdomains);
-    OriginAccessEntry::MatchResult result =
+    OriginAccessEntry access_entry(
+        GetSecurityOrigin()->Protocol(), new_domain,
+        network::cors::OriginAccessEntry::kAllowSubdomains);
+    network::cors::OriginAccessEntry::MatchResult result =
         access_entry.MatchesOrigin(*GetSecurityOrigin());
-    if (result == OriginAccessEntry::kDoesNotMatchOrigin) {
+    if (result == network::cors::OriginAccessEntry::kDoesNotMatchOrigin) {
       exception_state.ThrowSecurityError(
           "'" + new_domain + "' is not a suffix of '" + domain() + "'.");
       return;
     }
 
-    if (result == OriginAccessEntry::kMatchesOriginButIsPublicSuffix) {
+    if (result ==
+        network::cors::OriginAccessEntry::kMatchesOriginButIsPublicSuffix) {
       exception_state.ThrowSecurityError("'" + new_domain +
                                          "' is a top-level domain.");
       return;
@@ -5442,12 +5445,16 @@
   // document's SecurityOrigin. A sandboxed document has a unique opaque
   // origin, but that shouldn't affect first-/third-party status for cookies
   // and site data.
+  base::Optional<OriginAccessEntry> remote_entry;
+  if (!top.IsLocalFrame()) {
+    remote_entry.emplace(
+        top_document_url.Protocol(), top_document_url.Host(),
+        network::cors::OriginAccessEntry::kAllowRegisterableDomains);
+  }
   const OriginAccessEntry& access_entry =
-      top.IsLocalFrame()
-          ? ToLocalFrame(top).GetDocument()->AccessEntryFromURL()
-          : OriginAccessEntry(top_document_url.Protocol(),
-                              top_document_url.Host(),
-                              OriginAccessEntry::kAllowRegisterableDomains);
+      remote_entry ? *remote_entry
+                   : ToLocalFrame(top).GetDocument()->AccessEntryFromURL();
+
   const Frame* current_frame = GetFrame();
   while (current_frame) {
     // Skip over srcdoc documents, as they are always same-origin with their
@@ -5458,11 +5465,10 @@
     DCHECK(current_frame);
 
     // We use 'matchesDomain' here, as it turns out that some folks embed HTTPS
-    // login forms
-    // into HTTP pages; we should allow this kind of upgrade.
+    // login forms into HTTP pages; we should allow this kind of upgrade.
     if (access_entry.MatchesDomain(
             *current_frame->GetSecurityContext()->GetSecurityOrigin()) ==
-        OriginAccessEntry::kDoesNotMatchOrigin)
+        network::cors::OriginAccessEntry::kDoesNotMatchOrigin)
       return SecurityOrigin::UrlWithUniqueOpaqueOrigin();
 
     current_frame = current_frame->Tree().Parent();
diff --git a/third_party/blink/renderer/core/exported/web_hit_test_result.cc b/third_party/blink/renderer/core/exported/web_hit_test_result.cc
index c13ddd7..763fb423 100644
--- a/third_party/blink/renderer/core/exported/web_hit_test_result.cc
+++ b/third_party/blink/renderer/core/exported/web_hit_test_result.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/node.h"
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
+#include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 
 namespace blink {
@@ -77,6 +78,16 @@
   return RoundedIntPoint(private_->Result().LocalPoint());
 }
 
+WebPoint WebHitTestResult::LocalPointWithoutContentBoxOffset() const {
+  IntPoint local_point = RoundedIntPoint(private_->Result().LocalPoint());
+  LayoutObject* object = private_->Result().GetLayoutObject();
+  if (object->IsBox()) {
+    LayoutBox* box = ToLayoutBox(object);
+    local_point.Move(-RoundedIntSize(box->ContentBoxOffset()));
+  }
+  return local_point;
+}
+
 WebElement WebHitTestResult::UrlElement() const {
   return WebElement(private_->Result().URLElement());
 }
diff --git a/third_party/blink/renderer/core/fetch/data_consumer_handle_test_util.cc b/third_party/blink/renderer/core/fetch/data_consumer_handle_test_util.cc
index 45fc96c..808341e 100644
--- a/third_party/blink/renderer/core/fetch/data_consumer_handle_test_util.cc
+++ b/third_party/blink/renderer/core/fetch/data_consumer_handle_test_util.cc
@@ -61,7 +61,8 @@
   DCHECK(thread_->IsCurrentThread());
   if (initialization_policy_ >= kScriptExecution) {
     isolate_holder_ = std::make_unique<gin::IsolateHolder>(
-        scheduler::GetSingleThreadTaskRunnerForTesting());
+        scheduler::GetSingleThreadTaskRunnerForTesting(),
+        gin::IsolateHolder::IsolateType::kTest);
     GetIsolate()->Enter();
   }
   thread_->InitializeOnThread();
diff --git a/third_party/blink/renderer/core/frame/link_highlights.cc b/third_party/blink/renderer/core/frame/link_highlights.cc
index 1f1bc64..1f4cc617 100644
--- a/third_party/blink/renderer/core/frame/link_highlights.cc
+++ b/third_party/blink/renderer/core/frame/link_highlights.cc
@@ -58,7 +58,7 @@
       continue;
 
     Color highlight_color =
-        node->GetLayoutObject()->Style()->TapHighlightColor();
+        node->GetLayoutObject()->StyleRef().TapHighlightColor();
     // Safari documentation for -webkit-tap-highlight-color says if the
     // specified color has 0 alpha, then tap highlighting is disabled.
     // http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safaricssref/articles/standardcssproperties.html
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 3ea304f..7e427825 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -888,7 +888,7 @@
         if (first_layout_) {
           first_layout_ = false;
           last_viewport_size_ = GetLayoutSize();
-          last_zoom_factor_ = GetLayoutView()->Style()->Zoom();
+          last_zoom_factor_ = GetLayoutView()->StyleRef().Zoom();
 
           ScrollbarMode h_mode;
           ScrollbarMode v_mode;
@@ -1264,7 +1264,7 @@
 
   if (GetLayoutView() && frame_->IsMainFrame() &&
       frame_->GetPage()->GetBrowserControls().TotalHeight()) {
-    if (GetLayoutView()->Style()->HasFixedBackgroundImage()) {
+    if (GetLayoutView()->StyleRef().HasFixedBackgroundImage()) {
       // We've already issued a full invalidation above.
       GetLayoutView()->SetShouldDoFullPaintInvalidationOnResizeIfNeeded(
           width_changed, height_changed);
@@ -1380,8 +1380,8 @@
   for (auto* const viewport_constrained_object :
        *viewport_constrained_objects_) {
     LayoutObject* layout_object = viewport_constrained_object;
-    DCHECK(layout_object->Style()->HasViewportConstrainedPosition() ||
-           layout_object->Style()->HasStickyConstrainedPosition());
+    DCHECK(layout_object->StyleRef().HasViewportConstrainedPosition() ||
+           layout_object->StyleRef().HasStickyConstrainedPosition());
     DCHECK(layout_object->HasLayer());
     PaintLayer* layer = ToLayoutBoxModelObject(layout_object)->Layer();
 
@@ -3055,12 +3055,12 @@
   // Dumping externalRepresentation(m_frame->layoutObject()).ascii() is a good
   // trick to see the state of things before and after the layout
   if (LayoutView* layout_view = this->GetLayoutView()) {
-    float page_logical_width = layout_view->Style()->IsHorizontalWritingMode()
+    float page_logical_width = layout_view->StyleRef().IsHorizontalWritingMode()
                                    ? page_size.Width()
                                    : page_size.Height();
-    float page_logical_height = layout_view->Style()->IsHorizontalWritingMode()
-                                    ? page_size.Height()
-                                    : page_size.Width();
+    float page_logical_height =
+        layout_view->StyleRef().IsHorizontalWritingMode() ? page_size.Height()
+                                                          : page_size.Width();
 
     LayoutUnit floored_page_logical_width =
         static_cast<LayoutUnit>(page_logical_width);
@@ -3078,7 +3078,7 @@
     // FIXME: We are assuming a shrink-to-fit printing implementation.  A
     // cropping implementation should not do this!
     bool horizontal_writing_mode =
-        layout_view->Style()->IsHorizontalWritingMode();
+        layout_view->StyleRef().IsHorizontalWritingMode();
     const LayoutRect& document_rect = LayoutRect(layout_view->DocumentRect());
     LayoutUnit doc_logical_width = horizontal_writing_mode
                                        ? document_rect.Width()
@@ -3118,7 +3118,7 @@
                                          ? updated_document_rect.MaxX()
                                          : updated_document_rect.MaxY();
       LayoutUnit clipped_logical_left;
-      if (!layout_view->Style()->IsLeftToRightDirection()) {
+      if (!layout_view->StyleRef().IsLeftToRightDirection()) {
         clipped_logical_left =
             LayoutUnit(doc_logical_right - page_logical_width);
       }
@@ -4239,8 +4239,8 @@
     return false;
   for (const LayoutObject* layout_object : *ViewportConstrainedObjects()) {
     DCHECK(layout_object->IsBoxModelObject() && layout_object->HasLayer());
-    DCHECK(layout_object->Style()->GetPosition() == EPosition::kFixed ||
-           layout_object->Style()->GetPosition() == EPosition::kSticky);
+    DCHECK(layout_object->StyleRef().GetPosition() == EPosition::kFixed ||
+           layout_object->StyleRef().GetPosition() == EPosition::kSticky);
     if (ToLayoutBoxModelObject(layout_object)->IsSlowRepaintConstrainedObject())
       return true;
   }
@@ -4310,7 +4310,7 @@
   // smooth-scroll animations.  For this reason, we use HasOverflow instead of
   // ScrollsOverflow (which is false for overflow: hidden).
   if (LayoutViewport()->HasOverflow() &&
-      GetLayoutView()->Style()->VisibleToHitTesting() &&
+      GetLayoutView()->StyleRef().VisibleToHitTesting() &&
       HasVisibleSlowRepaintViewportConstrainedObjects()) {
     reasons |=
         MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects;
diff --git a/third_party/blink/renderer/core/frame/reporting_context.cc b/third_party/blink/renderer/core/frame/reporting_context.cc
index b8c64581..549ab18 100644
--- a/third_party/blink/renderer/core/frame/reporting_context.cc
+++ b/third_party/blink/renderer/core/frame/reporting_context.cc
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/report.h"
 #include "third_party/blink/renderer/core/frame/reporting_observer.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 
 namespace blink {
@@ -31,10 +32,11 @@
 }
 
 void ReportingContext::QueueReport(Report* report) {
+  CountReport(report);
   report_buffer_.insert(report);
 
   // Only the most recent 100 reports will remain buffered.
-  // https://wicg.github.io/reporting/#notify-observers
+  // https://w3c.github.io/reporting/#notify-observers
   if (report_buffer_.size() > 100)
     report_buffer_.RemoveFirst();
 
@@ -42,7 +44,25 @@
     observer->QueueReport(report);
 }
 
+void ReportingContext::CountReport(Report* report) {
+  const String& type = report->type();
+  WebFeature feature;
+
+  if (type == "deprecation") {
+    feature = WebFeature::kDeprecationReport;
+  } else if (type == "intervention") {
+    feature = WebFeature::kInterventionReport;
+  } else {
+    NOTREACHED();
+    return;
+  }
+
+  UseCounter::Count(execution_context_, feature);
+}
+
 void ReportingContext::RegisterObserver(ReportingObserver* observer) {
+  UseCounter::Count(execution_context_, WebFeature::kReportingObserver);
+
   observers_.insert(observer);
   if (!observer->Buffered())
     return;
diff --git a/third_party/blink/renderer/core/frame/reporting_context.h b/third_party/blink/renderer/core/frame/reporting_context.h
index f75fbdef8..c60b9d77 100644
--- a/third_party/blink/renderer/core/frame/reporting_context.h
+++ b/third_party/blink/renderer/core/frame/reporting_context.h
@@ -33,6 +33,9 @@
   // Queues a report in all registered observers.
   void QueueReport(Report*);
 
+  // Counts the use of a report type via UseCounter.
+  void CountReport(Report*);
+
   void RegisterObserver(ReportingObserver*);
   void UnregisterObserver(ReportingObserver*);
 
diff --git a/third_party/blink/renderer/core/frame/root_frame_viewport.cc b/third_party/blink/renderer/core/frame/root_frame_viewport.cc
index 171d036..7292b06 100644
--- a/third_party/blink/renderer/core/frame/root_frame_viewport.cc
+++ b/third_party/blink/renderer/core/frame/root_frame_viewport.cc
@@ -297,9 +297,9 @@
     if (params.is_for_scroll_sequence) {
       DCHECK(params.GetScrollType() == kProgrammaticScroll ||
              params.GetScrollType() == kUserScroll);
-      ScrollBehavior behavior =
-          DetermineScrollBehavior(params.GetScrollBehavior(),
-                                  GetLayoutBox()->Style()->GetScrollBehavior());
+      ScrollBehavior behavior = DetermineScrollBehavior(
+          params.GetScrollBehavior(),
+          GetLayoutBox()->StyleRef().GetScrollBehavior());
       GetSmoothScrollSequencer()->QueueAnimation(this, new_scroll_offset,
                                                  behavior);
     } else {
diff --git a/third_party/blink/renderer/core/frame/smart_clip.cc b/third_party/blink/renderer/core/frame/smart_clip.cc
index b0887aa..60a0b403 100644
--- a/third_party/blink/renderer/core/frame/smart_clip.cc
+++ b/third_party/blink/renderer/core/frame/smart_clip.cc
@@ -173,7 +173,7 @@
     if (layout_object && !node_rect.IsEmpty()) {
       if (layout_object->IsText() || layout_object->IsLayoutImage() ||
           node->IsFrameOwnerElement() ||
-          (layout_object->Style()->HasBackgroundImage() &&
+          (layout_object->StyleRef().HasBackgroundImage() &&
            !ShouldSkipBackgroundImage(node))) {
         if (resized_crop_rect.Intersects(node_rect)) {
           min_node = MinNodeContainsNodes(min_node, node);
@@ -203,8 +203,8 @@
   // or a width. On the other hand, if we've got a legit background image,
   // it's very likely the height or the width will be set to auto.
   LayoutObject* layout_object = node->GetLayoutObject();
-  if (layout_object && (layout_object->Style()->LogicalHeight().IsAuto() ||
-                        layout_object->Style()->LogicalWidth().IsAuto()))
+  if (layout_object && (layout_object->StyleRef().LogicalHeight().IsAuto() ||
+                        layout_object->StyleRef().LogicalWidth().IsAuto()))
     return true;
 
   return false;
diff --git a/third_party/blink/renderer/core/layout/api/line_layout_item.h b/third_party/blink/renderer/core/layout/api/line_layout_item.h
index fcc3467..d4d92293 100644
--- a/third_party/blink/renderer/core/layout/api/line_layout_item.h
+++ b/third_party/blink/renderer/core/layout/api/line_layout_item.h
@@ -121,7 +121,7 @@
     if (IsSVGInlineText())
       return false;
 
-    return Style()->PreserveNewline();
+    return StyleRef().PreserveNewline();
   }
 
   unsigned length() const { return layout_object_->length(); }
diff --git a/third_party/blink/renderer/core/layout/bidi_run_for_line.cc b/third_party/blink/renderer/core/layout/bidi_run_for_line.cc
index 59a9901..d304a550 100644
--- a/third_party/blink/renderer/core/layout/bidi_run_for_line.cc
+++ b/third_party/blink/renderer/core/layout/bidi_run_for_line.cc
@@ -83,8 +83,8 @@
   InlineIterator iter(LineLayoutItem(root), first_layout_object,
                       first_layout_object == current ? pos : 0);
   InlineBidiResolver observer;
-  observer.SetStatus(BidiStatus(root.Style()->Direction(),
-                                IsOverride(root.Style()->GetUnicodeBidi())));
+  observer.SetStatus(BidiStatus(root.StyleRef().Direction(),
+                                IsOverride(root.StyleRef().GetUnicodeBidi())));
   observer.SetPositionIgnoringNestedIsolates(iter);
   return observer.DetermineParagraphDirectionality();
 }
@@ -138,7 +138,7 @@
         isolated_resolver.GetMidpointState();
     isolated_line_midpoint_state =
         top_resolver.MidpointStateForIsolatedRun(isolated_run.run_to_replace);
-    UnicodeBidi unicode_bidi = isolated_inline.Style()->GetUnicodeBidi();
+    UnicodeBidi unicode_bidi = isolated_inline.StyleRef().GetUnicodeBidi();
     TextDirection direction;
     if (unicode_bidi == UnicodeBidi::kPlaintext) {
       direction = DeterminePlaintextDirectionality(
@@ -146,7 +146,7 @@
     } else {
       DCHECK(unicode_bidi == UnicodeBidi::kIsolate ||
              unicode_bidi == UnicodeBidi::kIsolateOverride);
-      direction = isolated_inline.Style()->Direction();
+      direction = isolated_inline.StyleRef().Direction();
     }
     isolated_resolver.SetStatus(BidiStatus::CreateForIsolate(
         direction, IsOverride(unicode_bidi), isolated_run.level));
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index 50501fd..f070bde 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -111,11 +111,11 @@
 
 bool FlexItem::HasAutoMarginsInCrossAxis() const {
   if (algorithm->IsHorizontalFlow()) {
-    return box->Style()->MarginTop().IsAuto() ||
-           box->Style()->MarginBottom().IsAuto();
+    return box->StyleRef().MarginTop().IsAuto() ||
+           box->StyleRef().MarginBottom().IsAuto();
   }
-  return box->Style()->MarginLeft().IsAuto() ||
-         box->Style()->MarginRight().IsAuto();
+  return box->StyleRef().MarginLeft().IsAuto() ||
+         box->StyleRef().MarginRight().IsAuto();
 }
 
 ItemPosition FlexItem::Alignment() const {
@@ -127,14 +127,14 @@
   DCHECK_GE(auto_margin_offset, LayoutUnit());
 
   if (algorithm->IsHorizontalFlow()) {
-    if (box->Style()->MarginLeft().IsAuto())
+    if (box->StyleRef().MarginLeft().IsAuto())
       box->SetMarginLeft(auto_margin_offset);
-    if (box->Style()->MarginRight().IsAuto())
+    if (box->StyleRef().MarginRight().IsAuto())
       box->SetMarginRight(auto_margin_offset);
   } else {
-    if (box->Style()->MarginTop().IsAuto())
+    if (box->StyleRef().MarginTop().IsAuto())
       box->SetMarginTop(auto_margin_offset);
-    if (box->Style()->MarginBottom().IsAuto())
+    if (box->StyleRef().MarginBottom().IsAuto())
       box->SetMarginBottom(auto_margin_offset);
   }
 }
@@ -145,10 +145,10 @@
     LayoutBox* child = violations[i]->box;
     LayoutUnit child_size = violations[i]->flexed_content_size;
     remaining_free_space -= child_size - violations[i]->flex_base_content_size;
-    total_flex_grow -= child->Style()->FlexGrow();
-    total_flex_shrink -= child->Style()->FlexShrink();
+    total_flex_grow -= child->StyleRef().FlexGrow();
+    total_flex_shrink -= child->StyleRef().FlexShrink();
     total_weighted_flex_shrink -=
-        child->Style()->FlexShrink() * violations[i]->flex_base_content_size;
+        child->StyleRef().FlexShrink() * violations[i]->flex_base_content_size;
     // totalWeightedFlexShrink can be negative when we exceed the precision of
     // a double when we initially calcuate totalWeightedFlexShrink. We then
     // subtract each child's weighted flex shrink with full precision, now
@@ -173,8 +173,8 @@
     DCHECK(!flex_item.box->IsOutOfFlowPositioned());
     DCHECK(!flex_item.frozen) << i;
     float flex_factor = (flex_sign == kPositiveFlexibility)
-                            ? child->Style()->FlexGrow()
-                            : child->Style()->FlexShrink();
+                            ? child->StyleRef().FlexGrow()
+                            : child->StyleRef().FlexShrink();
     if (flex_factor == 0 ||
         (flex_sign == kPositiveFlexibility &&
          flex_item.flex_base_content_size >
@@ -218,12 +218,12 @@
     if (remaining_free_space > 0 && total_flex_grow > 0 &&
         flex_sign == kPositiveFlexibility && std::isfinite(total_flex_grow)) {
       extra_space =
-          remaining_free_space * child->Style()->FlexGrow() / total_flex_grow;
+          remaining_free_space * child->StyleRef().FlexGrow() / total_flex_grow;
     } else if (remaining_free_space < 0 && total_weighted_flex_shrink > 0 &&
                flex_sign == kNegativeFlexibility &&
                std::isfinite(total_weighted_flex_shrink) &&
-               child->Style()->FlexShrink()) {
-      extra_space = remaining_free_space * child->Style()->FlexShrink() *
+               child->StyleRef().FlexShrink()) {
+      extra_space = remaining_free_space * child->StyleRef().FlexShrink() *
                     flex_item.flex_base_content_size /
                     total_weighted_flex_shrink;
     }
@@ -262,14 +262,14 @@
     LayoutBox* child = line_items[i].box;
     DCHECK(!child->IsOutOfFlowPositioned());
     if (is_horizontal) {
-      if (child->Style()->MarginLeft().IsAuto())
+      if (child->StyleRef().MarginLeft().IsAuto())
         ++number_of_auto_margins;
-      if (child->Style()->MarginRight().IsAuto())
+      if (child->StyleRef().MarginRight().IsAuto())
         ++number_of_auto_margins;
     } else {
-      if (child->Style()->MarginTop().IsAuto())
+      if (child->StyleRef().MarginTop().IsAuto())
         ++number_of_auto_margins;
-      if (child->Style()->MarginBottom().IsAuto())
+      if (child->StyleRef().MarginBottom().IsAuto())
         ++number_of_auto_margins;
     }
   }
@@ -302,7 +302,7 @@
       available_free_space, justify_content, line_items.size());
   LayoutUnit max_descent;  // Used when align-items: baseline.
   LayoutUnit max_child_cross_axis_extent;
-  bool should_flip_main_axis = !algorithm->Style()->IsColumnFlexDirection() &&
+  bool should_flip_main_axis = !algorithm->StyleRef().IsColumnFlexDirection() &&
                                !algorithm->IsLeftToRightFlow();
   for (size_t i = 0; i < line_items.size(); ++i) {
     FlexItem& flex_item = line_items[i];
@@ -392,10 +392,10 @@
     line_items.push_back(flex_item);
     line_has_in_flow_item = true;
     sum_flex_base_size += flex_item.FlexBaseMarginBoxSize();
-    total_flex_grow += flex_item.box->Style()->FlexGrow();
-    total_flex_shrink += flex_item.box->Style()->FlexShrink();
-    total_weighted_flex_shrink +=
-        flex_item.box->Style()->FlexShrink() * flex_item.flex_base_content_size;
+    total_flex_grow += flex_item.box->StyleRef().FlexGrow();
+    total_flex_shrink += flex_item.box->StyleRef().FlexShrink();
+    total_weighted_flex_shrink += flex_item.box->StyleRef().FlexShrink() *
+                                  flex_item.flex_base_content_size;
     sum_hypothetical_main_size += flex_item.HypotheticalMainAxisMarginBoxSize();
   }
   DCHECK(line_items.size() > 0 || next_item_index_ == all_items_.size());
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
index f7aae55..ea5bf0f 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
@@ -242,6 +242,7 @@
                       Vector<FlexItem>& all_items);
 
   const ComputedStyle* Style() const { return style_; }
+  const ComputedStyle& StyleRef() const { return *style_; }
 
   Vector<FlexLine>& FlexLines() { return flex_lines_; }
 
diff --git a/third_party/blink/renderer/core/layout/floating_objects.cc b/third_party/blink/renderer/core/layout/floating_objects.cc
index 9e58504..befe3dd 100644
--- a/third_party/blink/renderer/core/layout/floating_objects.cc
+++ b/third_party/blink/renderer/core/layout/floating_objects.cc
@@ -59,7 +59,7 @@
       is_in_placed_tree_(false)
 #endif
 {
-  EFloat type = layout_object->Style()->Floating();
+  EFloat type = layout_object->StyleRef().Floating();
   DCHECK_NE(type, EFloat::kNone);
   if (type == EFloat::kLeft)
     type_ = kFloatLeft;
diff --git a/third_party/blink/renderer/core/layout/hit_test_result.cc b/third_party/blink/renderer/core/layout/hit_test_result.cc
index e930b724..b9b95b5 100644
--- a/third_party/blink/renderer/core/layout/hit_test_result.cc
+++ b/third_party/blink/renderer/core/layout/hit_test_result.cc
@@ -238,7 +238,7 @@
       String title = ToElement(title_node)->title();
       if (!title.IsNull()) {
         if (LayoutObject* layout_object = title_node->GetLayoutObject())
-          dir = layout_object->Style()->Direction();
+          dir = layout_object->StyleRef().Direction();
         return title;
       }
     }
diff --git a/third_party/blink/renderer/core/layout/layout_analyzer.cc b/third_party/blink/renderer/core/layout/layout_analyzer.cc
index e5b6ef7..92ae9e1b 100644
--- a/third_party/blink/renderer/core/layout/layout_analyzer.cc
+++ b/third_party/blink/renderer/core/layout/layout_analyzer.cc
@@ -68,7 +68,7 @@
     Increment(kLayoutObjectsThatAreTableCells);
   if (o.IsFloating())
     Increment(kLayoutObjectsThatAreFloating);
-  if (o.Style()->SpecifiesColumns())
+  if (o.StyleRef().SpecifiesColumns())
     Increment(kLayoutObjectsThatSpecifyColumns);
   if (o.HasLayer())
     Increment(kLayoutObjectsThatHaveALayer);
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index 252aef8..75b3e60 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -463,7 +463,7 @@
   // if we have percentage padding, which is rather non-obvious. That method
   // returns true in other cases as well.
   width_available_to_children_has_changed |=
-      Style()->BoxSizing() == EBoxSizing::kBorderBox &&
+      StyleRef().BoxSizing() == EBoxSizing::kBorderBox &&
       NeedsPreferredWidthsRecalculation() &&
       View()->GetLayoutState()->ContainingBlockLogicalWidthChanged();
 
@@ -552,14 +552,14 @@
   for (auto* positioned_object : *positioned_descendants) {
     // Fixed positioned elements don't contribute to layout overflow, since they
     // don't scroll with the content.
-    if (positioned_object->Style()->GetPosition() != EPosition::kFixed)
+    if (positioned_object->StyleRef().GetPosition() != EPosition::kFixed)
       AddOverflowFromChild(*positioned_object,
                            ToLayoutSize(positioned_object->Location()));
   }
 }
 
 void LayoutBlock::AddVisualOverflowFromTheme() {
-  if (!Style()->HasAppearance())
+  if (!StyleRef().HasAppearance())
     return;
 
   IntRect inflated_rect = PixelSnappedBorderBoxRect();
@@ -571,10 +571,10 @@
 static inline bool ChangeInAvailableLogicalHeightAffectsChild(
     LayoutBlock* parent,
     LayoutBox& child) {
-  if (parent->Style()->BoxSizing() != EBoxSizing::kBorderBox)
+  if (parent->StyleRef().BoxSizing() != EBoxSizing::kBorderBox)
     return false;
-  return parent->Style()->IsHorizontalWritingMode() &&
-         !child.Style()->IsHorizontalWritingMode();
+  return parent->StyleRef().IsHorizontalWritingMode() &&
+         !child.StyleRef().IsHorizontalWritingMode();
 }
 
 void LayoutBlock::UpdateBlockChildDirtyBitsBeforeLayout(bool relayout_children,
@@ -696,19 +696,19 @@
 void LayoutBlock::MarkFixedPositionObjectForLayoutIfNeeded(
     LayoutObject* child,
     SubtreeLayoutScope& layout_scope) {
-  if (child->Style()->GetPosition() != EPosition::kFixed)
+  if (child->StyleRef().GetPosition() != EPosition::kFixed)
     return;
 
   bool has_static_block_position =
-      child->Style()->HasStaticBlockPosition(IsHorizontalWritingMode());
+      child->StyleRef().HasStaticBlockPosition(IsHorizontalWritingMode());
   bool has_static_inline_position =
-      child->Style()->HasStaticInlinePosition(IsHorizontalWritingMode());
+      child->StyleRef().HasStaticInlinePosition(IsHorizontalWritingMode());
   if (!has_static_block_position && !has_static_inline_position)
     return;
 
   LayoutObject* o = child->Parent();
   while (!o->IsLayoutView() &&
-         o->Style()->GetPosition() != EPosition::kAbsolute)
+         o->StyleRef().GetPosition() != EPosition::kAbsolute)
     o = o->Parent();
   // The LayoutView is absolute-positioned, but does not move.
   if (o->IsLayoutView())
@@ -1076,9 +1076,9 @@
 
 LayoutUnit LayoutBlock::TextIndentOffset() const {
   LayoutUnit cw;
-  if (Style()->TextIndent().IsPercentOrCalc())
+  if (StyleRef().TextIndent().IsPercentOrCalc())
     cw = ContainingBlock()->AvailableLogicalWidth();
-  return MinimumValueForLength(Style()->TextIndent(), cw);
+  return MinimumValueForLength(StyleRef().TextIndent(), cw);
 }
 
 bool LayoutBlock::IsPointInOverflowControl(
@@ -1242,7 +1242,7 @@
 
 static inline bool IsChildHitTestCandidate(LayoutBox* box) {
   return box->Size().Height() &&
-         box->Style()->Visibility() == EVisibility::kVisible &&
+         box->StyleRef().Visibility() == EVisibility::kVisible &&
          !box->IsOutOfFlowPositioned() && !box->IsLayoutFlowThread();
 }
 
@@ -1270,7 +1270,7 @@
   while (last_candidate_box && !IsChildHitTestCandidate(last_candidate_box))
     last_candidate_box = last_candidate_box->PreviousSiblingBox();
 
-  bool blocks_are_flipped = Style()->IsFlippedBlocksWritingMode();
+  bool blocks_are_flipped = StyleRef().IsFlippedBlocksWritingMode();
   if (last_candidate_box) {
     if (point_in_logical_contents.Y() >
             LogicalTopForChild(*last_candidate_box) ||
@@ -1494,7 +1494,7 @@
         // will attempt to overlap the float if the negative margin is smaller
         // than the float width.
         bool ltr = containing_block
-                       ? containing_block->Style()->IsLeftToRightDirection()
+                       ? containing_block->StyleRef().IsLeftToRightDirection()
                        : style_to_use.IsLeftToRightDirection();
         LayoutUnit margin_logical_left = ltr ? margin_start : margin_end;
         LayoutUnit margin_logical_right = ltr ? margin_end : margin_start;
@@ -1621,8 +1621,8 @@
     //        the theme is turned off, checkboxes/radios will still have decent
     //        baselines.
     // FIXME: Need to patch form controls to deal with vertical lines.
-    if (Style()->HasAppearance() &&
-        !LayoutTheme::GetTheme().IsControlContainer(Style()->Appearance())) {
+    if (StyleRef().HasAppearance() &&
+        !LayoutTheme::GetTheme().IsControlContainer(StyleRef().Appearance())) {
       return Size().Height() + MarginTop() +
              LayoutTheme::GetTheme().BaselinePositionAdjustment(StyleRef());
     }
@@ -1716,7 +1716,7 @@
   // We likewise avoid using the last line box in the case of size containment,
   // where the block's contents shouldn't be considered when laying out its
   // ancestors or siblings.
-  return (!Style()->IsOverflowVisible() &&
+  return (!StyleRef().IsOverflowVisible() &&
           !ShouldIgnoreOverflowPropertyForInlineBlockBaseline()) ||
          ShouldApplySizeContainment();
 }
@@ -1765,7 +1765,8 @@
   const LayoutBlock* first_line_block = this;
   bool has_pseudo = false;
   while (true) {
-    has_pseudo = first_line_block->Style()->HasPseudoStyle(kPseudoIdFirstLine);
+    has_pseudo =
+        first_line_block->StyleRef().HasPseudoStyle(kPseudoIdFirstLine);
     if (has_pseudo)
       break;
     LayoutObject* parent_block = first_line_block->Parent();
@@ -1853,7 +1854,7 @@
 
 LayoutBox* LayoutBlock::CreateAnonymousBoxWithSameTypeAs(
     const LayoutObject* parent) const {
-  return CreateAnonymousWithParentAndDisplay(parent, Style()->Display());
+  return CreateAnonymousWithParentAndDisplay(parent, StyleRef().Display());
 }
 
 void LayoutBlock::PaginatedContentWasLaidOut(
@@ -1904,15 +1905,17 @@
 bool LayoutBlock::HasMarginBeforeQuirk(const LayoutBox* child) const {
   // If the child has the same directionality as we do, then we can just return
   // its margin quirk.
-  if (!child->IsWritingModeRoot())
+  if (!child->IsWritingModeRoot()) {
     return child->IsLayoutBlock() ? ToLayoutBlock(child)->HasMarginBeforeQuirk()
-                                  : child->Style()->HasMarginBeforeQuirk();
+                                  : child->StyleRef().HasMarginBeforeQuirk();
+  }
 
   // The child has a different directionality. If the child is parallel, then
   // it's just flipped relative to us. We can use the opposite edge.
-  if (child->IsHorizontalWritingMode() == IsHorizontalWritingMode())
+  if (child->IsHorizontalWritingMode() == IsHorizontalWritingMode()) {
     return child->IsLayoutBlock() ? ToLayoutBlock(child)->HasMarginAfterQuirk()
-                                  : child->Style()->HasMarginAfterQuirk();
+                                  : child->StyleRef().HasMarginAfterQuirk();
+  }
 
   // The child is perpendicular to us and box sides are never quirky in
   // html.css, and we don't really care about whether or not authors specified
@@ -1923,15 +1926,17 @@
 bool LayoutBlock::HasMarginAfterQuirk(const LayoutBox* child) const {
   // If the child has the same directionality as we do, then we can just return
   // its margin quirk.
-  if (!child->IsWritingModeRoot())
+  if (!child->IsWritingModeRoot()) {
     return child->IsLayoutBlock() ? ToLayoutBlock(child)->HasMarginAfterQuirk()
-                                  : child->Style()->HasMarginAfterQuirk();
+                                  : child->StyleRef().HasMarginAfterQuirk();
+  }
 
   // The child has a different directionality. If the child is parallel, then
   // it's just flipped relative to us. We can use the opposite edge.
-  if (child->IsHorizontalWritingMode() == IsHorizontalWritingMode())
+  if (child->IsHorizontalWritingMode() == IsHorizontalWritingMode()) {
     return child->IsLayoutBlock() ? ToLayoutBlock(child)->HasMarginBeforeQuirk()
-                                  : child->Style()->HasMarginBeforeQuirk();
+                                  : child->StyleRef().HasMarginBeforeQuirk();
+  }
 
   // The child is perpendicular to us and box sides are never quirky in
   // html.css, and we don't really care about whether or not authors specified
@@ -2173,7 +2178,7 @@
 }
 
 bool LayoutBlock::NeedsPreferredWidthsRecalculation() const {
-  return (HasRelativeLogicalHeight() && Style()->LogicalWidth().IsAuto()) ||
+  return (HasRelativeLogicalHeight() && StyleRef().LogicalWidth().IsAuto()) ||
          LayoutBox::NeedsPreferredWidthsRecalculation();
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_block.h b/third_party/blink/renderer/core/layout/layout_block.h
index e7cd22d..9588bfc0 100644
--- a/third_party/blink/renderer/core/layout/layout_block.h
+++ b/third_party/blink/renderer/core/layout/layout_block.h
@@ -290,12 +290,12 @@
     return LogicalLeftOffsetForContent() + AvailableLogicalWidth();
   }
   LayoutUnit StartOffsetForContent() const {
-    return Style()->IsLeftToRightDirection()
+    return StyleRef().IsLeftToRightDirection()
                ? LogicalLeftOffsetForContent()
                : LogicalWidth() - LogicalRightOffsetForContent();
   }
   LayoutUnit EndOffsetForContent() const {
-    return !Style()->IsLeftToRightDirection()
+    return !StyleRef().IsLeftToRightDirection()
                ? LogicalLeftOffsetForContent()
                : LogicalWidth() - LogicalRightOffsetForContent();
   }
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index ff86543f..c7724a31 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -384,19 +384,19 @@
                                 "-webkit-input-placeholder"));
 
   if (LogicalHeight() > LayoutUnit() || BorderAndPaddingLogicalHeight() ||
-      Style()->LogicalMinHeight().IsPositive() ||
-      Style()->MarginBeforeCollapse() == EMarginCollapse::kSeparate ||
-      Style()->MarginAfterCollapse() == EMarginCollapse::kSeparate)
+      StyleRef().LogicalMinHeight().IsPositive() ||
+      StyleRef().MarginBeforeCollapse() == EMarginCollapse::kSeparate ||
+      StyleRef().MarginAfterCollapse() == EMarginCollapse::kSeparate)
     return false;
 
-  Length logical_height_length = Style()->LogicalHeight();
+  Length logical_height_length = StyleRef().LogicalHeight();
   bool has_auto_height = logical_height_length.IsAuto();
   if (logical_height_length.IsPercentOrCalc() &&
       !GetDocument().InQuirksMode()) {
     has_auto_height = true;
     for (LayoutBlock* cb = ContainingBlock(); !cb->IsLayoutView();
          cb = cb->ContainingBlock()) {
-      if (cb->Style()->LogicalHeight().IsFixed() || cb->IsTableCell())
+      if (cb->StyleRef().LogicalHeight().IsFixed() || cb->IsTableCell())
         has_auto_height = false;
     }
   }
@@ -568,8 +568,8 @@
   // have no margins, so we don't fill in the values for table cells.
   if (!IsTableCell()) {
     InitMaxMarginValues();
-    SetHasMarginBeforeQuirk(Style()->HasMarginBeforeQuirk());
-    SetHasMarginAfterQuirk(Style()->HasMarginAfterQuirk());
+    SetHasMarginBeforeQuirk(StyleRef().HasMarginBeforeQuirk());
+    SetHasMarginAfterQuirk(StyleRef().HasMarginAfterQuirk());
   }
 
   if (View()->GetLayoutState()->IsPaginated()) {
@@ -689,14 +689,14 @@
     // If the child is being centred then the margin calculated to do that has
     // factored in any offset required to avoid floats, so use it if necessary.
     if (StyleRef().GetTextAlign() == ETextAlign::kWebkitCenter ||
-        child.Style()->MarginStartUsing(StyleRef()).IsAuto())
+        child.StyleRef().MarginStartUsing(StyleRef()).IsAuto())
       new_position =
           std::max(new_position, position_to_avoid_floats + child_margin_start);
     else if (position_to_avoid_floats > initial_start_position)
       new_position = std::max(new_position, position_to_avoid_floats);
   }
 
-  SetLogicalLeftForChild(child, Style()->IsLeftToRightDirection()
+  SetLogicalLeftForChild(child, StyleRef().IsLeftToRightDirection()
                                     ? new_position
                                     : total_available_logical_width -
                                           new_position -
@@ -1147,7 +1147,7 @@
     if (total_logical_height > page_logical_height)
       return false;
   } else {
-    if (line_index > block.Style()->Orphans())
+    if (line_index > block.StyleRef().Orphans())
       return false;
 
     // Not enough orphans here. Push the entire block to the next column / page
@@ -2047,7 +2047,7 @@
 
     // In case the child discarded the before margin of the block we need to
     // reset the mustDiscardMarginBefore flag to the initial value.
-    SetMustDiscardMarginBefore(Style()->MarginBeforeCollapse() ==
+    SetMustDiscardMarginBefore(StyleRef().MarginBeforeCollapse() ==
                                EMarginCollapse::kDiscard);
   }
 
@@ -2096,13 +2096,13 @@
   // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
   if ((GetDocument().InQuirksMode() && HasMarginBeforeQuirk(&child) &&
        (IsTableCell() || IsBody())) ||
-      child.Style()->MarginBeforeCollapse() == EMarginCollapse::kSeparate)
+      child.StyleRef().MarginBeforeCollapse() == EMarginCollapse::kSeparate)
     return;
 
   // The margins are discarded by a child that specified
   // -webkit-margin-collapse: discard.
   // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
-  if (child.Style()->MarginBeforeCollapse() == EMarginCollapse::kDiscard) {
+  if (child.StyleRef().MarginBeforeCollapse() == EMarginCollapse::kDiscard) {
     positive_margin_before = LayoutUnit();
     negative_margin_before = LayoutUnit();
     discard_margin_before = true;
@@ -2147,9 +2147,9 @@
     if (grandchild_box->IsLayoutBlock()) {
       LayoutBlock* grandchild_block = ToLayoutBlock(grandchild_box);
       grandchild_block->SetHasMarginBeforeQuirk(
-          grandchild_box->Style()->HasMarginBeforeQuirk());
+          grandchild_box->StyleRef().HasMarginBeforeQuirk());
       grandchild_block->SetHasMarginAfterQuirk(
-          grandchild_box->Style()->HasMarginAfterQuirk());
+          grandchild_box->StyleRef().HasMarginAfterQuirk());
     }
   }
 
@@ -2157,7 +2157,7 @@
   // require clearance to move past any floats. If that's the case we want to be
   // sure we estimate the correct position including margins after any floats
   // rather than use 'clearance' later which could give us the wrong position.
-  if (grandchild_box->Style()->Clear() != EClear::kNone &&
+  if (grandchild_box->StyleRef().Clear() != EClear::kNone &&
       child_block_flow->MarginBeforeForChild(*grandchild_box) == 0)
     return;
 
@@ -2317,7 +2317,7 @@
 }
 
 void LayoutBlockFlow::SetMustDiscardMarginBefore(bool value) {
-  if (Style()->MarginBeforeCollapse() == EMarginCollapse::kDiscard) {
+  if (StyleRef().MarginBeforeCollapse() == EMarginCollapse::kDiscard) {
     DCHECK(value);
     return;
   }
@@ -2332,7 +2332,7 @@
 }
 
 void LayoutBlockFlow::SetMustDiscardMarginAfter(bool value) {
-  if (Style()->MarginAfterCollapse() == EMarginCollapse::kDiscard) {
+  if (StyleRef().MarginAfterCollapse() == EMarginCollapse::kDiscard) {
     DCHECK(value);
     return;
   }
@@ -2347,12 +2347,12 @@
 }
 
 bool LayoutBlockFlow::MustDiscardMarginBefore() const {
-  return Style()->MarginBeforeCollapse() == EMarginCollapse::kDiscard ||
+  return StyleRef().MarginBeforeCollapse() == EMarginCollapse::kDiscard ||
          (rare_data_ && rare_data_->discard_margin_before_);
 }
 
 bool LayoutBlockFlow::MustDiscardMarginAfter() const {
-  return Style()->MarginAfterCollapse() == EMarginCollapse::kDiscard ||
+  return StyleRef().MarginAfterCollapse() == EMarginCollapse::kDiscard ||
          (rare_data_ && rare_data_->discard_margin_after_);
 }
 
@@ -2362,13 +2362,13 @@
   if (!child.IsWritingModeRoot()) {
     return child.IsLayoutBlockFlow()
                ? ToLayoutBlockFlow(&child)->MustDiscardMarginBefore()
-               : (child.Style()->MarginBeforeCollapse() ==
+               : (child.StyleRef().MarginBeforeCollapse() ==
                   EMarginCollapse::kDiscard);
   }
   if (child.IsHorizontalWritingMode() == IsHorizontalWritingMode()) {
     return child.IsLayoutBlockFlow()
                ? ToLayoutBlockFlow(&child)->MustDiscardMarginAfter()
-               : (child.Style()->MarginAfterCollapse() ==
+               : (child.StyleRef().MarginAfterCollapse() ==
                   EMarginCollapse::kDiscard);
   }
 
@@ -2385,13 +2385,13 @@
   if (!child.IsWritingModeRoot()) {
     return child.IsLayoutBlockFlow()
                ? ToLayoutBlockFlow(&child)->MustDiscardMarginAfter()
-               : (child.Style()->MarginAfterCollapse() ==
+               : (child.StyleRef().MarginAfterCollapse() ==
                   EMarginCollapse::kDiscard);
   }
   if (child.IsHorizontalWritingMode() == IsHorizontalWritingMode()) {
     return child.IsLayoutBlockFlow()
                ? ToLayoutBlockFlow(&child)->MustDiscardMarginBefore()
-               : (child.Style()->MarginBeforeCollapse() ==
+               : (child.StyleRef().MarginBeforeCollapse() ==
                   EMarginCollapse::kDiscard);
   }
 
@@ -2720,7 +2720,7 @@
       return LayoutUnit(-1);
     // InlineFlowBox::placeBoxesInBlockDirection will flip lines in
     // case of verticalLR mode, so we can assume verticalRL for now.
-    if (Style()->IsFlippedLinesWritingMode()) {
+    if (StyleRef().IsFlippedLinesWritingMode()) {
       return LogicalHeight() - LastLineBox()->LogicalBottom() +
              font_data->GetFontMetrics().Ascent(LastRootBox()->BaselineType());
     }
@@ -2858,7 +2858,7 @@
 
   // At least one float is present. We need to perform the clearance
   // computation.
-  EClear clear = child->Style()->Clear();
+  EClear clear = child->StyleRef().Clear();
   LayoutUnit logical_bottom = LowestFloatLogicalBottom(clear);
 
   // We also clear floats if we are too big to sit on the same line as a float
@@ -3032,7 +3032,7 @@
     CreateOrDestroyMultiColumnFlowThreadIfNeeded(old_style);
   if (old_style) {
     if (LayoutMultiColumnFlowThread* flow_thread = MultiColumnFlowThread()) {
-      if (!Style()->ColumnRuleEquivalent(*old_style)) {
+      if (!StyleRef().ColumnRuleEquivalent(*old_style)) {
         // Column rules are painted by anonymous column set children of the
         // multicol container. We need to notify them.
         flow_thread->ColumnRuleStyleDidChange();
@@ -3054,7 +3054,7 @@
     LayoutBox& child,
     LayoutUnit logical_top,
     IndentTextOrNot indent_text) {
-  if (child.Style()->IsOriginalDisplayInlineType())
+  if (child.StyleRef().IsOriginalDisplayInlineType())
     SetStaticInlinePositionForChild(
         child, StartAlignedOffsetForLine(logical_top, indent_text));
   else
@@ -3621,7 +3621,7 @@
 LayoutPoint LayoutBlockFlow::FlipFloatForWritingModeForChild(
     const FloatingObject& child,
     const LayoutPoint& point) const {
-  if (!Style()->IsFlippedBlocksWritingMode())
+  if (!StyleRef().IsFlippedBlocksWritingMode())
     return point;
 
   // This is similar to LayoutBox::flipForWritingModeForChild. We have to
@@ -3661,7 +3661,7 @@
     IndentTextOrNot apply_text_indent) const {
   LayoutUnit left = offset_from_floats;
 
-  if (apply_text_indent == kIndentText && Style()->IsLeftToRightDirection())
+  if (apply_text_indent == kIndentText && StyleRef().IsLeftToRightDirection())
     left += TextIndentOffset();
 
   return left;
@@ -3672,7 +3672,7 @@
     IndentTextOrNot apply_text_indent) const {
   LayoutUnit right = offset_from_floats;
 
-  if (apply_text_indent == kIndentText && !Style()->IsLeftToRightDirection())
+  if (apply_text_indent == kIndentText && !StyleRef().IsLeftToRightDirection())
     right -= TextIndentOffset();
 
   return right;
@@ -3693,7 +3693,7 @@
 
   LayoutUnit float_logical_left;
 
-  if (child_box->Style()->Floating() == EFloat::kLeft) {
+  if (child_box->StyleRef().Floating() == EFloat::kLeft) {
     LayoutUnit height_remaining_left = LayoutUnit(1);
     LayoutUnit height_remaining_right = LayoutUnit(1);
     float_logical_left = LogicalLeftOffsetForPositioningFloat(
@@ -3880,7 +3880,7 @@
 
   logical_top_margin_edge =
       std::max(logical_top_margin_edge,
-               LowestFloatLogicalBottom(child.Style()->Clear()));
+               LowestFloatLogicalBottom(child.StyleRef().Clear()));
 
   bool is_paginated = View()->GetLayoutState()->IsPaginated();
   if (is_paginated && !ChildrenInline()) {
@@ -3981,7 +3981,7 @@
   }
 
   LayoutUnit child_logical_left_margin =
-      Style()->IsLeftToRightDirection() ? margin_start : margin_end;
+      StyleRef().IsLeftToRightDirection() ? margin_start : margin_end;
   SetLogicalLeftForChild(
       child, float_logical_location.X() + child_logical_left_margin);
   SetLogicalLeftForFloat(floating_object, float_logical_location.X());
@@ -4431,10 +4431,10 @@
   if (IsInline() || IsFloatingOrOutOfFlowPositioned() || HasOverflowClip() ||
       IsFlexItemIncludingDeprecated() || IsTableCell() || IsTableCaption() ||
       IsFieldset() || IsCustomItem() || IsDocumentElement() || IsGridItem() ||
-      IsWritingModeRoot() || Style()->Display() == EDisplay::kFlowRoot ||
+      IsWritingModeRoot() || StyleRef().Display() == EDisplay::kFlowRoot ||
       ShouldApplyPaintContainment() || ShouldApplyLayoutContainment() ||
-      Style()->SpecifiesColumns() ||
-      Style()->GetColumnSpan() == EColumnSpan::kAll) {
+      StyleRef().SpecifiesColumns() ||
+      StyleRef().GetColumnSpan() == EColumnSpan::kAll) {
     // The specs require this object to establish a new formatting context.
     return true;
   }
@@ -4675,8 +4675,8 @@
   if (!FirstRootBox())
     return CreatePositionWithAffinity(0);
 
-  bool lines_are_flipped = Style()->IsFlippedLinesWritingMode();
-  bool blocks_are_flipped = Style()->IsFlippedBlocksWritingMode();
+  bool lines_are_flipped = StyleRef().IsFlippedLinesWritingMode();
+  bool blocks_are_flipped = StyleRef().IsFlippedBlocksWritingMode();
 
   // look for the closest line box in the root box which is at the passed-in y
   // coordinate
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.h b/third_party/blink/renderer/core/layout/layout_block_flow.h
index ce749445..89d863fe 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.h
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -143,7 +143,7 @@
       LayoutUnit position,
       IndentTextOrNot indent_text,
       LayoutUnit logical_height = LayoutUnit()) const {
-    return Style()->IsLeftToRightDirection()
+    return StyleRef().IsLeftToRightDirection()
                ? LogicalLeftOffsetForLine(position, indent_text, logical_height)
                : LogicalWidth() - LogicalRightOffsetForLine(
                                       position, indent_text, logical_height);
@@ -171,7 +171,7 @@
   LayoutUnit StartOffsetForAvoidingFloats(
       LayoutUnit position,
       LayoutUnit logical_height = LayoutUnit()) const {
-    return Style()->IsLeftToRightDirection()
+    return StyleRef().IsLeftToRightDirection()
                ? LogicalLeftOffsetForAvoidingFloats(position, logical_height)
                : LogicalWidth() - LogicalRightOffsetForAvoidingFloats(
                                       position, logical_height);
@@ -179,7 +179,7 @@
   LayoutUnit EndOffsetForAvoidingFloats(
       LayoutUnit position,
       LayoutUnit logical_height = LayoutUnit()) const {
-    return !Style()->IsLeftToRightDirection()
+    return !StyleRef().IsLeftToRightDirection()
                ? LogicalLeftOffsetForAvoidingFloats(position, logical_height)
                : LogicalWidth() - LogicalRightOffsetForAvoidingFloats(
                                       position, logical_height);
@@ -305,7 +305,7 @@
 
   static bool ShouldSkipCreatingRunsForObject(LineLayoutItem obj) {
     return obj.IsFloating() || (obj.IsOutOfFlowPositioned() &&
-                                !obj.Style()->IsOriginalDisplayInlineType() &&
+                                !obj.StyleRef().IsOriginalDisplayInlineType() &&
                                 !obj.Container().IsLayoutInline());
   }
 
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow_line.cc b/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
index 527f2e5..4697ac5 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
@@ -101,7 +101,7 @@
         CHECK_LE(opportunities_in_run, total_opportunities_);
 
         // Don't justify for white-space: pre.
-        if (r->line_layout_item_.Style()->WhiteSpace() != EWhiteSpace::kPre) {
+        if (r->line_layout_item_.StyleRef().WhiteSpace() != EWhiteSpace::kPre) {
           InlineTextBox* text_box = ToInlineTextBox(r->box_);
           CHECK(total_opportunities_);
           int expansion = ((available_logical_width - total_logical_width) *
@@ -150,7 +150,7 @@
   if (text.IsBR())
     text_box->SetIsText(is_only_run || text.GetDocument().InNoQuirksMode());
   text_box->SetDirOverride(
-      run.DirOverride(text.Style()->RtlOrdering() == EOrder::kVisual));
+      run.DirOverride(text.StyleRef().RtlOrdering() == EOrder::kVisual));
   if (run.has_hyphen_)
     text_box->SetHasHyphen(true);
   return text_box;
@@ -291,10 +291,12 @@
   for (BidiRun* r = bidi_runs.FirstRun(); r; r = r->Next()) {
     // Create a box for our object.
     bool is_only_run = (run_count == 1);
-    if (run_count == 2 && !r->line_layout_item_.IsListMarker())
-      is_only_run = (!Style()->IsLeftToRightDirection() ? bidi_runs.LastRun()
-                                                        : bidi_runs.FirstRun())
-                        ->line_layout_item_.IsListMarker();
+    if (run_count == 2 && !r->line_layout_item_.IsListMarker()) {
+      is_only_run =
+          (!StyleRef().IsLeftToRightDirection() ? bidi_runs.LastRun()
+                                                : bidi_runs.FirstRun())
+              ->line_layout_item_.IsListMarker();
+    }
 
     if (line_info.IsEmpty())
       continue;
@@ -361,7 +363,7 @@
 
 ETextAlign LayoutBlockFlow::TextAlignmentForLine(
     bool ends_with_soft_break) const {
-  return Style()->GetTextAlign(!ends_with_soft_break);
+  return StyleRef().GetTextAlign(!ends_with_soft_break);
 }
 
 static bool TextAlignmentNeedsTrailingSpace(ETextAlign text_align,
@@ -482,10 +484,10 @@
   }
   layout_ruby_run->GetOverhang(
       line_info.IsFirstLine(),
-      layout_ruby_run->Style()->IsLeftToRightDirection() ? previous_object
-                                                         : next_object,
-      layout_ruby_run->Style()->IsLeftToRightDirection() ? next_object
-                                                         : previous_object,
+      layout_ruby_run->StyleRef().IsLeftToRightDirection() ? previous_object
+                                                           : next_object,
+      layout_ruby_run->StyleRef().IsLeftToRightDirection() ? next_object
+                                                           : previous_object,
       start_overhang, end_overhang);
   SetMarginStartForChild(*layout_ruby_run, LayoutUnit(-start_overhang));
   SetMarginEndForChild(*layout_ruby_run, LayoutUnit(-end_overhang));
@@ -582,7 +584,7 @@
                               run->Direction(), line_info.IsFirstLine());
         if (i > 0 && word_length == 1 &&
             layout_text.CharacterAt(word_measurement.start_offset) == ' ')
-          measured_width += layout_text.Style()->WordSpacing();
+          measured_width += layout_text.StyleRef().WordSpacing();
       } else {
         FloatRect word_glyph_bounds = word_measurement.glyph_bounds;
         word_glyph_bounds.Move(measured_width, 0);
@@ -658,11 +660,11 @@
     unsigned expansion_opportunity_count) {
   TextDirection direction;
   if (root_inline_box &&
-      root_inline_box->GetLineLayoutItem().Style()->GetUnicodeBidi() ==
+      root_inline_box->GetLineLayoutItem().StyleRef().GetUnicodeBidi() ==
           UnicodeBidi::kPlaintext)
     direction = root_inline_box->Direction();
   else
-    direction = Style()->Direction();
+    direction = StyleRef().Direction();
 
   // Armed with the total width of the line (without justification),
   // we now examine our text-align property in order to determine where to
@@ -672,19 +674,19 @@
     case ETextAlign::kLeft:
     case ETextAlign::kWebkitLeft:
       UpdateLogicalWidthForLeftAlignedBlock(
-          Style()->IsLeftToRightDirection(), trailing_space_run, logical_left,
+          StyleRef().IsLeftToRightDirection(), trailing_space_run, logical_left,
           total_logical_width, available_logical_width);
       break;
     case ETextAlign::kRight:
     case ETextAlign::kWebkitRight:
       UpdateLogicalWidthForRightAlignedBlock(
-          Style()->IsLeftToRightDirection(), trailing_space_run, logical_left,
+          StyleRef().IsLeftToRightDirection(), trailing_space_run, logical_left,
           total_logical_width, available_logical_width);
       break;
     case ETextAlign::kCenter:
     case ETextAlign::kWebkitCenter:
       UpdateLogicalWidthForCenterAlignedBlock(
-          Style()->IsLeftToRightDirection(), trailing_space_run, logical_left,
+          StyleRef().IsLeftToRightDirection(), trailing_space_run, logical_left,
           total_logical_width, available_logical_width);
       break;
     case ETextAlign::kJustify:
@@ -699,24 +701,26 @@
       }
       FALLTHROUGH;
     case ETextAlign::kStart:
-      if (direction == TextDirection::kLtr)
+      if (direction == TextDirection::kLtr) {
         UpdateLogicalWidthForLeftAlignedBlock(
-            Style()->IsLeftToRightDirection(), trailing_space_run, logical_left,
-            total_logical_width, available_logical_width);
-      else
+            StyleRef().IsLeftToRightDirection(), trailing_space_run,
+            logical_left, total_logical_width, available_logical_width);
+      } else {
         UpdateLogicalWidthForRightAlignedBlock(
-            Style()->IsLeftToRightDirection(), trailing_space_run, logical_left,
-            total_logical_width, available_logical_width);
+            StyleRef().IsLeftToRightDirection(), trailing_space_run,
+            logical_left, total_logical_width, available_logical_width);
+      }
       break;
     case ETextAlign::kEnd:
-      if (direction == TextDirection::kLtr)
+      if (direction == TextDirection::kLtr) {
         UpdateLogicalWidthForRightAlignedBlock(
-            Style()->IsLeftToRightDirection(), trailing_space_run, logical_left,
-            total_logical_width, available_logical_width);
-      else
+            StyleRef().IsLeftToRightDirection(), trailing_space_run,
+            logical_left, total_logical_width, available_logical_width);
+      } else {
         UpdateLogicalWidthForLeftAlignedBlock(
-            Style()->IsLeftToRightDirection(), trailing_space_run, logical_left,
-            total_logical_width, available_logical_width);
+            StyleRef().IsLeftToRightDirection(), trailing_space_run,
+            logical_left, total_logical_width, available_logical_width);
+      }
       break;
   }
   if (ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
@@ -803,7 +807,7 @@
   ExpansionOpportunities expansions;
   LayoutObject* previous_object = nullptr;
   ETextAlign text_align = line_info.GetTextAlign();
-  TextJustify text_justify = Style()->GetTextJustify();
+  TextJustify text_justify = StyleRef().GetTextJustify();
 
   BidiRun* r = first_run;
   size_t word_measurements_index = 0;
@@ -1255,7 +1259,7 @@
 
     if (!pagination_strut_from_deleted_line) {
       for (const auto& positioned_object : line_breaker.PositionedObjects()) {
-        if (positioned_object.Style()->IsOriginalDisplayInlineType()) {
+        if (positioned_object.StyleRef().IsOriginalDisplayInlineType()) {
           // Auto-positioned "inline" out-of-flow objects have already been
           // positioned, but if we're paginated, or just ceased to be so, we
           // need to update their position now, since the line they "belong" to
@@ -1295,7 +1299,7 @@
   // widows then we need to ignore the possibility of having a new widows
   // situation. Otherwise, we risk leaving empty containers which is against the
   // block fragmentation principles.
-  if (paginated && Style()->Widows() > 1 && !DidBreakAtLineToAvoidWidow()) {
+  if (paginated && StyleRef().Widows() > 1 && !DidBreakAtLineToAvoidWidow()) {
     // Check the line boxes to make sure we didn't create unacceptable widows.
     // However, we'll prioritize orphans - so nothing we do here should create
     // a new orphan.
@@ -1317,11 +1321,11 @@
         line_box == first_line_in_block)
       return;
 
-    if (num_lines_hanging < Style()->Widows()) {
+    if (num_lines_hanging < StyleRef().Widows()) {
       // We have detected a widow. Now we need to work out how many
       // lines there are on the previous page, and how many we need
       // to steal.
-      int num_lines_needed = Style()->Widows() - num_lines_hanging;
+      int num_lines_needed = StyleRef().Widows() - num_lines_hanging;
       RootInlineBox* current_first_line_of_new_page = line_box;
 
       // Count the number of lines in the previous page.
@@ -1339,7 +1343,7 @@
       // about orphans, but given the specification says the initial orphan
       // value is non-zero, this is ok. The author is always free to set orphans
       // explicitly as well.
-      int orphans = Style()->Orphans();
+      int orphans = StyleRef().Orphans();
       int num_lines_available = num_lines_in_previous_page - orphans;
       if (num_lines_available <= 0)
         return;
@@ -1531,10 +1535,10 @@
     }
 
     // FIXME: This ignores first-line.
-    const Font& font = text->Style()->GetFont();
+    const Font& font = text->StyleRef().GetFont();
     TextRun run =
         ConstructTextRun(font, &trailing_whitespace_char, 1, text->StyleRef(),
-                         text->Style()->Direction());
+                         text->StyleRef().Direction());
     float space_width = font.Width(run);
     inline_max -= LayoutUnit::FromFloatCeil(
         space_width + font.GetFontDescription().WordSpacing());
@@ -1623,8 +1627,8 @@
   bool should_break_line_after_text = false;
   while (LayoutObject* child = child_iterator.Next()) {
     auto_wrap = child->IsAtomicInlineLevel()
-                    ? child->Parent()->Style()->AutoWrap()
-                    : child->Style()->AutoWrap();
+                    ? child->Parent()->StyleRef().AutoWrap()
+                    : child->StyleRef().AutoWrap();
 
     if (!child->IsBR()) {
       // Step One: determine whether or not we need to go ahead and
@@ -1915,7 +1919,7 @@
     object_to_check = parent;
   }
   return object_to_check->HasOverflowClip() &&
-         object_to_check->Style()->TextOverflow() != ETextOverflow::kClip;
+         object_to_check->StyleRef().TextOverflow() != ETextOverflow::kClip;
 }
 
 DISABLE_CFI_PERF
@@ -1997,7 +2001,7 @@
   if (LastRootBox()) {
     LayoutUnit lowest_allowed_position =
         std::max(LastRootBox()->LineBottom(), LogicalHeight() + PaddingAfter());
-    if (!Style()->IsFlippedLinesWritingMode())
+    if (!StyleRef().IsFlippedLinesWritingMode())
       last_line_annotations_adjustment =
           LastRootBox()
               ->ComputeUnderAnnotationAdjustment(lowest_allowed_position)
@@ -2144,11 +2148,11 @@
     resolver.SetPosition(iter, NumberOfIsolateAncestors(iter));
     resolver.SetStatus(last->LineBreakBidiStatus());
   } else {
-    TextDirection direction = Style()->Direction();
-    if (Style()->GetUnicodeBidi() == UnicodeBidi::kPlaintext)
+    TextDirection direction = StyleRef().Direction();
+    if (StyleRef().GetUnicodeBidi() == UnicodeBidi::kPlaintext)
       direction = DeterminePlaintextDirectionality(LineLayoutItem(this));
     resolver.SetStatus(
-        BidiStatus(direction, IsOverride(Style()->GetUnicodeBidi())));
+        BidiStatus(direction, IsOverride(StyleRef().GetUnicodeBidi())));
     InlineIterator iter = InlineIterator(
         LineLayoutBlockFlow(this),
         BidiFirstSkippingEmptyInlines(LineLayoutBlockFlow(this),
@@ -2165,11 +2169,11 @@
   // difficulty.
   if (!curr->EndsWithBreak())
     return false;
-  InlineBox* last_box = Style()->IsLeftToRightDirection()
+  InlineBox* last_box = StyleRef().IsLeftToRightDirection()
                             ? curr->LastLeafChild()
                             : curr->FirstLeafChild();
   return last_box && last_box->GetLineLayoutItem().IsBR() &&
-         last_box->GetLineLayoutItem().Style()->Clear() != EClear::kNone;
+         last_box->GetLineLayoutItem().StyleRef().Clear() != EClear::kNone;
 }
 
 void LayoutBlockFlow::DetermineEndPosition(LineLayoutState& layout_state,
@@ -2316,7 +2320,7 @@
   // FIXME: Need to find another way to do this, since scrollbars could show
   // when we don't want them to.
   if (HasOverflowClip() && !end_padding && GetNode() &&
-      IsRootEditableElement(*GetNode()) && Style()->IsLeftToRightDirection())
+      IsRootEditableElement(*GetNode()) && StyleRef().IsLeftToRightDirection())
     end_padding = LayoutUnit(1);
   for (RootInlineBox* curr = FirstRootBox(); curr; curr = curr->NextRootBox()) {
     AddLayoutOverflow(curr->PaddedLayoutOverflowRect(end_padding));
@@ -2351,7 +2355,7 @@
 }
 
 void LayoutBlockFlow::DeleteEllipsisLineBoxes() {
-  ETextAlign text_align = Style()->GetTextAlign();
+  ETextAlign text_align = StyleRef().GetTextAlign();
   IndentTextOrNot indent_text = kIndentText;
   for (RootInlineBox* curr = FirstRootBox(); curr; curr = curr->NextRootBox()) {
     if (curr->HasEllipsisBox()) {
@@ -2377,7 +2381,7 @@
 }
 
 void LayoutBlockFlow::ClearTruncationOnAtomicInlines(RootInlineBox* root) {
-  bool ltr = Style()->IsLeftToRightDirection();
+  bool ltr = StyleRef().IsLeftToRightDirection();
   InlineBox* first_child = ltr ? root->LastChild() : root->FirstChild();
   for (InlineBox* box = first_child; box;
        box = ltr ? box->PrevOnLine() : box->NextOnLine()) {
@@ -2394,7 +2398,7 @@
 
 void LayoutBlockFlow::CheckLinesForTextOverflow() {
   // Determine the width of the ellipsis using the current font.
-  const Font& font = Style()->GetFont();
+  const Font& font = StyleRef().GetFont();
 
   const size_t kFullStopStringLength = 3;
   const UChar kFullStopString[] = {kFullstopCharacter, kFullstopCharacter,
@@ -2447,8 +2451,8 @@
   // For RTL, we use the left edge of the padding box and check the left edge of
   // the line box to see if it is less Include the scrollbar for overflow
   // blocks, which means we want to use "contentWidth()".
-  bool ltr = Style()->IsLeftToRightDirection();
-  ETextAlign text_align = Style()->GetTextAlign();
+  bool ltr = StyleRef().IsLeftToRightDirection();
+  ETextAlign text_align = StyleRef().GetTextAlign();
   IndentTextOrNot indent_text = kIndentText;
   for (RootInlineBox* curr = FirstRootBox(); curr; curr = curr->NextRootBox()) {
     LayoutUnit block_right_edge =
@@ -2503,7 +2507,7 @@
     const AtomicString& selected_ellipsis_str,
     InlineBox* box_truncation_starts_at) {
   bool found_box = box_truncation_starts_at ? true : false;
-  bool ltr = Style()->IsLeftToRightDirection();
+  bool ltr = StyleRef().IsLeftToRightDirection();
   LayoutUnit logical_left_offset = block_left_edge;
 
   // Each atomic inline block (e.g. a <span>) inside a blockflow is managed by
@@ -2603,17 +2607,17 @@
 LayoutUnit LayoutBlockFlow::StartAlignedOffsetForLine(
     LayoutUnit position,
     IndentTextOrNot indent_text) {
-  ETextAlign text_align = Style()->GetTextAlign();
+  ETextAlign text_align = StyleRef().GetTextAlign();
 
   bool apply_indent_text;
   switch (text_align) {  // FIXME: Handle TAEND here
     case ETextAlign::kLeft:
     case ETextAlign::kWebkitLeft:
-      apply_indent_text = Style()->IsLeftToRightDirection();
+      apply_indent_text = StyleRef().IsLeftToRightDirection();
       break;
     case ETextAlign::kRight:
     case ETextAlign::kWebkitRight:
-      apply_indent_text = !Style()->IsLeftToRightDirection();
+      apply_indent_text = !StyleRef().IsLeftToRightDirection();
       break;
     case ETextAlign::kStart:
       apply_indent_text = true;
@@ -2637,7 +2641,7 @@
                                  total_logical_width, available_logical_width,
                                  0);
 
-  if (!Style()->IsLeftToRightDirection())
+  if (!StyleRef().IsLeftToRightDirection())
     return LogicalWidth() - logical_left;
   return logical_left;
 }
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 5815cfbe..9251606 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -115,9 +115,9 @@
   // since position:static elements that are not flex-items get their z-index
   // coerced to auto.
   if (IsPositioned() || CreatesGroup() || HasTransformRelatedProperty() ||
-      HasHiddenBackface() || HasReflection() || Style()->SpecifiesColumns() ||
-      Style()->IsStackingContext() ||
-      Style()->ShouldCompositeForCurrentAnimations() ||
+      HasHiddenBackface() || HasReflection() || StyleRef().SpecifiesColumns() ||
+      StyleRef().IsStackingContext() ||
+      StyleRef().ShouldCompositeForCurrentAnimations() ||
       IsEffectiveRootScroller())
     return kNormalPaintLayer;
 
@@ -428,17 +428,17 @@
   if (!old_style || !Parent() || !Parent()->IsLayoutGrid())
     return;
 
-  if (old_style->GridColumnStart() == Style()->GridColumnStart() &&
-      old_style->GridColumnEnd() == Style()->GridColumnEnd() &&
-      old_style->GridRowStart() == Style()->GridRowStart() &&
-      old_style->GridRowEnd() == Style()->GridRowEnd() &&
-      old_style->Order() == Style()->Order() &&
-      old_style->HasOutOfFlowPosition() == Style()->HasOutOfFlowPosition())
+  if (old_style->GridColumnStart() == StyleRef().GridColumnStart() &&
+      old_style->GridColumnEnd() == StyleRef().GridColumnEnd() &&
+      old_style->GridRowStart() == StyleRef().GridRowStart() &&
+      old_style->GridRowEnd() == StyleRef().GridRowEnd() &&
+      old_style->Order() == StyleRef().Order() &&
+      old_style->HasOutOfFlowPosition() == StyleRef().HasOutOfFlowPosition())
     return;
 
   // Positioned items don't participate on the layout of the grid,
   // so we don't need to mark the grid as dirty if they change positions.
-  if (old_style->HasOutOfFlowPosition() && Style()->HasOutOfFlowPosition())
+  if (old_style->HasOutOfFlowPosition() && StyleRef().HasOutOfFlowPosition())
     return;
 
   // It should be possible to not dirty the grid in some cases (like moving an
@@ -559,7 +559,7 @@
     return GetScrollableArea()->ScrollWidth();
   // For objects with visible overflow, this matches IE.
   // FIXME: Need to work right with writing modes.
-  if (Style()->IsLeftToRightDirection())
+  if (StyleRef().IsLeftToRightDirection())
     return std::max(ClientWidth(), LayoutOverflowRect().MaxX() - BorderLeft());
   return ClientWidth() -
          std::min(LayoutUnit(), LayoutOverflowRect().X() - BorderLeft());
@@ -704,7 +704,7 @@
 
   // If we are fixed-position and stick to the viewport, it is useless to
   // scroll the parent.
-  if (Style()->GetPosition() == EPosition::kFixed && Container() == View())
+  if (StyleRef().GetPosition() == EPosition::kFixed && Container() == View())
     return absolute_rect_for_parent;
 
   if (parent_box) {
@@ -764,7 +764,7 @@
   if (!overflow_ || HasOverflowClip())
     return LogicalHeight();
   LayoutRect overflow = LayoutOverflowRect();
-  if (Style()->IsHorizontalWritingMode())
+  if (StyleRef().IsHorizontalWritingMode())
     return overflow.MaxY();
   return overflow.MaxX();
 }
@@ -878,7 +878,7 @@
 LayoutRect LayoutBox::BackgroundRect(BackgroundRectType rect_type) const {
   EFillBox background_box = EFillBox::kText;
   // Find the largest background rect of the given opaqueness.
-  if (const FillLayer* current = &(Style()->BackgroundLayers())) {
+  if (const FillLayer* current = &(StyleRef().BackgroundLayers())) {
     do {
       const FillLayer* cur = current;
       current = current->Next();
@@ -955,7 +955,7 @@
   // hasOverflowClip(). However, they do "implicitly" clip their contents, so
   // we want to allow resizing them also.
   return (HasOverflowClip() || IsLayoutIFrame()) &&
-         Style()->Resize() != EResize::kNone;
+         StyleRef().Resize() != EResize::kNone;
 }
 
 void LayoutBox::AddLayerHitTestRects(
@@ -978,14 +978,14 @@
 }
 
 int LayoutBox::VerticalScrollbarWidth() const {
-  if (!HasOverflowClip() || Style()->OverflowY() == EOverflow::kOverlay)
+  if (!HasOverflowClip() || StyleRef().OverflowY() == EOverflow::kOverlay)
     return 0;
 
   return GetScrollableArea()->VerticalScrollbarWidth();
 }
 
 int LayoutBox::HorizontalScrollbarHeight() const {
-  if (!HasOverflowClip() || Style()->OverflowX() == EOverflow::kOverlay)
+  if (!HasOverflowClip() || StyleRef().OverflowX() == EOverflow::kOverlay)
     return 0;
 
   return GetScrollableArea()->HorizontalScrollbarHeight();
@@ -1144,8 +1144,8 @@
 }
 
 bool LayoutBox::NeedsPreferredWidthsRecalculation() const {
-  return Style()->PaddingStart().IsPercentOrCalc() ||
-         Style()->PaddingEnd().IsPercentOrCalc();
+  return StyleRef().PaddingStart().IsPercentOrCalc() ||
+         StyleRef().PaddingEnd().IsPercentOrCalc();
 }
 
 IntSize LayoutBox::OriginAdjustmentForScrollbars() const {
@@ -1188,7 +1188,7 @@
     const LayoutObject* ancestor,
     VisualRectFlags visual_rect_flags,
     TransformState& transform_state) const {
-  bool container_preserve_3d = container_object->Style()->Preserves3D();
+  bool container_preserve_3d = container_object->StyleRef().Preserves3D();
 
   TransformState::TransformAccumulation accumulation =
       container_preserve_3d ? TransformState::kAccumulateTransform
@@ -1247,7 +1247,7 @@
 
   // d) Perspective applied by container.
   if (container_object && container_object->HasLayer() &&
-      container_object->Style()->HasPerspective()) {
+      container_object->StyleRef().HasPerspective()) {
     // Perspective on the container affects us, so we have to factor it in here.
     DCHECK(container_object->HasLayer());
     FloatPoint perspective_origin =
@@ -1255,7 +1255,7 @@
 
     TransformationMatrix perspective_matrix;
     perspective_matrix.ApplyPerspective(
-        container_object->Style()->Perspective());
+        container_object->StyleRef().Perspective());
     perspective_matrix.ApplyTransformOrigin(perspective_origin.X(),
                                             perspective_origin.Y(), 0);
 
@@ -1477,7 +1477,7 @@
     float width) const {
   LayoutUnit borders_plus_padding = CollapsedBorderAndCSSPaddingLogicalWidth();
   LayoutUnit result(width);
-  if (Style()->BoxSizing() == EBoxSizing::kContentBox)
+  if (StyleRef().BoxSizing() == EBoxSizing::kContentBox)
     return result + borders_plus_padding;
   return std::max(result, borders_plus_padding);
 }
@@ -1486,7 +1486,7 @@
     float height) const {
   LayoutUnit borders_plus_padding = CollapsedBorderAndCSSPaddingLogicalHeight();
   LayoutUnit result(height);
-  if (Style()->BoxSizing() == EBoxSizing::kContentBox)
+  if (StyleRef().BoxSizing() == EBoxSizing::kContentBox)
     return result + borders_plus_padding;
   return std::max(result, borders_plus_padding);
 }
@@ -1494,7 +1494,7 @@
 LayoutUnit LayoutBox::AdjustContentBoxLogicalWidthForBoxSizing(
     float width) const {
   LayoutUnit result(width);
-  if (Style()->BoxSizing() == EBoxSizing::kBorderBox)
+  if (StyleRef().BoxSizing() == EBoxSizing::kBorderBox)
     result -= CollapsedBorderAndCSSPaddingLogicalWidth();
   return std::max(LayoutUnit(), result);
 }
@@ -1502,7 +1502,7 @@
 LayoutUnit LayoutBox::AdjustContentBoxLogicalHeightForBoxSizing(
     float height) const {
   LayoutUnit result(height);
-  if (Style()->BoxSizing() == EBoxSizing::kBorderBox)
+  if (StyleRef().BoxSizing() == EBoxSizing::kBorderBox)
     result -= CollapsedBorderAndCSSPaddingLogicalHeight();
   return std::max(LayoutUnit(), result);
 }
@@ -1552,10 +1552,10 @@
             adjusted_location, kExcludeOverlayScrollbarSizeForHitTesting))) {
       skip_children = true;
     }
-    if (!skip_children && Style()->HasBorderRadius()) {
+    if (!skip_children && StyleRef().HasBorderRadius()) {
       LayoutRect bounds_rect(adjusted_location, Size());
       skip_children = !location_in_container.Intersects(
-          Style()->GetRoundedInnerBorderFor(bounds_rect));
+          StyleRef().GetRoundedInnerBorderFor(bounds_rect));
     }
   }
 
@@ -1564,7 +1564,7 @@
     return true;
   }
 
-  if (Style()->HasBorderRadius() &&
+  if (StyleRef().HasBorderRadius() &&
       HitTestClippedOutByBorder(location_in_container, adjusted_location))
     return false;
 
@@ -1608,7 +1608,7 @@
   LayoutRect border_rect = BorderBoxRect();
   border_rect.MoveBy(border_box_location);
   return !location_in_container.Intersects(
-      Style()->GetRoundedBorderFor(border_rect));
+      StyleRef().GetRoundedBorderFor(border_rect));
 }
 
 void LayoutBox::Paint(const PaintInfo& paint_info) const {
@@ -1636,8 +1636,8 @@
     return true;
   }
 
-  if (!Style()->BackgroundLayers().GetImage() ||
-      Style()->BackgroundLayers().Next()) {
+  if (!StyleRef().BackgroundLayers().GetImage() ||
+      StyleRef().BackgroundLayers().Next()) {
     painted_extent = background_rect;
     return true;
   }
@@ -1647,7 +1647,7 @@
   // and outside of the paint phase. Potentially returning different results at
   // different phases. crbug.com/732934
   geometry.Calculate(nullptr, PaintPhase::kBlockBackground,
-                     kGlobalPaintNormalPhase, Style()->BackgroundLayers(),
+                     kGlobalPaintNormalPhase, StyleRef().BackgroundLayers(),
                      background_rect);
   if (geometry.HasNonLocalGeometry())
     return false;
@@ -1664,16 +1664,16 @@
   // We cannot be sure if theme paints the background opaque.
   // In this case it is safe to not assume opaqueness.
   // FIXME: May be ask theme if it paints opaque.
-  if (Style()->HasAppearance())
+  if (StyleRef().HasAppearance())
     return false;
   // FIXME: Check the opaqueness of background images.
 
   // FIXME: Use rounded rect if border radius is present.
-  if (Style()->HasBorderRadius())
+  if (StyleRef().HasBorderRadius())
     return false;
   if (HasClipPath())
     return false;
-  if (Style()->HasBlendMode())
+  if (StyleRef().HasBlendMode())
     return false;
   return BackgroundRect(kBackgroundKnownOpaqueRect).Contains(local_rect);
 }
@@ -1755,7 +1755,7 @@
   if (IsLayoutView())
     return false;
   // FIXME: box-shadow is painted while background painting.
-  if (Style()->BoxShadow())
+  if (StyleRef().BoxShadow())
     return false;
   LayoutRect background_rect;
   if (!GetBackgroundPaintedExtent(background_rect))
@@ -1822,7 +1822,7 @@
     }
   }
 
-  ShapeValue* shape_outside_value = Style()->ShapeOutside();
+  ShapeValue* shape_outside_value = StyleRef().ShapeOutside();
   if (!GetFrameView()->IsInPerformLayout() && IsFloating() &&
       shape_outside_value && shape_outside_value->GetImage() &&
       shape_outside_value->GetImage()->Data() == image) {
@@ -1966,26 +1966,28 @@
   LayoutRect clip_rect =
       LayoutRect(border_box_rect.Location() + location, border_box_rect.Size());
 
-  if (!Style()->ClipLeft().IsAuto()) {
-    LayoutUnit c = ValueForLength(Style()->ClipLeft(), border_box_rect.Width());
+  if (!StyleRef().ClipLeft().IsAuto()) {
+    LayoutUnit c =
+        ValueForLength(StyleRef().ClipLeft(), border_box_rect.Width());
     clip_rect.Move(c, LayoutUnit());
     clip_rect.Contract(c, LayoutUnit());
   }
 
-  if (!Style()->ClipRight().IsAuto())
+  if (!StyleRef().ClipRight().IsAuto())
     clip_rect.Contract(
-        Size().Width() - ValueForLength(Style()->ClipRight(), Size().Width()),
+        Size().Width() - ValueForLength(StyleRef().ClipRight(), Size().Width()),
         LayoutUnit());
 
-  if (!Style()->ClipTop().IsAuto()) {
-    LayoutUnit c = ValueForLength(Style()->ClipTop(), border_box_rect.Height());
+  if (!StyleRef().ClipTop().IsAuto()) {
+    LayoutUnit c =
+        ValueForLength(StyleRef().ClipTop(), border_box_rect.Height());
     clip_rect.Move(LayoutUnit(), c);
     clip_rect.Contract(LayoutUnit(), c);
   }
 
-  if (!Style()->ClipBottom().IsAuto()) {
+  if (!StyleRef().ClipBottom().IsAuto()) {
     clip_rect.Contract(LayoutUnit(),
-                       Size().Height() - ValueForLength(Style()->ClipBottom(),
+                       Size().Height() - ValueForLength(StyleRef().ClipBottom(),
                                                         Size().Height()));
   }
 
@@ -2123,7 +2125,7 @@
 void LayoutBox::MapLocalToAncestor(const LayoutBoxModelObject* ancestor,
                                    TransformState& transform_state,
                                    MapCoordinatesFlags mode) const {
-  bool is_fixed_pos = Style()->GetPosition() == EPosition::kFixed;
+  bool is_fixed_pos = StyleRef().GetPosition() == EPosition::kFixed;
 
   // If this box has a transform or contains paint, it acts as a fixed position
   // container for fixed descendants, and may itself also be fixed position. So
@@ -2142,7 +2144,7 @@
   if (this == ancestor)
     return;
 
-  bool is_fixed_pos = Style()->GetPosition() == EPosition::kFixed;
+  bool is_fixed_pos = StyleRef().GetPosition() == EPosition::kFixed;
 
   // If this box has a transform or contains paint, it acts as a fixed position
   // container for fixed descendants, and may itself also be fixed position. So
@@ -2170,7 +2172,7 @@
     offset += OffsetFromScrollableContainer(o, ignore_scroll_offset);
 
   if (IsOutOfFlowPositioned() && o->IsLayoutInline() &&
-      o->CanContainOutOfFlowPositionedElement(Style()->GetPosition())) {
+      o->CanContainOutOfFlowPositionedElement(StyleRef().GetPosition())) {
     offset += ToLayoutInline(o)->OffsetForInFlowPositionedInline(*this);
   }
 
@@ -2210,7 +2212,7 @@
 void LayoutBox::PositionLineBox(InlineBox* box) {
   if (IsOutOfFlowPositioned()) {
     // Cache the x position only if we were an INLINE type originally.
-    bool originally_inline = Style()->IsOriginalDisplayInlineType();
+    bool originally_inline = StyleRef().IsOriginalDisplayInlineType();
     if (originally_inline) {
       // The value is cached in the xPos of the box.  We only need this value if
       // our object was inline originally, since otherwise it would have ended
@@ -2242,7 +2244,7 @@
   DCHECK(IsOutOfFlowPositioned());
   DCHECK(Container()->IsLayoutInline());
   DCHECK(Container()->CanContainOutOfFlowPositionedElement(
-      Style()->GetPosition()));
+      StyleRef().GetPosition()));
   // If this object is inside a relative positioned inline and its inline
   // position is an explicit offset from the edge of its container then it will
   // need to move if its inline container has changed width. We do not track if
@@ -2250,7 +2252,7 @@
   // inside it, so it probably has - mark our object for layout so that it can
   // move to the new offset created by the new width.
   if (!NormalChildNeedsLayout() &&
-      !Style()->HasStaticInlinePosition(is_horizontal))
+      !StyleRef().HasStaticInlinePosition(is_horizontal))
     SetChildNeedsLayout(kMarkOnlyThis);
 }
 
@@ -2354,7 +2356,7 @@
 }
 
 EBreakBetween LayoutBox::BreakAfter() const {
-  EBreakBetween break_value = Style()->BreakAfter();
+  EBreakBetween break_value = StyleRef().BreakAfter();
   if (break_value == EBreakBetween::kAuto ||
       IsBreakBetweenControllable(break_value))
     return break_value;
@@ -2362,7 +2364,7 @@
 }
 
 EBreakBetween LayoutBox::BreakBefore() const {
-  EBreakBetween break_value = Style()->BreakBefore();
+  EBreakBetween break_value = StyleRef().BreakBefore();
   if (break_value == EBreakBetween::kAuto ||
       IsBreakBetweenControllable(break_value))
     return break_value;
@@ -2370,7 +2372,7 @@
 }
 
 EBreakInside LayoutBox::BreakInside() const {
-  EBreakInside break_value = Style()->BreakInside();
+  EBreakInside break_value = StyleRef().BreakInside();
   if (break_value == EBreakInside::kAuto ||
       IsBreakInsideControllable(break_value))
     return break_value;
@@ -2522,7 +2524,7 @@
     return false;
 
   if (skip_info.AncestorSkipped()) {
-    bool preserve3D = container->Style()->Preserves3D();
+    bool preserve3D = container->StyleRef().Preserves3D();
     TransformState::TransformAccumulation accumulation =
         preserve3D ? TransformState::kAccumulateTransform
                    : TransformState::kFlattenTransform;
@@ -2615,7 +2617,7 @@
   Node* parent_node = layout_object->GeneratingNode();
   DCHECK(parent_node);
   DCHECK(IsHTMLOListElement(parent_node) || IsHTMLUListElement(parent_node));
-  DCHECK_NE(layout_object->Style()->TextAutosizingMultiplier(), 1);
+  DCHECK_NE(layout_object->StyleRef().TextAutosizingMultiplier(), 1);
 #endif
   float max_width = 0;
   for (LayoutObject* child = layout_object->SlowFirstChild(); child;
@@ -2666,8 +2668,9 @@
   // https://bugs.webkit.org/show_bug.cgi?id=46418
   bool in_vertical_box =
       Parent()->IsDeprecatedFlexibleBox() &&
-      (Parent()->Style()->BoxOrient() == EBoxOrient::kVertical);
-  bool stretching = (Parent()->Style()->BoxAlign() == EBoxAlignment::kStretch);
+      (Parent()->StyleRef().BoxOrient() == EBoxOrient::kVertical);
+  bool stretching =
+      (Parent()->StyleRef().BoxAlign() == EBoxAlignment::kStretch);
   // TODO (lajava): Stretching is the only reason why we don't want the box to
   // be treated as a replaced element, so we could perhaps refactor all this
   // logic, not only for flex and grid since alignment is intended to be applied
@@ -2725,7 +2728,7 @@
   ComputeMarginsForDirection(
       kInlineDirection, cb, container_logical_width, computed_values.extent_,
       computed_values.margins_.start_, computed_values.margins_.end_,
-      Style()->MarginStart(), Style()->MarginEnd());
+      StyleRef().MarginStart(), StyleRef().MarginEnd());
 
   if (!has_perpendicular_containing_block && container_logical_width &&
       container_logical_width !=
@@ -2735,8 +2738,8 @@
       !cb->IsLayoutGrid()) {
     LayoutUnit new_margin_total =
         container_logical_width - computed_values.extent_;
-    bool has_inverted_direction = cb->Style()->IsLeftToRightDirection() !=
-                                  Style()->IsLeftToRightDirection();
+    bool has_inverted_direction = cb->StyleRef().IsLeftToRightDirection() !=
+                                  StyleRef().IsLeftToRightDirection();
     if (has_inverted_direction) {
       computed_values.margins_.start_ =
           new_margin_total - computed_values.margins_.end_;
@@ -2756,8 +2759,8 @@
       const float adjusted_margin =
           (1 - 1.0 / style_to_use.TextAutosizingMultiplier()) *
           GetMaxWidthListMarker(this);
-      bool has_inverted_direction = cb->Style()->IsLeftToRightDirection() !=
-                                    Style()->IsLeftToRightDirection();
+      bool has_inverted_direction = cb->StyleRef().IsLeftToRightDirection() !=
+                                    StyleRef().IsLeftToRightDirection();
       if (has_inverted_direction)
         computed_values.margins_.end_ += adjusted_margin;
       else
@@ -2784,9 +2787,9 @@
   LayoutUnit available_size_for_resolving_margin =
       isOrthogonalElement ? ContainingBlockLogicalWidthForContent()
                           : available_logical_width;
-  margin_start = MinimumValueForLength(Style()->MarginStart(),
+  margin_start = MinimumValueForLength(StyleRef().MarginStart(),
                                        available_size_for_resolving_margin);
-  margin_end = MinimumValueForLength(Style()->MarginEnd(),
+  margin_end = MinimumValueForLength(StyleRef().MarginEnd(),
                                      available_size_for_resolving_margin);
   LayoutUnit available = available_logical_width - margin_start - margin_end;
   available = std::max(available, LayoutUnit());
@@ -2892,15 +2895,15 @@
 bool LayoutBox::IsStretchingColumnFlexItem() const {
   LayoutObject* parent = Parent();
   if (parent->IsDeprecatedFlexibleBox() &&
-      parent->Style()->BoxOrient() == EBoxOrient::kVertical &&
-      parent->Style()->BoxAlign() == EBoxAlignment::kStretch)
+      parent->StyleRef().BoxOrient() == EBoxOrient::kVertical &&
+      parent->StyleRef().BoxAlign() == EBoxAlignment::kStretch)
     return true;
 
   // We don't stretch multiline flexboxes because they need to apply line
   // spacing (align-content) first.
   if (parent->IsFlexibleBox() &&
-      parent->Style()->FlexWrap() == EFlexWrap::kNowrap &&
-      parent->Style()->IsColumnFlexDirection() &&
+      parent->StyleRef().FlexWrap() == EFlexWrap::kNowrap &&
+      parent->StyleRef().IsColumnFlexDirection() &&
       ColumnFlexItemHasStretchAlignment())
     return true;
   return false;
@@ -2948,8 +2951,8 @@
   if (Parent()->IsFlexibleBox()) {
     // For multiline columns, we need to apply align-content first, so we can't
     // stretch now.
-    if (!Parent()->Style()->IsColumnFlexDirection() ||
-        Parent()->Style()->FlexWrap() != EFlexWrap::kNowrap)
+    if (!Parent()->StyleRef().IsColumnFlexDirection() ||
+        Parent()->StyleRef().FlexWrap() != EFlexWrap::kNowrap)
       return true;
     if (!ColumnFlexItemHasStretchAlignment())
       return true;
@@ -2961,8 +2964,8 @@
   // FIXME: Think about writing-mode here.
   // https://bugs.webkit.org/show_bug.cgi?id=46473
   if (Parent()->IsDeprecatedFlexibleBox() &&
-      (Parent()->Style()->BoxOrient() == EBoxOrient::kHorizontal ||
-       Parent()->Style()->BoxAlign() != EBoxAlignment::kStretch))
+      (Parent()->StyleRef().BoxOrient() == EBoxOrient::kHorizontal ||
+       Parent()->StyleRef().BoxAlign() != EBoxAlignment::kStretch))
     return true;
 
   // Button, input, select, textarea, and legend treat width value of 'auto' as
@@ -3043,7 +3046,7 @@
   // width of the containing block, then any 'auto' values for 'margin-left' or
   // 'margin-right' are, for the following rules, treated as zero.
   LayoutUnit margin_box_width =
-      child_width + (!Style()->Width().IsAuto()
+      child_width + (!StyleRef().Width().IsAuto()
                          ? margin_start_width + margin_end_width
                          : LayoutUnit());
 
@@ -3119,8 +3122,8 @@
 static inline Length HeightForDocumentElement(const Document& document) {
   return document.documentElement()
       ->GetLayoutObject()
-      ->Style()
-      ->LogicalHeight();
+      ->StyleRef()
+      .LogicalHeight();
 }
 
 void LayoutBox::ComputeLogicalHeight(
@@ -3169,8 +3172,8 @@
       ComputeMarginsForDirection(
           flow_direction, cb, ContainingBlockLogicalWidthForContent(),
           computed_values.extent_, computed_values.margins_.before_,
-          computed_values.margins_.after_, Style()->MarginBefore(),
-          Style()->MarginAfter());
+          computed_values.margins_.after_, StyleRef().MarginBefore(),
+          StyleRef().MarginAfter());
       return;
     }
 
@@ -3178,8 +3181,9 @@
     // https://bugs.webkit.org/show_bug.cgi?id=46418
     bool in_horizontal_box =
         Parent()->IsDeprecatedFlexibleBox() &&
-        Parent()->Style()->BoxOrient() == EBoxOrient::kHorizontal;
-    bool stretching = Parent()->Style()->BoxAlign() == EBoxAlignment::kStretch;
+        Parent()->StyleRef().BoxOrient() == EBoxOrient::kHorizontal;
+    bool stretching =
+        Parent()->StyleRef().BoxAlign() == EBoxAlignment::kStretch;
     bool treat_as_replaced =
         ShouldComputeSizeAsReplaced() && (!in_horizontal_box || !stretching);
     bool check_min_max_height = false;
@@ -3193,7 +3197,7 @@
           ComputeReplacedLogicalHeight() + BorderAndPaddingLogicalHeight(),
           kFixed);
     } else {
-      h = Style()->LogicalHeight();
+      h = StyleRef().LogicalHeight();
       check_min_max_height = true;
     }
 
@@ -3211,7 +3215,7 @@
     LayoutUnit height_result;
     if (check_min_max_height) {
       height_result = ComputeLogicalHeightUsing(
-          kMainOrPreferredSize, Style()->LogicalHeight(),
+          kMainOrPreferredSize, StyleRef().LogicalHeight(),
           computed_values.extent_ - BorderAndPaddingLogicalHeight());
       if (height_result == -1)
         height_result = computed_values.extent_;
@@ -3227,8 +3231,8 @@
     ComputeMarginsForDirection(
         flow_direction, cb, ContainingBlockLogicalWidthForContent(),
         computed_values.extent_, computed_values.margins_.before_,
-        computed_values.margins_.after_, Style()->MarginBefore(),
-        Style()->MarginAfter());
+        computed_values.margins_.after_, StyleRef().MarginBefore(),
+        StyleRef().MarginAfter());
   }
 
   // WinIE quirk: The <html> block always fills the entire canvas in quirks
@@ -3357,7 +3361,7 @@
 bool LayoutBox::StretchesToViewportInQuirksMode() const {
   if (!IsDocumentElement() && !IsBody())
     return false;
-  return Style()->LogicalHeight().IsAuto() &&
+  return StyleRef().LogicalHeight().IsAuto() &&
          !IsFloatingOrOutOfFlowPositioned() && !IsInline() &&
          !FlowThreadContainingBlock();
 }
@@ -3387,7 +3391,7 @@
   return GetDocument().InQuirksMode() && !containing_block->IsTableCell() &&
          !containing_block->IsOutOfFlowPositioned() &&
          !containing_block->IsLayoutGrid() &&
-         containing_block->Style()->LogicalHeight().IsAuto();
+         containing_block->StyleRef().LogicalHeight().IsAuto();
 }
 
 LayoutUnit LayoutBox::ComputePercentageLogicalHeight(
@@ -3429,11 +3433,11 @@
         // height if they have overflow set to visible or hidden or if
         // they are replaced elements, and a 0px height if they have not.
         LayoutTableCell* cell = ToLayoutTableCell(cb);
-        if (Style()->OverflowY() != EOverflow::kVisible &&
-            Style()->OverflowY() != EOverflow::kHidden &&
+        if (StyleRef().OverflowY() != EOverflow::kVisible &&
+            StyleRef().OverflowY() != EOverflow::kHidden &&
             !ShouldBeConsideredAsReplaced() &&
-            (!cell->Style()->LogicalHeight().IsAuto() ||
-             !cell->Table()->Style()->LogicalHeight().IsAuto()))
+            (!cell->StyleRef().LogicalHeight().IsAuto() ||
+             !cell->Table()->StyleRef().LogicalHeight().IsAuto()))
           return LayoutUnit();
         return LayoutUnit(-1);
       }
@@ -3464,7 +3468,7 @@
       IsTable() ||
       (cb->IsTableCell() && !skipped_auto_height_containing_block &&
        cb->HasOverrideLogicalHeight() &&
-       Style()->BoxSizing() == EBoxSizing::kContentBox);
+       StyleRef().BoxSizing() == EBoxSizing::kContentBox);
   if (subtract_border_and_padding) {
     result -= BorderAndPaddingLogicalHeight();
     return std::max(LayoutUnit(), result);
@@ -3476,7 +3480,7 @@
     ShouldComputePreferred should_compute_preferred) const {
   return ComputeReplacedLogicalWidthRespectingMinMaxWidth(
       ComputeReplacedLogicalWidthUsing(kMainOrPreferredSize,
-                                       Style()->LogicalWidth()),
+                                       StyleRef().LogicalWidth()),
       should_compute_preferred);
 }
 
@@ -3485,17 +3489,17 @@
     ShouldComputePreferred should_compute_preferred) const {
   LayoutUnit min_logical_width =
       (should_compute_preferred == kComputePreferred &&
-       Style()->LogicalMinWidth().IsPercentOrCalc())
+       StyleRef().LogicalMinWidth().IsPercentOrCalc())
           ? logical_width
           : ComputeReplacedLogicalWidthUsing(kMinSize,
-                                             Style()->LogicalMinWidth());
+                                             StyleRef().LogicalMinWidth());
   LayoutUnit max_logical_width =
       (should_compute_preferred == kComputePreferred &&
-       Style()->LogicalMaxWidth().IsPercentOrCalc()) ||
-              Style()->LogicalMaxWidth().IsMaxSizeNone()
+       StyleRef().LogicalMaxWidth().IsPercentOrCalc()) ||
+              StyleRef().LogicalMaxWidth().IsMaxSizeNone()
           ? logical_width
           : ComputeReplacedLogicalWidthUsing(kMaxSize,
-                                             Style()->LogicalMaxWidth());
+                                             StyleRef().LogicalMaxWidth());
   return std::max(min_logical_width,
                   std::min(logical_width, max_logical_width));
 }
@@ -3535,7 +3539,7 @@
                  : PerpendicularContainingBlockLogicalHeight();
       }
       Length container_logical_width =
-          ContainingBlock()->Style()->LogicalWidth();
+          ContainingBlock()->StyleRef().LogicalWidth();
       // FIXME: Handle cases when containing block width is calculated or
       // viewport percent. https://bugs.webkit.org/show_bug.cgi?id=91071
       if (logical_width.IsIntrinsic())
@@ -3564,13 +3568,13 @@
 LayoutUnit LayoutBox::ComputeReplacedLogicalHeight(LayoutUnit) const {
   return ComputeReplacedLogicalHeightRespectingMinMaxHeight(
       ComputeReplacedLogicalHeightUsing(kMainOrPreferredSize,
-                                        Style()->LogicalHeight()));
+                                        StyleRef().LogicalHeight()));
 }
 
 bool LayoutBox::LogicalHeightComputesAsNone(SizeType size_type) const {
   DCHECK(size_type == kMinSize || size_type == kMaxSize);
-  Length logical_height = size_type == kMinSize ? Style()->LogicalMinHeight()
-                                                : Style()->LogicalMaxHeight();
+  Length logical_height = size_type == kMinSize ? StyleRef().LogicalMinHeight()
+                                                : StyleRef().LogicalMaxHeight();
   Length initial_logical_height =
       size_type == kMinSize ? ComputedStyleInitialValues::InitialMinHeight()
                             : ComputedStyleInitialValues::InitialMaxHeight();
@@ -3590,13 +3594,15 @@
   // the percentage value is treated as '0' (for 'min-height') or 'none' (for
   // 'max-height').
   LayoutUnit min_logical_height;
-  if (!LogicalHeightComputesAsNone(kMinSize))
+  if (!LogicalHeightComputesAsNone(kMinSize)) {
     min_logical_height = ComputeReplacedLogicalHeightUsing(
-        kMinSize, Style()->LogicalMinHeight());
+        kMinSize, StyleRef().LogicalMinHeight());
+  }
   LayoutUnit max_logical_height = logical_height;
-  if (!LogicalHeightComputesAsNone(kMaxSize))
+  if (!LogicalHeightComputesAsNone(kMaxSize)) {
     max_logical_height = ComputeReplacedLogicalHeightUsing(
-        kMaxSize, Style()->LogicalMaxHeight());
+        kMaxSize, StyleRef().LogicalMaxHeight());
+  }
   return std::max(min_logical_height,
                   std::min(logical_height, max_logical_height));
 }
@@ -3639,8 +3645,9 @@
         }
       }
 
-      if (cb->IsOutOfFlowPositioned() && cb->Style()->Height().IsAuto() &&
-          !(cb->Style()->Top().IsAuto() || cb->Style()->Bottom().IsAuto())) {
+      if (cb->IsOutOfFlowPositioned() && cb->StyleRef().Height().IsAuto() &&
+          !(cb->StyleRef().Top().IsAuto() ||
+            cb->StyleRef().Bottom().IsAuto())) {
         SECURITY_DCHECK(cb->IsLayoutBlock());
         LayoutBlock* block = ToLayoutBlock(cb);
         LogicalExtentComputedValues computed_values;
@@ -3671,8 +3678,8 @@
         // image are perpendicular writing-modes, this isn't right.
         // https://bugs.webkit.org/show_bug.cgi?id=46997
         while (cb && !cb->IsLayoutView() &&
-               (cb->Style()->LogicalHeight().IsAuto() ||
-                cb->Style()->LogicalHeight().IsPercentOrCalc())) {
+               (cb->StyleRef().LogicalHeight().IsAuto() ||
+                cb->StyleRef().LogicalHeight().IsPercentOrCalc())) {
           if (cb->IsTableCell()) {
             // Don't let table cells squeeze percent-height replaced elements
             // <http://bugs.webkit.org/show_bug.cgi?id=15359>
@@ -3713,7 +3720,7 @@
     // This code gets executed 740 times in the test case.
     // https://chromium-review.googlesource.com/c/chromium/src/+/1103289
     LayoutUnit height =
-        AvailableLogicalHeightUsing(Style()->LogicalHeight(), height_type);
+        AvailableLogicalHeightUsing(StyleRef().LogicalHeight(), height_type);
     if (UNLIKELY(height == -1))
       return height;
     return ConstrainContentBoxLogicalHeightByMinMax(height, LayoutUnit(-1));
@@ -3722,7 +3729,7 @@
   // in the content height.
   // FIXME: Should we pass intrinsicContentLogicalHeight() instead of -1 here?
   return ConstrainContentBoxLogicalHeightByMinMax(
-      AvailableLogicalHeightUsing(Style()->LogicalHeight(), height_type),
+      AvailableLogicalHeightUsing(StyleRef().LogicalHeight(), height_type),
       LayoutUnit(-1));
 }
 
@@ -3776,8 +3783,8 @@
   // writing-mode.
   // https://bugs.webkit.org/show_bug.cgi?id=46500
   if (IsLayoutBlock() && IsOutOfFlowPositioned() &&
-      Style()->Height().IsAuto() &&
-      !(Style()->Top().IsAuto() || Style()->Bottom().IsAuto())) {
+      StyleRef().Height().IsAuto() &&
+      !(StyleRef().Top().IsAuto() || StyleRef().Bottom().IsAuto())) {
     LayoutBlock* block = const_cast<LayoutBlock*>(ToLayoutBlock(this));
     LogicalExtentComputedValues computed_values;
     block->ComputeLogicalHeight(block->LogicalHeight(), LayoutUnit(),
@@ -3826,7 +3833,7 @@
     return ContainingBlockLogicalHeightForPositioned(containing_block, false);
 
   // Use viewport as container for top-level fixed-position elements.
-  if (Style()->GetPosition() == EPosition::kFixed &&
+  if (StyleRef().GetPosition() == EPosition::kFixed &&
       containing_block->IsLayoutView() && !GetDocument().Printing()) {
     const LayoutView* view = ToLayoutView(containing_block);
     if (LocalFrameView* frame_view = view->GetFrameView()) {
@@ -3856,7 +3863,7 @@
 
   DCHECK(containing_block->IsLayoutInline());
   DCHECK(containing_block->CanContainOutOfFlowPositionedElement(
-      Style()->GetPosition()));
+      StyleRef().GetPosition()));
 
   const LayoutInline* flow = ToLayoutInline(containing_block);
   InlineFlowBox* first = flow->FirstLineBox();
@@ -3868,7 +3875,7 @@
 
   LayoutUnit from_left;
   LayoutUnit from_right;
-  if (containing_block->Style()->IsLeftToRightDirection()) {
+  if (containing_block->StyleRef().IsLeftToRightDirection()) {
     from_left = first->LogicalLeft() + first->BorderLogicalLeft();
     from_right =
         last->LogicalLeft() + last->LogicalWidth() - last->BorderLogicalRight();
@@ -3889,7 +3896,7 @@
     return ContainingBlockLogicalWidthForPositioned(containing_block, false);
 
   // Use viewport as container for top-level fixed-position elements.
-  if (Style()->GetPosition() == EPosition::kFixed &&
+  if (StyleRef().GetPosition() == EPosition::kFixed &&
       containing_block->IsLayoutView() && !GetDocument().Printing()) {
     const LayoutView* view = ToLayoutView(containing_block);
     if (LocalFrameView* frame_view = view->GetFrameView()) {
@@ -3911,7 +3918,7 @@
 
   DCHECK(containing_block->IsLayoutInline());
   DCHECK(containing_block->CanContainOutOfFlowPositionedElement(
-      Style()->GetPosition()));
+      StyleRef().GetPosition()));
 
   const LayoutInline* flow = ToLayoutInline(containing_block);
   InlineFlowBox* first = flow->FirstLineBox();
@@ -3960,7 +3967,7 @@
     return;
 
   LayoutObject* parent = child->Parent();
-  TextDirection parent_direction = parent->Style()->Direction();
+  TextDirection parent_direction = parent->StyleRef().Direction();
 
   // This method is using EnclosingBox() which is wrong for absolutely
   // positioned grid items, as they rely on the grid area. So for grid items if
@@ -3995,13 +4002,13 @@
               *ToLayoutBox(curr), static_position, static_block_position);
       } else if (curr->IsInline()) {
         if (curr->IsInFlowPositioned()) {
-          if (!curr->Style()->LogicalLeft().IsAuto())
+          if (!curr->StyleRef().LogicalLeft().IsAuto())
             static_position +=
-                ValueForLength(curr->Style()->LogicalLeft(),
+                ValueForLength(curr->StyleRef().LogicalLeft(),
                                curr->ContainingBlock()->AvailableWidth());
           else
             static_position -=
-                ValueForLength(curr->Style()->LogicalRight(),
+                ValueForLength(curr->StyleRef().LogicalRight(),
                                curr->ContainingBlock()->AvailableWidth());
         }
       }
@@ -4033,13 +4040,13 @@
         }
       } else if (curr->IsInline()) {
         if (curr->IsInFlowPositioned()) {
-          if (!curr->Style()->LogicalLeft().IsAuto())
+          if (!curr->StyleRef().LogicalLeft().IsAuto())
             static_position -=
-                ValueForLength(curr->Style()->LogicalLeft(),
+                ValueForLength(curr->StyleRef().LogicalLeft(),
                                curr->ContainingBlock()->AvailableWidth());
           else
             static_position +=
-                ValueForLength(curr->Style()->LogicalRight(),
+                ValueForLength(curr->StyleRef().LogicalRight(),
                                curr->ContainingBlock()->AvailableWidth());
         }
       }
@@ -4079,17 +4086,17 @@
   // Use the container block's direction except when calculating the static
   // distance. This conforms with the reference results for
   // abspos-replaced-width-margin-000.htm of the CSS 2.1 test suite.
-  TextDirection container_direction = container_block->Style()->Direction();
+  TextDirection container_direction = container_block->StyleRef().Direction();
 
   bool is_horizontal = IsHorizontalWritingMode();
   const LayoutUnit borders_plus_padding = BorderAndPaddingLogicalWidth();
   const Length margin_logical_left =
-      is_horizontal ? Style()->MarginLeft() : Style()->MarginTop();
+      is_horizontal ? StyleRef().MarginLeft() : StyleRef().MarginTop();
   const Length margin_logical_right =
-      is_horizontal ? Style()->MarginRight() : Style()->MarginBottom();
+      is_horizontal ? StyleRef().MarginRight() : StyleRef().MarginBottom();
 
-  Length logical_left_length = Style()->LogicalLeft();
-  Length logical_right_length = Style()->LogicalRight();
+  Length logical_left_length = StyleRef().LogicalLeft();
+  Length logical_right_length = StyleRef().LogicalRight();
   // ---------------------------------------------------------------------------
   //  For the purposes of this section and the next, the term "static position"
   //  (of an element) refers, roughly, to the position an element would have had
@@ -4120,17 +4127,17 @@
 
   // Calculate constraint equation values for 'width' case.
   ComputePositionedLogicalWidthUsing(
-      kMainOrPreferredSize, Style()->LogicalWidth(), container_block,
+      kMainOrPreferredSize, StyleRef().LogicalWidth(), container_block,
       container_direction, container_logical_width, borders_plus_padding,
       logical_left_length, logical_right_length, margin_logical_left,
       margin_logical_right, computed_values);
 
   // Calculate constraint equation values for 'max-width' case.
-  if (!Style()->LogicalMaxWidth().IsMaxSizeNone()) {
+  if (!StyleRef().LogicalMaxWidth().IsMaxSizeNone()) {
     LogicalExtentComputedValues max_values;
 
     ComputePositionedLogicalWidthUsing(
-        kMaxSize, Style()->LogicalMaxWidth(), container_block,
+        kMaxSize, StyleRef().LogicalMaxWidth(), container_block,
         container_direction, container_logical_width, borders_plus_padding,
         logical_left_length, logical_right_length, margin_logical_left,
         margin_logical_right, max_values);
@@ -4144,12 +4151,12 @@
   }
 
   // Calculate constraint equation values for 'min-width' case.
-  if (!Style()->LogicalMinWidth().IsZero() ||
-      Style()->LogicalMinWidth().IsIntrinsic()) {
+  if (!StyleRef().LogicalMinWidth().IsZero() ||
+      StyleRef().LogicalMinWidth().IsIntrinsic()) {
     LogicalExtentComputedValues min_values;
 
     ComputePositionedLogicalWidthUsing(
-        kMinSize, Style()->LogicalMinWidth(), container_block,
+        kMinSize, StyleRef().LogicalMinWidth(), container_block,
         container_direction, container_logical_width, borders_plus_padding,
         logical_left_length, logical_right_length, margin_logical_left,
         margin_logical_right, min_values);
@@ -4177,7 +4184,7 @@
   // if the containing block is both a flipped mode and perpendicular to us.
   if (container_block->IsHorizontalWritingMode() !=
           child->IsHorizontalWritingMode() &&
-      container_block->Style()->IsFlippedBlocksWritingMode()) {
+      container_block->StyleRef().IsFlippedBlocksWritingMode()) {
     logical_left_pos =
         container_logical_width - logical_width_value - logical_left_pos;
     logical_left_pos +=
@@ -4246,12 +4253,12 @@
   bool logical_width_is_auto = logical_width.IsAuto();
   bool logical_left_is_auto = logical_left.IsAuto();
   bool logical_right_is_auto = logical_right.IsAuto();
-  LayoutUnit& margin_logical_left_value = Style()->IsLeftToRightDirection()
+  LayoutUnit& margin_logical_left_value = StyleRef().IsLeftToRightDirection()
                                               ? computed_values.margins_.start_
                                               : computed_values.margins_.end_;
   LayoutUnit& margin_logical_right_value =
-      Style()->IsLeftToRightDirection() ? computed_values.margins_.end_
-                                        : computed_values.margins_.start_;
+      StyleRef().IsLeftToRightDirection() ? computed_values.margins_.end_
+                                          : computed_values.margins_.start_;
   if (!logical_left_is_auto && !logical_width_is_auto &&
       !logical_right_is_auto) {
     // -------------------------------------------------------------------------
@@ -4412,7 +4419,7 @@
   // logical left position of the first line box when really it should use the
   // last line box. When this is fixed elsewhere, this block should be removed.
   if (container_block->IsLayoutInline() &&
-      !container_block->Style()->IsLeftToRightDirection()) {
+      !container_block->StyleRef().IsLeftToRightDirection()) {
     const LayoutInline* flow = ToLayoutInline(container_block);
     InlineFlowBox* first_line = flow->FirstLineBox();
     InlineFlowBox* last_line = flow->LastLineBox();
@@ -4582,11 +4589,11 @@
   // containing block's coordinate space. If the containing block is flipped
   // along this axis, then we need to flip the coordinate.  This can only happen
   // if the containing block is both a flipped mode and perpendicular to us.
-  if ((child->Style()->IsFlippedBlocksWritingMode() &&
+  if ((child->StyleRef().IsFlippedBlocksWritingMode() &&
        child->IsHorizontalWritingMode() !=
            container_block->IsHorizontalWritingMode()) ||
-      (child->Style()->IsFlippedBlocksWritingMode() !=
-           container_block->Style()->IsFlippedBlocksWritingMode() &&
+      (child->StyleRef().IsFlippedBlocksWritingMode() !=
+           container_block->StyleRef().IsFlippedBlocksWritingMode() &&
        child->IsHorizontalWritingMode() ==
            container_block->IsHorizontalWritingMode()))
     logical_top_pos =
@@ -4594,7 +4601,7 @@
 
   // Our offset is from the logical bottom edge in a flipped environment, e.g.,
   // right for vertical-rl.
-  if (container_block->Style()->IsFlippedBlocksWritingMode() &&
+  if (container_block->StyleRef().IsFlippedBlocksWritingMode() &&
       child->IsHorizontalWritingMode() ==
           container_block->IsHorizontalWritingMode()) {
     if (child->IsHorizontalWritingMode())
@@ -4813,7 +4820,7 @@
   LayoutUnit caret_width = GetFrameView()->CaretWidth();
   LayoutRect rect(Location(), LayoutSize(caret_width, Size().Height()));
   bool ltr =
-      box ? box->IsLeftToRightDirection() : Style()->IsLeftToRightDirection();
+      box ? box->IsLeftToRightDirection() : StyleRef().IsLeftToRightDirection();
 
   if ((!caret_offset) ^ ltr)
     rect.Move(LayoutSize(Size().Width() - caret_width, LayoutUnit()));
@@ -4834,7 +4841,7 @@
   // giant tall-as-window insertion point
   //
   // FIXME: ignoring :first-line, missing good reason to take care of
-  const SimpleFontData* font_data = Style()->GetFont().PrimaryFont();
+  const SimpleFontData* font_data = StyleRef().GetFont().PrimaryFont();
   LayoutUnit font_height =
       LayoutUnit(font_data ? font_data->GetFontMetrics().Height() : 0);
   if (font_height > rect.Height() || (!IsAtomicInlineLevel() && !IsTable()))
@@ -4896,7 +4903,7 @@
        layout_object = layout_object->NextSibling()) {
     if ((!layout_object->SlowFirstChild() && !layout_object->IsInline() &&
          !layout_object->IsLayoutBlockFlow()) ||
-        layout_object->Style()->Visibility() != EVisibility::kVisible)
+        layout_object->StyleRef().Visibility() != EVisibility::kVisible)
       continue;
 
     if (!layout_object->IsBox())
@@ -4971,7 +4978,7 @@
     return false;
 
   // Only auto width objects can possibly shrink to avoid floats.
-  if (!Style()->Width().IsAuto())
+  if (!StyleRef().Width().IsAuto())
     return false;
 
   // If the containing block is LayoutNG, we will not let legacy layout deal
@@ -5113,7 +5120,7 @@
 }
 
 void LayoutBox::AddVisualEffectOverflow() {
-  if (!Style()->HasVisualOverflowingEffect())
+  if (!StyleRef().HasVisualOverflowingEffect())
     return;
 
   // Add in the final overflow with shadows, outsets and outline combined.
@@ -5188,11 +5195,11 @@
 }
 
 bool LayoutBox::HasTopOverflow() const {
-  return !Style()->IsLeftToRightDirection() && !IsHorizontalWritingMode();
+  return !StyleRef().IsLeftToRightDirection() && !IsHorizontalWritingMode();
 }
 
 bool LayoutBox::HasLeftOverflow() const {
-  return !Style()->IsLeftToRightDirection() && IsHorizontalWritingMode();
+  return !StyleRef().IsLeftToRightDirection() && IsHorizontalWritingMode();
 }
 
 DISABLE_CFI_PERF
@@ -5313,14 +5320,14 @@
   // under these conditions, but it should work out to be good enough for common
   // cases. Paginating overflow with scrollbars present is not the end of the
   // world and is what we used to do in the old model anyway.
-  return !Style()->LogicalHeight().IsIntrinsicOrAuto() ||
-         (!Style()->LogicalMaxHeight().IsIntrinsicOrAuto() &&
-          !Style()->LogicalMaxHeight().IsMaxSizeNone() &&
-          (!Style()->LogicalMaxHeight().IsPercentOrCalc() ||
+  return !StyleRef().LogicalHeight().IsIntrinsicOrAuto() ||
+         (!StyleRef().LogicalMaxHeight().IsIntrinsicOrAuto() &&
+          !StyleRef().LogicalMaxHeight().IsMaxSizeNone() &&
+          (!StyleRef().LogicalMaxHeight().IsPercentOrCalc() ||
            PercentageLogicalHeightIsResolvable())) ||
-         (!Style()->LogicalMinHeight().IsIntrinsicOrAuto() &&
-          Style()->LogicalMinHeight().IsPositive() &&
-          (!Style()->LogicalMinHeight().IsPercentOrCalc() ||
+         (!StyleRef().LogicalMinHeight().IsIntrinsicOrAuto() &&
+          StyleRef().LogicalMinHeight().IsPositive() &&
+          (!StyleRef().LogicalMinHeight().IsPercentOrCalc() ||
            PercentageLogicalHeightIsResolvable()));
 }
 
@@ -5329,7 +5336,8 @@
   // actually look for replaced elements.
   if (IsAtomicInlineLevel() || HasUnsplittableScrollingOverflow() ||
       (Parent() && IsWritingModeRoot()) ||
-      (IsOutOfFlowPositioned() && Style()->GetPosition() == EPosition::kFixed))
+      (IsOutOfFlowPositioned() &&
+       StyleRef().GetPosition() == EPosition::kFixed))
     return kForbidBreaks;
 
   EBreakInside break_value = BreakInside();
@@ -5521,7 +5529,7 @@
 LayoutPoint LayoutBox::FlipForWritingModeForChild(
     const LayoutBox* child,
     const LayoutPoint& point) const {
-  if (!Style()->IsFlippedBlocksWritingMode())
+  if (!StyleRef().IsFlippedBlocksWritingMode())
     return point;
 
   // The child is going to add in its x(), so we have to make sure it ends up in
@@ -5559,15 +5567,15 @@
 }
 
 bool LayoutBox::HasRelativeLogicalWidth() const {
-  return Style()->LogicalWidth().IsPercentOrCalc() ||
-         Style()->LogicalMinWidth().IsPercentOrCalc() ||
-         Style()->LogicalMaxWidth().IsPercentOrCalc();
+  return StyleRef().LogicalWidth().IsPercentOrCalc() ||
+         StyleRef().LogicalMinWidth().IsPercentOrCalc() ||
+         StyleRef().LogicalMaxWidth().IsPercentOrCalc();
 }
 
 bool LayoutBox::HasRelativeLogicalHeight() const {
-  return Style()->LogicalHeight().IsPercentOrCalc() ||
-         Style()->LogicalMinHeight().IsPercentOrCalc() ||
-         Style()->LogicalMaxHeight().IsPercentOrCalc();
+  return StyleRef().LogicalHeight().IsPercentOrCalc() ||
+         StyleRef().LogicalMinHeight().IsPercentOrCalc() ||
+         StyleRef().LogicalMaxHeight().IsPercentOrCalc();
 }
 
 static void MarkBoxForRelayoutAfterSplit(LayoutBox* box) {
@@ -5787,18 +5795,18 @@
 
 bool LayoutBox::MustInvalidateBackgroundOrBorderPaintOnWidthChange() const {
   if (HasMask() &&
-      MustInvalidateFillLayersPaintOnWidthChange(Style()->MaskLayers()))
+      MustInvalidateFillLayersPaintOnWidthChange(StyleRef().MaskLayers()))
     return true;
 
   // If we don't have a background/border/mask, then nothing to do.
   if (!HasBoxDecorationBackground())
     return false;
 
-  if (MustInvalidateFillLayersPaintOnWidthChange(Style()->BackgroundLayers()))
+  if (MustInvalidateFillLayersPaintOnWidthChange(StyleRef().BackgroundLayers()))
     return true;
 
   // Our fill layers are ok. Let's check border.
-  if (Style()->CanRenderBorderImage())
+  if (StyleRef().CanRenderBorderImage())
     return true;
 
   return false;
@@ -5806,18 +5814,19 @@
 
 bool LayoutBox::MustInvalidateBackgroundOrBorderPaintOnHeightChange() const {
   if (HasMask() &&
-      MustInvalidateFillLayersPaintOnHeightChange(Style()->MaskLayers()))
+      MustInvalidateFillLayersPaintOnHeightChange(StyleRef().MaskLayers()))
     return true;
 
   // If we don't have a background/border/mask, then nothing to do.
   if (!HasBoxDecorationBackground())
     return false;
 
-  if (MustInvalidateFillLayersPaintOnHeightChange(Style()->BackgroundLayers()))
+  if (MustInvalidateFillLayersPaintOnHeightChange(
+          StyleRef().BackgroundLayers()))
     return true;
 
   // Our fill layers are ok.  Let's check border.
-  if (Style()->CanRenderBorderImage())
+  if (StyleRef().CanRenderBorderImage())
     return true;
 
   return false;
@@ -6094,7 +6103,7 @@
     if (InlineBoxWrapper())
       return InlineBoxWrapper()->Direction();
   }
-  return Style()->Direction();
+  return StyleRef().Direction();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 0bb8a00..f8e7b716 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -262,22 +262,22 @@
   }
 
   LayoutUnit LogicalLeft() const {
-    return Style()->IsHorizontalWritingMode() ? frame_rect_.X()
-                                              : frame_rect_.Y();
+    return StyleRef().IsHorizontalWritingMode() ? frame_rect_.X()
+                                                : frame_rect_.Y();
   }
   LayoutUnit LogicalRight() const { return LogicalLeft() + LogicalWidth(); }
   LayoutUnit LogicalTop() const {
-    return Style()->IsHorizontalWritingMode() ? frame_rect_.Y()
-                                              : frame_rect_.X();
+    return StyleRef().IsHorizontalWritingMode() ? frame_rect_.Y()
+                                                : frame_rect_.X();
   }
   LayoutUnit LogicalBottom() const { return LogicalTop() + LogicalHeight(); }
   LayoutUnit LogicalWidth() const {
-    return Style()->IsHorizontalWritingMode() ? frame_rect_.Width()
-                                              : frame_rect_.Height();
+    return StyleRef().IsHorizontalWritingMode() ? frame_rect_.Width()
+                                                : frame_rect_.Height();
   }
   LayoutUnit LogicalHeight() const {
-    return Style()->IsHorizontalWritingMode() ? frame_rect_.Height()
-                                              : frame_rect_.Width();
+    return StyleRef().IsHorizontalWritingMode() ? frame_rect_.Height()
+                                                : frame_rect_.Width();
   }
 
   // Logical height of the object, including content overflowing the
@@ -295,12 +295,12 @@
       LayoutUnit intrinsic_content_height) const;
 
   int PixelSnappedLogicalHeight() const {
-    return Style()->IsHorizontalWritingMode() ? PixelSnappedHeight()
-                                              : PixelSnappedWidth();
+    return StyleRef().IsHorizontalWritingMode() ? PixelSnappedHeight()
+                                                : PixelSnappedWidth();
   }
   int PixelSnappedLogicalWidth() const {
-    return Style()->IsHorizontalWritingMode() ? PixelSnappedWidth()
-                                              : PixelSnappedHeight();
+    return StyleRef().IsHorizontalWritingMode() ? PixelSnappedWidth()
+                                                : PixelSnappedHeight();
   }
 
   LayoutUnit MinimumLogicalHeightForEmptyLine() const {
@@ -312,31 +312,31 @@
   }
 
   void SetLogicalLeft(LayoutUnit left) {
-    if (Style()->IsHorizontalWritingMode())
+    if (StyleRef().IsHorizontalWritingMode())
       SetX(left);
     else
       SetY(left);
   }
   void SetLogicalTop(LayoutUnit top) {
-    if (Style()->IsHorizontalWritingMode())
+    if (StyleRef().IsHorizontalWritingMode())
       SetY(top);
     else
       SetX(top);
   }
   void SetLogicalLocation(const LayoutPoint& location) {
-    if (Style()->IsHorizontalWritingMode())
+    if (StyleRef().IsHorizontalWritingMode())
       SetLocation(location);
     else
       SetLocation(location.TransposedPoint());
   }
   void SetLogicalWidth(LayoutUnit size) {
-    if (Style()->IsHorizontalWritingMode())
+    if (StyleRef().IsHorizontalWritingMode())
       SetWidth(size);
     else
       SetHeight(size);
   }
   void SetLogicalHeight(LayoutUnit size) {
-    if (Style()->IsHorizontalWritingMode())
+    if (StyleRef().IsHorizontalWritingMode())
       SetHeight(size);
     else
       SetWidth(size);
@@ -479,12 +479,12 @@
     return LayoutSize(LayoutOverflowRect().MaxX(), LayoutOverflowRect().MaxY());
   }
   LayoutUnit LogicalLeftLayoutOverflow() const {
-    return Style()->IsHorizontalWritingMode() ? LayoutOverflowRect().X()
-                                              : LayoutOverflowRect().Y();
+    return StyleRef().IsHorizontalWritingMode() ? LayoutOverflowRect().X()
+                                                : LayoutOverflowRect().Y();
   }
   LayoutUnit LogicalRightLayoutOverflow() const {
-    return Style()->IsHorizontalWritingMode() ? LayoutOverflowRect().MaxX()
-                                              : LayoutOverflowRect().MaxY();
+    return StyleRef().IsHorizontalWritingMode() ? LayoutOverflowRect().MaxX()
+                                                : LayoutOverflowRect().MaxY();
   }
 
   LayoutRect VisualOverflowRect() const override;
@@ -494,12 +494,12 @@
     return overflow_rect;
   }
   LayoutUnit LogicalLeftVisualOverflow() const {
-    return Style()->IsHorizontalWritingMode() ? VisualOverflowRect().X()
-                                              : VisualOverflowRect().Y();
+    return StyleRef().IsHorizontalWritingMode() ? VisualOverflowRect().X()
+                                                : VisualOverflowRect().Y();
   }
   LayoutUnit LogicalRightVisualOverflow() const {
-    return Style()->IsHorizontalWritingMode() ? VisualOverflowRect().MaxX()
-                                              : VisualOverflowRect().MaxY();
+    return StyleRef().IsHorizontalWritingMode() ? VisualOverflowRect().MaxX()
+                                                : VisualOverflowRect().MaxY();
   }
 
   LayoutRect SelfVisualOverflowRect() const {
@@ -556,12 +556,12 @@
     return LayoutSize(ContentWidth(), ContentHeight());
   }
   LayoutUnit ContentLogicalWidth() const {
-    return Style()->IsHorizontalWritingMode() ? ContentWidth()
-                                              : ContentHeight();
+    return StyleRef().IsHorizontalWritingMode() ? ContentWidth()
+                                                : ContentHeight();
   }
   LayoutUnit ContentLogicalHeight() const {
-    return Style()->IsHorizontalWritingMode() ? ContentHeight()
-                                              : ContentWidth();
+    return StyleRef().IsHorizontalWritingMode() ? ContentHeight()
+                                                : ContentWidth();
   }
 
   // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines
@@ -586,10 +586,12 @@
   LayoutUnit ClientWidth() const;
   LayoutUnit ClientHeight() const;
   DISABLE_CFI_PERF LayoutUnit ClientLogicalWidth() const {
-    return Style()->IsHorizontalWritingMode() ? ClientWidth() : ClientHeight();
+    return StyleRef().IsHorizontalWritingMode() ? ClientWidth()
+                                                : ClientHeight();
   }
   DISABLE_CFI_PERF LayoutUnit ClientLogicalHeight() const {
-    return Style()->IsHorizontalWritingMode() ? ClientHeight() : ClientWidth();
+    return StyleRef().IsHorizontalWritingMode() ? ClientHeight()
+                                                : ClientWidth();
   }
   DISABLE_CFI_PERF LayoutUnit ClientLogicalBottom() const {
     return BorderBefore() + ClientLogicalHeight();
@@ -914,12 +916,12 @@
 
   virtual LayoutSize IntrinsicSize() const { return LayoutSize(); }
   LayoutUnit IntrinsicLogicalWidth() const {
-    return Style()->IsHorizontalWritingMode() ? IntrinsicSize().Width()
-                                              : IntrinsicSize().Height();
+    return StyleRef().IsHorizontalWritingMode() ? IntrinsicSize().Width()
+                                                : IntrinsicSize().Height();
   }
   LayoutUnit IntrinsicLogicalHeight() const {
-    return Style()->IsHorizontalWritingMode() ? IntrinsicSize().Height()
-                                              : IntrinsicSize().Width();
+    return StyleRef().IsHorizontalWritingMode() ? IntrinsicSize().Height()
+                                                : IntrinsicSize().Width();
   }
   virtual LayoutUnit IntrinsicContentLogicalHeight() const {
     return intrinsic_content_logical_height_;
@@ -980,12 +982,12 @@
   // physical width and available physical height. Relative positioning is one
   // of those cases, since left/top offsets are physical.
   LayoutUnit AvailableWidth() const {
-    return Style()->IsHorizontalWritingMode()
+    return StyleRef().IsHorizontalWritingMode()
                ? AvailableLogicalWidth()
                : AvailableLogicalHeight(kIncludeMarginBorderPadding);
   }
   LayoutUnit AvailableHeight() const {
-    return Style()->IsHorizontalWritingMode()
+    return StyleRef().IsHorizontalWritingMode()
                ? AvailableLogicalHeight(kIncludeMarginBorderPadding)
                : AvailableLogicalWidth();
   }
@@ -993,12 +995,12 @@
   int VerticalScrollbarWidth() const;
   int HorizontalScrollbarHeight() const;
   int ScrollbarLogicalWidth() const {
-    return Style()->IsHorizontalWritingMode() ? VerticalScrollbarWidth()
-                                              : HorizontalScrollbarHeight();
+    return StyleRef().IsHorizontalWritingMode() ? VerticalScrollbarWidth()
+                                                : HorizontalScrollbarHeight();
   }
   int ScrollbarLogicalHeight() const {
-    return Style()->IsHorizontalWritingMode() ? HorizontalScrollbarHeight()
-                                              : VerticalScrollbarWidth();
+    return StyleRef().IsHorizontalWritingMode() ? HorizontalScrollbarHeight()
+                                                : VerticalScrollbarWidth();
   }
 
   // Return the width of the vertical scrollbar, unless it's larger than the
@@ -1019,16 +1021,16 @@
   virtual void DispatchFakeMouseMoveEventSoon(EventHandler&);
 
   DISABLE_CFI_PERF bool HasAutoVerticalScrollbar() const {
-    return HasOverflowClip() && Style()->HasAutoVerticalScroll();
+    return HasOverflowClip() && StyleRef().HasAutoVerticalScroll();
   }
   DISABLE_CFI_PERF bool HasAutoHorizontalScrollbar() const {
-    return HasOverflowClip() && Style()->HasAutoHorizontalScroll();
+    return HasOverflowClip() && StyleRef().HasAutoHorizontalScroll();
   }
   DISABLE_CFI_PERF bool ScrollsOverflow() const {
-    return HasOverflowClip() && Style()->ScrollsOverflow();
+    return HasOverflowClip() && StyleRef().ScrollsOverflow();
   }
   virtual bool ShouldPlaceBlockDirectionScrollbarOnLogicalLeft() const {
-    return Style()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft();
+    return StyleRef().ShouldPlaceBlockDirectionScrollbarOnLogicalLeft();
   }
 
   bool HasScrollableOverflowX() const {
@@ -1040,10 +1042,10 @@
            PixelSnappedScrollHeight() != PixelSnappedClientHeight();
   }
   virtual bool ScrollsOverflowX() const {
-    return HasOverflowClip() && Style()->ScrollsOverflowX();
+    return HasOverflowClip() && StyleRef().ScrollsOverflowX();
   }
   virtual bool ScrollsOverflowY() const {
-    return HasOverflowClip() && Style()->ScrollsOverflowY();
+    return HasOverflowClip() && StyleRef().ScrollsOverflowY();
   }
 
   // Elements such as the <input> field override this to specify that they are
@@ -1116,7 +1118,7 @@
 
   bool IsWritingModeRoot() const {
     return !Parent() ||
-           Parent()->Style()->GetWritingMode() != Style()->GetWritingMode();
+           Parent()->StyleRef().GetWritingMode() != StyleRef().GetWritingMode();
   }
   bool IsOrthogonalWritingModeRoot() const {
     return Parent() &&
@@ -1315,7 +1317,7 @@
   }
 
   bool HasSameDirectionAs(const LayoutBox* object) const {
-    return Style()->Direction() == object->Style()->Direction();
+    return StyleRef().Direction() == object->StyleRef().Direction();
   }
 
   ShapeOutsideInfo* GetShapeOutsideInfo() const;
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index 63ebb6a..7d802ae 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -49,15 +49,15 @@
 inline bool IsOutOfFlowPositionedWithImplicitHeight(
     const LayoutBoxModelObject* child) {
   return child->IsOutOfFlowPositioned() &&
-         !child->Style()->LogicalTop().IsAuto() &&
-         !child->Style()->LogicalBottom().IsAuto();
+         !child->StyleRef().LogicalTop().IsAuto() &&
+         !child->StyleRef().LogicalBottom().IsAuto();
 }
 
 // Inclusive of |from|, exclusive of |to|.
 PaintLayer* FindFirstStickyBetween(LayoutObject* from, LayoutObject* to) {
   LayoutObject* maybe_sticky_ancestor = from;
   while (maybe_sticky_ancestor && maybe_sticky_ancestor != to) {
-    if (maybe_sticky_ancestor->Style()->HasStickyConstrainedPosition()) {
+    if (maybe_sticky_ancestor->StyleRef().HasStickyConstrainedPosition()) {
       return ToLayoutBoxModelObject(maybe_sticky_ancestor)->Layer();
     }
 
@@ -118,7 +118,7 @@
   // TODO(flackr): Remove this when box shadows are still painted correctly when
   // painting into the composited scrolling contents layer.
   // https://crbug.com/646464
-  if (Style()->BoxShadow()) {
+  if (StyleRef().BoxShadow()) {
     if (reasons)
       *reasons |= MainThreadScrollingReason::kHasBoxShadowFromNonRootLayer;
     return kBackgroundPaintInGraphicsLayer;
@@ -127,7 +127,7 @@
   // Assume optimistically that the background can be painted in the scrolling
   // contents until we find otherwise.
   BackgroundPaintLocation paint_location = kBackgroundPaintInScrollingContents;
-  const FillLayer* layer = &(Style()->BackgroundLayers());
+  const FillLayer* layer = &(StyleRef().BackgroundLayers());
   for (; layer; layer = layer->Next()) {
     if (layer->Attachment() == EFillAttachment::kLocal)
       continue;
@@ -143,20 +143,20 @@
       // there is no border and we don't have custom scrollbars.
       if (clip == EFillBox::kBorder) {
         if (!has_custom_scrollbars &&
-            (Style()->BorderTopWidth() == 0 ||
+            (StyleRef().BorderTopWidth() == 0 ||
              !ResolveColor(GetCSSPropertyBorderTopColor()).HasAlpha()) &&
-            (Style()->BorderLeftWidth() == 0 ||
+            (StyleRef().BorderLeftWidth() == 0 ||
              !ResolveColor(GetCSSPropertyBorderLeftColor()).HasAlpha()) &&
-            (Style()->BorderRightWidth() == 0 ||
+            (StyleRef().BorderRightWidth() == 0 ||
              !ResolveColor(GetCSSPropertyBorderRightColor()).HasAlpha()) &&
-            (Style()->BorderBottomWidth() == 0 ||
+            (StyleRef().BorderBottomWidth() == 0 ||
              !ResolveColor(GetCSSPropertyBorderBottomColor()).HasAlpha())) {
           continue;
         }
         // If we have an opaque background color only, we can safely paint it
         // into both the scrolling contents layer and the graphics layer to
         // preserve LCD text.
-        if (layer == (&Style()->BackgroundLayers()) &&
+        if (layer == (&StyleRef().BackgroundLayers()) &&
             ResolveColor(GetCSSPropertyBackgroundColor()).Alpha() < 255)
           return kBackgroundPaintInGraphicsLayer;
         paint_location |= kBackgroundPaintInGraphicsLayer;
@@ -164,9 +164,10 @@
       }
       // A content fill box can be treated as a padding fill box if there is no
       // padding.
-      if (clip == EFillBox::kContent && Style()->PaddingTop().IsZero() &&
-          Style()->PaddingLeft().IsZero() && Style()->PaddingRight().IsZero() &&
-          Style()->PaddingBottom().IsZero()) {
+      if (clip == EFillBox::kContent && StyleRef().PaddingTop().IsZero() &&
+          StyleRef().PaddingLeft().IsZero() &&
+          StyleRef().PaddingRight().IsZero() &&
+          StyleRef().PaddingBottom().IsZero()) {
         continue;
       }
     }
@@ -190,8 +191,8 @@
     // 0 during destruction.
     if (LocalFrame* frame = GetFrame()) {
       if (LocalFrameView* frame_view = frame->View()) {
-        if (Style()->HasViewportConstrainedPosition() ||
-            Style()->HasStickyConstrainedPosition())
+        if (StyleRef().HasViewportConstrainedPosition() ||
+            StyleRef().HasStickyConstrainedPosition())
           frame_view->RemoveViewportConstrainedObject(*this);
       }
     }
@@ -218,8 +219,8 @@
   // invalidate the current compositing container chain which may have painted
   // cached subsequences containing this object or descendant objects.
   if (Style() &&
-      (Style()->IsStacked() != new_style.IsStacked() ||
-       Style()->IsStackingContext() != new_style.IsStackingContext()) &&
+      (StyleRef().IsStacked() != new_style.IsStacked() ||
+       StyleRef().IsStackingContext() != new_style.IsStackingContext()) &&
       // ObjectPaintInvalidator requires this.
       IsRooted()) {
     if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
@@ -358,7 +359,7 @@
           old_style && ToLayoutBoxModelObject(body_layout)
                            ->BackgroundStolenForBeingBody(old_style);
       if (new_stole_body_background != old_stole_body_background &&
-          body_layout->Style() && body_layout->Style()->HasBackground()) {
+          body_layout->Style() && body_layout->StyleRef().HasBackground()) {
         body_layout->SetShouldDoFullPaintInvalidation();
       }
     }
@@ -366,10 +367,10 @@
 
   if (LocalFrameView* frame_view = View()->GetFrameView()) {
     bool new_style_is_viewport_constained =
-        Style()->GetPosition() == EPosition::kFixed;
+        StyleRef().GetPosition() == EPosition::kFixed;
     bool old_style_is_viewport_constrained =
         old_style && old_style->GetPosition() == EPosition::kFixed;
-    bool new_style_is_sticky = Style()->HasStickyConstrainedPosition();
+    bool new_style_is_sticky = StyleRef().HasStickyConstrainedPosition();
     bool old_style_is_sticky =
         old_style && old_style->HasStickyConstrainedPosition();
 
@@ -674,7 +675,7 @@
   // TODO(rego): Check if we can somehow reuse LayoutBlock::
   // availableLogicalHeightForPercentageComputation() (see crbug.com/635655).
   const LayoutBox* this_box = IsBox() ? ToLayoutBox(this) : nullptr;
-  Length logical_height_length = Style()->LogicalHeight();
+  Length logical_height_length = StyleRef().LogicalHeight();
   LayoutBlock* cb =
       ContainingBlockForAutoHeightDetection(logical_height_length);
   if (logical_height_length.IsPercentOrCalc() && cb && IsBox())
@@ -715,11 +716,14 @@
   // https://drafts.csswg.org/css-position-3/#rel-pos
   base::Optional<LayoutUnit> left;
   base::Optional<LayoutUnit> right;
-  if (!Style()->Left().IsAuto())
-    left = ValueForLength(Style()->Left(), containing_block->AvailableWidth());
-  if (!Style()->Right().IsAuto())
+  if (!StyleRef().Left().IsAuto()) {
+    left =
+        ValueForLength(StyleRef().Left(), containing_block->AvailableWidth());
+  }
+  if (!StyleRef().Right().IsAuto()) {
     right =
-        ValueForLength(Style()->Right(), containing_block->AvailableWidth());
+        ValueForLength(StyleRef().Right(), containing_block->AvailableWidth());
+  }
   if (!left && !right) {
     left = LayoutUnit();
     right = LayoutUnit();
@@ -728,8 +732,8 @@
     left = -right.value();
   if (!right)
     right = -left.value();
-  bool is_ltr = containing_block->Style()->IsLeftToRightDirection();
-  WritingMode writing_mode = containing_block->Style()->GetWritingMode();
+  bool is_ltr = containing_block->StyleRef().IsLeftToRightDirection();
+  WritingMode writing_mode = containing_block->StyleRef().GetWritingMode();
   switch (writing_mode) {
     case WritingMode::kHorizontalTb:
       if (is_ltr)
@@ -757,18 +761,18 @@
 
   base::Optional<LayoutUnit> top;
   base::Optional<LayoutUnit> bottom;
-  if (!Style()->Top().IsAuto() &&
+  if (!StyleRef().Top().IsAuto() &&
       (!containing_block->HasAutoHeightOrContainingBlockWithAutoHeight() ||
-       !Style()->Top().IsPercentOrCalc() ||
+       !StyleRef().Top().IsPercentOrCalc() ||
        containing_block->StretchesToViewport())) {
-    top = ValueForLength(Style()->Top(), containing_block->AvailableHeight());
+    top = ValueForLength(StyleRef().Top(), containing_block->AvailableHeight());
   }
-  if (!Style()->Bottom().IsAuto() &&
+  if (!StyleRef().Bottom().IsAuto() &&
       (!containing_block->HasAutoHeightOrContainingBlockWithAutoHeight() ||
-       !Style()->Bottom().IsPercentOrCalc() ||
+       !StyleRef().Bottom().IsPercentOrCalc() ||
        containing_block->StretchesToViewport())) {
-    bottom =
-        ValueForLength(Style()->Bottom(), containing_block->AvailableHeight());
+    bottom = ValueForLength(StyleRef().Bottom(),
+                            containing_block->AvailableHeight());
   }
   if (!top && !bottom) {
     top = LayoutUnit();
@@ -867,18 +871,18 @@
   // It is an open issue whether the margin should collapse.
   // See https://www.w3.org/TR/css-position-3/#sticky-pos
   scroll_container_relative_containing_block_rect.ContractEdges(
-      MinimumValueForLength(containing_block->Style()->PaddingTop(),
+      MinimumValueForLength(containing_block->StyleRef().PaddingTop(),
                             max_container_width) +
-          MinimumValueForLength(Style()->MarginTop(), max_width),
-      MinimumValueForLength(containing_block->Style()->PaddingRight(),
+          MinimumValueForLength(StyleRef().MarginTop(), max_width),
+      MinimumValueForLength(containing_block->StyleRef().PaddingRight(),
                             max_container_width) +
-          MinimumValueForLength(Style()->MarginRight(), max_width),
-      MinimumValueForLength(containing_block->Style()->PaddingBottom(),
+          MinimumValueForLength(StyleRef().MarginRight(), max_width),
+      MinimumValueForLength(containing_block->StyleRef().PaddingBottom(),
                             max_container_width) +
-          MinimumValueForLength(Style()->MarginBottom(), max_width),
-      MinimumValueForLength(containing_block->Style()->PaddingLeft(),
+          MinimumValueForLength(StyleRef().MarginBottom(), max_width),
+      MinimumValueForLength(containing_block->StyleRef().PaddingLeft(),
                             max_container_width) +
-          MinimumValueForLength(Style()->MarginLeft(), max_width));
+          MinimumValueForLength(StyleRef().MarginLeft(), max_width));
 
   constraints.scroll_container_relative_containing_block_rect =
       FloatRect(scroll_container_relative_containing_block_rect);
@@ -923,31 +927,31 @@
   // We skip the right or top sticky offset if there is not enough space to
   // honor both the left/right or top/bottom offsets.
   LayoutUnit horizontal_offsets =
-      MinimumValueForLength(Style()->Right(),
+      MinimumValueForLength(StyleRef().Right(),
                             LayoutUnit(constraining_size.Width())) +
-      MinimumValueForLength(Style()->Left(),
+      MinimumValueForLength(StyleRef().Left(),
                             LayoutUnit(constraining_size.Width()));
   bool skip_right = false;
   bool skip_left = false;
-  if (!Style()->Left().IsAuto() && !Style()->Right().IsAuto()) {
+  if (!StyleRef().Left().IsAuto() && !StyleRef().Right().IsAuto()) {
     if (horizontal_offsets >
             scroll_container_relative_containing_block_rect.Width() ||
         horizontal_offsets + sticky_box_rect.Width() >
             constraining_size.Width()) {
-      skip_right = Style()->IsLeftToRightDirection();
+      skip_right = StyleRef().IsLeftToRightDirection();
       skip_left = !skip_right;
     }
   }
 
-  if (!Style()->Left().IsAuto() && !skip_left) {
+  if (!StyleRef().Left().IsAuto() && !skip_left) {
     constraints.left_offset = MinimumValueForLength(
-        Style()->Left(), LayoutUnit(constraining_size.Width()));
+        StyleRef().Left(), LayoutUnit(constraining_size.Width()));
     constraints.is_anchored_left = true;
   }
 
-  if (!Style()->Right().IsAuto() && !skip_right) {
+  if (!StyleRef().Right().IsAuto() && !skip_right) {
     constraints.right_offset = MinimumValueForLength(
-        Style()->Right(), LayoutUnit(constraining_size.Width()));
+        StyleRef().Right(), LayoutUnit(constraining_size.Width()));
     constraints.is_anchored_right = true;
   }
 
@@ -956,11 +960,11 @@
   // mode when related sections are fixed in spec.
   // See http://lists.w3.org/Archives/Public/www-style/2014May/0286.html
   LayoutUnit vertical_offsets =
-      MinimumValueForLength(Style()->Top(),
+      MinimumValueForLength(StyleRef().Top(),
                             LayoutUnit(constraining_size.Height())) +
-      MinimumValueForLength(Style()->Bottom(),
+      MinimumValueForLength(StyleRef().Bottom(),
                             LayoutUnit(constraining_size.Height()));
-  if (!Style()->Top().IsAuto() && !Style()->Bottom().IsAuto()) {
+  if (!StyleRef().Top().IsAuto() && !StyleRef().Bottom().IsAuto()) {
     if (vertical_offsets >
             scroll_container_relative_containing_block_rect.Height() ||
         vertical_offsets + sticky_box_rect.Height() >
@@ -969,15 +973,15 @@
     }
   }
 
-  if (!Style()->Top().IsAuto()) {
+  if (!StyleRef().Top().IsAuto()) {
     constraints.top_offset = MinimumValueForLength(
-        Style()->Top(), LayoutUnit(constraining_size.Height()));
+        StyleRef().Top(), LayoutUnit(constraining_size.Height()));
     constraints.is_anchored_top = true;
   }
 
-  if (!Style()->Bottom().IsAuto() && !skip_bottom) {
+  if (!StyleRef().Bottom().IsAuto() && !skip_bottom) {
     constraints.bottom_offset = MinimumValueForLength(
-        Style()->Bottom(), LayoutUnit(constraining_size.Height()));
+        StyleRef().Bottom(), LayoutUnit(constraining_size.Height()));
     constraints.is_anchored_bottom = true;
   }
   PaintLayerScrollableArea* scrollable_area =
@@ -986,8 +990,8 @@
 }
 
 bool LayoutBoxModelObject::IsSlowRepaintConstrainedObject() const {
-  if (!HasLayer() || (Style()->GetPosition() != EPosition::kFixed &&
-                      Style()->GetPosition() != EPosition::kSticky)) {
+  if (!HasLayer() || (StyleRef().GetPosition() != EPosition::kFixed &&
+                      StyleRef().GetPosition() != EPosition::kSticky)) {
     return false;
   }
 
@@ -1105,7 +1109,7 @@
 
       if (IsBox() && IsOutOfFlowPositioned() &&
           inline_parent->CanContainOutOfFlowPositionedElement(
-              Style()->GetPosition())) {
+              StyleRef().GetPosition())) {
         // Offset for out of flow positioned elements with inline containers is
         // a special case in the CSS spec
         reference_point +=
@@ -1258,7 +1262,7 @@
   }
   x = std::min(x, (max_x - caret_width).ClampNegativeToZero());
 
-  const Font& font = Style()->GetFont();
+  const Font& font = StyleRef().GetFont();
   const SimpleFontData* font_data = font.PrimaryFont();
   LayoutUnit height;
   // crbug.com/595692 This check should not be needed but sometimes
@@ -1288,7 +1292,8 @@
     return nullptr;
 
   bool is_inline = IsLayoutInline();
-  bool is_fixed_pos = !is_inline && Style()->GetPosition() == EPosition::kFixed;
+  bool is_fixed_pos =
+      !is_inline && StyleRef().GetPosition() == EPosition::kFixed;
   bool contains_fixed_position = CanContainFixedPositionObjects();
 
   TransformationMatrix adjustment_for_skipped_ancestor;
@@ -1311,10 +1316,12 @@
     offset_depends_on_point = true;
   } else {
     offset_depends_on_point =
-        container->Style()->IsFlippedBlocksWritingMode() && container->IsBox();
+        container->StyleRef().IsFlippedBlocksWritingMode() &&
+        container->IsBox();
   }
 
-  bool preserve3d = container->Style()->Preserves3D() || Style()->Preserves3D();
+  bool preserve3d =
+      container->StyleRef().Preserves3D() || StyleRef().Preserves3D();
   GeometryInfoFlags flags = 0;
   if (preserve3d)
     flags |= kAccumulatingTransform;
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.h b/third_party/blink/renderer/core/layout/layout_box_model_object.h
index 87a4b950..2d69d72 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.h
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.h
@@ -133,7 +133,7 @@
 
   LayoutSize RelativePositionOffset() const;
   LayoutSize RelativePositionLogicalOffset() const {
-    return Style()->IsHorizontalWritingMode()
+    return StyleRef().IsHorizontalWritingMode()
                ? RelativePositionOffset()
                : RelativePositionOffset().TransposedSize();
   }
@@ -191,34 +191,34 @@
 
   // These return the CSS computed padding values.
   LayoutUnit ComputedCSSPaddingTop() const {
-    return ComputedCSSPadding(Style()->PaddingTop());
+    return ComputedCSSPadding(StyleRef().PaddingTop());
   }
   LayoutUnit ComputedCSSPaddingBottom() const {
-    return ComputedCSSPadding(Style()->PaddingBottom());
+    return ComputedCSSPadding(StyleRef().PaddingBottom());
   }
   LayoutUnit ComputedCSSPaddingLeft() const {
-    return ComputedCSSPadding(Style()->PaddingLeft());
+    return ComputedCSSPadding(StyleRef().PaddingLeft());
   }
   LayoutUnit ComputedCSSPaddingRight() const {
-    return ComputedCSSPadding(Style()->PaddingRight());
+    return ComputedCSSPadding(StyleRef().PaddingRight());
   }
   LayoutUnit ComputedCSSPaddingBefore() const {
-    return ComputedCSSPadding(Style()->PaddingBefore());
+    return ComputedCSSPadding(StyleRef().PaddingBefore());
   }
   LayoutUnit ComputedCSSPaddingAfter() const {
-    return ComputedCSSPadding(Style()->PaddingAfter());
+    return ComputedCSSPadding(StyleRef().PaddingAfter());
   }
   LayoutUnit ComputedCSSPaddingStart() const {
-    return ComputedCSSPadding(Style()->PaddingStart());
+    return ComputedCSSPadding(StyleRef().PaddingStart());
   }
   LayoutUnit ComputedCSSPaddingEnd() const {
-    return ComputedCSSPadding(Style()->PaddingEnd());
+    return ComputedCSSPadding(StyleRef().PaddingEnd());
   }
   LayoutUnit ComputedCSSPaddingOver() const {
-    return ComputedCSSPadding(Style()->PaddingOver());
+    return ComputedCSSPadding(StyleRef().PaddingOver());
   }
   LayoutUnit ComputedCSSPaddingUnder() const {
-    return ComputedCSSPadding(Style()->PaddingUnder());
+    return ComputedCSSPadding(StyleRef().PaddingUnder());
   }
 
   // These functions are used during layout.
@@ -242,16 +242,16 @@
   LayoutUnit PaddingUnder() const { return PhysicalPaddingToLogical().Under(); }
 
   virtual LayoutUnit BorderTop() const {
-    return LayoutUnit(Style()->BorderTopWidth());
+    return LayoutUnit(StyleRef().BorderTopWidth());
   }
   virtual LayoutUnit BorderBottom() const {
-    return LayoutUnit(Style()->BorderBottomWidth());
+    return LayoutUnit(StyleRef().BorderBottomWidth());
   }
   virtual LayoutUnit BorderLeft() const {
-    return LayoutUnit(Style()->BorderLeftWidth());
+    return LayoutUnit(StyleRef().BorderLeftWidth());
   }
   virtual LayoutUnit BorderRight() const {
-    return LayoutUnit(Style()->BorderRightWidth());
+    return LayoutUnit(StyleRef().BorderRightWidth());
   }
 
   LayoutUnit BorderBefore() const { return PhysicalBorderToLogical().Before(); }
@@ -281,7 +281,7 @@
   }
 
   bool HasBorderOrPadding() const {
-    return Style()->HasBorder() || Style()->HasPadding();
+    return StyleRef().HasBorder() || StyleRef().HasPadding();
   }
 
   LayoutUnit BorderAndPaddingStart() const {
@@ -315,17 +315,17 @@
     return BorderStart() + BorderEnd() + PaddingStart() + PaddingEnd();
   }
   DISABLE_CFI_PERF LayoutUnit BorderAndPaddingLogicalLeft() const {
-    return Style()->IsHorizontalWritingMode() ? BorderLeft() + PaddingLeft()
-                                              : BorderTop() + PaddingTop();
+    return StyleRef().IsHorizontalWritingMode() ? BorderLeft() + PaddingLeft()
+                                                : BorderTop() + PaddingTop();
   }
 
   LayoutUnit BorderLogicalLeft() const {
-    return LayoutUnit(Style()->IsHorizontalWritingMode() ? BorderLeft()
-                                                         : BorderTop());
+    return LayoutUnit(StyleRef().IsHorizontalWritingMode() ? BorderLeft()
+                                                           : BorderTop());
   }
   LayoutUnit BorderLogicalRight() const {
-    return LayoutUnit(Style()->IsHorizontalWritingMode() ? BorderRight()
-                                                         : BorderBottom());
+    return LayoutUnit(StyleRef().IsHorizontalWritingMode() ? BorderRight()
+                                                           : BorderBottom());
   }
 
   LayoutUnit PaddingLogicalWidth() const {
diff --git a/third_party/blink/renderer/core/layout/layout_button.cc b/third_party/blink/renderer/core/layout/layout_button.cc
index 054433df..b5c23c5 100644
--- a/third_party/blink/renderer/core/layout/layout_button.cc
+++ b/third_party/blink/renderer/core/layout/layout_button.cc
@@ -34,7 +34,7 @@
   if (!inner_) {
     // Create an anonymous block.
     DCHECK(!FirstChild());
-    inner_ = CreateAnonymousBlock(Style()->Display());
+    inner_ = CreateAnonymousBlock(StyleRef().Display());
     LayoutFlexibleBox::AddChild(inner_);
   }
 
@@ -66,13 +66,13 @@
   // when the content overflows, treat it the same as align-items: flex-start.
   child_style.SetMarginTop(Length());
   child_style.SetMarginBottom(Length());
-  child_style.SetFlexDirection(Style()->FlexDirection());
-  child_style.SetJustifyContent(Style()->JustifyContent());
-  child_style.SetFlexWrap(Style()->FlexWrap());
+  child_style.SetFlexDirection(StyleRef().FlexDirection());
+  child_style.SetJustifyContent(StyleRef().JustifyContent());
+  child_style.SetFlexWrap(StyleRef().FlexWrap());
   // TODO (lajava): An anonymous box must not be used to resolve children's auto
   // values.
-  child_style.SetAlignItems(Style()->AlignItems());
-  child_style.SetAlignContent(Style()->AlignContent());
+  child_style.SetAlignItems(StyleRef().AlignItems());
+  child_style.SetAlignContent(StyleRef().AlignContent());
 }
 
 LayoutRect LayoutButton::ControlClipRect(
diff --git a/third_party/blink/renderer/core/layout/layout_counter.cc b/third_party/blink/renderer/core/layout/layout_counter.cc
index 81eab5fb..afab92ce 100644
--- a/third_party/blink/renderer/core/layout/layout_counter.cc
+++ b/third_party/blink/renderer/core/layout/layout_counter.cc
@@ -484,7 +484,7 @@
           !before_after_container->IsPseudoElement())
         return nullptr;  // LayoutCounters are restricted to before and after
                          // pseudo elements
-      PseudoId container_style = before_after_container->Style()->StyleType();
+      PseudoId container_style = before_after_container->StyleRef().StyleType();
       if ((container_style == kPseudoIdBefore) ||
           (container_style == kPseudoIdAfter))
         break;
@@ -602,7 +602,7 @@
 static void UpdateCounters(LayoutObject& layout_object) {
   DCHECK(layout_object.Style());
   const CounterDirectiveMap* directive_map =
-      layout_object.Style()->GetCounterDirectives();
+      layout_object.StyleRef().GetCounterDirectives();
   if (!directive_map)
     return;
   CounterDirectiveMap::const_iterator end = directive_map->end();
diff --git a/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
index f7ff1a8a..228b90af 100644
--- a/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
@@ -42,18 +42,18 @@
  public:
   FlexBoxIterator(LayoutDeprecatedFlexibleBox* parent)
       : box_(parent), largest_ordinal_(1) {
-    if (box_->Style()->BoxOrient() == EBoxOrient::kHorizontal &&
-        !box_->Style()->IsLeftToRightDirection())
-      forward_ = box_->Style()->BoxDirection() != EBoxDirection::kNormal;
+    if (box_->StyleRef().BoxOrient() == EBoxOrient::kHorizontal &&
+        !box_->StyleRef().IsLeftToRightDirection())
+      forward_ = box_->StyleRef().BoxDirection() != EBoxDirection::kNormal;
     else
-      forward_ = box_->Style()->BoxDirection() == EBoxDirection::kNormal;
+      forward_ = box_->StyleRef().BoxDirection() == EBoxDirection::kNormal;
     if (!forward_) {
       // No choice, since we're going backwards, we have to find out the highest
       // ordinal up front.
       LayoutBox* child = box_->FirstChildBox();
       while (child) {
-        if (child->Style()->BoxOrdinalGroup() > largest_ordinal_)
-          largest_ordinal_ = child->Style()->BoxOrdinalGroup();
+        if (child->StyleRef().BoxOrdinalGroup() > largest_ordinal_)
+          largest_ordinal_ = child->StyleRef().BoxOrdinalGroup();
         child = child->NextSiblingBox();
       }
     }
@@ -105,10 +105,10 @@
       }
 
       if (current_child_ && NotFirstOrdinalValue())
-        ordinal_values_.insert(current_child_->Style()->BoxOrdinalGroup());
-    } while (!current_child_ ||
-             (!current_child_->IsAnonymous() &&
-              current_child_->Style()->BoxOrdinalGroup() != current_ordinal_));
+        ordinal_values_.insert(current_child_->StyleRef().BoxOrdinalGroup());
+    } while (!current_child_ || (!current_child_->IsAnonymous() &&
+                                 current_child_->StyleRef().BoxOrdinalGroup() !=
+                                     current_ordinal_));
 
     // This peice of code just exists for detecting if this iterator actually
     // does something other than returning the default order.
@@ -129,7 +129,7 @@
   bool NotFirstOrdinalValue() {
     unsigned first_ordinal_value = forward_ ? 1 : largest_ordinal_;
     return current_ordinal_ == first_ordinal_value &&
-           current_child_->Style()->BoxOrdinalGroup() != first_ordinal_value;
+           current_child_->StyleRef().BoxOrdinalGroup() != first_ordinal_value;
   }
 
   LayoutDeprecatedFlexibleBox* box_;
@@ -148,14 +148,14 @@
 // (crawling into blocks).
 static bool ShouldCheckLines(LayoutBlockFlow* block_flow) {
   return !block_flow->IsFloatingOrOutOfFlowPositioned() &&
-         block_flow->Style()->Height().IsAuto();
+         block_flow->StyleRef().Height().IsAuto();
 }
 
 static int GetHeightForLineCount(const LayoutBlockFlow* block_flow,
                                  int line_count,
                                  bool include_bottom,
                                  int& count) {
-  if (block_flow->Style()->Visibility() != EVisibility::kVisible)
+  if (block_flow->StyleRef().Visibility() != EVisibility::kVisible)
     return -1;
   if (block_flow->ChildrenInline()) {
     for (RootInlineBox* box = block_flow->FirstRootBox(); box;
@@ -197,7 +197,7 @@
 static RootInlineBox* LineAtIndex(const LayoutBlockFlow* block_flow, int i) {
   DCHECK_GE(i, 0);
 
-  if (block_flow->Style()->Visibility() != EVisibility::kVisible)
+  if (block_flow->StyleRef().Visibility() != EVisibility::kVisible)
     return nullptr;
 
   if (block_flow->ChildrenInline()) {
@@ -225,7 +225,7 @@
 static int LineCount(const LayoutBlockFlow* block_flow,
                      const RootInlineBox* stop_root_inline_box = nullptr,
                      bool* found = nullptr) {
-  if (block_flow->Style()->Visibility() != EVisibility::kVisible)
+  if (block_flow->StyleRef().Visibility() != EVisibility::kVisible)
     return 0;
   int count = 0;
   if (block_flow->ChildrenInline()) {
@@ -260,7 +260,7 @@
 }
 
 static void ClearTruncation(LayoutBlockFlow* block_flow) {
-  if (block_flow->Style()->Visibility() != EVisibility::kVisible)
+  if (block_flow->StyleRef().Visibility() != EVisibility::kVisible)
     return;
   if (block_flow->ChildrenInline() && block_flow->HasMarkupTruncation()) {
     block_flow->SetHasMarkupTruncation(false);
@@ -303,8 +303,8 @@
   // A margin basically has three types: fixed, percentage, and auto (variable).
   // Auto and percentage margins simply become 0 when computing min/max width.
   // Fixed margins can be added in as is.
-  Length margin_left = child->Style()->MarginLeft();
-  Length margin_right = child->Style()->MarginRight();
+  Length margin_left = child->StyleRef().MarginLeft();
+  Length margin_right = child->StyleRef().MarginRight();
   LayoutUnit margin;
   if (margin_left.IsFixed())
     margin += margin_left.Value();
@@ -316,7 +316,7 @@
 static bool ChildDoesNotAffectWidthOrFlexing(LayoutObject* child) {
   // Positioned children and collapsed children don't affect the min/max width.
   return child->IsOutOfFlowPositioned() ||
-         child->Style()->Visibility() == EVisibility::kCollapse;
+         child->StyleRef().Visibility() == EVisibility::kCollapse;
 }
 
 static LayoutUnit WidthForChild(LayoutBox* child) {
@@ -393,14 +393,14 @@
 
   UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxLayout);
 
-  if (Style()->BoxAlign() != ComputedStyleInitialValues::InitialBoxAlign())
+  if (StyleRef().BoxAlign() != ComputedStyleInitialValues::InitialBoxAlign())
     UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxAlignNotInitial);
 
-  if (Style()->BoxDirection() !=
+  if (StyleRef().BoxDirection() !=
       ComputedStyleInitialValues::InitialBoxDirection())
     UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxDirectionNotInitial);
 
-  if (Style()->BoxPack() != ComputedStyleInitialValues::InitialBoxPack())
+  if (StyleRef().BoxPack() != ComputedStyleInitialValues::InitialBoxPack())
     UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxPackNotInitial);
 
   if (!FirstChildBox()) {
@@ -433,8 +433,8 @@
 
     if (previous_size != Size() ||
         (Parent()->IsDeprecatedFlexibleBox() &&
-         Parent()->Style()->BoxOrient() == EBoxOrient::kHorizontal &&
-         Parent()->Style()->BoxAlign() == EBoxAlignment::kStretch))
+         Parent()->StyleRef().BoxOrient() == EBoxOrient::kHorizontal &&
+         Parent()->StyleRef().BoxAlign() == EBoxAlignment::kStretch))
       relayout_children = true;
 
     SetHeight(LayoutUnit());
@@ -471,11 +471,11 @@
                                    bool relayout_children,
                                    bool& have_flex) {
   for (LayoutBox* child = iterator.First(); child; child = iterator.Next()) {
-    if (child->Style()->BoxFlex() !=
+    if (child->StyleRef().BoxFlex() !=
         ComputedStyleInitialValues::InitialBoxFlex())
       UseCounter::Count(document, WebFeature::kWebkitBoxChildFlexNotInitial);
 
-    if (child->Style()->BoxOrdinalGroup() !=
+    if (child->StyleRef().BoxOrdinalGroup() !=
         ComputedStyleInitialValues::InitialBoxOrdinalGroup()) {
       UseCounter::Count(document,
                         WebFeature::kWebkitBoxChildOrdinalGroupNotInitial);
@@ -483,7 +483,7 @@
 
     // Check to see if this child flexes.
     if (!ChildDoesNotAffectWidthOrFlexing(child) &&
-        child->Style()->BoxFlex() > 0.0f) {
+        child->StyleRef().BoxFlex() > 0.0f) {
       // We always have to lay out flexible objects again, since the flex
       // distribution
       // may have changed, and we need to reallocate space.
@@ -534,8 +534,8 @@
       // this file.
       // We probably want to check if the element is replaced.
       if (relayout_children || (child->IsAtomicInlineLevel() &&
-                                (child->Style()->Width().IsPercentOrCalc() ||
-                                 child->Style()->Height().IsPercentOrCalc())))
+                                (child->StyleRef().Width().IsPercentOrCalc() ||
+                                 child->StyleRef().Height().IsPercentOrCalc())))
         layout_scope.SetChildNeedsLayout(child);
 
       // Compute the child's vertical margins.
@@ -548,7 +548,7 @@
       child->LayoutIfNeeded();
 
       // Update our height and overflow height.
-      if (Style()->BoxAlign() == EBoxAlignment::kBaseline) {
+      if (StyleRef().BoxAlign() == EBoxAlignment::kBaseline) {
         LayoutUnit ascent(child->FirstLineBoxBaseline());
         if (ascent == -1)
           ascent = child->Size().Height() + child->MarginBottom();
@@ -573,12 +573,14 @@
         UpdateFragmentationInfoForChild(*child);
     }
 
-    if (!iterator.First() && HasLineIfEmpty())
-      SetHeight(Size().Height() + LineHeight(true,
-                                             Style()->IsHorizontalWritingMode()
-                                                 ? kHorizontalLine
-                                                 : kVerticalLine,
-                                             kPositionOfInteriorLineBoxes));
+    if (!iterator.First() && HasLineIfEmpty()) {
+      SetHeight(Size().Height() +
+                LineHeight(true,
+                           StyleRef().IsHorizontalWritingMode()
+                               ? kHorizontalLine
+                               : kVerticalLine,
+                           kPositionOfInteriorLineBoxes));
+    }
 
     SetHeight(Size().Height() + to_add);
 
@@ -590,7 +592,7 @@
       height_specified = true;
 
     // Now that our height is actually known, we can place our boxes.
-    stretching_children_ = (Style()->BoxAlign() == EBoxAlignment::kStretch);
+    stretching_children_ = (StyleRef().BoxAlign() == EBoxAlignment::kStretch);
     for (LayoutBox* child = iterator.First(); child; child = iterator.Next()) {
       if (child->IsOutOfFlowPositioned()) {
         child->ContainingBlock()->InsertPositionedObject(child);
@@ -598,14 +600,14 @@
         child_layer->SetStaticInlinePosition(x_pos);
         if (child_layer->StaticBlockPosition() != y_pos) {
           child_layer->SetStaticBlockPosition(y_pos);
-          if (child->Style()->HasStaticBlockPosition(
-                  Style()->IsHorizontalWritingMode()))
+          if (child->StyleRef().HasStaticBlockPosition(
+                  StyleRef().IsHorizontalWritingMode()))
             child->SetChildNeedsLayout(kMarkOnlyThis);
         }
         continue;
       }
 
-      if (child->Style()->Visibility() == EVisibility::kCollapse) {
+      if (child->StyleRef().Visibility() == EVisibility::kCollapse) {
         // visibility: collapsed children do not participate in our positioning.
         // But we need to lay them down.
         child->LayoutIfNeeded();
@@ -635,7 +637,7 @@
       // We can place the child now, using our value of box-align.
       x_pos += child->MarginLeft();
       LayoutUnit child_y = y_pos;
-      switch (Style()->BoxAlign()) {
+      switch (StyleRef().BoxAlign()) {
         case EBoxAlignment::kCenter:
           child_y += child->MarginTop() +
                      ((ContentHeight() -
@@ -691,7 +693,7 @@
         for (LayoutBox* child = iterator.First(); child;
              child = iterator.Next()) {
           if (AllowedChildFlex(child, expanding))
-            total_flex += child->Style()->BoxFlex();
+            total_flex += child->StyleRef().BoxFlex();
         }
         LayoutUnit space_available_this_pass = remaining_space;
         for (LayoutBox* child = iterator.First(); child;
@@ -702,7 +704,7 @@
                 (allowed_flex == LayoutUnit::Max())
                     ? allowed_flex
                     : LayoutUnit(allowed_flex *
-                                 (total_flex / child->Style()->BoxFlex()));
+                                 (total_flex / child->StyleRef().BoxFlex()));
             space_available_this_pass =
                 expanding ? std::min(space_available_this_pass, projected_flex)
                           : std::max(space_available_this_pass, projected_flex);
@@ -717,13 +719,13 @@
         for (LayoutBox* child = iterator.First();
              child && space_available_this_pass && total_flex;
              child = iterator.Next()) {
-          if (child->Style()->Visibility() == EVisibility::kCollapse)
+          if (child->StyleRef().Visibility() == EVisibility::kCollapse)
             continue;
 
           if (AllowedChildFlex(child, expanding)) {
             LayoutUnit space_add =
                 LayoutUnit(space_available_this_pass *
-                           (child->Style()->BoxFlex() / total_flex));
+                           (child->StyleRef().BoxFlex() / total_flex));
             if (space_add) {
               child->SetOverrideLogicalWidth(WidthForChild(child) + space_add);
               flexing_children = true;
@@ -733,7 +735,7 @@
             space_available_this_pass -= space_add;
             remaining_space -= space_add;
 
-            total_flex -= child->Style()->BoxFlex();
+            total_flex -= child->StyleRef().BoxFlex();
           }
         }
         if (remaining_space == remaining_space_at_beginning) {
@@ -758,13 +760,13 @@
     }
   } while (have_flex);
 
-  if (remaining_space > 0 && ((Style()->IsLeftToRightDirection() &&
-                               Style()->BoxPack() != EBoxPack::kStart) ||
-                              (!Style()->IsLeftToRightDirection() &&
-                               Style()->BoxPack() != EBoxPack::kEnd))) {
+  if (remaining_space > 0 && ((StyleRef().IsLeftToRightDirection() &&
+                               StyleRef().BoxPack() != EBoxPack::kStart) ||
+                              (!StyleRef().IsLeftToRightDirection() &&
+                               StyleRef().BoxPack() != EBoxPack::kEnd))) {
     // Children must be repositioned.
     LayoutUnit offset;
-    if (Style()->BoxPack() == EBoxPack::kJustify) {
+    if (StyleRef().BoxPack() == EBoxPack::kJustify) {
       // Determine the total number of children.
       int total_children = 0;
       for (LayoutBox* child = iterator.First(); child;
@@ -798,7 +800,7 @@
         }
       }
     } else {
-      if (Style()->BoxPack() == EBoxPack::kCenter)
+      if (StyleRef().BoxPack() == EBoxPack::kCenter)
         offset += remaining_space / 2;
       else  // END for LTR, START for RTL
         offset += remaining_space;
@@ -836,7 +838,7 @@
   // We confine the line clamp ugliness to vertical flexible boxes (thus keeping
   // it out of
   // mainstream block layout); this is not really part of the XUL box model.
-  if (Style()->HasLineClamp())
+  if (StyleRef().HasLineClamp())
     ApplyLineClamp(iterator, relayout_children);
 
   PaintLayerScrollableArea::DelayScrollOffsetClampScope delay_clamp_scope;
@@ -856,21 +858,22 @@
         child_layer->SetStaticInlinePosition(BorderStart() + PaddingStart());
         if (child_layer->StaticBlockPosition() != Size().Height()) {
           child_layer->SetStaticBlockPosition(Size().Height());
-          if (child->Style()->HasStaticBlockPosition(
-                  Style()->IsHorizontalWritingMode()))
+          if (child->StyleRef().HasStaticBlockPosition(
+                  StyleRef().IsHorizontalWritingMode()))
             child->SetChildNeedsLayout(kMarkOnlyThis);
         }
         continue;
       }
 
       SubtreeLayoutScope layout_scope(*child);
-      if (!Style()->HasLineClamp() &&
-          (relayout_children || (child->IsAtomicInlineLevel() &&
-                                 (child->Style()->Width().IsPercentOrCalc() ||
-                                  child->Style()->Height().IsPercentOrCalc()))))
+      if (!StyleRef().HasLineClamp() &&
+          (relayout_children ||
+           (child->IsAtomicInlineLevel() &&
+            (child->StyleRef().Width().IsPercentOrCalc() ||
+             child->StyleRef().Height().IsPercentOrCalc()))))
         layout_scope.SetChildNeedsLayout(child);
 
-      if (child->Style()->Visibility() == EVisibility::kCollapse) {
+      if (child->StyleRef().Visibility() == EVisibility::kCollapse) {
         // visibility: collapsed children do not participate in our positioning.
         // But we need to lay them down.
         child->LayoutIfNeeded();
@@ -891,7 +894,7 @@
 
       // We can place the child now, using our value of box-align.
       LayoutUnit child_x = BorderLeft() + PaddingLeft();
-      switch (Style()->BoxAlign()) {
+      switch (StyleRef().BoxAlign()) {
         case EBoxAlignment::kCenter:
         case EBoxAlignment::kBaseline:  // Baseline just maps to center for
                                         // vertical boxes
@@ -902,7 +905,7 @@
                          .ClampNegativeToZero();
           break;
         case EBoxAlignment::kEnd:
-          if (!Style()->IsLeftToRightDirection()) {
+          if (!StyleRef().IsLeftToRightDirection()) {
             child_x += child->MarginLeft();
           } else {
             child_x +=
@@ -910,7 +913,7 @@
           }
           break;
         default:  // BSTART/BSTRETCH
-          if (Style()->IsLeftToRightDirection()) {
+          if (StyleRef().IsLeftToRightDirection()) {
             child_x += child->MarginLeft();
           } else {
             child_x +=
@@ -930,12 +933,14 @@
 
     y_pos = Size().Height();
 
-    if (!iterator.First() && HasLineIfEmpty())
-      SetHeight(Size().Height() + LineHeight(true,
-                                             Style()->IsHorizontalWritingMode()
-                                                 ? kHorizontalLine
-                                                 : kVerticalLine,
-                                             kPositionOfInteriorLineBoxes));
+    if (!iterator.First() && HasLineIfEmpty()) {
+      SetHeight(Size().Height() +
+                LineHeight(true,
+                           StyleRef().IsHorizontalWritingMode()
+                               ? kHorizontalLine
+                               : kVerticalLine,
+                           kPositionOfInteriorLineBoxes));
+    }
 
     SetHeight(Size().Height() + to_add);
 
@@ -977,7 +982,7 @@
         for (LayoutBox* child = iterator.First(); child;
              child = iterator.Next()) {
           if (AllowedChildFlex(child, expanding))
-            total_flex += child->Style()->BoxFlex();
+            total_flex += child->StyleRef().BoxFlex();
         }
         LayoutUnit space_available_this_pass = remaining_space;
         for (LayoutBox* child = iterator.First(); child;
@@ -989,7 +994,7 @@
                     ? allowed_flex
                     : static_cast<LayoutUnit>(
                           allowed_flex *
-                          (total_flex / child->Style()->BoxFlex()));
+                          (total_flex / child->StyleRef().BoxFlex()));
             space_available_this_pass =
                 expanding ? std::min(space_available_this_pass, projected_flex)
                           : std::max(space_available_this_pass, projected_flex);
@@ -1007,7 +1012,7 @@
           if (AllowedChildFlex(child, expanding)) {
             LayoutUnit space_add = static_cast<LayoutUnit>(
                 space_available_this_pass *
-                (child->Style()->BoxFlex() / total_flex));
+                (child->StyleRef().BoxFlex() / total_flex));
             if (space_add) {
               child->SetOverrideLogicalHeight(HeightForChild(child) +
                                               space_add);
@@ -1018,7 +1023,7 @@
             space_available_this_pass -= space_add;
             remaining_space -= space_add;
 
-            total_flex -= child->Style()->BoxFlex();
+            total_flex -= child->StyleRef().BoxFlex();
           }
         }
         if (remaining_space == remaining_space_at_beginning) {
@@ -1044,10 +1049,10 @@
     }
   } while (have_flex);
 
-  if (Style()->BoxPack() != EBoxPack::kStart && remaining_space > 0) {
+  if (StyleRef().BoxPack() != EBoxPack::kStart && remaining_space > 0) {
     // Children must be repositioned.
     LayoutUnit offset;
-    if (Style()->BoxPack() == EBoxPack::kJustify) {
+    if (StyleRef().BoxPack() == EBoxPack::kJustify) {
       // Determine the total number of children.
       int total_children = 0;
       for (LayoutBox* child = iterator.First(); child;
@@ -1081,7 +1086,7 @@
         }
       }
     } else {
-      if (Style()->BoxPack() == EBoxPack::kCenter)
+      if (StyleRef().BoxPack() == EBoxPack::kCenter)
         offset += remaining_space / 2;
       else  // END
         offset += remaining_space;
@@ -1131,9 +1136,9 @@
     child->ClearOverrideSize();
     if (relayout_children ||
         (child->IsAtomicInlineLevel() &&
-         (child->Style()->Width().IsPercentOrCalc() ||
-          child->Style()->Height().IsPercentOrCalc())) ||
-        (child->Style()->Height().IsAuto() && child->IsLayoutBlock())) {
+         (child->StyleRef().Width().IsPercentOrCalc() ||
+          child->StyleRef().Height().IsPercentOrCalc())) ||
+        (child->StyleRef().Height().IsAuto() && child->IsLayoutBlock())) {
       child->SetChildNeedsLayout(kMarkOnlyThis);
 
       // Dirty all the positioned objects.
@@ -1143,7 +1148,7 @@
       }
     }
     child->LayoutIfNeeded();
-    if (child->Style()->Height().IsAuto() && child->IsLayoutBlockFlow())
+    if (child->StyleRef().Height().IsAuto() && child->IsLayoutBlockFlow())
       max_line_count =
           std::max(max_line_count, LineCount(ToLayoutBlockFlow(child)));
   }
@@ -1151,7 +1156,7 @@
   // Get the number of lines and then alter all block flow children with auto
   // height to use the
   // specified height. We always try to leave room for at least one line.
-  int num_visible_lines = Style()->LineClamp();
+  int num_visible_lines = StyleRef().LineClamp();
   DCHECK_GT(num_visible_lines, 0);
 
   if (num_visible_lines >= max_line_count)
@@ -1159,7 +1164,7 @@
 
   for (LayoutBox* child = iterator.First(); child; child = iterator.Next()) {
     if (ChildDoesNotAffectWidthOrFlexing(child) ||
-        !child->Style()->Height().IsAuto() || !child->IsLayoutBlockFlow())
+        !child->StyleRef().Height().IsAuto() || !child->IsLayoutBlockFlow())
       continue;
 
     LayoutBlockFlow* block_child = ToLayoutBlockFlow(child);
@@ -1177,7 +1182,7 @@
     child->ForceChildLayout();
 
     // FIXME: For now don't support RTL.
-    if (Style()->Direction() != TextDirection::kLtr)
+    if (StyleRef().Direction() != TextDirection::kLtr)
       continue;
 
     // Get the last line
@@ -1195,7 +1200,7 @@
     const Font& font = Style(num_visible_lines == 1)->GetFont();
     float total_width =
         font.Width(ConstructTextRun(font, &kHorizontalEllipsisCharacter, 1,
-                                    StyleRef(), Style()->Direction()));
+                                    StyleRef(), StyleRef().Direction()));
 
     // See if this width can be accommodated on the last visible line
     LineLayoutBlockFlow dest_block = last_visible_line->Block();
@@ -1203,10 +1208,10 @@
 
     // FIXME: Directions of src/destBlock could be different from our direction
     // and from one another.
-    if (!src_block.Style()->IsLeftToRightDirection())
+    if (!src_block.StyleRef().IsLeftToRightDirection())
       continue;
 
-    bool left_to_right = dest_block.Style()->IsLeftToRightDirection();
+    bool left_to_right = dest_block.StyleRef().IsLeftToRightDirection();
     if (!left_to_right)
       continue;
 
@@ -1243,9 +1248,9 @@
 
     child->ClearOverrideSize();
     if ((child->IsAtomicInlineLevel() &&
-         (child->Style()->Width().IsPercentOrCalc() ||
-          child->Style()->Height().IsPercentOrCalc())) ||
-        (child->Style()->Height().IsAuto() && child->IsLayoutBlock())) {
+         (child->StyleRef().Width().IsPercentOrCalc() ||
+          child->StyleRef().Height().IsPercentOrCalc())) ||
+        (child->StyleRef().Height().IsAuto() && child->IsLayoutBlock())) {
       child->SetChildNeedsLayout();
 
       if (child->IsLayoutBlockFlow()) {
@@ -1269,7 +1274,7 @@
 LayoutUnit LayoutDeprecatedFlexibleBox::AllowedChildFlex(LayoutBox* child,
                                                          bool expanding) {
   if (ChildDoesNotAffectWidthOrFlexing(child) ||
-      child->Style()->BoxFlex() == 0.0f)
+      child->StyleRef().BoxFlex() == 0.0f)
     return LayoutUnit();
 
   if (expanding) {
@@ -1277,8 +1282,8 @@
       // FIXME: For now just handle fixed values.
       LayoutUnit max_width = LayoutUnit::Max();
       LayoutUnit width = ContentWidthForChild(child);
-      if (child->Style()->MaxWidth().IsFixed())
-        max_width = LayoutUnit(child->Style()->MaxWidth().Value());
+      if (child->StyleRef().MaxWidth().IsFixed())
+        max_width = LayoutUnit(child->StyleRef().MaxWidth().Value());
       if (max_width == LayoutUnit::Max())
         return max_width;
       return (max_width - width).ClampNegativeToZero();
@@ -1286,8 +1291,8 @@
     // FIXME: For now just handle fixed values.
     LayoutUnit max_height = LayoutUnit::Max();
     LayoutUnit height = ContentHeightForChild(child);
-    if (child->Style()->MaxHeight().IsFixed())
-      max_height = LayoutUnit(child->Style()->MaxHeight().Value());
+    if (child->StyleRef().MaxHeight().IsFixed())
+      max_height = LayoutUnit(child->StyleRef().MaxHeight().Value());
     if (max_height == LayoutUnit::Max())
       return max_height;
     return (max_height - height).ClampNegativeToZero();
@@ -1297,7 +1302,7 @@
   if (IsHorizontal()) {
     LayoutUnit min_width = child->MinPreferredLogicalWidth();
     LayoutUnit width = ContentWidthForChild(child);
-    const Length& min_width_length = child->Style()->MinWidth();
+    const Length& min_width_length = child->StyleRef().MinWidth();
     if (min_width_length.IsFixed())
       min_width = LayoutUnit(min_width_length.Value());
     else if (min_width_length.IsAuto())
@@ -1306,7 +1311,7 @@
     LayoutUnit allowed_shrinkage = (min_width - width).ClampPositiveToZero();
     return allowed_shrinkage;
   }
-  const Length& min_height_length = child->Style()->MinHeight();
+  const Length& min_height_length = child->StyleRef().MinHeight();
   if (min_height_length.IsFixed() || min_height_length.IsAuto()) {
     LayoutUnit min_height(min_height_length.Value());
     LayoutUnit height = ContentHeightForChild(child);
diff --git a/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h b/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
index 5b52ab81..f7000047 100644
--- a/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
+++ b/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
@@ -56,10 +56,10 @@
   LayoutUnit AllowedChildFlex(LayoutBox* child, bool expanding);
 
   bool IsVertical() const {
-    return Style()->BoxOrient() == EBoxOrient::kVertical;
+    return StyleRef().BoxOrient() == EBoxOrient::kVertical;
   }
   bool IsHorizontal() const {
-    return Style()->BoxOrient() == EBoxOrient::kHorizontal;
+    return StyleRef().BoxOrient() == EBoxOrient::kHorizontal;
   }
 
   void ApplyLineClamp(FlexBoxIterator&, bool relayout_children);
diff --git a/third_party/blink/renderer/core/layout/layout_details_marker.cc b/third_party/blink/renderer/core/layout/layout_details_marker.cc
index b5fdf263..16f354e 100644
--- a/third_party/blink/renderer/core/layout/layout_details_marker.cc
+++ b/third_party/blink/renderer/core/layout/layout_details_marker.cc
@@ -33,17 +33,17 @@
     : LayoutBlockFlow(element) {}
 
 LayoutDetailsMarker::Orientation LayoutDetailsMarker::GetOrientation() const {
-  switch (Style()->GetWritingMode()) {
+  switch (StyleRef().GetWritingMode()) {
     case WritingMode::kHorizontalTb:
-      if (Style()->IsLeftToRightDirection())
+      if (StyleRef().IsLeftToRightDirection())
         return IsOpen() ? kDown : kRight;
       return IsOpen() ? kDown : kLeft;
     case WritingMode::kVerticalRl:
-      if (Style()->IsLeftToRightDirection())
+      if (StyleRef().IsLeftToRightDirection())
         return IsOpen() ? kLeft : kDown;
       return IsOpen() ? kLeft : kUp;
     case WritingMode::kVerticalLr:
-      if (Style()->IsLeftToRightDirection())
+      if (StyleRef().IsLeftToRightDirection())
         return IsOpen() ? kRight : kDown;
       return IsOpen() ? kRight : kUp;
     // TODO(layout-dev): Sideways-lr and sideways-rl are not yet supported.
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content.cc b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
index 0023ca9..6c5b17f 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_content.cc
+++ b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
@@ -258,7 +258,7 @@
   if (!embedded_content_view)
     return;
 
-  if (Style()->Visibility() != EVisibility::kVisible) {
+  if (StyleRef().Visibility() != EVisibility::kVisible) {
     embedded_content_view->Hide();
   } else {
     embedded_content_view->Show();
@@ -319,7 +319,7 @@
   if (!NeedsLayout())
     UpdateGeometry(*embedded_content_view);
 
-  if (Style()->Visibility() != EVisibility::kVisible) {
+  if (StyleRef().Visibility() != EVisibility::kVisible) {
     embedded_content_view->Hide();
   } else {
     embedded_content_view->Show();
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_object.cc b/third_party/blink/renderer/core/layout/layout_embedded_object.cc
index a136627..58387dc 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_embedded_object.cc
@@ -118,7 +118,7 @@
   if (frame_view && frame_view->GetIntrinsicSizingInfo(intrinsic_sizing_info)) {
     // Handle zoom & vertical writing modes here, as the embedded document
     // doesn't know about them.
-    intrinsic_sizing_info.size.Scale(Style()->EffectiveZoom());
+    intrinsic_sizing_info.size.Scale(StyleRef().EffectiveZoom());
 
     if (!IsHorizontalWritingMode())
       intrinsic_sizing_info.Transpose();
diff --git a/third_party/blink/renderer/core/layout/layout_fieldset.cc b/third_party/blink/renderer/core/layout/layout_fieldset.cc
index b872b41..2d661fb 100644
--- a/third_party/blink/renderer/core/layout/layout_fieldset.cc
+++ b/third_party/blink/renderer/core/layout/layout_fieldset.cc
@@ -39,8 +39,8 @@
   if (LayoutBox* legend = FindInFlowLegend()) {
     int legend_min_width = legend->MinPreferredLogicalWidth().ToInt();
 
-    Length legend_margin_left = legend->Style()->MarginLeft();
-    Length legend_margin_right = legend->Style()->MarginRight();
+    Length legend_margin_left = legend->StyleRef().MarginLeft();
+    Length legend_margin_right = legend->StyleRef().MarginRight();
 
     if (legend_margin_left.IsFixed())
       legend_min_width += legend_margin_left.Value();
@@ -66,8 +66,8 @@
     legend->LayoutIfNeeded();
 
     LayoutUnit logical_left;
-    if (Style()->IsLeftToRightDirection()) {
-      switch (legend->Style()->GetTextAlign()) {
+    if (StyleRef().IsLeftToRightDirection()) {
+      switch (legend->StyleRef().GetTextAlign()) {
         case ETextAlign::kCenter:
           logical_left = (LogicalWidth() - LogicalWidthForChild(*legend)) / 2;
           break;
@@ -81,7 +81,7 @@
           break;
       }
     } else {
-      switch (legend->Style()->GetTextAlign()) {
+      switch (legend->StyleRef().GetTextAlign()) {
         case ETextAlign::kLeft:
           logical_left = BorderStart() + PaddingStart();
           break;
diff --git a/third_party/blink/renderer/core/layout/layout_file_upload_control.cc b/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
index ac4ec435..6bdb6aa 100644
--- a/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
+++ b/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
@@ -88,7 +88,7 @@
   // characters (using "0" as the nominal character).
   const UChar kCharacter = '0';
   const String character_as_string = String(&kCharacter, 1);
-  const Font& font = Style()->GetFont();
+  const Font& font = StyleRef().GetFont();
   float min_default_label_width =
       kDefaultWidthNumChars *
       font.Width(ConstructTextRun(font, character_as_string, StyleRef(),
@@ -106,7 +106,7 @@
   max_logical_width =
       LayoutUnit(ceilf(std::max(min_default_label_width, default_label_width)));
 
-  if (!Style()->Width().IsPercentOrCalc())
+  if (!StyleRef().Width().IsPercentOrCalc())
     min_logical_width = max_logical_width;
 }
 
@@ -178,7 +178,7 @@
   HTMLInputElement* input = ToHTMLInputElement(GetNode());
   DCHECK(input->files());
   return LayoutTheme::GetTheme().FileListNameForWidth(
-      input->GetLocale(), input->files(), Style()->GetFont(),
+      input->GetLocale(), input->files(), StyleRef().GetFont(),
       MaxFilenameWidth());
 }
 
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 9131c71..0791219 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -246,9 +246,9 @@
   if (!adjustment_width && !adjustment_height)
     return size;
 
-  EFlexDirection flex_direction = Style()->FlexDirection();
-  TextDirection text_direction = Style()->Direction();
-  WritingMode writing_mode = Style()->GetWritingMode();
+  EFlexDirection flex_direction = StyleRef().FlexDirection();
+  TextDirection text_direction = StyleRef().Direction();
+  WritingMode writing_mode = StyleRef().GetWritingMode();
 
   if (flex_direction == EFlexDirection::kRow) {
     if (text_direction == TextDirection::kRtl) {
@@ -294,18 +294,18 @@
 }
 
 bool LayoutFlexibleBox::HasTopOverflow() const {
-  EFlexDirection flex_direction = Style()->FlexDirection();
+  EFlexDirection flex_direction = StyleRef().FlexDirection();
   if (IsHorizontalWritingMode())
     return flex_direction == EFlexDirection::kColumnReverse;
-  return flex_direction == (Style()->IsLeftToRightDirection()
+  return flex_direction == (StyleRef().IsLeftToRightDirection()
                                 ? EFlexDirection::kRowReverse
                                 : EFlexDirection::kRow);
 }
 
 bool LayoutFlexibleBox::HasLeftOverflow() const {
-  EFlexDirection flex_direction = Style()->FlexDirection();
+  EFlexDirection flex_direction = StyleRef().FlexDirection();
   if (IsHorizontalWritingMode()) {
-    return flex_direction == (Style()->IsLeftToRightDirection()
+    return flex_direction == (StyleRef().IsLeftToRightDirection()
                                   ? EFlexDirection::kRowReverse
                                   : EFlexDirection::kRow);
   }
@@ -438,7 +438,7 @@
 
   AlignChildren(line_contexts);
 
-  if (Style()->FlexWrap() == EFlexWrap::kWrapReverse)
+  if (StyleRef().FlexWrap() == EFlexWrap::kWrapReverse)
     FlipForWrapReverse(line_contexts, cross_axis_start_edge);
 
   // direction:rtl + flex-direction:column means the cross-axis direction is
@@ -468,7 +468,7 @@
 }
 
 bool LayoutFlexibleBox::IsColumnFlow() const {
-  return Style()->IsColumnFlexDirection();
+  return StyleRef().IsColumnFlexDirection();
 }
 
 bool LayoutFlexibleBox::IsHorizontalFlow() const {
@@ -479,22 +479,23 @@
 
 bool LayoutFlexibleBox::IsLeftToRightFlow() const {
   if (IsColumnFlow()) {
-    return blink::IsHorizontalWritingMode(Style()->GetWritingMode()) ||
-           IsFlippedLinesWritingMode(Style()->GetWritingMode());
+    return blink::IsHorizontalWritingMode(StyleRef().GetWritingMode()) ||
+           IsFlippedLinesWritingMode(StyleRef().GetWritingMode());
   }
-  return Style()->IsLeftToRightDirection() ^
-         (Style()->FlexDirection() == EFlexDirection::kRowReverse);
+  return StyleRef().IsLeftToRightDirection() ^
+         (StyleRef().FlexDirection() == EFlexDirection::kRowReverse);
 }
 
 bool LayoutFlexibleBox::IsMultiline() const {
-  return Style()->FlexWrap() != EFlexWrap::kNowrap;
+  return StyleRef().FlexWrap() != EFlexWrap::kNowrap;
 }
 
 Length LayoutFlexibleBox::FlexBasisForChild(const LayoutBox& child) const {
-  Length flex_length = child.Style()->FlexBasis();
-  if (flex_length.IsAuto())
-    flex_length =
-        IsHorizontalFlow() ? child.Style()->Width() : child.Style()->Height();
+  Length flex_length = child.StyleRef().FlexBasis();
+  if (flex_length.IsAuto()) {
+    flex_length = IsHorizontalFlow() ? child.StyleRef().Width()
+                                     : child.StyleRef().Height();
+  }
   return flex_length;
 }
 
@@ -942,7 +943,7 @@
 
     LayoutUnit main_axis_offset =
         FlowAwareBorderStart() + FlowAwarePaddingStart();
-    if (Style()->FlexDirection() == EFlexDirection::kRowReverse &&
+    if (StyleRef().FlexDirection() == EFlexDirection::kRowReverse &&
         ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
       main_axis_offset += IsHorizontalFlow() ? VerticalScrollbarWidth()
                                              : HorizontalScrollbarHeight();
@@ -971,11 +972,12 @@
 
 bool LayoutFlexibleBox::HasAutoMarginsInCrossAxis(
     const LayoutBox& child) const {
-  if (IsHorizontalFlow())
-    return child.Style()->MarginTop().IsAuto() ||
-           child.Style()->MarginBottom().IsAuto();
-  return child.Style()->MarginLeft().IsAuto() ||
-         child.Style()->MarginRight().IsAuto();
+  if (IsHorizontalFlow()) {
+    return child.StyleRef().MarginTop().IsAuto() ||
+           child.StyleRef().MarginBottom().IsAuto();
+  }
+  return child.StyleRef().MarginLeft().IsAuto() ||
+         child.StyleRef().MarginRight().IsAuto();
 }
 
 bool LayoutFlexibleBox::UpdateAutoMarginsInCrossAxis(
@@ -985,10 +987,10 @@
   DCHECK_GE(available_alignment_space, LayoutUnit());
 
   bool is_horizontal = IsHorizontalFlow();
-  Length top_or_left =
-      is_horizontal ? child.Style()->MarginTop() : child.Style()->MarginLeft();
-  Length bottom_or_right = is_horizontal ? child.Style()->MarginBottom()
-                                         : child.Style()->MarginRight();
+  Length top_or_left = is_horizontal ? child.StyleRef().MarginTop()
+                                     : child.StyleRef().MarginLeft();
+  Length bottom_or_right = is_horizontal ? child.StyleRef().MarginBottom()
+                                         : child.StyleRef().MarginRight();
   if (top_or_left.IsAuto() && bottom_or_right.IsAuto()) {
     AdjustAlignmentForChild(child, available_alignment_space / 2);
     if (is_horizontal) {
@@ -1001,13 +1003,13 @@
     return true;
   }
   bool should_adjust_top_or_left = true;
-  if (IsColumnFlow() && !child.Style()->IsLeftToRightDirection()) {
+  if (IsColumnFlow() && !child.StyleRef().IsLeftToRightDirection()) {
     // For column flows, only make this adjustment if topOrLeft corresponds to
     // the "before" margin, so that flipForRightToLeftColumn will do the right
     // thing.
     should_adjust_top_or_left = false;
   }
-  if (!IsColumnFlow() && child.Style()->IsFlippedBlocksWritingMode()) {
+  if (!IsColumnFlow() && child.StyleRef().IsFlippedBlocksWritingMode()) {
     // If we are a flipped writing mode, we need to adjust the opposite side.
     // This is only needed for row flows because this only affects the
     // block-direction axis.
@@ -1061,13 +1063,14 @@
     // start/end margins.
     if (IsHorizontalFlow()) {
       child->SetMarginLeft(
-          ComputeChildMarginValue(child->Style()->MarginLeft()));
+          ComputeChildMarginValue(child->StyleRef().MarginLeft()));
       child->SetMarginRight(
-          ComputeChildMarginValue(child->Style()->MarginRight()));
+          ComputeChildMarginValue(child->StyleRef().MarginRight()));
     } else {
-      child->SetMarginTop(ComputeChildMarginValue(child->Style()->MarginTop()));
+      child->SetMarginTop(
+          ComputeChildMarginValue(child->StyleRef().MarginTop()));
       child->SetMarginBottom(
-          ComputeChildMarginValue(child->Style()->MarginBottom()));
+          ComputeChildMarginValue(child->StyleRef().MarginBottom()));
     }
   }
 }
@@ -1077,8 +1080,8 @@
     const LayoutBox& child) const {
   MinMaxSize sizes{LayoutUnit(), LayoutUnit::Max()};
 
-  Length max = IsHorizontalFlow() ? child.Style()->MaxWidth()
-                                  : child.Style()->MaxHeight();
+  Length max = IsHorizontalFlow() ? child.StyleRef().MaxWidth()
+                                  : child.StyleRef().MaxHeight();
   if (max.IsSpecifiedOrIntrinsic()) {
     sizes.max_size = ComputeMainAxisExtentForChild(child, kMaxSize, max);
     if (sizes.max_size == -1)
@@ -1086,8 +1089,8 @@
     DCHECK_GE(sizes.max_size, LayoutUnit());
   }
 
-  Length min = IsHorizontalFlow() ? child.Style()->MinWidth()
-                                  : child.Style()->MinHeight();
+  Length min = IsHorizontalFlow() ? child.StyleRef().MinWidth()
+                                  : child.StyleRef().MinHeight();
   if (min.IsSpecifiedOrIntrinsic()) {
     sizes.min_size = ComputeMainAxisExtentForChild(child, kMinSize, min);
     // computeMainAxisExtentForChild can return -1 when the child has a
@@ -1197,10 +1200,10 @@
 LayoutUnit LayoutFlexibleBox::AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
     const LayoutBox& child,
     LayoutUnit child_size) const {
-  Length cross_min = IsHorizontalFlow() ? child.Style()->MinHeight()
-                                        : child.Style()->MinWidth();
-  Length cross_max = IsHorizontalFlow() ? child.Style()->MaxHeight()
-                                        : child.Style()->MaxWidth();
+  Length cross_min = IsHorizontalFlow() ? child.StyleRef().MinHeight()
+                                        : child.StyleRef().MinWidth();
+  Length cross_max = IsHorizontalFlow() ? child.StyleRef().MaxHeight()
+                                        : child.StyleRef().MaxWidth();
 
   if (CrossAxisLengthIsDefinite(child, cross_max)) {
     LayoutUnit max_value =
@@ -1380,8 +1383,8 @@
       FlowAwareBorderStart() + FlowAwarePaddingStart();
   if (child_layer->StaticInlinePosition() != static_inline_position) {
     child_layer->SetStaticInlinePosition(static_inline_position);
-    if (child.Style()->HasStaticInlinePosition(
-            Style()->IsHorizontalWritingMode()))
+    if (child.StyleRef().HasStaticInlinePosition(
+            StyleRef().IsHorizontalWritingMode()))
       child.SetChildNeedsLayout(kMarkOnlyThis);
   }
 
@@ -1389,8 +1392,8 @@
       FlowAwareBorderBefore() + FlowAwarePaddingBefore();
   if (child_layer->StaticBlockPosition() != static_block_position) {
     child_layer->SetStaticBlockPosition(static_block_position);
-    if (child.Style()->HasStaticBlockPosition(
-            Style()->IsHorizontalWritingMode()))
+    if (child.StyleRef().HasStaticBlockPosition(
+            StyleRef().IsHorizontalWritingMode()))
       child.SetChildNeedsLayout(kMarkOnlyThis);
   }
 }
@@ -1400,14 +1403,14 @@
   if (HasAutoMarginsInCrossAxis(child)) {
     child.UpdateLogicalHeight();
     if (IsHorizontalFlow()) {
-      if (child.Style()->MarginTop().IsAuto())
+      if (child.StyleRef().MarginTop().IsAuto())
         child.SetMarginTop(LayoutUnit());
-      if (child.Style()->MarginBottom().IsAuto())
+      if (child.StyleRef().MarginBottom().IsAuto())
         child.SetMarginBottom(LayoutUnit());
     } else {
-      if (child.Style()->MarginLeft().IsAuto())
+      if (child.StyleRef().MarginLeft().IsAuto())
         child.SetMarginLeft(LayoutUnit());
-      if (child.Style()->MarginRight().IsAuto())
+      if (child.StyleRef().MarginRight().IsAuto())
         child.SetMarginRight(LayoutUnit());
     }
   }
@@ -1437,10 +1440,10 @@
   bool result = false;
   if (IsHorizontalFlow() != child.StyleRef().IsHorizontalWritingMode()) {
     Length child_flex_basis = FlexBasisForChild(child);
-    Length child_min_size = IsHorizontalFlow() ? child.Style()->MinWidth()
-                                               : child.Style()->MinHeight();
-    Length child_max_size = IsHorizontalFlow() ? child.Style()->MaxWidth()
-                                               : child.Style()->MaxHeight();
+    Length child_min_size = IsHorizontalFlow() ? child.StyleRef().MinWidth()
+                                               : child.StyleRef().MinHeight();
+    Length child_max_size = IsHorizontalFlow() ? child.StyleRef().MaxWidth()
+                                               : child.StyleRef().MaxHeight();
     if (child_flex_basis.IsIntrinsic() || child_min_size.IsIntrinsicOrAuto() ||
         child_max_size.IsIntrinsic())
       result = true;
@@ -1544,7 +1547,7 @@
                              CrossAxisScrollbarExtent()));
   }
 
-  if (Style()->FlexDirection() == EFlexDirection::kColumnReverse) {
+  if (StyleRef().FlexDirection() == EFlexDirection::kColumnReverse) {
     // We have to do an extra pass for column-reverse to reposition the flex
     // items since the start depends on the height of the flexbox, which we
     // only know after we've positioned all the flex items.
@@ -1690,7 +1693,7 @@
     min_margin_after_baselines.push_back(min_margin_after_baseline);
   }
 
-  if (Style()->FlexWrap() != EFlexWrap::kWrapReverse)
+  if (StyleRef().FlexWrap() != EFlexWrap::kWrapReverse)
     return;
 
   // wrap-reverse flips the cross axis start and end. For baseline alignment,
@@ -1716,7 +1719,7 @@
     LayoutUnit line_cross_axis_extent) {
   LayoutBox& child = *flex_item.box;
   if (!flex_item.HasOrthogonalFlow() &&
-      child.Style()->LogicalHeight().IsAuto()) {
+      child.StyleRef().LogicalHeight().IsAuto()) {
     LayoutUnit stretched_logical_height =
         std::max(child.BorderAndPaddingLogicalHeight(),
                  line_cross_axis_extent - flex_item.CrossAxisMarginExtent());
@@ -1754,7 +1757,7 @@
           child_intrinsic_content_logical_height);
     }
   } else if (flex_item.HasOrthogonalFlow() &&
-             child.Style()->LogicalWidth().IsAuto()) {
+             child.StyleRef().LogicalWidth().IsAuto()) {
     LayoutUnit child_width =
         (line_cross_axis_extent - flex_item.CrossAxisMarginExtent())
             .ClampNegativeToZero();
@@ -1771,7 +1774,7 @@
 
 void LayoutFlexibleBox::FlipForRightToLeftColumn(
     const Vector<FlexLine>& line_contexts) {
-  if (Style()->IsLeftToRightDirection() || !IsColumnFlow())
+  if (StyleRef().IsLeftToRightDirection() || !IsColumnFlow())
     return;
 
   LayoutUnit cross_extent = CrossAxisExtent();
diff --git a/third_party/blink/renderer/core/layout/layout_frame.cc b/third_party/blink/renderer/core/layout/layout_frame.cc
index 73500ad..5f31c15 100644
--- a/third_party/blink/renderer/core/layout/layout_frame.cc
+++ b/third_party/blink/renderer/core/layout/layout_frame.cc
@@ -44,7 +44,7 @@
 void LayoutFrame::ImageChanged(WrappedImagePtr image,
                                CanDeferInvalidation,
                                const IntRect*) {
-  if (const CursorList* cursors = Style()->Cursors()) {
+  if (const CursorList* cursors = StyleRef().Cursors()) {
     for (const CursorData& cursor : *cursors) {
       if (cursor.GetImage() && cursor.GetImage()->CachedImage() == image) {
         if (LocalFrame* frame = GetFrame()) {
diff --git a/third_party/blink/renderer/core/layout/layout_frame_set.cc b/third_party/blink/renderer/core/layout/layout_frame_set.cc
index 9e31845..0faa36f5 100644
--- a/third_party/blink/renderer/core/layout/layout_frame_set.cc
+++ b/third_party/blink/renderer/core/layout/layout_frame_set.cc
@@ -96,7 +96,7 @@
   int count_fixed = 0;
   int count_percent = 0;
 
-  float effective_zoom = Style()->EffectiveZoom();
+  float effective_zoom = StyleRef().EffectiveZoom();
 
   // First we need to investigate how many columns of each type we have and
   // how much space these columns are going to require.
@@ -588,4 +588,22 @@
   return LayoutBox::GetCursor(point, cursor);
 }
 
+void LayoutFrameSet::InsertedIntoTree() {
+  LayoutBox::InsertedIntoTree();
+  // User scrollability on the scroll paint property depends on framesets (see:
+  // LayoutView::CalculateScrollbarModes) so we need to ensure the property gets
+  // updated.
+  if (Parent() && Parent() == View())
+    Parent()->SetNeedsPaintPropertyUpdate();
+}
+
+void LayoutFrameSet::WillBeRemovedFromTree() {
+  LayoutBox::WillBeRemovedFromTree();
+  // User scrollability on the scroll paint property depends on framesets (see:
+  // LayoutView::CalculateScrollbarModes) so we need to ensure the property gets
+  // updated.
+  if (Parent() && Parent() == View())
+    Parent()->SetNeedsPaintPropertyUpdate();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_frame_set.h b/third_party/blink/renderer/core/layout/layout_frame_set.h
index 6e4df71..843744e1 100644
--- a/third_party/blink/renderer/core/layout/layout_frame_set.h
+++ b/third_party/blink/renderer/core/layout/layout_frame_set.h
@@ -153,6 +153,9 @@
     return false;
   }
 
+  void InsertedIntoTree() override;
+  void WillBeRemovedFromTree() override;
+
   LayoutObjectChildList children_;
 
   GridAxis rows_;
diff --git a/third_party/blink/renderer/core/layout/layout_geometry_map.cc b/third_party/blink/renderer/core/layout/layout_geometry_map.cc
index c9948bf..73c4c9b 100644
--- a/third_party/blink/renderer/core/layout/layout_geometry_map.cc
+++ b/third_party/blink/renderer/core/layout/layout_geometry_map.cc
@@ -269,8 +269,8 @@
     base::AutoReset<size_t> position_change(&insertion_position_,
                                             mapping_.size());
     bool accumulating_transform =
-        layout_object.Style()->Preserves3D() ||
-        ancestor_layer->GetLayoutObject().Style()->Preserves3D();
+        layout_object.StyleRef().Preserves3D() ||
+        ancestor_layer->GetLayoutObject().StyleRef().Preserves3D();
     Push(&layout_object, ToLayoutSize(layer_offset),
          accumulating_transform ? kAccumulatingTransform : 0);
     return;
diff --git a/third_party/blink/renderer/core/layout/layout_grid.cc b/third_party/blink/renderer/core/layout/layout_grid.cc
index 66e5e93..351edfd 100644
--- a/third_party/blink/renderer/core/layout/layout_grid.cc
+++ b/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -960,7 +960,7 @@
     Grid& grid,
     const Vector<LayoutBox*>& auto_grid_items) const {
   bool is_for_columns = AutoPlacementMajorAxisDirection() == kForColumns;
-  bool is_grid_auto_flow_dense = Style()->IsGridAutoFlowAlgorithmDense();
+  bool is_grid_auto_flow_dense = StyleRef().IsGridAutoFlowAlgorithmDense();
 
   // Mapping between the major axis tracks (rows or columns) and the last
   // auto-placed item's position inserted on that track. This is needed to
@@ -1009,7 +1009,7 @@
     Grid& grid,
     const Vector<LayoutBox*>& auto_grid_items) const {
   std::pair<size_t, size_t> auto_placement_cursor = std::make_pair(0, 0);
-  bool is_grid_auto_flow_dense = Style()->IsGridAutoFlowAlgorithmDense();
+  bool is_grid_auto_flow_dense = StyleRef().IsGridAutoFlowAlgorithmDense();
 
   for (auto* const auto_grid_item : auto_grid_items) {
     PlaceAutoMajorAxisItemOnGrid(grid, *auto_grid_item, auto_placement_cursor);
@@ -1115,11 +1115,11 @@
 }
 
 GridTrackSizingDirection LayoutGrid::AutoPlacementMajorAxisDirection() const {
-  return Style()->IsGridAutoFlowDirectionColumn() ? kForColumns : kForRows;
+  return StyleRef().IsGridAutoFlowDirectionColumn() ? kForColumns : kForRows;
 }
 
 GridTrackSizingDirection LayoutGrid::AutoPlacementMinorAxisDirection() const {
-  return Style()->IsGridAutoFlowDirectionColumn() ? kForRows : kForColumns;
+  return StyleRef().IsGridAutoFlowDirectionColumn() ? kForRows : kForColumns;
 }
 
 void LayoutGrid::DirtyGrid() {
@@ -1975,11 +1975,11 @@
   int end_line = span.UntranslatedEndLine() + smallest_start;
   int last_line = NumTracks(direction, *grid_);
   GridPosition start_position = direction == kForColumns
-                                    ? child.Style()->GridColumnStart()
-                                    : child.Style()->GridRowStart();
+                                    ? child.StyleRef().GridColumnStart()
+                                    : child.StyleRef().GridRowStart();
   GridPosition end_position = direction == kForColumns
-                                  ? child.Style()->GridColumnEnd()
-                                  : child.Style()->GridRowEnd();
+                                  ? child.StyleRef().GridColumnEnd()
+                                  : child.StyleRef().GridRowEnd();
 
   bool start_is_auto =
       GridPositionIsAutoForOutOfFlow(start_position, direction) ||
@@ -2040,7 +2040,7 @@
   LayoutUnit child_margin =
       is_flowaware_row_axis ? child.MarginLineLeft() : child.MarginBefore();
   LayoutUnit offset = child_position - grid_border - child_margin;
-  if (!is_row_axis || Style()->IsLeftToRightDirection())
+  if (!is_row_axis || StyleRef().IsLeftToRightDirection())
     return offset;
 
   LayoutUnit child_breadth =
@@ -2297,7 +2297,7 @@
   // We stored column_position_'s data ignoring the direction, hence we might
   // need now to translate positions from RTL to LTR, as it's more convenient
   // for painting.
-  if (!Style()->IsLeftToRightDirection()) {
+  if (!StyleRef().IsLeftToRightDirection()) {
     row_axis_offset =
         (child.IsOutOfFlowPositioned()
              ? TranslateOutOfFlowRTLCoordinate(child, row_axis_offset)
@@ -2321,7 +2321,7 @@
 
   // See comment in findChildLogicalPosition() about why we need sometimes to
   // translate from RTL to LTR the rowAxisOffset coordinate.
-  return LayoutPoint(Style()->IsLeftToRightDirection()
+  return LayoutPoint(StyleRef().IsLeftToRightDirection()
                          ? row_axis_offset
                          : TranslateRTLCoordinate(row_axis_offset),
                      column_axis_offset);
diff --git a/third_party/blink/renderer/core/layout/layout_html_canvas.cc b/third_party/blink/renderer/core/layout/layout_html_canvas.cc
index ad04b69..c3276c2 100644
--- a/third_party/blink/renderer/core/layout/layout_html_canvas.cc
+++ b/third_party/blink/renderer/core/layout/layout_html_canvas.cc
@@ -52,8 +52,8 @@
 
 void LayoutHTMLCanvas::CanvasSizeChanged() {
   IntSize canvas_size = ToHTMLCanvasElement(GetNode())->Size();
-  LayoutSize zoomed_size(canvas_size.Width() * Style()->EffectiveZoom(),
-                         canvas_size.Height() * Style()->EffectiveZoom());
+  LayoutSize zoomed_size(canvas_size.Width() * StyleRef().EffectiveZoom(),
+                         canvas_size.Height() * StyleRef().EffectiveZoom());
 
   if (zoomed_size == IntrinsicSize())
     return;
diff --git a/third_party/blink/renderer/core/layout/layout_iframe.cc b/third_party/blink/renderer/core/layout/layout_iframe.cc
index b0c1de4..b13a56e 100644
--- a/third_party/blink/renderer/core/layout/layout_iframe.cc
+++ b/third_party/blink/renderer/core/layout/layout_iframe.cc
@@ -41,7 +41,7 @@
 }
 
 PaintLayerType LayoutIFrame::LayerTypeRequired() const {
-  if (Style()->Resize() != EResize::kNone)
+  if (StyleRef().Resize() != EResize::kNone)
     return kNormalPaintLayer;
   return LayoutEmbeddedContent::LayerTypeRequired();
 }
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc
index 1c907c9..27b17a7 100644
--- a/third_party/blink/renderer/core/layout/layout_image.cc
+++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -129,7 +129,7 @@
   bool old_orientation =
       old_style ? old_style->RespectImageOrientation()
                 : ComputedStyleInitialValues::InitialRespectImageOrientation();
-  if (Style() && Style()->RespectImageOrientation() != old_orientation)
+  if (Style() && StyleRef().RespectImageOrientation() != old_orientation)
     IntrinsicSizeChanged();
 }
 
@@ -202,7 +202,7 @@
     CanDeferInvalidation defer) {
   LayoutSize old_intrinsic_size = IntrinsicSize();
   LayoutSize new_intrinsic_size =
-      RoundedLayoutSize(image_resource_->ImageSize(Style()->EffectiveZoom()));
+      RoundedLayoutSize(image_resource_->ImageSize(StyleRef().EffectiveZoom()));
   UpdateIntrinsicSizeIfNeeded(new_intrinsic_size);
 
   // In the case of generated image content using :before/:after/content, we
@@ -218,17 +218,17 @@
 
   // If the actual area occupied by the image has changed and it is not
   // constrained by style then a layout is required.
-  bool image_size_is_constrained = Style()->LogicalWidth().IsSpecified() &&
-                                   Style()->LogicalHeight().IsSpecified();
+  bool image_size_is_constrained = StyleRef().LogicalWidth().IsSpecified() &&
+                                   StyleRef().LogicalHeight().IsSpecified();
 
   // FIXME: We only need to recompute the containing block's preferred size if
   // the containing block's size depends on the image's size (i.e., the
   // container uses shrink-to-fit sizing). There's no easy way to detect that
   // shrink-to-fit is needed, always force a layout.
   bool containing_block_needs_to_recompute_preferred_size =
-      Style()->LogicalWidth().IsPercentOrCalc() ||
-      Style()->LogicalMaxWidth().IsPercentOrCalc() ||
-      Style()->LogicalMinWidth().IsPercentOrCalc();
+      StyleRef().LogicalWidth().IsPercentOrCalc() ||
+      StyleRef().LogicalMaxWidth().IsPercentOrCalc() ||
+      StyleRef().LogicalMinWidth().IsPercentOrCalc();
 
   if (image_source_has_changed_size &&
       (!image_size_is_constrained ||
@@ -307,23 +307,23 @@
     return false;
   if (!ContentBoxRect().Contains(local_rect))
     return false;
-  EFillBox background_clip = Style()->BackgroundClip();
+  EFillBox background_clip = StyleRef().BackgroundClip();
   // Background paints under borders.
-  if (background_clip == EFillBox::kBorder && Style()->HasBorder() &&
-      !Style()->BorderObscuresBackground())
+  if (background_clip == EFillBox::kBorder && StyleRef().HasBorder() &&
+      !StyleRef().BorderObscuresBackground())
     return false;
   // Background shows in padding area.
   if ((background_clip == EFillBox::kBorder ||
        background_clip == EFillBox::kPadding) &&
-      Style()->HasPadding())
+      StyleRef().HasPadding())
     return false;
   // Object-position may leave parts of the content box empty, regardless of the
   // value of object-fit.
-  if (Style()->ObjectPosition() !=
+  if (StyleRef().ObjectPosition() !=
       ComputedStyleInitialValues::InitialObjectPosition())
     return false;
   // Object-fit may leave parts of the content box empty.
-  EObjectFit object_fit = Style()->GetObjectFit();
+  EObjectFit object_fit = StyleRef().GetObjectFit();
   if (object_fit != EObjectFit::kFill && object_fit != EObjectFit::kCover)
     return false;
   // Check for image with alpha.
@@ -375,8 +375,8 @@
 
     // Handle zoom & vertical writing modes here, as the embedded SVG document
     // doesn't know about them.
-    intrinsic_sizing_info.size.Scale(Style()->EffectiveZoom());
-    if (Style()->GetObjectFit() != EObjectFit::kScaleDown)
+    intrinsic_sizing_info.size.Scale(StyleRef().EffectiveZoom());
+    if (StyleRef().GetObjectFit() != EObjectFit::kScaleDown)
       intrinsic_sizing_info.size.Scale(ImageDevicePixelRatio());
 
     if (!IsHorizontalWritingMode())
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index 44bc054..9e367c81 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -290,8 +290,8 @@
       (parent_layout_inline && parent_layout_inline->AlwaysCreateLineBoxes()) ||
       (parent_layout_inline &&
        parent_style.VerticalAlign() != EVerticalAlign::kBaseline) ||
-      Style()->VerticalAlign() != EVerticalAlign::kBaseline ||
-      Style()->GetTextEmphasisMark() != TextEmphasisMark::kNone ||
+      StyleRef().VerticalAlign() != EVerticalAlign::kBaseline ||
+      StyleRef().GetTextEmphasisMark() != TextEmphasisMark::kNone ||
       (check_fonts &&
        (!StyleRef().HasIdenticalAscentDescentAndLineGap(parent_style) ||
         parent_style.LineHeight() != StyleRef().LineHeight()));
@@ -421,7 +421,7 @@
     // collect the x/y offsets from inline parents later.
     if (LayoutObject* positioned_ancestor =
             InFlowPositionedInlineAncestor(this))
-      new_style->SetPosition(positioned_ancestor->Style()->GetPosition());
+      new_style->SetPosition(positioned_ancestor->StyleRef().GetPosition());
 
     LayoutBlockFlow* new_box =
         LayoutBlockFlow::CreateAnonymous(&GetDocument(), std::move(new_style));
@@ -710,7 +710,7 @@
   if (!CulledInlineFirstLineBox())
     return;
 
-  bool is_horizontal = Style()->IsHorizontalWritingMode();
+  bool is_horizontal = StyleRef().IsHorizontalWritingMode();
 
   LayoutUnit logical_top, logical_height;
   for (LayoutObject* curr = FirstChild(); curr; curr = curr->NextSibling()) {
@@ -890,19 +890,19 @@
 }
 
 LayoutUnit LayoutInline::MarginLeft() const {
-  return ComputeMargin(this, Style()->MarginLeft());
+  return ComputeMargin(this, StyleRef().MarginLeft());
 }
 
 LayoutUnit LayoutInline::MarginRight() const {
-  return ComputeMargin(this, Style()->MarginRight());
+  return ComputeMargin(this, StyleRef().MarginRight());
 }
 
 LayoutUnit LayoutInline::MarginTop() const {
-  return ComputeMargin(this, Style()->MarginTop());
+  return ComputeMargin(this, StyleRef().MarginTop());
 }
 
 LayoutUnit LayoutInline::MarginBottom() const {
-  return ComputeMargin(this, Style()->MarginBottom());
+  return ComputeMargin(this, StyleRef().MarginBottom());
 }
 
 bool LayoutInline::NodeAtPoint(HitTestResult& result,
@@ -1092,7 +1092,7 @@
         logical_right_side = curr->LogicalRight();
     }
 
-    bool is_horizontal = Style()->IsHorizontalWritingMode();
+    bool is_horizontal = StyleRef().IsHorizontalWritingMode();
 
     LayoutUnit x = is_horizontal ? logical_left_side : FirstLineBox()->X();
     LayoutUnit y = is_horizontal ? FirstLineBox()->Y() : logical_left_side;
@@ -1159,7 +1159,7 @@
   LinesBoundingBoxGeneratorContext context(float_result);
   GenerateCulledLineBoxRects(context, this);
   LayoutRect result(EnclosingLayoutRect(float_result));
-  bool is_horizontal = Style()->IsHorizontalWritingMode();
+  bool is_horizontal = StyleRef().IsHorizontalWritingMode();
   for (LayoutObject* curr = FirstChild(); curr; curr = curr->NextSibling()) {
     if (curr->IsFloatingOrOutOfFlowPositioned())
       continue;
@@ -1239,7 +1239,7 @@
 
   LayoutRect rect(logical_left_side, logical_top, logical_width,
                   logical_height);
-  if (!Style()->IsHorizontalWritingMode())
+  if (!StyleRef().IsHorizontalWritingMode())
     rect = rect.TransposedRect();
   return rect;
 }
@@ -1298,7 +1298,7 @@
 
 LayoutRect LayoutInline::VisualOverflowRect() const {
   LayoutRect overflow_rect = LinesVisualOverflowBoundingBox();
-  LayoutUnit outline_outset(Style()->OutlineOutsetExtent());
+  LayoutUnit outline_outset(StyleRef().OutlineOutsetExtent());
   if (outline_outset) {
     Vector<LayoutRect> rects;
     if (GetDocument().InNoQuirksMode()) {
@@ -1336,13 +1336,13 @@
   if (!container)
     return true;
 
-  bool preserve3d = container->Style()->Preserves3D();
+  bool preserve3d = container->StyleRef().Preserves3D();
 
   TransformState::TransformAccumulation accumulation =
       preserve3d ? TransformState::kAccumulateTransform
                  : TransformState::kFlattenTransform;
 
-  if (Style()->HasInFlowPosition() && Layer()) {
+  if (StyleRef().HasInFlowPosition() && Layer()) {
     // Apply the in-flow position offset when invalidating a rectangle. The
     // layer is translated, but the layout box isn't, so we need to do this to
     // get the right dirty rect. Since this is called from LayoutObject::
@@ -1386,7 +1386,7 @@
 
 PaintLayerType LayoutInline::LayerTypeRequired() const {
   return IsInFlowPositioned() || CreatesGroup() ||
-                 Style()->ShouldCompositeForCurrentAnimations() ||
+                 StyleRef().ShouldCompositeForCurrentAnimations() ||
                  ShouldApplyPaintContainment()
              ? kNormalPaintLayer
              : kNoPaintLayer;
@@ -1492,7 +1492,7 @@
       return LayoutUnit(s->ComputedLineHeight());
   }
 
-  return LayoutUnit(Style()->ComputedLineHeight());
+  return LayoutUnit(StyleRef().ComputedLineHeight());
 }
 
 LayoutUnit LayoutInline::BaselinePosition(
@@ -1542,19 +1542,19 @@
   // relative-positioned inline has a negative offset we need to compensate for
   // it so that we align the positioned object with the edge of its containing
   // block.
-  if (child.Style()->HasStaticInlinePosition(
-          Style()->IsHorizontalWritingMode()))
+  if (child.StyleRef().HasStaticInlinePosition(
+          StyleRef().IsHorizontalWritingMode()))
     logical_offset.SetWidth(
         std::max(LayoutUnit(), -OffsetForInFlowPosition().Width()));
   else
     logical_offset.SetWidth(inline_position);
 
-  if (!child.Style()->HasStaticBlockPosition(
-          Style()->IsHorizontalWritingMode()))
+  if (!child.StyleRef().HasStaticBlockPosition(
+          StyleRef().IsHorizontalWritingMode()))
     logical_offset.SetHeight(block_position);
 
-  return Style()->IsHorizontalWritingMode() ? logical_offset
-                                            : logical_offset.TransposedSize();
+  return StyleRef().IsHorizontalWritingMode() ? logical_offset
+                                              : logical_offset.TransposedSize();
 }
 
 void LayoutInline::ImageChanged(WrappedImagePtr,
@@ -1650,15 +1650,15 @@
 
 void LayoutInline::AddAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) {
   // Convert the style regions to absolute coordinates.
-  if (Style()->Visibility() != EVisibility::kVisible)
+  if (StyleRef().Visibility() != EVisibility::kVisible)
     return;
 
-  if (Style()->DraggableRegionMode() == EDraggableRegionMode::kNone)
+  if (StyleRef().DraggableRegionMode() == EDraggableRegionMode::kNone)
     return;
 
   AnnotatedRegionValue region;
   region.draggable =
-      Style()->DraggableRegionMode() == EDraggableRegionMode::kDrag;
+      StyleRef().DraggableRegionMode() == EDraggableRegionMode::kDrag;
   region.bounds = LayoutRect(LinesBoundingBox());
 
   LayoutObject* container = ContainingBlock();
diff --git a/third_party/blink/renderer/core/layout/layout_list_box.cc b/third_party/blink/renderer/core/layout/layout_list_box.cc
index 2e51a69f..7e9a28f3 100644
--- a/third_party/blink/renderer/core/layout/layout_list_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_list_box.cc
@@ -70,7 +70,7 @@
 }
 
 LayoutUnit LayoutListBox::DefaultItemHeight() const {
-  const SimpleFontData* font_data = Style()->GetFont().PrimaryFont();
+  const SimpleFontData* font_data = StyleRef().GetFont().PrimaryFont();
   if (!font_data)
     return LayoutUnit();
   return LayoutUnit(font_data->GetFontMetrics().Height() +
@@ -127,7 +127,7 @@
     LayoutUnit& max_logical_width) const {
   LayoutBlockFlow::ComputeIntrinsicLogicalWidths(min_logical_width,
                                                  max_logical_width);
-  if (Style()->Width().IsPercentOrCalc())
+  if (StyleRef().Width().IsPercentOrCalc())
     min_logical_width = LayoutUnit();
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_list_item.cc b/third_party/blink/renderer/core/layout/layout_list_item.cc
index 4c9de99..1a1b193 100644
--- a/third_party/blink/renderer/core/layout/layout_list_item.cc
+++ b/third_party/blink/renderer/core/layout/layout_list_item.cc
@@ -51,8 +51,8 @@
                                     const ComputedStyle* old_style) {
   LayoutBlockFlow::StyleDidChange(diff, old_style);
 
-  StyleImage* current_image = Style()->ListStyleImage();
-  if (Style()->ListStyleType() != EListStyleType::kNone ||
+  StyleImage* current_image = StyleRef().ListStyleImage();
+  if (StyleRef().ListStyleType() != EListStyleType::kNone ||
       (current_image && !current_image->ErrorOccurred())) {
     if (!marker_)
       marker_ = LayoutListMarker::CreateAnonymous(this);
@@ -80,8 +80,8 @@
 
   LayoutBlockFlow::WillBeDestroyed();
 
-  if (Style() && Style()->ListStyleImage())
-    Style()->ListStyleImage()->RemoveClient(this);
+  if (Style() && StyleRef().ListStyleImage())
+    StyleRef().ListStyleImage()->RemoveClient(this);
 }
 
 void LayoutListItem::InsertedIntoTree() {
@@ -397,7 +397,7 @@
     // TODO(jchaffraix): Propagating the overflow to the line boxes seems
     // pretty wrong (https://crbug.com/554160).
     // FIXME: Need to account for relative positioning in the layout overflow.
-    if (Style()->IsLeftToRightDirection()) {
+    if (StyleRef().IsLeftToRightDirection()) {
       LayoutUnit marker_line_offset =
           std::min(marker_->LineOffset(),
                    LogicalLeftOffsetForLine(marker_->LogicalTop(),
@@ -482,7 +482,7 @@
           LayoutPoint(marker_logical_left + line_offset,
                       block_offset + marker_inline_box->LogicalTop()),
           marker_->Size());
-      if (!Style()->IsHorizontalWritingMode())
+      if (!StyleRef().IsHorizontalWritingMode())
         marker_rect = marker_rect.TransposedRect();
       LayoutBox* o = marker_;
       bool propagate_visual_overflow = true;
diff --git a/third_party/blink/renderer/core/layout/layout_list_marker.cc b/third_party/blink/renderer/core/layout/layout_list_marker.cc
index 4e86707..e52e558 100644
--- a/third_party/blink/renderer/core/layout/layout_list_marker.cc
+++ b/third_party/blink/renderer/core/layout/layout_list_marker.cc
@@ -64,7 +64,7 @@
 
 LayoutSize LayoutListMarker::ImageBulletSize() const {
   DCHECK(IsImage());
-  const SimpleFontData* font_data = Style()->GetFont().PrimaryFont();
+  const SimpleFontData* font_data = StyleRef().GetFont().PrimaryFont();
   DCHECK(font_data);
   if (!font_data)
     return LayoutSize();
@@ -76,15 +76,15 @@
   LayoutUnit bullet_width =
       font_data->GetFontMetrics().Ascent() / LayoutUnit(2);
   return RoundedLayoutSize(
-      image_->ImageSize(GetDocument(), Style()->EffectiveZoom(),
+      image_->ImageSize(GetDocument(), StyleRef().EffectiveZoom(),
                         LayoutSize(bullet_width, bullet_width)));
 }
 
 void LayoutListMarker::StyleWillChange(StyleDifference diff,
                                        const ComputedStyle& new_style) {
   if (Style() &&
-      (new_style.ListStylePosition() != Style()->ListStylePosition() ||
-       new_style.ListStyleType() != Style()->ListStyleType()))
+      (new_style.ListStylePosition() != StyleRef().ListStylePosition() ||
+       new_style.ListStyleType() != StyleRef().ListStyleType()))
     SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
         LayoutInvalidationReason::kStyleChange);
 
@@ -95,10 +95,10 @@
                                       const ComputedStyle* old_style) {
   LayoutBox::StyleDidChange(diff, old_style);
 
-  if (image_ != Style()->ListStyleImage()) {
+  if (image_ != StyleRef().ListStyleImage()) {
     if (image_)
       image_->RemoveClient(this);
-    image_ = Style()->ListStyleImage();
+    image_ = StyleRef().ListStyleImage();
     if (image_)
       image_->AddClient(this);
   }
@@ -126,7 +126,7 @@
   for (LayoutBox* o = ParentBox(); o && o != ListItem(); o = o->ParentBox()) {
     block_offset += o->LogicalTop();
   }
-  if (ListItem()->Style()->IsLeftToRightDirection()) {
+  if (ListItem()->StyleRef().IsLeftToRightDirection()) {
     line_offset_ = ListItem()->LogicalLeftOffsetForLine(
         block_offset, kDoNotIndentText, LayoutUnit());
   } else {
@@ -139,7 +139,7 @@
     SetWidth(image_size.Width());
     SetHeight(image_size.Height());
   } else {
-    const SimpleFontData* font_data = Style()->GetFont().PrimaryFont();
+    const SimpleFontData* font_data = StyleRef().GetFont().PrimaryFont();
     DCHECK(font_data);
     SetLogicalWidth(MinPreferredLogicalWidth());
     SetLogicalHeight(
@@ -149,8 +149,8 @@
   SetMarginStart(LayoutUnit());
   SetMarginEnd(LayoutUnit());
 
-  Length start_margin = Style()->MarginStart();
-  Length end_margin = Style()->MarginEnd();
+  Length start_margin = StyleRef().MarginStart();
+  Length end_margin = StyleRef().MarginEnd();
   if (start_margin.IsFixed())
     SetMarginStart(LayoutUnit(start_margin.Value()));
   if (end_margin.IsFixed())
@@ -194,11 +194,11 @@
     case ListStyleCategory::kNone:
       break;
     case ListStyleCategory::kSymbol:
-      text_ = ListMarkerText::GetText(Style()->ListStyleType(),
+      text_ = ListMarkerText::GetText(StyleRef().ListStyleType(),
                                       0);  // value is ignored for these types
       break;
     case ListStyleCategory::kLanguage:
-      text_ = ListMarkerText::GetText(Style()->ListStyleType(),
+      text_ = ListMarkerText::GetText(StyleRef().ListStyleType(),
                                       list_item_->Value());
       break;
   }
@@ -206,7 +206,7 @@
 
 String LayoutListMarker::TextAlternative() const {
   UChar suffix =
-      ListMarkerText::Suffix(Style()->ListStyleType(), list_item_->Value());
+      ListMarkerText::Suffix(StyleRef().ListStyleType(), list_item_->Value());
   // Return suffix after the marker text, even in RTL, reflecting speech order.
   return text_ + suffix + ' ';
 }
@@ -214,15 +214,15 @@
 LayoutUnit LayoutListMarker::GetWidthOfTextWithSuffix() const {
   if (text_.IsEmpty())
     return LayoutUnit();
-  const Font& font = Style()->GetFont();
+  const Font& font = StyleRef().GetFont();
   LayoutUnit item_width = LayoutUnit(font.Width(TextRun(text_)));
   // TODO(wkorman): Look into constructing a text run for both text and suffix
   // and painting them together.
   UChar suffix[2] = {
-      ListMarkerText::Suffix(Style()->ListStyleType(), list_item_->Value()),
+      ListMarkerText::Suffix(StyleRef().ListStyleType(), list_item_->Value()),
       ' '};
   TextRun run =
-      ConstructTextRun(font, suffix, 2, StyleRef(), Style()->Direction());
+      ConstructTextRun(font, suffix, 2, StyleRef(), StyleRef().Direction());
   LayoutUnit suffix_space_width = LayoutUnit(font.Width(run));
   return item_width + suffix_space_width;
 }
@@ -234,8 +234,8 @@
   if (IsImage()) {
     LayoutSize image_size(ImageBulletSize());
     min_preferred_logical_width_ = max_preferred_logical_width_ =
-        Style()->IsHorizontalWritingMode() ? image_size.Width()
-                                           : image_size.Height();
+        StyleRef().IsHorizontalWritingMode() ? image_size.Width()
+                                             : image_size.Height();
     ClearPreferredLogicalWidthsDirty();
     UpdateMargins();
     return;
@@ -460,7 +460,7 @@
 
 bool LayoutListMarker::IsInside() const {
   return list_item_->Ordinal().NotInList() ||
-         Style()->ListStylePosition() == EListStylePosition::kInside;
+         StyleRef().ListStylePosition() == EListStylePosition::kInside;
 }
 
 LayoutRect LayoutListMarker::GetRelativeMarkerRect() const {
@@ -474,7 +474,7 @@
     case ListStyleCategory::kSymbol:
       return RelativeSymbolMarkerRect(StyleRef(), Size().Width());
     case ListStyleCategory::kLanguage: {
-      const SimpleFontData* font_data = Style()->GetFont().PrimaryFont();
+      const SimpleFontData* font_data = StyleRef().GetFont().PrimaryFont();
       DCHECK(font_data);
       if (!font_data)
         return relative_rect;
@@ -485,7 +485,7 @@
     }
   }
 
-  if (!Style()->IsHorizontalWritingMode()) {
+  if (!StyleRef().IsHorizontalWritingMode()) {
     relative_rect = relative_rect.TransposedRect();
     relative_rect.SetX(Size().Width() - relative_rect.X() -
                        relative_rect.Width());
@@ -524,8 +524,8 @@
   if (Style()) {
     // Reuse the current margins. Otherwise resetting the margins to initial
     // values would trigger unnecessary layout.
-    new_style->SetMarginStart(Style()->MarginStart());
-    new_style->SetMarginEnd(Style()->MarginRight());
+    new_style->SetMarginStart(StyleRef().MarginStart());
+    new_style->SetMarginEnd(StyleRef().MarginRight());
   }
   SetStyle(std::move(new_style));
 }
diff --git a/third_party/blink/renderer/core/layout/layout_menu_list.cc b/third_party/blink/renderer/core/layout/layout_menu_list.cc
index 7d60efb..f9d218a 100644
--- a/third_party/blink/renderer/core/layout/layout_menu_list.cc
+++ b/third_party/blink/renderer/core/layout/layout_menu_list.cc
@@ -125,7 +125,7 @@
   // when the content overflows, treat it the same as align-items: flex-start.
   // But we only do that for the cases where html.css would otherwise use
   // center.
-  if (Style()->AlignItemsPosition() == ItemPosition::kCenter) {
+  if (StyleRef().AlignItemsPosition() == ItemPosition::kCenter) {
     inner_style.SetMarginTop(Length());
     inner_style.SetMarginBottom(Length());
     inner_style.SetAlignSelfPosition(ItemPosition::kFlexStart);
@@ -199,7 +199,7 @@
 }
 
 void LayoutMenuList::UpdateInnerBlockHeight() {
-  const SimpleFontData* font_data = Style()->GetFont().PrimaryFont();
+  const SimpleFontData* font_data = StyleRef().GetFont().PrimaryFont();
   DCHECK(font_data);
   inner_block_height_ = (font_data ? font_data->GetFontMetrics().Height() : 0) +
                         inner_block_->BorderAndPaddingHeight();
@@ -215,9 +215,9 @@
     item_style->ApplyTextTransform(&text);
     // We apply SELECT's style, not OPTION's style because m_optionsWidth is
     // used to determine intrinsic width of the menulist box.
-    TextRun text_run = ConstructTextRun(Style()->GetFont(), text, *Style());
+    TextRun text_run = ConstructTextRun(StyleRef().GetFont(), text, *Style());
     max_option_width =
-        std::max(max_option_width, Style()->GetFont().Width(text_run));
+        std::max(max_option_width, StyleRef().GetFont().Width(text_run));
   }
   options_width_ = static_cast<int>(ceilf(max_option_width));
 }
@@ -316,7 +316,7 @@
       std::max(options_width_,
                LayoutTheme::GetTheme().MinimumMenuListSize(StyleRef())) +
       inner_block_->PaddingLeft() + inner_block_->PaddingRight();
-  if (!Style()->Width().IsPercentOrCalc())
+  if (!StyleRef().Width().IsPercentOrCalc())
     min_logical_width = max_logical_width;
   else
     min_logical_width = LayoutUnit();
@@ -326,7 +326,7 @@
     LayoutUnit logical_height,
     LayoutUnit logical_top,
     LogicalExtentComputedValues& computed_values) const {
-  if (Style()->HasAppearance())
+  if (StyleRef().HasAppearance())
     logical_height = inner_block_height_ + BorderAndPaddingHeight();
   LayoutBox::ComputeLogicalHeight(logical_height, logical_top, computed_values);
 }
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
index 4f96b5b..5fc48cc 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
@@ -330,7 +330,7 @@
     return column_height_available_;
   }
   const LayoutBlockFlow* multicol_block = MultiColumnBlockFlow();
-  Length logical_max_height = multicol_block->Style()->LogicalMaxHeight();
+  Length logical_max_height = multicol_block->StyleRef().LogicalMaxHeight();
   if (!logical_max_height.IsMaxSizeNone()) {
     LayoutUnit resolved_logical_max_height =
         multicol_block->ComputeContentLogicalHeight(
@@ -889,7 +889,7 @@
 
   // The spec says that column-span only applies to in-flow block-level
   // elements.
-  if (descendant->Style()->GetColumnSpan() != EColumnSpan::kAll ||
+  if (descendant->StyleRef().GetColumnSpan() != EColumnSpan::kAll ||
       !descendant->IsBox() || descendant->IsInline() ||
       descendant->IsFloatingOrOutOfFlowPositioned())
     return false;
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
index 66b6ce78..5d3fcefb 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
@@ -346,7 +346,7 @@
     // 'balance' - in accordance with the spec).
     // Pretending that column-fill is auto also matches the old multicol
     // implementation, which has no support for this property.
-    if (MultiColumnBlockFlow()->Style()->GetColumnFill() ==
+    if (MultiColumnBlockFlow()->StyleRef().GetColumnFill() ==
         EColumnFill::kBalance)
       return true;
     if (LayoutBox* next = NextSiblingBox()) {
@@ -492,12 +492,12 @@
 LayoutUnit LayoutMultiColumnSet::ColumnGap() const {
   LayoutBlockFlow* parent_block = MultiColumnBlockFlow();
 
-  if (parent_block->Style()->ColumnGap().IsNormal()) {
+  if (parent_block->StyleRef().ColumnGap().IsNormal()) {
     // "1em" is recommended as the normal gap setting. Matches <p> margins.
     return LayoutUnit(
-        parent_block->Style()->GetFontDescription().ComputedPixelSize());
+        parent_block->StyleRef().GetFontDescription().ComputedPixelSize());
   }
-  return ValueForLength(parent_block->Style()->ColumnGap().GetLength(),
+  return ValueForLength(parent_block->StyleRef().ColumnGap().GetLength(),
                         AvailableLogicalWidth());
 }
 
@@ -591,7 +591,7 @@
   if (col_count <= 1)
     return false;
 
-  bool left_to_right = Style()->IsLeftToRightDirection();
+  bool left_to_right = StyleRef().IsLeftToRightDirection();
   LayoutUnit curr_logical_left_offset =
       left_to_right ? LayoutUnit() : ContentLogicalWidth();
   LayoutUnit rule_add = BorderAndPaddingLogicalLeft();
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
index 087c84f..97f9fff 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
@@ -46,7 +46,7 @@
   if (FlowThread()->RemoveSpannerPlaceholderIfNoLongerValid(
           object_in_flow_thread)) {
     // No longer a valid spanner, due to style changes. |this| is now dead.
-    if (object_in_flow_thread->Style()->HasOutOfFlowPosition() &&
+    if (object_in_flow_thread->StyleRef().HasOutOfFlowPosition() &&
         !old_style->HasOutOfFlowPosition()) {
       // We went from being a spanner to being out-of-flow positioned. When an
       // object becomes out-of-flow positioned, we need to lay out its parent,
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 040739d..4f03d57 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -136,8 +136,8 @@
   // LayoutObject::Container() method can actually be used to obtain the inline
   // directly.
   if (container && container->IsInline() && !container->IsAtomicInlineLevel()) {
-    DCHECK(container->Style()->HasInFlowPosition() ||
-           container->Style()->HasFilter());
+    DCHECK(container->StyleRef().HasInFlowPosition() ||
+           container->StyleRef().HasFilter());
     container = container->ContainingBlock(skip_info);
   }
 
@@ -381,7 +381,7 @@
   }
 
   if (new_child->IsText() &&
-      new_child->Style()->TextTransform() == ETextTransform::kCapitalize)
+      new_child->StyleRef().TextTransform() == ETextTransform::kCapitalize)
     ToLayoutText(new_child)->TransformText();
 }
 
@@ -890,7 +890,7 @@
     LayoutObject* container = object->Container();
     if (!container && !object->IsLayoutView())
       return;
-    if (!last->IsTextOrSVGChild() && last->Style()->HasOutOfFlowPosition()) {
+    if (!last->IsTextOrSVGChild() && last->StyleRef().HasOutOfFlowPosition()) {
       object = last->ContainingBlock();
       if (object->PosChildNeedsLayout())
         return;
@@ -942,7 +942,7 @@
     MarkingBehavior mark_parents) {
   bitfields_.SetPreferredLogicalWidthsDirty(true);
   if (mark_parents == kMarkContainerChain &&
-      (IsText() || !Style()->HasOutOfFlowPosition()))
+      (IsText() || !StyleRef().HasOutOfFlowPosition()))
     InvalidateContainerPreferredLogicalWidths();
 }
 
@@ -981,7 +981,7 @@
     o->bitfields_.SetPreferredLogicalWidthsDirty(true);
     // A positioned object has no effect on the min/max width of its containing
     // block ever. We can optimize this case and not go up any further.
-    if (o->Style()->HasOutOfFlowPosition())
+    if (o->StyleRef().HasOutOfFlowPosition())
       break;
     o = container;
   }
@@ -1682,7 +1682,7 @@
         transform_state.SetQuad(FloatQuad(FloatRect(rect)));
       }
 
-      bool preserve3d = parent->Style()->Preserves3D() && !parent->IsText();
+      bool preserve3d = parent->StyleRef().Preserves3D() && !parent->IsText();
 
       TransformState::TransformAccumulation accumulation =
           preserve3d ? TransformState::kAccumulateTransform
@@ -1807,8 +1807,8 @@
 #endif  // NDEBUG
 
 bool LayoutObject::IsSelectable() const {
-  return !IsInert() && !(Style()->UserSelect() == EUserSelect::kNone &&
-                         Style()->UserModify() == EUserModify::kReadOnly);
+  return !IsInert() && !(StyleRef().UserSelect() == EUserSelect::kNone &&
+                         StyleRef().UserModify() == EUserModify::kReadOnly);
 }
 
 // Called when an object that was floating or positioned becomes a normal flow
@@ -1818,7 +1818,7 @@
   // We have gone from not affecting the inline status of the parent flow to
   // suddenly having an impact.  See if there is a mismatch between the parent
   // flow's childrenInline() state and our state.
-  object->SetInline(object->Style()->IsDisplayInlineType());
+  object->SetInline(object->StyleRef().IsDisplayInlineType());
   if (object->IsInline() != object->Parent()->ChildrenInline()) {
     if (!object->IsInline()) {
       ToLayoutBoxModelObject(object->Parent())->ChildBecameNonInline(object);
@@ -1852,15 +1852,15 @@
   // needed if we have style or text affected by these properties.
   if (diff.TextDecorationOrColorChanged() &&
       !diff.NeedsFullPaintInvalidation()) {
-    if (Style()->HasBorderColorReferencingCurrentColor() ||
-        Style()->HasOutlineWithCurrentColor() ||
-        Style()->HasBackgroundRelatedColorReferencingCurrentColor() ||
+    if (StyleRef().HasBorderColorReferencingCurrentColor() ||
+        StyleRef().HasOutlineWithCurrentColor() ||
+        StyleRef().HasBackgroundRelatedColorReferencingCurrentColor() ||
         // Skip any text nodes that do not contain text boxes. Whitespace cannot
         // be skipped or we will miss invalidating decorations (e.g.,
         // underlines).
         (IsText() && !IsBR() && ToLayoutText(this)->HasTextBoxes()) ||
-        (IsSVG() && Style()->SvgStyle().IsFillColorCurrentColor()) ||
-        (IsSVG() && Style()->SvgStyle().IsStrokeColorCurrentColor()) ||
+        (IsSVG() && StyleRef().SvgStyle().IsFillColorCurrentColor()) ||
+        (IsSVG() && StyleRef().SvgStyle().IsStrokeColorCurrentColor()) ||
         IsListMarker())
       diff.SetNeedsPaintInvalidationObject();
   }
@@ -2320,7 +2320,7 @@
   // properties.
   for (LayoutObject* child = SlowFirstChild(); child;
        child = child->NextSibling()) {
-    if (!child->IsAnonymous() || child->Style()->StyleType() != kPseudoIdNone)
+    if (!child->IsAnonymous() || child->StyleRef().StyleType() != kPseudoIdNone)
       continue;
 
     if (child->AnonymousHasStylePropagationOverride())
@@ -2328,17 +2328,17 @@
 
     scoped_refptr<ComputedStyle> new_style =
         ComputedStyle::CreateAnonymousStyleWithDisplay(
-            StyleRef(), child->Style()->Display());
+            StyleRef(), child->StyleRef().Display());
 
     // Preserve the position style of anonymous block continuations as they can
     // have relative position when they contain block descendants of relative
     // positioned inlines.
     if (child->IsInFlowPositioned() && child->IsLayoutBlockFlow() &&
         ToLayoutBlockFlow(child)->IsAnonymousBlockContinuation())
-      new_style->SetPosition(child->Style()->GetPosition());
+      new_style->SetPosition(child->StyleRef().GetPosition());
 
     if (child->IsLayoutNGListMarker())
-      new_style->SetWhiteSpace(child->Style()->WhiteSpace());
+      new_style->SetWhiteSpace(child->StyleRef().WhiteSpace());
 
     UpdateAnonymousChildStyle(child, *new_style);
 
@@ -2475,7 +2475,7 @@
     if (IsBox()) {
       mode &= ~kApplyContainerFlip;
     } else if (container->IsBox()) {
-      if (container->Style()->IsFlippedBlocksWritingMode()) {
+      if (container->StyleRef().IsFlippedBlocksWritingMode()) {
         IntPoint center_point = RoundedIntPoint(transform_state.MappedPoint());
         transform_state.Move(ToLayoutBox(container)->FlipForWritingMode(
                                  LayoutPoint(center_point)) -
@@ -2506,8 +2506,8 @@
   // them.
   bool preserve3d =
       mode & kUseTransforms &&
-      ((container->Style()->Preserves3D() && !container->IsText()) ||
-       (Style()->Preserves3D() && !IsText()));
+      ((container->StyleRef().Preserves3D() && !container->IsText()) ||
+       (StyleRef().Preserves3D() && !IsText()));
   if (mode & kUseTransforms && ShouldUseTransformFromContainer(container)) {
     TransformationMatrix t;
     GetTransformFromContainer(container, container_offset, t);
@@ -2531,7 +2531,7 @@
                                     : TransformState::kFlattenTransform);
     // If the ancestor is fixed, then the rect is already in its coordinates so
     // doesn't need viewport-adjusting.
-    if (ancestor->Style()->GetPosition() != EPosition::kFixed &&
+    if (ancestor->StyleRef().GetPosition() != EPosition::kFixed &&
         container->IsLayoutView() &&
         StyleRef().GetPosition() == EPosition::kFixed) {
       LayoutSize adjustment = ToLayoutView(container)->OffsetForFixedPosition();
@@ -2566,7 +2566,7 @@
     if (IsBox()) {
       mode &= ~kApplyContainerFlip;
     } else if (container->IsBox()) {
-      apply_container_flip = container->Style()->IsFlippedBlocksWritingMode();
+      apply_container_flip = container->StyleRef().IsFlippedBlocksWritingMode();
       mode &= ~kApplyContainerFlip;
     }
   }
@@ -2577,7 +2577,7 @@
   LayoutSize container_offset = OffsetFromContainer(container);
   bool preserve3d =
       mode & kUseTransforms &&
-      (container->Style()->Preserves3D() || Style()->Preserves3D());
+      (container->StyleRef().Preserves3D() || StyleRef().Preserves3D());
   if (mode & kUseTransforms && ShouldUseTransformFromContainer(container)) {
     TransformationMatrix t;
     GetTransformFromContainer(container, container_offset, t);
@@ -2611,7 +2611,7 @@
     transform_state.Move(-container_offset.Width(), -container_offset.Height());
     // If the ancestor is fixed, then the rect is already in its coordinates so
     // doesn't need viewport-adjusting.
-    if (ancestor->Style()->GetPosition() != EPosition::kFixed &&
+    if (ancestor->StyleRef().GetPosition() != EPosition::kFixed &&
         container->IsLayoutView() &&
         StyleRef().GetPosition() == EPosition::kFixed) {
       LayoutSize adjustment = ToLayoutView(container)->OffsetForFixedPosition();
@@ -2626,7 +2626,7 @@
   // or perspective. We just care about transform, so check the layer's
   // transform directly.
   return (HasLayer() && ToLayoutBoxModelObject(this)->Layer()->Transform()) ||
-         (container_object && container_object->Style()->HasPerspective());
+         (container_object && container_object->StyleRef().HasPerspective());
 }
 
 void LayoutObject::GetTransformFromContainer(
@@ -2643,7 +2643,7 @@
                           offset_in_container.Height().ToFloat());
 
   if (container_object && container_object->HasLayer() &&
-      container_object->Style()->HasPerspective()) {
+      container_object->StyleRef().HasPerspective()) {
     // Perspective on the container affects us, so we have to factor it in here.
     DCHECK(container_object->HasLayer());
     FloatPoint perspective_origin =
@@ -2651,7 +2651,7 @@
 
     TransformationMatrix perspective_matrix;
     perspective_matrix.ApplyPerspective(
-        container_object->Style()->Perspective());
+        container_object->StyleRef().Perspective());
     perspective_matrix.ApplyTransformOrigin(perspective_origin.X(),
                                             perspective_origin.Y(), 0);
 
@@ -2871,7 +2871,7 @@
     iter_value = &iter->value;
   }
   TouchAction whitelisted_touch_action =
-      Style()->GetEffectiveTouchAction() & supported_fast_actions;
+      StyleRef().GetEffectiveTouchAction() & supported_fast_actions;
   for (size_t i = 0; i < own_rects.size(); i++) {
     // If we have a different touch action than the container the rect needs to
     // be reported even if it is contained.
@@ -2946,7 +2946,7 @@
     return kRespectImageOrientation;
 
   if (layout_object->Style() &&
-      layout_object->Style()->RespectImageOrientation() ==
+      layout_object->StyleRef().RespectImageOrientation() ==
           kRespectImageOrientation)
     return kRespectImageOrientation;
 
@@ -3105,8 +3105,8 @@
   // If |this| is visible but this object was not, tell the layer it has some
   // visible content that needs to be drawn and layer visibility optimization
   // can't be used
-  if (Parent()->Style()->Visibility() != EVisibility::kVisible &&
-      Style()->Visibility() == EVisibility::kVisible && !HasLayer()) {
+  if (Parent()->StyleRef().Visibility() != EVisibility::kVisible &&
+      StyleRef().Visibility() == EVisibility::kVisible && !HasLayer()) {
     if (!layer)
       layer = Parent()->EnclosingLayer();
     if (layer)
@@ -3156,8 +3156,8 @@
   // If we remove a visible child from an invisible parent, we don't know the
   // layer visibility any more.
   PaintLayer* layer = nullptr;
-  if (Parent()->Style()->Visibility() != EVisibility::kVisible &&
-      Style()->Visibility() == EVisibility::kVisible && !HasLayer()) {
+  if (Parent()->StyleRef().Visibility() != EVisibility::kVisible &&
+      StyleRef().Visibility() == EVisibility::kVisible && !HasLayer()) {
     layer = Parent()->EnclosingLayer();
     if (layer)
       layer->DirtyVisibleContentStatus();
@@ -3526,10 +3526,10 @@
 
 void LayoutObject::AddAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) {
   // Convert the style regions to absolute coordinates.
-  if (Style()->Visibility() != EVisibility::kVisible || !IsBox())
+  if (StyleRef().Visibility() != EVisibility::kVisible || !IsBox())
     return;
 
-  if (Style()->DraggableRegionMode() == EDraggableRegionMode::kNone)
+  if (StyleRef().DraggableRegionMode() == EDraggableRegionMode::kNone)
     return;
 
   LayoutBox* box = ToLayoutBox(this);
@@ -3538,7 +3538,7 @@
 
   AnnotatedRegionValue region;
   region.draggable =
-      Style()->DraggableRegionMode() == EDraggableRegionMode::kDrag;
+      StyleRef().DraggableRegionMode() == EDraggableRegionMode::kDrag;
   region.bounds = LayoutRect(abs_bounds);
   regions.push_back(region);
 }
@@ -3546,7 +3546,7 @@
 bool LayoutObject::WillRenderImage() {
   // Without visibility we won't render (and therefore don't care about
   // animation).
-  if (Style()->Visibility() != EVisibility::kVisible)
+  if (StyleRef().Visibility() != EVisibility::kVisible)
     return false;
 
   // We will not render a new image when PausableObjects is paused
@@ -3609,7 +3609,7 @@
   if (IsFixedPositioned())
     return nullptr;
 
-  float effective_zoom = Style()->EffectiveZoom();
+  float effective_zoom = StyleRef().EffectiveZoom();
   Node* node = nullptr;
   for (LayoutObject* ancestor = Parent(); ancestor;
        ancestor = ancestor->Parent()) {
@@ -3644,7 +3644,7 @@
       break;
 
     // Webkit specific extension where offsetParent stops at zoom level changes.
-    if (effective_zoom != ancestor->Style()->EffectiveZoom())
+    if (effective_zoom != ancestor->StyleRef().EffectiveZoom())
       break;
   }
 
@@ -4057,7 +4057,7 @@
 }
 
 bool LayoutObject::CanBeSelectionLeaf() const {
-  if (SlowFirstChild() || Style()->Visibility() != EVisibility::kVisible)
+  if (SlowFirstChild() || StyleRef().Visibility() != EVisibility::kVisible)
     return false;
   return CanBeSelectionLeafInternal();
 }
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 17e9e4d7..8383b47b 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -904,7 +904,7 @@
   }
 
   // CSS clip only applies when position is absolute or fixed. Prefer this check
-  // over !Style()->HasAutoClip().
+  // over !StyleRef().HasAutoClip().
   bool HasClip() const {
     return IsOutOfFlowPositioned() && !StyleRef().HasAutoClip();
   }
diff --git a/third_party/blink/renderer/core/layout/layout_paged_flow_thread.cc b/third_party/blink/renderer/core/layout/layout_paged_flow_thread.cc
index b60ba59..ab2d39d 100644
--- a/third_party/blink/renderer/core/layout/layout_paged_flow_thread.cc
+++ b/third_party/blink/renderer/core/layout/layout_paged_flow_thread.cc
@@ -26,7 +26,7 @@
 
 bool LayoutPagedFlowThread::NeedsNewWidth() const {
   return ProgressionIsInline() !=
-         PagedBlockFlow()->Style()->HasInlinePaginationAxis();
+         PagedBlockFlow()->StyleRef().HasInlinePaginationAxis();
 }
 
 void LayoutPagedFlowThread::UpdateLogicalWidth() {
@@ -39,7 +39,8 @@
 void LayoutPagedFlowThread::UpdateLayout() {
   // There should either be zero or one of those for paged layout.
   DCHECK_EQ(FirstMultiColumnBox(), LastMultiColumnBox());
-  SetProgressionIsInline(PagedBlockFlow()->Style()->HasInlinePaginationAxis());
+  SetProgressionIsInline(
+      PagedBlockFlow()->StyleRef().HasInlinePaginationAxis());
   LayoutMultiColumnFlowThread::UpdateLayout();
 
   LayoutMultiColumnSet* column_set = FirstMultiColumnSet();
diff --git a/third_party/blink/renderer/core/layout/layout_progress.cc b/third_party/blink/renderer/core/layout/layout_progress.cc
index 83fe6ed2..ebc3235 100644
--- a/third_party/blink/renderer/core/layout/layout_progress.cc
+++ b/third_party/blink/renderer/core/layout/layout_progress.cc
@@ -91,7 +91,7 @@
   animation_repeat_interval_ =
       LayoutTheme::GetTheme().AnimationRepeatIntervalForProgressBar();
 
-  bool animating = !IsDeterminate() && Style()->HasAppearance() &&
+  bool animating = !IsDeterminate() && StyleRef().HasAppearance() &&
                    animation_duration_ > TimeDelta();
   if (animating == animating_)
     return;
diff --git a/third_party/blink/renderer/core/layout/layout_quote.cc b/third_party/blink/renderer/core/layout/layout_quote.cc
index 335af89..473122e 100644
--- a/third_party/blink/renderer/core/layout/layout_quote.cc
+++ b/third_party/blink/renderer/core/layout/layout_quote.cc
@@ -302,10 +302,10 @@
 }
 
 const QuotesData* LayoutQuote::GetQuotesData() const {
-  if (const QuotesData* custom_quotes = Style()->Quotes())
+  if (const QuotesData* custom_quotes = StyleRef().Quotes())
     return custom_quotes;
 
-  if (const QuotesData* quotes = QuotesDataForLanguage(Style()->Locale()))
+  if (const QuotesData* quotes = QuotesDataForLanguage(StyleRef().Locale()))
     return quotes;
 
   return BasicQuotesData();
diff --git a/third_party/blink/renderer/core/layout/layout_replaced.cc b/third_party/blink/renderer/core/layout/layout_replaced.cc
index c70b4316..6535b0f 100644
--- a/third_party/blink/renderer/core/layout/layout_replaced.cc
+++ b/third_party/blink/renderer/core/layout/layout_replaced.cc
@@ -84,7 +84,7 @@
   bool had_style = !!old_style;
   float old_zoom = had_style ? old_style->EffectiveZoom()
                              : ComputedStyleInitialValues::InitialZoom();
-  if (Style() && Style()->EffectiveZoom() != old_zoom)
+  if (Style() && StyleRef().EffectiveZoom() != old_zoom)
     IntrinsicSizeChanged();
 }
 
@@ -110,9 +110,10 @@
 }
 
 void LayoutReplaced::IntrinsicSizeChanged() {
-  int scaled_width = static_cast<int>(kDefaultWidth * Style()->EffectiveZoom());
+  int scaled_width =
+      static_cast<int>(kDefaultWidth * StyleRef().EffectiveZoom());
   int scaled_height =
-      static_cast<int>(kDefaultHeight * Style()->EffectiveZoom());
+      static_cast<int>(kDefaultHeight * StyleRef().EffectiveZoom());
   intrinsic_size_ = LayoutSize(scaled_width, scaled_height);
   SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
       LayoutInvalidationReason::kSizeChanged);
@@ -123,16 +124,16 @@
 }
 
 bool LayoutReplaced::HasReplacedLogicalHeight() const {
-  if (Style()->LogicalHeight().IsAuto())
+  if (StyleRef().LogicalHeight().IsAuto())
     return false;
 
-  if (Style()->LogicalHeight().IsSpecified()) {
+  if (StyleRef().LogicalHeight().IsSpecified()) {
     if (HasAutoHeightOrContainingBlockWithAutoHeight())
       return false;
     return true;
   }
 
-  if (Style()->LogicalHeight().IsIntrinsic())
+  if (StyleRef().LogicalHeight().IsIntrinsic())
     return true;
 
   return false;
@@ -142,7 +143,7 @@
   // If the height is a percentage and the width is auto, then the
   // containingBlocks's height changing can cause this node to change it's
   // preferred width because it maintains aspect ratio.
-  return HasRelativeLogicalHeight() && Style()->LogicalWidth().IsAuto();
+  return HasRelativeLogicalHeight() && StyleRef().LogicalWidth().IsAuto();
 }
 
 static inline bool LayoutObjectHasAspectRatio(
@@ -180,7 +181,8 @@
   FloatSize constrained_size = intrinsic_sizing_info.size;
   if (!intrinsic_sizing_info.aspect_ratio.IsEmpty() &&
       !intrinsic_sizing_info.size.IsEmpty() &&
-      Style()->LogicalWidth().IsAuto() && Style()->LogicalHeight().IsAuto()) {
+      StyleRef().LogicalWidth().IsAuto() &&
+      StyleRef().LogicalHeight().IsAuto()) {
     // We can't multiply or divide by 'intrinsicSizingInfo.aspectRatio' here, it
     // breaks tests, like images/zoomed-img-size.html, which
     // can only be fixed once subpixel precision is available for things like
@@ -215,22 +217,22 @@
 
   // To match WinIE, in quirks mode use the parent's 'direction' property
   // instead of the the container block's.
-  TextDirection container_direction = container_block->Style()->Direction();
+  TextDirection container_direction = container_block->StyleRef().Direction();
 
   // Variables to solve.
   bool is_horizontal = IsHorizontalWritingMode();
-  Length logical_left = Style()->LogicalLeft();
-  Length logical_right = Style()->LogicalRight();
+  Length logical_left = StyleRef().LogicalLeft();
+  Length logical_right = StyleRef().LogicalRight();
   Length margin_logical_left =
-      is_horizontal ? Style()->MarginLeft() : Style()->MarginTop();
+      is_horizontal ? StyleRef().MarginLeft() : StyleRef().MarginTop();
   Length margin_logical_right =
-      is_horizontal ? Style()->MarginRight() : Style()->MarginBottom();
-  LayoutUnit& margin_logical_left_alias = Style()->IsLeftToRightDirection()
+      is_horizontal ? StyleRef().MarginRight() : StyleRef().MarginBottom();
+  LayoutUnit& margin_logical_left_alias = StyleRef().IsLeftToRightDirection()
                                               ? computed_values.margins_.start_
                                               : computed_values.margins_.end_;
   LayoutUnit& margin_logical_right_alias =
-      Style()->IsLeftToRightDirection() ? computed_values.margins_.end_
-                                        : computed_values.margins_.start_;
+      StyleRef().IsLeftToRightDirection() ? computed_values.margins_.end_
+                                          : computed_values.margins_.start_;
 
   // ---------------------------------------------------------------------------
   // 1. The used value of 'width' is determined as for inline replaced
@@ -394,7 +396,7 @@
   // should use the last line box. When this is fixed elsewhere, this block
   // should be removed.
   if (container_block->IsLayoutInline() &&
-      !container_block->Style()->IsLeftToRightDirection()) {
+      !container_block->StyleRef().IsLeftToRightDirection()) {
     const LayoutInline* flow = ToLayoutInline(container_block);
     InlineFlowBox* first_line = flow->FirstLineBox();
     InlineFlowBox* last_line = flow->LastLineBox();
@@ -433,13 +435,13 @@
       ContainingBlockLogicalWidthForPositioned(container_block, false);
 
   // Variables to solve.
-  Length margin_before = Style()->MarginBefore();
-  Length margin_after = Style()->MarginAfter();
+  Length margin_before = StyleRef().MarginBefore();
+  Length margin_after = StyleRef().MarginAfter();
   LayoutUnit& margin_before_alias = computed_values.margins_.before_;
   LayoutUnit& margin_after_alias = computed_values.margins_.after_;
 
-  Length logical_top = Style()->LogicalTop();
-  Length logical_bottom = Style()->LogicalBottom();
+  Length logical_top = StyleRef().LogicalTop();
+  Length logical_bottom = StyleRef().LogicalBottom();
 
   // ---------------------------------------------------------------------------
   // 1. The used value of 'height' is determined as for inline replaced
@@ -575,10 +577,10 @@
 LayoutRect LayoutReplaced::ComputeObjectFit(
     const LayoutSize* overridden_intrinsic_size) const {
   LayoutRect content_rect = ContentBoxRect();
-  EObjectFit object_fit = Style()->GetObjectFit();
+  EObjectFit object_fit = StyleRef().GetObjectFit();
 
   if (object_fit == EObjectFit::kFill &&
-      Style()->ObjectPosition() ==
+      StyleRef().ObjectPosition() ==
           ComputedStyleInitialValues::InitialObjectPosition()) {
     return content_rect;
   }
@@ -624,10 +626,11 @@
       NOTREACHED();
   }
 
-  LayoutUnit x_offset = MinimumValueForLength(
-      Style()->ObjectPosition().X(), content_rect.Width() - final_rect.Width());
+  LayoutUnit x_offset =
+      MinimumValueForLength(StyleRef().ObjectPosition().X(),
+                            content_rect.Width() - final_rect.Width());
   LayoutUnit y_offset =
-      MinimumValueForLength(Style()->ObjectPosition().Y(),
+      MinimumValueForLength(StyleRef().ObjectPosition().Y(),
                             content_rect.Height() - final_rect.Height());
   final_rect.Move(x_offset, y_offset);
 
@@ -684,9 +687,9 @@
 
   // This solves above equation for 'width' (== logicalWidth).
   LayoutUnit margin_start =
-      MinimumValueForLength(Style()->MarginStart(), logical_width);
+      MinimumValueForLength(StyleRef().MarginStart(), logical_width);
   LayoutUnit margin_end =
-      MinimumValueForLength(Style()->MarginEnd(), logical_width);
+      MinimumValueForLength(StyleRef().MarginEnd(), logical_width);
   logical_width = (logical_width - (margin_start + margin_end +
                                     (Size().Width() - ClientWidth())))
                       .ClampNegativeToZero();
@@ -696,11 +699,11 @@
 
 LayoutUnit LayoutReplaced::ComputeReplacedLogicalWidth(
     ShouldComputePreferred should_compute_preferred) const {
-  if (Style()->LogicalWidth().IsSpecified() ||
-      Style()->LogicalWidth().IsIntrinsic())
+  if (StyleRef().LogicalWidth().IsSpecified() ||
+      StyleRef().LogicalWidth().IsIntrinsic())
     return ComputeReplacedLogicalWidthRespectingMinMaxWidth(
         ComputeReplacedLogicalWidthUsing(kMainOrPreferredSize,
-                                         Style()->LogicalWidth()),
+                                         StyleRef().LogicalWidth()),
         should_compute_preferred);
 
   // 10.3.2 Inline, replaced elements:
@@ -711,8 +714,8 @@
   FloatSize constrained_size =
       ConstrainIntrinsicSizeToMinMax(intrinsic_sizing_info);
 
-  if (Style()->LogicalWidth().IsAuto()) {
-    bool computed_height_is_auto = Style()->LogicalHeight().IsAuto();
+  if (StyleRef().LogicalWidth().IsAuto()) {
+    bool computed_height_is_auto = StyleRef().LogicalHeight().IsAuto();
 
     // If 'height' and 'width' both have computed values of 'auto' and the
     // element also has an intrinsic width, then that intrinsic width is the
@@ -783,10 +786,11 @@
     LayoutUnit estimated_used_width) const {
   // 10.5 Content height: the 'height' property:
   // http://www.w3.org/TR/CSS21/visudet.html#propdef-height
-  if (HasReplacedLogicalHeight())
+  if (HasReplacedLogicalHeight()) {
     return ComputeReplacedLogicalHeightRespectingMinMaxHeight(
         ComputeReplacedLogicalHeightUsing(kMainOrPreferredSize,
-                                          Style()->LogicalHeight()));
+                                          StyleRef().LogicalHeight()));
+  }
 
   // 10.6.2 Inline, replaced elements:
   // http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-height
@@ -796,7 +800,7 @@
   FloatSize constrained_size =
       ConstrainIntrinsicSizeToMinMax(intrinsic_sizing_info);
 
-  bool width_is_auto = Style()->LogicalWidth().IsAuto();
+  bool width_is_auto = StyleRef().LogicalWidth().IsAuto();
 
   // If 'height' and 'width' both have computed values of 'auto' and the element
   // also has an intrinsic height, then that intrinsic height is the used value
@@ -842,7 +846,7 @@
   // We cannot resolve some logical width here (i.e. percent, fill-available or
   // fit-content) as the available logical width may not be set on our
   // containing block.
-  const Length& logical_width = Style()->LogicalWidth();
+  const Length& logical_width = StyleRef().LogicalWidth();
   if (logical_width.IsPercentOrCalc() || logical_width.IsFillAvailable() ||
       logical_width.IsFitContent())
     ComputeIntrinsicLogicalWidths(min_preferred_logical_width_,
@@ -994,10 +998,10 @@
 
   RootInlineBox& root = InlineBoxWrapper()->Root();
   LayoutUnit new_logical_top =
-      root.Block().Style()->IsFlippedBlocksWritingMode()
+      root.Block().StyleRef().IsFlippedBlocksWritingMode()
           ? InlineBoxWrapper()->LogicalBottom() - root.SelectionBottom()
           : root.SelectionTop() - InlineBoxWrapper()->LogicalTop();
-  if (root.Block().Style()->IsHorizontalWritingMode())
+  if (root.Block().StyleRef().IsHorizontalWritingMode())
     return LayoutRect(LayoutUnit(), new_logical_top, Size().Width(),
                       root.SelectionHeight());
   return LayoutRect(new_logical_top, LayoutUnit(), root.SelectionHeight(),
diff --git a/third_party/blink/renderer/core/layout/layout_replaced.h b/third_party/blink/renderer/core/layout/layout_replaced.h
index 5074401..62be25f 100644
--- a/third_party/blink/renderer/core/layout/layout_replaced.h
+++ b/third_party/blink/renderer/core/layout/layout_replaced.h
@@ -81,7 +81,7 @@
   LayoutRect LocalSelectionRect() const final;
 
   bool HasObjectFit() const {
-    return Style()->GetObjectFit() !=
+    return StyleRef().GetObjectFit() !=
            ComputedStyleInitialValues::InitialObjectFit();
   }
 
diff --git a/third_party/blink/renderer/core/layout/layout_ruby_run.cc b/third_party/blink/renderer/core/layout/layout_ruby_run.cc
index 141eee16..699e128 100644
--- a/third_party/blink/renderer/core/layout/layout_ruby_run.cc
+++ b/third_party/blink/renderer/core/layout/layout_ruby_run.cc
@@ -237,8 +237,8 @@
     last_line_ruby_text_bottom = root_box->LogicalBottomLayoutOverflow();
   }
 
-  if (Style()->IsFlippedLinesWritingMode() ==
-      (Style()->GetRubyPosition() == RubyPosition::kAfter)) {
+  if (StyleRef().IsFlippedLinesWritingMode() ==
+      (StyleRef().GetRubyPosition() == RubyPosition::kAfter)) {
     LayoutUnit first_line_top;
     if (LayoutRubyBase* rb = RubyBase()) {
       RootInlineBox* root_box = rb->FirstRootBox();
@@ -295,10 +295,10 @@
         (logical_width - root_inline_box->LogicalRight()).ToInt());
   }
 
-  start_overhang = Style()->IsLeftToRightDirection() ? logical_left_overhang
-                                                     : logical_right_overhang;
-  end_overhang = Style()->IsLeftToRightDirection() ? logical_right_overhang
-                                                   : logical_left_overhang;
+  start_overhang = StyleRef().IsLeftToRightDirection() ? logical_left_overhang
+                                                       : logical_right_overhang;
+  end_overhang = StyleRef().IsLeftToRightDirection() ? logical_right_overhang
+                                                     : logical_left_overhang;
 
   if (!start_layout_object || !start_layout_object->IsText() ||
       start_layout_object->Style(first_line)->FontSize() >
diff --git a/third_party/blink/renderer/core/layout/layout_ruby_text.cc b/third_party/blink/renderer/core/layout/layout_ruby_text.cc
index 7c63b99..5990208 100644
--- a/third_party/blink/renderer/core/layout/layout_ruby_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_ruby_text.cc
@@ -44,7 +44,7 @@
 
 ETextAlign LayoutRubyText::TextAlignmentForLine(
     bool ends_with_soft_break) const {
-  ETextAlign text_align = Style()->GetTextAlign();
+  ETextAlign text_align = StyleRef().GetTextAlign();
   // FIXME: This check is bogus since user can set the initial value.
   if (text_align != ComputedStyleInitialValues::InitialTextAlign())
     return LayoutBlockFlow::TextAlignmentForLine(ends_with_soft_break);
@@ -58,7 +58,7 @@
     unsigned expansion_opportunity_count,
     LayoutUnit& logical_left,
     LayoutUnit& logical_width) const {
-  ETextAlign text_align = Style()->GetTextAlign();
+  ETextAlign text_align = StyleRef().GetTextAlign();
   // FIXME: This check is bogus since user can set the initial value.
   if (text_align != ComputedStyleInitialValues::InitialTextAlign())
     return LayoutBlockFlow::AdjustInlineDirectionLineBounds(
@@ -73,7 +73,7 @@
   LayoutUnit inset = (logical_width - max_preferred_logical_width) /
                      (expansion_opportunity_count + 1);
   if (expansion_opportunity_count)
-    inset = std::min(LayoutUnit(2 * Style()->FontSize()), inset);
+    inset = std::min(LayoutUnit(2 * StyleRef().FontSize()), inset);
 
   logical_left += inset / 2;
   logical_width -= inset;
diff --git a/third_party/blink/renderer/core/layout/layout_scrollbar_part.cc b/third_party/blink/renderer/core/layout/layout_scrollbar_part.cc
index a11e72a8..7900a41 100644
--- a/third_party/blink/renderer/core/layout/layout_scrollbar_part.cc
+++ b/third_party/blink/renderer/core/layout/layout_scrollbar_part.cc
@@ -165,18 +165,18 @@
   // up to date, especially since we are called at style change.
   // FIXME: Querying the style's border information doesn't work on table cells
   // with collapsing borders.
-  int visible_size = box->Size().Width() - box->Style()->BorderLeftWidth() -
-                     box->Style()->BorderRightWidth();
+  int visible_size = box->Size().Width() - box->StyleRef().BorderLeftWidth() -
+                     box->StyleRef().BorderRightWidth();
   SetWidth(LayoutUnit(ComputeScrollbarWidth(visible_size, Style())));
 
   // Buttons and track pieces can all have margins along the axis of the
   // scrollbar. Values are rounded because scrollbar parts need to be rendered
   // at device pixel boundaries.
   SetMarginLeft(LayoutUnit(
-      MinimumValueForLength(Style()->MarginLeft(), LayoutUnit(visible_size))
+      MinimumValueForLength(StyleRef().MarginLeft(), LayoutUnit(visible_size))
           .Round()));
   SetMarginRight(LayoutUnit(
-      MinimumValueForLength(Style()->MarginRight(), LayoutUnit(visible_size))
+      MinimumValueForLength(StyleRef().MarginRight(), LayoutUnit(visible_size))
           .Round()));
 }
 
@@ -188,18 +188,18 @@
   // up to date, especially since we are called at style change.
   // FIXME: Querying the style's border information doesn't work on table cells
   // with collapsing borders.
-  int visible_size = box->Size().Height() - box->Style()->BorderTopWidth() -
-                     box->Style()->BorderBottomWidth();
+  int visible_size = box->Size().Height() - box->StyleRef().BorderTopWidth() -
+                     box->StyleRef().BorderBottomWidth();
   SetHeight(LayoutUnit(ComputeScrollbarHeight(visible_size, Style())));
 
   // Buttons and track pieces can all have margins along the axis of the
   // scrollbar. Values are rounded because scrollbar parts need to be rendered
   // at device pixel boundaries.
   SetMarginTop(LayoutUnit(
-      MinimumValueForLength(Style()->MarginTop(), LayoutUnit(visible_size))
+      MinimumValueForLength(StyleRef().MarginTop(), LayoutUnit(visible_size))
           .Round()));
   SetMarginBottom(LayoutUnit(
-      MinimumValueForLength(Style()->MarginBottom(), LayoutUnit(visible_size))
+      MinimumValueForLength(StyleRef().MarginBottom(), LayoutUnit(visible_size))
           .Round()));
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_slider.cc b/third_party/blink/renderer/core/layout/layout_slider.cc
index a442b80..7918e4b 100644
--- a/third_party/blink/renderer/core/layout/layout_slider.cc
+++ b/third_party/blink/renderer/core/layout/layout_slider.cc
@@ -52,8 +52,8 @@
     LayoutUnit& min_logical_width,
     LayoutUnit& max_logical_width) const {
   max_logical_width =
-      LayoutUnit(kDefaultTrackLength * Style()->EffectiveZoom());
-  if (!Style()->Width().IsPercentOrCalc())
+      LayoutUnit(kDefaultTrackLength * StyleRef().EffectiveZoom());
+  if (!StyleRef().Width().IsPercentOrCalc())
     min_logical_width = max_logical_width;
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_slider_container.cc b/third_party/blink/renderer/core/layout/layout_slider_container.cc
index 111cbab..4a8785dd 100644
--- a/third_party/blink/renderer/core/layout/layout_slider_container.cc
+++ b/third_party/blink/renderer/core/layout/layout_slider_container.cc
@@ -76,7 +76,7 @@
       int tick_length = LayoutTheme::GetTheme().SliderTickSize().Height();
       track_height = LayoutUnit(2 * (offset_from_center + tick_length));
     }
-    float zoom_factor = Style()->EffectiveZoom();
+    float zoom_factor = StyleRef().EffectiveZoom();
     if (zoom_factor != 1.0)
       track_height *= zoom_factor;
 
@@ -133,7 +133,7 @@
   if (is_vertical) {
     thumb_location.SetY(thumb_location.Y() + track->ContentHeight() -
                         thumb->Size().Height() - offset);
-  } else if (Style()->IsLeftToRightDirection()) {
+  } else if (StyleRef().IsLeftToRightDirection()) {
     thumb_location.SetX(thumb_location.X() + offset);
   } else {
     thumb_location.SetX(thumb_location.X() - offset);
diff --git a/third_party/blink/renderer/core/layout/layout_state.cc b/third_party/blink/renderer/core/layout/layout_state.cc
index 1dc29c6d..c352cdc 100644
--- a/third_party/blink/renderer/core/layout/layout_state.cc
+++ b/third_party/blink/renderer/core/layout/layout_state.cc
@@ -85,7 +85,7 @@
   if (!layout_object.IsOutOfFlowPositioned())
     return;
   if (LayoutObject* container = layout_object.Container()) {
-    if (container->Style()->HasInFlowPosition() &&
+    if (container->StyleRef().HasInFlowPosition() &&
         container->IsLayoutInline()) {
       pagination_offset_ +=
           ToLayoutInline(container)->OffsetForInFlowPositionedInline(
diff --git a/third_party/blink/renderer/core/layout/layout_table.cc b/third_party/blink/renderer/core/layout/layout_table.cc
index abc5986..f2497d62 100644
--- a/third_party/blink/renderer/core/layout/layout_table.cc
+++ b/third_party/blink/renderer/core/layout/layout_table.cc
@@ -90,20 +90,21 @@
       old_style ? old_style->IsFixedTableLayout() : false;
 
   // In the collapsed border model, there is no cell spacing.
-  h_spacing_ = ShouldCollapseBorders() ? 0 : Style()->HorizontalBorderSpacing();
-  v_spacing_ = ShouldCollapseBorders() ? 0 : Style()->VerticalBorderSpacing();
+  h_spacing_ =
+      ShouldCollapseBorders() ? 0 : StyleRef().HorizontalBorderSpacing();
+  v_spacing_ = ShouldCollapseBorders() ? 0 : StyleRef().VerticalBorderSpacing();
   DCHECK_GE(h_spacing_, 0);
   DCHECK_GE(v_spacing_, 0);
 
   if (!table_layout_ ||
-      Style()->IsFixedTableLayout() != old_fixed_table_layout) {
+      StyleRef().IsFixedTableLayout() != old_fixed_table_layout) {
     if (table_layout_)
       table_layout_->WillChangeTableLayout();
 
     // According to the CSS2 spec, you only use fixed table layout if an
     // explicit width is specified on the table. Auto width implies auto table
     // layout.
-    if (Style()->IsFixedTableLayout())
+    if (StyleRef().IsFixedTableLayout())
       table_layout_ = std::make_unique<TableLayoutAlgorithmFixed>(this);
     else
       table_layout_ = std::make_unique<TableLayoutAlgorithmAuto>(this);
@@ -138,7 +139,7 @@
 static inline bool NeedsTableSection(LayoutObject* object) {
   // Return true if 'object' can't exist in an anonymous table without being
   // wrapped in a table section box.
-  EDisplay display = object->Style()->Display();
+  EDisplay display = object->StyleRef().Display();
   return display != EDisplay::kTableCaption &&
          display != EDisplay::kTableColumnGroup &&
          display != EDisplay::kTableColumn;
@@ -153,7 +154,7 @@
     has_col_elements_ = true;
     wrap_in_anonymous_section = false;
   } else if (child->IsTableSection()) {
-    switch (child->Style()->Display()) {
+    switch (child->StyleRef().Display()) {
       case EDisplay::kTableHeaderGroup:
         ResetSectionPointerIfNotBefore(head_, before_child);
         if (!head_) {
@@ -266,7 +267,7 @@
 }
 
 bool LayoutTable::IsLogicalWidthAuto() const {
-  Length style_logical_width = Style()->LogicalWidth();
+  Length style_logical_width = StyleRef().LogicalWidth();
   return (!style_logical_width.IsSpecified() ||
           !style_logical_width.IsPositive()) &&
          !style_logical_width.IsIntrinsic();
@@ -302,24 +303,24 @@
 
   LayoutUnit available_logical_width = ContainingBlockLogicalWidthForContent();
   bool has_perpendicular_containing_block =
-      cb->Style()->IsHorizontalWritingMode() !=
-      Style()->IsHorizontalWritingMode();
+      cb->StyleRef().IsHorizontalWritingMode() !=
+      StyleRef().IsHorizontalWritingMode();
   LayoutUnit container_width_in_inline_direction =
       has_perpendicular_containing_block
           ? PerpendicularContainingBlockLogicalHeight()
           : available_logical_width;
 
-  Length style_logical_width = Style()->LogicalWidth();
+  Length style_logical_width = StyleRef().LogicalWidth();
   if (!IsLogicalWidthAuto()) {
     SetLogicalWidth(ConvertStyleLogicalWidthToComputedWidth(
         style_logical_width, container_width_in_inline_direction));
   } else {
     // Subtract out any fixed margins from our available width for auto width
     // tables.
-    LayoutUnit margin_start =
-        MinimumValueForLength(Style()->MarginStart(), available_logical_width);
+    LayoutUnit margin_start = MinimumValueForLength(StyleRef().MarginStart(),
+                                                    available_logical_width);
     LayoutUnit margin_end =
-        MinimumValueForLength(Style()->MarginEnd(), available_logical_width);
+        MinimumValueForLength(StyleRef().MarginEnd(), available_logical_width);
     LayoutUnit margin_total = margin_start + margin_end;
 
     // Subtract out our margins to get the available content width.
@@ -346,7 +347,7 @@
   }
 
   // Ensure we aren't bigger than our max-width style.
-  Length style_max_logical_width = Style()->LogicalMaxWidth();
+  Length style_max_logical_width = StyleRef().LogicalMaxWidth();
   if ((style_max_logical_width.IsSpecified() &&
        !style_max_logical_width.IsNegative()) ||
       style_max_logical_width.IsIntrinsic()) {
@@ -364,7 +365,7 @@
       LayoutUnit(std::max(LogicalWidth(), MinPreferredLogicalWidth()).Floor()));
 
   // Ensure we aren't smaller than our min-width style.
-  Length style_min_logical_width = Style()->LogicalMinWidth();
+  Length style_min_logical_width = StyleRef().LogicalMinWidth();
   if ((style_min_logical_width.IsSpecified() &&
        !style_min_logical_width.IsNegative()) ||
       style_min_logical_width.IsIntrinsic()) {
@@ -379,8 +380,8 @@
   ComputedMarginValues margin_values;
   ComputeMarginsForDirection(kInlineDirection, cb, available_logical_width,
                              LogicalWidth(), margin_values.start_,
-                             margin_values.end_, Style()->MarginStart(),
-                             Style()->MarginEnd());
+                             margin_values.end_, StyleRef().MarginStart(),
+                             StyleRef().MarginEnd());
   SetMarginStart(margin_values.start_);
   SetMarginEnd(margin_values.end_);
 
@@ -408,7 +409,7 @@
   bool is_css_table = !IsHTMLTableElement(GetNode());
   if (is_css_table && style_logical_width.IsSpecified() &&
       style_logical_width.IsPositive() &&
-      Style()->BoxSizing() == EBoxSizing::kContentBox) {
+      StyleRef().BoxSizing() == EBoxSizing::kContentBox) {
     borders = BorderStart() + BorderEnd() +
               (ShouldCollapseBorders() ? LayoutUnit()
                                        : PaddingStart() + PaddingEnd());
@@ -434,7 +435,7 @@
     // FIXME: We cannot apply box-sizing: content-box on <table> which other
     // browsers allow.
     if (IsHTMLTableElement(GetNode()) ||
-        Style()->BoxSizing() == EBoxSizing::kBorderBox) {
+        StyleRef().BoxSizing() == EBoxSizing::kBorderBox) {
       borders = border_and_padding;
     }
     computed_logical_height =
@@ -508,7 +509,7 @@
 
 LayoutUnit LayoutTable::LogicalHeightFromStyle() const {
   LayoutUnit computed_logical_height;
-  Length logical_height_length = Style()->LogicalHeight();
+  Length logical_height_length = StyleRef().LogicalHeight();
   if (logical_height_length.IsIntrinsic() ||
       (logical_height_length.IsSpecified() &&
        logical_height_length.IsPositive())) {
@@ -516,7 +517,7 @@
         ConvertStyleLogicalHeightToComputedHeight(logical_height_length);
   }
 
-  Length logical_max_height_length = Style()->LogicalMaxHeight();
+  Length logical_max_height_length = StyleRef().LogicalMaxHeight();
   if (logical_max_height_length.IsIntrinsic() ||
       (logical_max_height_length.IsSpecified() &&
        !logical_max_height_length.IsNegative())) {
@@ -526,7 +527,7 @@
         std::min(computed_logical_height, computed_max_logical_height);
   }
 
-  Length logical_min_height_length = Style()->LogicalMinHeight();
+  Length logical_min_height_length = StyleRef().LogicalMinHeight();
   if (logical_min_height_length.IsIntrinsic() ||
       (logical_min_height_length.IsSpecified() &&
        !logical_min_height_length.IsNegative())) {
@@ -630,7 +631,7 @@
     // Lay out top captions.
     // FIXME: Collapse caption margin.
     for (unsigned i = 0; i < captions_.size(); i++) {
-      if (captions_[i]->Style()->CaptionSide() == ECaptionSide::kBottom)
+      if (captions_[i]->StyleRef().CaptionSide() == ECaptionSide::kBottom)
         continue;
       LayoutCaption(*captions_[i], layouter);
     }
@@ -652,10 +653,10 @@
     SetLogicalHeight(table_box_logical_top + border_and_padding_before);
 
     LayoutUnit section_logical_left = LayoutUnit(
-        Style()->IsLeftToRightDirection() ? BorderStart() : BorderEnd());
+        StyleRef().IsLeftToRightDirection() ? BorderStart() : BorderEnd());
     if (!collapsing) {
       section_logical_left +=
-          Style()->IsLeftToRightDirection() ? PaddingStart() : PaddingEnd();
+          StyleRef().IsLeftToRightDirection() ? PaddingStart() : PaddingEnd();
     }
     LayoutUnit current_available_logical_height =
         AvailableLogicalHeight(kIncludeMarginBorderPadding);
@@ -797,7 +798,7 @@
 
     // Lay out bottom captions.
     for (unsigned i = 0; i < captions_.size(); i++) {
-      if (captions_[i]->Style()->CaptionSide() != ECaptionSide::kBottom)
+      if (captions_[i]->StyleRef().CaptionSide() != ECaptionSide::kBottom)
         continue;
       LayoutCaption(*captions_[i], layouter);
     }
@@ -869,9 +870,9 @@
   ColAndColGroup colElement = ColElementAtAbsoluteColumn(absolute_column_index);
   LayoutTableCol* col = colElement.col;
   LayoutTableCol* colgroup = colElement.colgroup;
-  return (col && col->Style()->Visibility() == EVisibility::kCollapse) ||
+  return (col && col->StyleRef().Visibility() == EVisibility::kCollapse) ||
          (colgroup &&
-          colgroup->Style()->Visibility() == EVisibility::kCollapse);
+          colgroup->StyleRef().Visibility() == EVisibility::kCollapse);
 }
 
 void LayoutTable::InvalidateCollapsedBorders() {
@@ -946,9 +947,9 @@
                                         captions_[i]->MarginBefore() +
                                         captions_[i]->MarginAfter();
     bool caption_is_before =
-        (captions_[i]->Style()->CaptionSide() != ECaptionSide::kBottom) ^
-        Style()->IsFlippedBlocksWritingMode();
-    if (Style()->IsHorizontalWritingMode()) {
+        (captions_[i]->StyleRef().CaptionSide() != ECaptionSide::kBottom) ^
+        StyleRef().IsFlippedBlocksWritingMode();
+    if (StyleRef().IsHorizontalWritingMode()) {
       rect.SetHeight(rect.Height() - caption_logical_height);
       if (caption_is_before)
         rect.Move(LayoutUnit(), caption_logical_height);
@@ -1204,7 +1205,7 @@
   LayoutObject* next_sibling;
   for (LayoutObject* child = FirstChild(); child; child = next_sibling) {
     next_sibling = child->NextSibling();
-    switch (child->Style()->Display()) {
+    switch (child->StyleRef().Display()) {
       case EDisplay::kTableColumn:
       case EDisplay::kTableColumnGroup:
         has_col_elements_ = true;
@@ -1512,7 +1513,7 @@
   // mapping them to top/bottom, we might have to hack this code first
   // (depending on what order we do these bug fixes in).
   if (!captions_.IsEmpty()) {
-    if (Style()->IsHorizontalWritingMode()) {
+    if (StyleRef().IsHorizontalWritingMode()) {
       rect.SetHeight(Size().Height());
       rect.SetY(location.Y());
     } else {
diff --git a/third_party/blink/renderer/core/layout/layout_table.h b/third_party/blink/renderer/core/layout/layout_table.h
index 2c5835d..045eff0 100644
--- a/third_party/blink/renderer/core/layout/layout_table.h
+++ b/third_party/blink/renderer/core/layout/layout_table.h
@@ -145,7 +145,7 @@
   int VBorderSpacing() const { return v_spacing_; }
 
   bool ShouldCollapseBorders() const {
-    return Style()->BorderCollapse() == EBorderCollapse::kCollapse;
+    return StyleRef().BorderCollapse() == EBorderCollapse::kCollapse;
   }
 
   LayoutUnit BorderLeft() const override;
diff --git a/third_party/blink/renderer/core/layout/layout_table_box_component.cc b/third_party/blink/renderer/core/layout/layout_table_box_component.cc
index 4b09846b..b080706 100644
--- a/third_party/blink/renderer/core/layout/layout_table_box_component.cc
+++ b/third_party/blink/renderer/core/layout/layout_table_box_component.cc
@@ -61,7 +61,7 @@
                                              const ComputedStyle* old_style) {
   LayoutBox::StyleDidChange(diff, old_style);
   SetCanContainFixedPositionObjects(
-      Style()->CanContainFixedPositionObjects(false) ||
+      StyleRef().CanContainFixedPositionObjects(false) ||
       ShouldApplyPaintContainment() || ShouldApplyLayoutContainment());
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_table_cell.cc b/third_party/blink/renderer/core/layout/layout_table_cell.cc
index 07472c7e..9c7f0761f 100644
--- a/third_party/blink/renderer/core/layout/layout_table_cell.cc
+++ b/third_party/blink/renderer/core/layout/layout_table_cell.cc
@@ -150,7 +150,7 @@
   unsigned col_span_count = ColSpan();
   int col_width_sum = 0;
   for (unsigned i = 1; i <= col_span_count; i++) {
-    Length col_width = table_col->Style()->LogicalWidth();
+    Length col_width = table_col->StyleRef().LogicalWidth();
 
     // Percentage value should be returned only for colSpan == 1.
     // Otherwise we return original width for the cell.
@@ -198,7 +198,7 @@
   if (logical_height > -1)
     SetOverrideLogicalHeight(logical_height);
 
-  if (GetNode() && Style()->AutoWrap()) {
+  if (GetNode() && StyleRef().AutoWrap()) {
     // See if nowrap was set.
     Length w = StyleOrColLogicalWidth();
     const AtomicString& nowrap = ToElement(GetNode())->getAttribute(nowrapAttr);
@@ -316,8 +316,8 @@
       ComputedCSSPaddingTop() + LogicalIntrinsicPaddingToPhysical().Top();
   // TODO(crbug.com/377847): The ToInt call should be removed when Table is
   // sub-pixel aware.
-  return Style()->IsHorizontalWritingMode() ? LayoutUnit(result.ToInt())
-                                            : result;
+  return StyleRef().IsHorizontalWritingMode() ? LayoutUnit(result.ToInt())
+                                              : result;
 }
 
 LayoutUnit LayoutTableCell::PaddingBottom() const {
@@ -325,8 +325,8 @@
       ComputedCSSPaddingBottom() + LogicalIntrinsicPaddingToPhysical().Bottom();
   // TODO(crbug.com/377847): The ToInt call should be removed when Table is
   // sub-pixel aware.
-  return Style()->IsHorizontalWritingMode() ? LayoutUnit(result.ToInt())
-                                            : result;
+  return StyleRef().IsHorizontalWritingMode() ? LayoutUnit(result.ToInt())
+                                              : result;
 }
 
 LayoutUnit LayoutTableCell::PaddingLeft() const {
@@ -334,8 +334,8 @@
       ComputedCSSPaddingLeft() + LogicalIntrinsicPaddingToPhysical().Left();
   // TODO(crbug.com/377847): The ToInt call should be removed when Table is
   // sub-pixel aware.
-  return Style()->IsHorizontalWritingMode() ? result
-                                            : LayoutUnit(result.ToInt());
+  return StyleRef().IsHorizontalWritingMode() ? result
+                                              : LayoutUnit(result.ToInt());
 }
 
 LayoutUnit LayoutTableCell::PaddingRight() const {
@@ -343,8 +343,8 @@
       ComputedCSSPaddingRight() + LogicalIntrinsicPaddingToPhysical().Right();
   // TODO(crbug.com/377847): The ToInt call should be removed when Table is
   // sub-pixel aware.
-  return Style()->IsHorizontalWritingMode() ? result
-                                            : LayoutUnit(result.ToInt());
+  return StyleRef().IsHorizontalWritingMode() ? result
+                                              : LayoutUnit(result.ToInt());
 }
 
 void LayoutTableCell::SetOverrideLogicalHeightFromRowHeight(
@@ -452,7 +452,7 @@
 
 void LayoutTableCell::StyleDidChange(StyleDifference diff,
                                      const ComputedStyle* old_style) {
-  DCHECK_EQ(Style()->Display(), EDisplay::kTableCell);
+  DCHECK_EQ(StyleRef().Display(), EDisplay::kTableCell);
 
   LayoutBlockFlow::StyleDidChange(diff, old_style);
   SetHasBoxDecorationBackground(true);
@@ -460,14 +460,14 @@
   if (!old_style)
     return;
 
-  if (Parent() && Section() && Style()->Height() != old_style->Height())
+  if (Parent() && Section() && StyleRef().Height() != old_style->Height())
     Section()->RowLogicalHeightChanged(Row());
 
   // Our intrinsic padding pushes us down to align with the baseline of other
   // cells on the row. If our vertical-align has changed then so will the
   // padding needed to align with other cells - clear it so we can recalculate
   // it from scratch.
-  if (Style()->VerticalAlign() != old_style->VerticalAlign())
+  if (StyleRef().VerticalAlign() != old_style->VerticalAlign())
     ClearIntrinsicPadding();
 
   if (!Parent())
@@ -797,14 +797,14 @@
   const CSSProperty& after_color_property =
       ResolveBorderProperty(GetCSSPropertyBorderBlockEndColor());
   CollapsedBorderValue result = CollapsedBorderValue(
-      Style()->BorderBeforeStyle(), Style()->BorderBeforeWidth(),
+      StyleRef().BorderBeforeStyle(), StyleRef().BorderBeforeWidth(),
       ResolveColor(before_color_property), kBorderPrecedenceCell);
 
   if (cell_above) {
     // (2) A before cell's after border.
     result = ChooseBorder(
-        CollapsedBorderValue(cell_above->Style()->BorderAfterStyle(),
-                             cell_above->Style()->BorderAfterWidth(),
+        CollapsedBorderValue(cell_above->StyleRef().BorderAfterStyle(),
+                             cell_above->StyleRef().BorderAfterWidth(),
                              cell_above->ResolveColor(after_color_property),
                              kBorderPrecedenceCell),
         result);
@@ -815,8 +815,8 @@
   // (3) Our row's before border.
   result = ChooseBorder(
       result,
-      CollapsedBorderValue(Parent()->Style()->BorderBeforeStyle(),
-                           Parent()->Style()->BorderBeforeWidth(),
+      CollapsedBorderValue(Parent()->StyleRef().BorderBeforeStyle(),
+                           Parent()->StyleRef().BorderBeforeWidth(),
                            Parent()->ResolveColor(before_color_property),
                            kBorderPrecedenceRow));
   if (!result.Exists())
@@ -832,8 +832,8 @@
 
     if (prev_row) {
       result = ChooseBorder(
-          CollapsedBorderValue(prev_row->Style()->BorderAfterStyle(),
-                               prev_row->Style()->BorderAfterWidth(),
+          CollapsedBorderValue(prev_row->StyleRef().BorderAfterStyle(),
+                               prev_row->StyleRef().BorderAfterWidth(),
                                prev_row->ResolveColor(after_color_property),
                                kBorderPrecedenceRow),
           result);
@@ -848,8 +848,8 @@
     // (5) Our row group's before border.
     result = ChooseBorder(
         result,
-        CollapsedBorderValue(curr_section->Style()->BorderBeforeStyle(),
-                             curr_section->Style()->BorderBeforeWidth(),
+        CollapsedBorderValue(curr_section->StyleRef().BorderBeforeStyle(),
+                             curr_section->StyleRef().BorderBeforeWidth(),
                              curr_section->ResolveColor(before_color_property),
                              kBorderPrecedenceRowGroup));
     if (!result.Exists())
@@ -859,8 +859,8 @@
     curr_section = table->SectionAbove(curr_section, kSkipEmptySections);
     if (curr_section) {
       result = ChooseBorder(
-          CollapsedBorderValue(curr_section->Style()->BorderAfterStyle(),
-                               curr_section->Style()->BorderAfterWidth(),
+          CollapsedBorderValue(curr_section->StyleRef().BorderAfterStyle(),
+                               curr_section->StyleRef().BorderAfterWidth(),
                                curr_section->ResolveColor(after_color_property),
                                kBorderPrecedenceRowGroup),
           result);
@@ -877,8 +877,8 @@
     if (col_elt) {
       result = ChooseBorder(
           result,
-          CollapsedBorderValue(col_elt->Style()->BorderBeforeStyle(),
-                               col_elt->Style()->BorderBeforeWidth(),
+          CollapsedBorderValue(col_elt->StyleRef().BorderBeforeStyle(),
+                               col_elt->StyleRef().BorderBeforeWidth(),
                                col_elt->ResolveColor(before_color_property),
                                kBorderPrecedenceColumn));
       if (!result.Exists())
@@ -888,8 +888,8 @@
         result = ChooseBorder(
             result,
             CollapsedBorderValue(
-                enclosing_column_group->Style()->BorderBeforeStyle(),
-                enclosing_column_group->Style()->BorderBeforeWidth(),
+                enclosing_column_group->StyleRef().BorderBeforeStyle(),
+                enclosing_column_group->StyleRef().BorderBeforeWidth(),
                 enclosing_column_group->ResolveColor(before_color_property),
                 kBorderPrecedenceColumnGroup));
         if (!result.Exists())
@@ -899,8 +899,8 @@
 
     // (9) The table's before border.
     result = ChooseBorder(
-        result, CollapsedBorderValue(table->Style()->BorderBeforeStyle(),
-                                     table->Style()->BorderBeforeWidth(),
+        result, CollapsedBorderValue(table->StyleRef().BorderBeforeStyle(),
+                                     table->StyleRef().BorderBeforeWidth(),
                                      table->ResolveColor(before_color_property),
                                      kBorderPrecedenceTable));
     if (!result.Exists())
@@ -928,15 +928,15 @@
   const CSSProperty& after_color_property =
       ResolveBorderProperty(GetCSSPropertyBorderBlockEndColor());
   CollapsedBorderValue result = CollapsedBorderValue(
-      Style()->BorderAfterStyle(), Style()->BorderAfterWidth(),
+      StyleRef().BorderAfterStyle(), StyleRef().BorderAfterWidth(),
       ResolveColor(after_color_property), kBorderPrecedenceCell);
 
   if (cell_below) {
     // (2) An after cell's before border.
     result = ChooseBorder(
         result,
-        CollapsedBorderValue(cell_below->Style()->BorderBeforeStyle(),
-                             cell_below->Style()->BorderBeforeWidth(),
+        CollapsedBorderValue(cell_below->StyleRef().BorderBeforeStyle(),
+                             cell_below->StyleRef().BorderBeforeWidth(),
                              cell_below->ResolveColor(before_color_property),
                              kBorderPrecedenceCell));
     if (!result.Exists())
@@ -945,8 +945,8 @@
 
   // (3) Our row's after border. (FIXME: Deal with rowspan!)
   result = ChooseBorder(
-      result, CollapsedBorderValue(Parent()->Style()->BorderAfterStyle(),
-                                   Parent()->Style()->BorderAfterWidth(),
+      result, CollapsedBorderValue(Parent()->StyleRef().BorderAfterStyle(),
+                                   Parent()->StyleRef().BorderAfterWidth(),
                                    Parent()->ResolveColor(after_color_property),
                                    kBorderPrecedenceRow));
   if (!result.Exists())
@@ -956,8 +956,8 @@
   if (cell_below) {
     result = ChooseBorder(
         result, CollapsedBorderValue(
-                    cell_below->Parent()->Style()->BorderBeforeStyle(),
-                    cell_below->Parent()->Style()->BorderBeforeWidth(),
+                    cell_below->Parent()->StyleRef().BorderBeforeStyle(),
+                    cell_below->Parent()->StyleRef().BorderBeforeWidth(),
                     cell_below->Parent()->ResolveColor(before_color_property),
                     kBorderPrecedenceRow));
     if (!result.Exists())
@@ -970,8 +970,8 @@
     // (5) Our row group's after border.
     result = ChooseBorder(
         result,
-        CollapsedBorderValue(curr_section->Style()->BorderAfterStyle(),
-                             curr_section->Style()->BorderAfterWidth(),
+        CollapsedBorderValue(curr_section->StyleRef().BorderAfterStyle(),
+                             curr_section->StyleRef().BorderAfterWidth(),
                              curr_section->ResolveColor(after_color_property),
                              kBorderPrecedenceRowGroup));
     if (!result.Exists())
@@ -982,8 +982,8 @@
     if (curr_section) {
       result = ChooseBorder(
           result, CollapsedBorderValue(
-                      curr_section->Style()->BorderBeforeStyle(),
-                      curr_section->Style()->BorderBeforeWidth(),
+                      curr_section->StyleRef().BorderBeforeStyle(),
+                      curr_section->StyleRef().BorderBeforeWidth(),
                       curr_section->ResolveColor(before_color_property),
                       kBorderPrecedenceRowGroup));
       if (!result.Exists())
@@ -999,8 +999,8 @@
     if (col_elt) {
       result = ChooseBorder(
           result,
-          CollapsedBorderValue(col_elt->Style()->BorderAfterStyle(),
-                               col_elt->Style()->BorderAfterWidth(),
+          CollapsedBorderValue(col_elt->StyleRef().BorderAfterStyle(),
+                               col_elt->StyleRef().BorderAfterWidth(),
                                col_elt->ResolveColor(after_color_property),
                                kBorderPrecedenceColumn));
       if (!result.Exists())
@@ -1010,8 +1010,8 @@
         result = ChooseBorder(
             result,
             CollapsedBorderValue(
-                enclosing_column_group->Style()->BorderAfterStyle(),
-                enclosing_column_group->Style()->BorderAfterWidth(),
+                enclosing_column_group->StyleRef().BorderAfterStyle(),
+                enclosing_column_group->StyleRef().BorderAfterWidth(),
                 enclosing_column_group->ResolveColor(after_color_property),
                 kBorderPrecedenceColumnGroup));
         if (!result.Exists())
@@ -1021,8 +1021,8 @@
 
     // (9) The table's after border.
     result = ChooseBorder(
-        result, CollapsedBorderValue(table->Style()->BorderAfterStyle(),
-                                     table->Style()->BorderAfterWidth(),
+        result, CollapsedBorderValue(table->StyleRef().BorderAfterStyle(),
+                                     table->StyleRef().BorderAfterWidth(),
                                      table->ResolveColor(after_color_property),
                                      kBorderPrecedenceTable));
     if (!result.Exists())
@@ -1142,7 +1142,7 @@
 
   // Shrink our intrinsic padding as much as possible to accommodate the
   // scrollbar.
-  if (Style()->VerticalAlign() == EVerticalAlign::kMiddle) {
+  if (StyleRef().VerticalAlign() == EVerticalAlign::kMiddle) {
     LayoutUnit total_height = LogicalHeight();
     LayoutUnit height_without_intrinsic_padding =
         total_height - IntrinsicPaddingBefore() - IntrinsicPaddingAfter();
diff --git a/third_party/blink/renderer/core/layout/layout_table_cell.h b/third_party/blink/renderer/core/layout/layout_table_cell.h
index 2299fe6..44dedd1 100644
--- a/third_party/blink/renderer/core/layout/layout_table_cell.h
+++ b/third_party/blink/renderer/core/layout/layout_table_cell.h
@@ -144,7 +144,7 @@
   }
 
   Length StyleOrColLogicalWidth() const {
-    Length style_width = Style()->LogicalWidth();
+    Length style_width = StyleRef().LogicalWidth();
     if (!style_width.IsAuto())
       return style_width;
     if (LayoutTableCol* first_column =
@@ -156,7 +156,7 @@
   }
 
   int LogicalHeightFromStyle() const {
-    Length height = Style()->LogicalHeight();
+    Length height = StyleRef().LogicalHeight();
     int style_logical_height =
         height.IsIntrinsicOrAuto()
             ? 0
@@ -166,7 +166,7 @@
     // add in the border and padding.
     // Call computedCSSPadding* directly to avoid including implicitPadding.
     if (!GetDocument().InQuirksMode() &&
-        Style()->BoxSizing() != EBoxSizing::kBorderBox) {
+        StyleRef().BoxSizing() != EBoxSizing::kBorderBox) {
       style_logical_height +=
           (ComputedCSSPaddingBefore() + ComputedCSSPaddingAfter()).Floor() +
           (BorderBefore() + BorderAfter()).Floor();
@@ -199,7 +199,7 @@
 
   LayoutUnit CellBaselinePosition() const;
   bool IsBaselineAligned() const {
-    EVerticalAlign va = Style()->VerticalAlign();
+    EVerticalAlign va = StyleRef().VerticalAlign();
     return va == EVerticalAlign::kBaseline ||
            va == EVerticalAlign::kTextBottom ||
            va == EVerticalAlign::kTextTop || va == EVerticalAlign::kSuper ||
diff --git a/third_party/blink/renderer/core/layout/layout_table_col.cc b/third_party/blink/renderer/core/layout/layout_table_col.cc
index d24abbb..f70ca59 100644
--- a/third_party/blink/renderer/core/layout/layout_table_col.cc
+++ b/third_party/blink/renderer/core/layout/layout_table_col.cc
@@ -43,8 +43,8 @@
 
 void LayoutTableCol::StyleDidChange(StyleDifference diff,
                                     const ComputedStyle* old_style) {
-  DCHECK(Style()->Display() == EDisplay::kTableColumn ||
-         Style()->Display() == EDisplay::kTableColumnGroup);
+  DCHECK(StyleRef().Display() == EDisplay::kTableColumn ||
+         StyleRef().Display() == EDisplay::kTableColumnGroup);
 
   LayoutTableBoxComponent::StyleDidChange(diff, old_style);
 
@@ -58,7 +58,7 @@
   LayoutTableBoxComponent::InvalidateCollapsedBordersOnStyleChange(
       *this, *table, diff, *old_style);
 
-  if ((old_style->LogicalWidth() != Style()->LogicalWidth()) ||
+  if ((old_style->LogicalWidth() != StyleRef().LogicalWidth()) ||
       LayoutTableBoxComponent::DoCellsHaveDirtyWidth(*this, *table, diff,
                                                      *old_style)) {
     // TODO(dgrogan): Optimization opportunities:
diff --git a/third_party/blink/renderer/core/layout/layout_table_col.h b/third_party/blink/renderer/core/layout/layout_table_col.h
index 2496e1b4..56634d3d 100644
--- a/third_party/blink/renderer/core/layout/layout_table_col.h
+++ b/third_party/blink/renderer/core/layout/layout_table_col.h
@@ -68,10 +68,10 @@
 
   bool IsTableColumnGroupWithColumnChildren() { return FirstChild(); }
   bool IsTableColumn() const {
-    return Style()->Display() == EDisplay::kTableColumn;
+    return StyleRef().Display() == EDisplay::kTableColumn;
   }
   bool IsTableColumnGroup() const {
-    return Style()->Display() == EDisplay::kTableColumnGroup;
+    return StyleRef().Display() == EDisplay::kTableColumnGroup;
   }
 
   LayoutTableCol* EnclosingColumnGroup() const;
diff --git a/third_party/blink/renderer/core/layout/layout_table_row.cc b/third_party/blink/renderer/core/layout/layout_table_row.cc
index a8f12d0..3d6f912 100644
--- a/third_party/blink/renderer/core/layout/layout_table_row.cc
+++ b/third_party/blink/renderer/core/layout/layout_table_row.cc
@@ -53,7 +53,7 @@
 
 void LayoutTableRow::StyleDidChange(StyleDifference diff,
                                     const ComputedStyle* old_style) {
-  DCHECK_EQ(Style()->Display(), EDisplay::kTableRow);
+  DCHECK_EQ(StyleRef().Display(), EDisplay::kTableRow);
 
   LayoutTableBoxComponent::StyleDidChange(diff, old_style);
   PropagateStyleToAnonymousChildren();
@@ -61,7 +61,7 @@
   if (!old_style)
     return;
 
-  if (Section() && Style()->LogicalHeight() != old_style->LogicalHeight())
+  if (Section() && StyleRef().LogicalHeight() != old_style->LogicalHeight())
     Section()->RowLogicalHeightChanged(this);
 
   if (!Parent())
@@ -100,7 +100,7 @@
   // When a row gets collapsed or uncollapsed, it's necessary to check all the
   // rows to find any cell that may span the current row.
   if ((old_style->Visibility() == EVisibility::kCollapse) !=
-      (Style()->Visibility() == EVisibility::kCollapse)) {
+      (StyleRef().Visibility() == EVisibility::kCollapse)) {
     for (LayoutTableRow* row = Section()->FirstRow(); row;
          row = row->NextRow()) {
       for (LayoutTableCell* cell = row->FirstCell(); cell;
diff --git a/third_party/blink/renderer/core/layout/layout_table_row.h b/third_party/blink/renderer/core/layout/layout_table_row.h
index 649d16a7..f70334f4 100644
--- a/third_party/blink/renderer/core/layout/layout_table_row.h
+++ b/third_party/blink/renderer/core/layout/layout_table_row.h
@@ -138,7 +138,7 @@
 
   PaintLayerType LayerTypeRequired() const override {
     if (HasTransformRelatedProperty() || HasHiddenBackface() ||
-        CreatesGroup() || Style()->ShouldCompositeForCurrentAnimations() ||
+        CreatesGroup() || StyleRef().ShouldCompositeForCurrentAnimations() ||
         IsStickyPositioned())
       return kNormalPaintLayer;
 
diff --git a/third_party/blink/renderer/core/layout/layout_table_section.cc b/third_party/blink/renderer/core/layout/layout_table_section.cc
index 48c2d52..ca17a55d 100644
--- a/third_party/blink/renderer/core/layout/layout_table_section.cc
+++ b/third_party/blink/renderer/core/layout/layout_table_section.cc
@@ -106,9 +106,9 @@
 
 void LayoutTableSection::StyleDidChange(StyleDifference diff,
                                         const ComputedStyle* old_style) {
-  DCHECK(Style()->Display() == EDisplay::kTableFooterGroup ||
-         Style()->Display() == EDisplay::kTableRowGroup ||
-         Style()->Display() == EDisplay::kTableHeaderGroup);
+  DCHECK(StyleRef().Display() == EDisplay::kTableFooterGroup ||
+         StyleRef().Display() == EDisplay::kTableRowGroup ||
+         StyleRef().Display() == EDisplay::kTableHeaderGroup);
 
   LayoutTableBoxComponent::StyleDidChange(diff, old_style);
   PropagateStyleToAnonymousChildren();
@@ -774,8 +774,8 @@
 
 bool LayoutTableSection::RowHasVisibilityCollapse(unsigned row) const {
   return ((grid_[row].row &&
-           grid_[row].row->Style()->Visibility() == EVisibility::kCollapse) ||
-          Style()->Visibility() == EVisibility::kCollapse);
+           grid_[row].row->StyleRef().Visibility() == EVisibility::kCollapse) ||
+          StyleRef().Visibility() == EVisibility::kCollapse);
 }
 
 // Find out the baseline of the cell
@@ -1142,7 +1142,7 @@
 }
 
 bool CellHasExplicitlySpecifiedHeight(const LayoutTableCell& cell) {
-  if (cell.Style()->LogicalHeight().IsFixed())
+  if (cell.StyleRef().LogicalHeight().IsFixed())
     return true;
   LayoutBlock* cb = cell.ContainingBlock();
   if (cb->AvailableLogicalHeightForPercentageComputation() == -1)
@@ -1154,8 +1154,8 @@
                                 LayoutObject* cell_descendant) {
   if (!CellHasExplicitlySpecifiedHeight(cell))
     return false;
-  if (cell_descendant->Style()->OverflowY() == EOverflow::kVisible ||
-      cell_descendant->Style()->OverflowY() == EOverflow::kHidden)
+  if (cell_descendant->StyleRef().OverflowY() == EOverflow::kVisible ||
+      cell_descendant->StyleRef().OverflowY() == EOverflow::kHidden)
     return true;
   return cell_descendant->IsBox() &&
          ToLayoutBox(cell_descendant)->ShouldBeConsideredAsReplaced();
@@ -1244,7 +1244,7 @@
                               LayoutUnit(r_height)))
         cell_vertical_align = EVerticalAlign::kTop;
       else
-        cell_vertical_align = cell->Style()->VerticalAlign();
+        cell_vertical_align = cell->StyleRef().VerticalAlign();
 
       // Calculate total collapsed height affecting one cell.
       int collapsed_height = 0;
@@ -1903,12 +1903,13 @@
   // as we discover new bugs. :)
   bool cell_children_flex = false;
   bool flex_all_children = CellHasExplicitlySpecifiedHeight(cell) ||
-                           (!Table()->Style()->LogicalHeight().IsAuto() &&
+                           (!Table()->StyleRef().LogicalHeight().IsAuto() &&
                             row_height != cell.LogicalHeight());
 
   for (LayoutObject* child = cell.FirstChild(); child;
        child = child->NextSibling()) {
-    if (!child->IsText() && child->Style()->LogicalHeight().IsPercentOrCalc() &&
+    if (!child->IsText() &&
+        child->StyleRef().LogicalHeight().IsPercentOrCalc() &&
         (flex_all_children || ShouldFlexCellChild(cell, child)) &&
         (!child->IsTable() || ToLayoutTable(child)->HasSections())) {
       cell_children_flex = true;
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index 61df7611..c436e1de 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -436,7 +436,7 @@
                                 const LayoutRect& passed_boundaries) const {
   FloatRect boundaries(passed_boundaries);
   if (!ellipsis_rect.IsEmpty()) {
-    if (Style()->IsHorizontalWritingMode())
+    if (StyleRef().IsHorizontalWritingMode())
       boundaries.SetWidth(ellipsis_rect.MaxX() - boundaries.X());
     else
       boundaries.SetHeight(ellipsis_rect.MaxY() - boundaries.Y());
@@ -739,7 +739,7 @@
       FirstTextBox()->IsHorizontal() ? point.X() : point.Y();
   LayoutUnit point_block_direction =
       FirstTextBox()->IsHorizontal() ? point.Y() : point.X();
-  bool blocks_are_flipped = Style()->IsFlippedBlocksWritingMode();
+  bool blocks_are_flipped = StyleRef().IsFlippedBlocksWritingMode();
 
   InlineTextBox* last_box = nullptr;
   for (InlineTextBox* box : TextBoxes()) {
@@ -869,7 +869,7 @@
 
   // for unicode-bidi: plaintext, use inlineBoxBidiLevel() to test the correct
   // direction for the cursor.
-  if (right_aligned && Style()->GetUnicodeBidi() == UnicodeBidi::kPlaintext) {
+  if (right_aligned && StyleRef().GetUnicodeBidi() == UnicodeBidi::kPlaintext) {
     if (inline_box->BidiLevel() % 2 != 1)
       right_aligned = false;
   }
@@ -883,7 +883,7 @@
   }
 
   return LayoutRect(
-      Style()->IsHorizontalWritingMode()
+      StyleRef().IsHorizontalWritingMode()
           ? IntRect(left.ToInt(), top, caret_width.ToInt(), height)
           : IntRect(top, left.ToInt(), height, caret_width.ToInt()));
 }
@@ -898,7 +898,7 @@
     HashSet<const SimpleFontData*>* fallback_fonts,
     FloatRect* glyph_bounds_accumulation,
     float expansion) const {
-  if (Style()->HasTextCombine() && IsCombineText()) {
+  if (StyleRef().HasTextCombine() && IsCombineText()) {
     const LayoutTextCombine* combine_text = ToLayoutTextCombine(this);
     if (combine_text->IsCombined())
       return combine_text->CombinedTextWidth(f);
@@ -908,7 +908,7 @@
       ConstructTextRun(f, this, start, len, StyleRef(), text_direction);
   run.SetCharactersLength(TextLength() - start);
   DCHECK_GE(run.CharactersLength(), run.length());
-  run.SetTabSize(!Style()->CollapseWhiteSpace(), Style()->GetTabSize());
+  run.SetTabSize(!StyleRef().CollapseWhiteSpace(), StyleRef().GetTabSize());
   run.SetXPos(lead_width + text_width_so_far);
   run.SetExpansion(expansion);
 
@@ -942,7 +942,7 @@
   // below.
   float lead_width = lead_width_layout_unit.ToFloat();
 
-  bool collapse_white_space = Style()->CollapseWhiteSpace();
+  bool collapse_white_space = StyleRef().CollapseWhiteSpace();
   if (!collapse_white_space)
     strip_front_spaces = false;
 
@@ -978,9 +978,9 @@
   DCHECK(text_);
   StringImpl& text = *text_.Impl();
   if (text[0] == kSpaceCharacter ||
-      (text[0] == kNewlineCharacter && !Style()->PreserveNewline()) ||
+      (text[0] == kNewlineCharacter && !StyleRef().PreserveNewline()) ||
       text[0] == kTabulationCharacter) {
-    const Font& font = Style()->GetFont();  // FIXME: This ignores first-line.
+    const Font& font = StyleRef().GetFont();  // FIXME: This ignores first-line.
     if (strip_front_spaces) {
       const UChar kSpaceChar = kSpaceCharacter;
       TextRun run =
@@ -994,12 +994,12 @@
 
   strip_front_spaces = collapse_white_space && has_end_white_space_;
 
-  if (!Style()->AutoWrap() || float_min_width > float_max_width)
+  if (!StyleRef().AutoWrap() || float_min_width > float_max_width)
     float_min_width = float_max_width;
 
   // Compute our max widths by scanning the string for newlines.
   if (has_break) {
-    const Font& f = Style()->GetFont();  // FIXME: This ignores first-line.
+    const Font& f = StyleRef().GetFont();  // FIXME: This ignores first-line.
     bool first_line = true;
     first_line_max_width = LayoutUnit(float_max_width);
     last_line_max_width = LayoutUnit(float_max_width);
@@ -1424,7 +1424,7 @@
     } else {
       // Nowrap can never be broken, so don't bother setting the breakable
       // character boolean. Pre can only be broken if we encounter a newline.
-      if (Style()->AutoWrap() || is_newline)
+      if (StyleRef().AutoWrap() || is_newline)
         has_breakable_char_ = true;
 
       if (curr_min_width > min_width_)
@@ -1448,7 +1448,8 @@
             ConstructTextRun(f, this, i, 1, style_to_use, text_direction);
         run.SetCharactersLength(len - i);
         DCHECK_GE(run.CharactersLength(), run.length());
-        run.SetTabSize(!Style()->CollapseWhiteSpace(), Style()->GetTabSize());
+        run.SetTabSize(!StyleRef().CollapseWhiteSpace(),
+                       StyleRef().GetTabSize());
         run.SetXPos(lead_width + curr_max_width);
 
         curr_max_width += f.Width(run);
@@ -1492,13 +1493,13 @@
   unsigned length = TextLength();
   if (Is8Bit()) {
     for (unsigned i = 0; i < length; ++i) {
-      if (!Style()->IsCollapsibleWhiteSpace(Characters8()[i]))
+      if (!StyleRef().IsCollapsibleWhiteSpace(Characters8()[i]))
         return false;
     }
     return true;
   }
   for (unsigned i = 0; i < length; ++i) {
-    if (!Style()->IsCollapsibleWhiteSpace(Characters16()[i]))
+    if (!StyleRef().IsCollapsibleWhiteSpace(Characters16()[i]))
       return false;
   }
   return true;
@@ -1886,8 +1887,8 @@
     return 0;
 
   float w;
-  if (&f == &Style()->GetFont()) {
-    if (!Style()->PreserveNewline() && !from && len == TextLength()) {
+  if (&f == &StyleRef().GetFont()) {
+    if (!StyleRef().PreserveNewline() && !from && len == TextLength()) {
       if (fallback_fonts) {
         DCHECK(glyph_bounds);
         if (PreferredLogicalWidthsDirty() ||
@@ -1913,7 +1914,7 @@
     run.SetCharactersLength(TextLength() - from);
     DCHECK_GE(run.CharactersLength(), run.length());
 
-    run.SetTabSize(!Style()->CollapseWhiteSpace(), Style()->GetTabSize());
+    run.SetTabSize(!StyleRef().CollapseWhiteSpace(), StyleRef().GetTabSize());
     run.SetXPos(x_pos.ToFloat());
     w = f.Width(run, fallback_fonts, glyph_bounds);
   }
@@ -1947,7 +1948,7 @@
         logical_right_side = curr->LogicalRight().ToFloat();
     }
 
-    bool is_horizontal = Style()->IsHorizontalWritingMode();
+    bool is_horizontal = StyleRef().IsHorizontalWritingMode();
 
     float x = is_horizontal ? logical_left_side : FirstTextBox()->X().ToFloat();
     float y = is_horizontal ? FirstTextBox()->Y().ToFloat() : logical_left_side;
@@ -2001,7 +2002,7 @@
 
   LayoutRect rect(logical_left_side, logical_top, logical_width,
                   logical_height);
-  if (!Style()->IsHorizontalWritingMode())
+  if (!StyleRef().IsHorizontalWritingMode())
     rect = rect.TransposedRect();
   return rect;
 }
diff --git a/third_party/blink/renderer/core/layout/layout_text.h b/third_party/blink/renderer/core/layout/layout_text.h
index 36a11637..e1d4868 100644
--- a/third_party/blink/renderer/core/layout/layout_text.h
+++ b/third_party/blink/renderer/core/layout/layout_text.h
@@ -278,7 +278,7 @@
   bool ContainsReversedText() const { return contains_reversed_text_; }
 
   bool IsSecure() const {
-    return Style()->TextSecurity() != ETextSecurity::kNone;
+    return StyleRef().TextSecurity() != ETextSecurity::kNone;
   }
   void MomentarilyRevealLastTypedCharacter(
       unsigned last_typed_character_offset);
diff --git a/third_party/blink/renderer/core/layout/layout_text_combine.cc b/third_party/blink/renderer/core/layout/layout_text_combine.cc
index dde546f..4056a1f 100644
--- a/third_party/blink/renderer/core/layout/layout_text_combine.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_combine.cc
@@ -149,7 +149,7 @@
 
 void LayoutTextCombine::UpdateIsCombined() {
   // CSS3 spec says text-combine works only in vertical writing mode.
-  is_combined_ = !Style()->IsHorizontalWritingMode()
+  is_combined_ = !StyleRef().IsHorizontalWritingMode()
                  // Nothing to combine.
                  && !HasEmptyText();
 }
diff --git a/third_party/blink/renderer/core/layout/layout_text_combine.h b/third_party/blink/renderer/core/layout/layout_text_combine.h
index 9ad8dc9..d356152 100644
--- a/third_party/blink/renderer/core/layout/layout_text_combine.h
+++ b/third_party/blink/renderer/core/layout/layout_text_combine.h
@@ -39,7 +39,7 @@
   float CombinedTextWidth(const Font& font) const {
     return font.GetFontDescription().ComputedSize();
   }
-  const Font& OriginalFont() const { return Parent()->Style()->GetFont(); }
+  const Font& OriginalFont() const { return Parent()->StyleRef().GetFont(); }
   void TransformToInlineCoordinates(GraphicsContext&,
                                     const LayoutRect& box_rect,
                                     bool clip = false) const;
diff --git a/third_party/blink/renderer/core/layout/layout_text_control.cc b/third_party/blink/renderer/core/layout/layout_text_control.cc
index 921bc92..42e0196 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_control.cc
@@ -108,9 +108,9 @@
 
     // We are able to have a horizontal scrollbar if the overflow style is
     // scroll, or if its auto and there's no word wrap.
-    if (Style()->OverflowInlineDirection() == EOverflow::kScroll ||
-        (Style()->OverflowInlineDirection() == EOverflow::kAuto &&
-         inner_editor->GetLayoutObject()->Style()->OverflowWrap() ==
+    if (StyleRef().OverflowInlineDirection() == EOverflow::kScroll ||
+        (StyleRef().OverflowInlineDirection() == EOverflow::kAuto &&
+         inner_editor->GetLayoutObject()->StyleRef().OverflowWrap() ==
              EOverflowWrap::kNormal))
       logical_height += ScrollbarThickness();
 
@@ -214,7 +214,7 @@
 }
 
 float LayoutTextControl::GetAvgCharWidth(const AtomicString& family) const {
-  const Font& font = Style()->GetFont();
+  const Font& font = StyleRef().GetFont();
 
   const SimpleFontData* primary_font = font.PrimaryFont();
   if (primary_font && HasValidAvgCharWidth(primary_font, family))
@@ -231,7 +231,7 @@
   // This matches the unitsPerEm value for MS Shell Dlg and Courier New from the
   // "head" font table.
   float units_per_em = 2048.0f;
-  return roundf(Style()->GetFont().GetFontDescription().ComputedSize() * x /
+  return roundf(StyleRef().GetFont().GetFontDescription().ComputedSize() * x /
                 units_per_em);
 }
 
@@ -240,7 +240,7 @@
     LayoutUnit& max_logical_width) const {
   // Use average character width. Matches IE.
   AtomicString family =
-      Style()->GetFont().GetFontDescription().Family().Family();
+      StyleRef().GetFont().GetFontDescription().Family().Family();
   max_logical_width = PreferredContentLogicalWidth(
       const_cast<LayoutTextControl*>(this)->GetAvgCharWidth(family));
   if (InnerEditorElement()) {
@@ -249,7 +249,7 @@
       max_logical_width += inner_editor_layout_box->PaddingStart() +
                            inner_editor_layout_box->PaddingEnd();
   }
-  if (!Style()->LogicalWidth().IsPercentOrCalc())
+  if (!StyleRef().LogicalWidth().IsPercentOrCalc())
     min_logical_width = max_logical_width;
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc b/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
index f01b6cd9..b119224d 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
@@ -223,7 +223,7 @@
   LayoutUnit result = LayoutUnit::FromFloatCeil(char_width * factor);
 
   float max_char_width = 0.f;
-  const Font& font = Style()->GetFont();
+  const Font& font = StyleRef().GetFont();
   AtomicString family = font.GetFontDescription().Family().Family();
   // Match the default system font to the width of MS Shell Dlg, the default
   // font for textareas in Firefox, Safari Win and IE for some encodings (in
diff --git a/third_party/blink/renderer/core/layout/layout_tree_as_text.cc b/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
index 02b79e4..71941d1a 100644
--- a/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
@@ -156,8 +156,8 @@
   if (behavior & kLayoutAsTextShowAddresses)
     ts << " " << static_cast<const void*>(&o);
 
-  if (o.Style() && o.Style()->ZIndex())
-    ts << " zI: " << o.Style()->ZIndex();
+  if (o.Style() && o.StyleRef().ZIndex())
+    ts << " zI: " << o.StyleRef().ZIndex();
 
   if (o.GetNode()) {
     String tag_name = GetTagName(o.GetNode());
@@ -201,10 +201,10 @@
           text_stroke_color != color && text_stroke_color.Rgb())
         ts << " [textStrokeColor=" << text_stroke_color << "]";
 
-      if (o.Parent()->Style()->TextStrokeWidth() !=
-              o.Style()->TextStrokeWidth() &&
-          o.Style()->TextStrokeWidth() > 0)
-        ts << " [textStrokeWidth=" << o.Style()->TextStrokeWidth() << "]";
+      if (o.Parent()->StyleRef().TextStrokeWidth() !=
+              o.StyleRef().TextStrokeWidth() &&
+          o.StyleRef().TextStrokeWidth() > 0)
+        ts << " [textStrokeWidth=" << o.StyleRef().TextStrokeWidth() << "]";
     }
 
     if (!o.IsBoxModelObject())
@@ -215,44 +215,44 @@
         box.BorderLeft()) {
       ts << " [border:";
 
-      BorderValue prev_border = o.Style()->BorderTop();
+      BorderValue prev_border = o.StyleRef().BorderTop();
       if (!box.BorderTop()) {
         ts << " none";
       } else {
         ts << " (" << box.BorderTop() << "px ";
-        PrintBorderStyle(ts, o.Style()->BorderTopStyle());
+        PrintBorderStyle(ts, o.StyleRef().BorderTopStyle());
         ts << o.ResolveColor(GetCSSPropertyBorderTopColor()) << ")";
       }
 
-      if (!o.Style()->BorderRightEquals(prev_border)) {
-        prev_border = o.Style()->BorderRight();
+      if (!o.StyleRef().BorderRightEquals(prev_border)) {
+        prev_border = o.StyleRef().BorderRight();
         if (!box.BorderRight()) {
           ts << " none";
         } else {
           ts << " (" << box.BorderRight() << "px ";
-          PrintBorderStyle(ts, o.Style()->BorderRightStyle());
+          PrintBorderStyle(ts, o.StyleRef().BorderRightStyle());
           ts << o.ResolveColor(GetCSSPropertyBorderRightColor()) << ")";
         }
       }
 
-      if (!o.Style()->BorderBottomEquals(prev_border)) {
-        prev_border = box.Style()->BorderBottom();
+      if (!o.StyleRef().BorderBottomEquals(prev_border)) {
+        prev_border = box.StyleRef().BorderBottom();
         if (!box.BorderBottom()) {
           ts << " none";
         } else {
           ts << " (" << box.BorderBottom() << "px ";
-          PrintBorderStyle(ts, o.Style()->BorderBottomStyle());
+          PrintBorderStyle(ts, o.StyleRef().BorderBottomStyle());
           ts << o.ResolveColor(GetCSSPropertyBorderBottomColor()) << ")";
         }
       }
 
-      if (!o.Style()->BorderLeftEquals(prev_border)) {
-        prev_border = o.Style()->BorderLeft();
+      if (!o.StyleRef().BorderLeftEquals(prev_border)) {
+        prev_border = o.StyleRef().BorderLeft();
         if (!box.BorderLeft()) {
           ts << " none";
         } else {
           ts << " (" << box.BorderLeft() << "px ";
-          PrintBorderStyle(ts, o.Style()->BorderLeftStyle());
+          PrintBorderStyle(ts, o.StyleRef().BorderLeftStyle());
           ts << o.ResolveColor(GetCSSPropertyBorderLeftColor()) << ")";
         }
       }
@@ -443,9 +443,10 @@
   ts << ": "
      << QuoteAndEscapeNonPrintables(
             String(o.GetText()).Substring(run.Start(), run.Len()));
-  if (run.HasHyphen())
+  if (run.HasHyphen()) {
     ts << " + hyphen string "
-       << QuoteAndEscapeNonPrintables(o.Style()->HyphenString());
+       << QuoteAndEscapeNonPrintables(o.StyleRef().HyphenString());
+  }
   ts << "\n";
 }
 
@@ -609,7 +610,7 @@
 
   WriteIndent(ts, indent);
 
-  if (layer.GetLayoutObject().Style()->Visibility() == EVisibility::kHidden)
+  if (layer.GetLayoutObject().StyleRef().Visibility() == EVisibility::kHidden)
     ts << "hidden ";
 
   ts << "layer ";
@@ -653,11 +654,11 @@
   else if (paint_phase == kLayerPaintPhaseForeground)
     ts << " layerType: foreground only";
 
-  if (layer.GetLayoutObject().Style()->HasBlendMode()) {
+  if (layer.GetLayoutObject().StyleRef().HasBlendMode()) {
     ts << " blendMode: "
        << CompositeOperatorName(
               kCompositeSourceOver,
-              layer.GetLayoutObject().Style()->GetBlendMode());
+              layer.GetLayoutObject().StyleRef().GetBlendMode());
   }
 
   if (behavior & kLayoutAsTextShowCompositedLayers) {
diff --git a/third_party/blink/renderer/core/layout/layout_video.cc b/third_party/blink/renderer/core/layout/layout_video.cc
index 964735e..9b5702b 100644
--- a/third_party/blink/renderer/core/layout/layout_video.cc
+++ b/third_party/blink/renderer/core/layout/layout_video.cc
@@ -52,7 +52,7 @@
 
 void LayoutVideo::UpdateIntrinsicSize() {
   LayoutSize size = CalculateIntrinsicSize();
-  size.Scale(Style()->EffectiveZoom());
+  size.Scale(StyleRef().EffectiveZoom());
 
   // Never set the element size to zero when in a media document.
   if (size.IsEmpty() && GetNode()->ownerDocument() &&
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc
index 3241d32..da81439 100644
--- a/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -251,11 +251,11 @@
   // should fully invalidate on viewport resize if the background image is not
   // composited and needs full paint invalidation on background positioning area
   // resize.
-  if (Style()->HasFixedBackgroundImage()) {
+  if (StyleRef().HasFixedBackgroundImage()) {
     if ((width_changed && MustInvalidateFillLayersPaintOnWidthChange(
-                              Style()->BackgroundLayers())) ||
+                              StyleRef().BackgroundLayers())) ||
         (height_changed && MustInvalidateFillLayersPaintOnHeightChange(
-                               Style()->BackgroundLayers())))
+                               StyleRef().BackgroundLayers())))
       SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kBackground);
   }
 }
@@ -269,8 +269,8 @@
   // sufficient.
   if (Element* body = GetDocument().body()) {
     if (LayoutObject* body_layout_object = body->GetLayoutObject()) {
-      return body_layout_object->Style()
-          ->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft();
+      return body_layout_object->StyleRef()
+          .ShouldPlaceBlockDirectionScrollbarOnLogicalLeft();
     }
   }
   return false;
@@ -294,9 +294,9 @@
         continue;
 
       if ((child->IsBox() && ToLayoutBox(child)->HasRelativeLogicalHeight()) ||
-          child->Style()->LogicalHeight().IsPercentOrCalc() ||
-          child->Style()->LogicalMinHeight().IsPercentOrCalc() ||
-          child->Style()->LogicalMaxHeight().IsPercentOrCalc())
+          child->StyleRef().LogicalHeight().IsPercentOrCalc() ||
+          child->StyleRef().LogicalMinHeight().IsPercentOrCalc() ||
+          child->StyleRef().LogicalMaxHeight().IsPercentOrCalc())
         layout_scope.SetChildNeedsLayout(child);
     }
 
@@ -761,14 +761,14 @@
 
 int LayoutView::ViewLogicalWidth(
     IncludeScrollbarsInRect scrollbar_inclusion) const {
-  return Style()->IsHorizontalWritingMode() ? ViewWidth(scrollbar_inclusion)
-                                            : ViewHeight(scrollbar_inclusion);
+  return StyleRef().IsHorizontalWritingMode() ? ViewWidth(scrollbar_inclusion)
+                                              : ViewHeight(scrollbar_inclusion);
 }
 
 int LayoutView::ViewLogicalHeight(
     IncludeScrollbarsInRect scrollbar_inclusion) const {
-  return Style()->IsHorizontalWritingMode() ? ViewHeight(scrollbar_inclusion)
-                                            : ViewWidth(scrollbar_inclusion);
+  return StyleRef().IsHorizontalWritingMode() ? ViewHeight(scrollbar_inclusion)
+                                              : ViewWidth(scrollbar_inclusion);
 }
 
 LayoutUnit LayoutView::ViewLogicalHeightForPercentages() const {
diff --git a/third_party/blink/renderer/core/layout/layout_vtt_cue.cc b/third_party/blink/renderer/core/layout/layout_vtt_cue.cc
index 5f78b14e..04c9b6c7 100644
--- a/third_party/blink/renderer/core/layout/layout_vtt_cue.cc
+++ b/third_party/blink/renderer/core/layout/layout_vtt_cue.cc
@@ -84,7 +84,7 @@
   // 7. Round line to an integer by adding 0.5 and then flooring it.
   LayoutUnit line_position(floorf(cue_box_.SnapToLinesPosition() + 0.5f));
 
-  WritingMode writing_mode = cue_box_.Style()->GetWritingMode();
+  WritingMode writing_mode = cue_box_.StyleRef().GetWritingMode();
   // 8. Vertical Growing Left: Add one to line then negate it.
   if (IsFlippedBlocksWritingMode(writing_mode))
     line_position = -(line_position + 1);
@@ -195,7 +195,7 @@
   // into which cues will not be placed.
   // 2. Horizontal: Let full dimension be the height of video's rendering area
   //    Vertical: Let full dimension be the width of video's rendering area.
-  WritingMode writing_mode = cue_box_.Style()->GetWritingMode();
+  WritingMode writing_mode = cue_box_.StyleRef().GetWritingMode();
   LayoutBlock* parent_block = cue_box_.ContainingBlock();
   LayoutUnit full_dimension = blink::IsHorizontalWritingMode(writing_mode)
                                   ? parent_block->Size().Height()
diff --git a/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc b/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
index 26865edd..2d8baac 100644
--- a/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
@@ -138,7 +138,7 @@
   if (!inline_text_box_ || !GetLineLayoutItem())
     return kLeftToRight;
 
-  if (GetLineLayoutItem().Style()->IsHorizontalWritingMode()) {
+  if (GetLineLayoutItem().StyleRef().IsHorizontalWritingMode()) {
     return (inline_text_box_->Direction() == TextDirection::kRtl
                 ? kRightToLeft
                 : kLeftToRight);
diff --git a/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h b/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
index 9a3994b..346446333 100644
--- a/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
+++ b/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
@@ -254,8 +254,8 @@
   if (flow.GetDocument().InNoQuirksMode() &&
       (flow.Style(line_info.IsFirstLine())->LineHeight() !=
            parent.Style(line_info.IsFirstLine())->LineHeight() ||
-       flow.Style()->VerticalAlign() != parent.Style()->VerticalAlign() ||
-       !parent.Style()->HasIdenticalAscentDescentAndLineGap(flow.StyleRef())))
+       flow.StyleRef().VerticalAlign() != parent.StyleRef().VerticalAlign() ||
+       !parent.StyleRef().HasIdenticalAscentDescentAndLineGap(flow.StyleRef())))
     return true;
   return false;
 }
@@ -356,12 +356,13 @@
           current_.GetLineLayoutItem().Parent()))
     include_end_width_ = true;
 
-  curr_ws_ = current_.GetLineLayoutItem().IsLayoutInline()
-                 ? current_style_->WhiteSpace()
-                 : current_.GetLineLayoutItem().Parent().Style()->WhiteSpace();
+  curr_ws_ =
+      current_.GetLineLayoutItem().IsLayoutInline()
+          ? current_style_->WhiteSpace()
+          : current_.GetLineLayoutItem().Parent().StyleRef().WhiteSpace();
   last_ws_ = last_object_.IsLayoutInline()
-                 ? last_object_.Style()->WhiteSpace()
-                 : last_object_.Parent().Style()->WhiteSpace();
+                 ? last_object_.StyleRef().WhiteSpace()
+                 : last_object_.Parent().StyleRef().WhiteSpace();
 
   bool is_svg_text = current_.GetLineLayoutItem().IsSVGInlineText();
   auto_wrap_ = !is_svg_text && ComputedStyle::AutoWrap(curr_ws_);
@@ -481,7 +482,7 @@
   // If our original display wasn't an inline type, then we can
   // go ahead and determine our static inline position now.
   LineLayoutBox box(current_.GetLineLayoutItem());
-  bool is_inline_type = box.Style()->IsOriginalDisplayInlineType();
+  bool is_inline_type = box.StyleRef().IsOriginalDisplayInlineType();
   if (!is_inline_type) {
     block_.SetStaticInlinePositionForChild(box, block_.StartOffsetForContent());
   } else {
@@ -573,7 +574,7 @@
       LineLayoutText(next).TextLength() > 0) {
     LineLayoutText next_text(next);
     UChar next_char = next_text.CharacterAt(0);
-    if (next_text.Style()->IsCollapsibleWhiteSpace(next_char)) {
+    if (next_text.StyleRef().IsCollapsibleWhiteSpace(next_char)) {
       line_midpoint_state.StartIgnoringSpaces(InlineIterator(nullptr, o, 0));
       return true;
     }
@@ -718,12 +719,14 @@
     bool collapse_white_space,
     HashSet<const SimpleFontData*>* fallback_fonts = nullptr,
     FloatRect* glyph_bounds = nullptr) {
-  if ((!from && len == text.TextLength()) || text.Style()->HasTextCombine())
+  if ((!from && len == text.TextLength()) || text.StyleRef().HasTextCombine()) {
     return text.Width(from, len, font, LayoutUnit(x_pos),
-                      text.Style()->Direction(), fallback_fonts, glyph_bounds);
+                      text.StyleRef().Direction(), fallback_fonts,
+                      glyph_bounds);
+  }
 
   TextRun run = ConstructTextRun(font, text, from, len, text.StyleRef());
-  run.SetTabSize(!collapse_white_space, text.Style()->GetTabSize());
+  run.SetTabSize(!collapse_white_space, text.StyleRef().GetTabSize());
   run.SetXPos(x_pos);
   return font.Width(run, fallback_fonts, glyph_bounds);
 }
@@ -1506,7 +1509,7 @@
     check_for_break = true;
   } else if (next_object_ && current_.GetLineLayoutItem().IsText() &&
              next_object_.IsText() && !next_object_.IsBR() &&
-             (auto_wrap_ || next_object_.Style()->AutoWrap())) {
+             (auto_wrap_ || next_object_.StyleRef().AutoWrap())) {
     if (auto_wrap_ && current_character_is_space_) {
       check_for_break = true;
     } else {
diff --git a/third_party/blink/renderer/core/layout/line/inline_flow_box.cc b/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
index 07e0c550..ddb0ad2 100644
--- a/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
+++ b/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
@@ -355,14 +355,14 @@
 
   // The root inline box never has borders/margins/padding.
   if (Parent()) {
-    bool ltr = GetLineLayoutItem().Style()->IsLeftToRightDirection();
+    bool ltr = GetLineLayoutItem().StyleRef().IsLeftToRightDirection();
 
     // Check to see if all initial lines are unconstructed.  If so, then
     // we know the inline began on this line (unless we are a continuation).
     LineBoxList* line_box_list = LineBoxes();
     if (!line_box_list->First()->IsConstructed() &&
         !GetLineLayoutItem().IsInlineElementContinuation()) {
-      if (GetLineLayoutItem().Style()->BoxDecorationBreak() ==
+      if (GetLineLayoutItem().StyleRef().BoxDecorationBreak() ==
           EBoxDecorationBreak::kClone)
         include_left_edge = include_right_edge = true;
       else if (ltr && line_box_list->First() == this)
@@ -391,7 +391,7 @@
       //     next line.
       // (4) The decoration break is set to clone therefore there will be
       //     borders on every sides.
-      if (GetLineLayoutItem().Style()->BoxDecorationBreak() ==
+      if (GetLineLayoutItem().StyleRef().BoxDecorationBreak() ==
           EBoxDecorationBreak::kClone) {
         include_left_edge = include_right_edge = true;
       } else if (ltr) {
@@ -485,8 +485,8 @@
       if (curr->GetLineLayoutItem().IsOutOfFlowPositioned()) {
         if (curr->GetLineLayoutItem()
                 .Parent()
-                .Style()
-                ->IsLeftToRightDirection()) {
+                .StyleRef()
+                .IsLeftToRightDirection()) {
           curr->SetLogicalLeft(logical_left);
         } else {
           // Our offset that we cache needs to be from the edge of the right
@@ -825,8 +825,8 @@
         // being part of the overall lineTop/lineBottom.
         // Really this is a workaround hack for the fact that ruby should have
         // been done as line layout and not done using inline-block.
-        if (GetLineLayoutItem().Style()->IsFlippedLinesWritingMode() ==
-            (curr->GetLineLayoutItem().Style()->GetRubyPosition() ==
+        if (GetLineLayoutItem().StyleRef().IsFlippedLinesWritingMode() ==
+            (curr->GetLineLayoutItem().StyleRef().GetRubyPosition() ==
              RubyPosition::kAfter))
           has_annotations_before = true;
         else
@@ -845,7 +845,7 @@
               (ruby_base.FirstRootBox() ? ruby_base.FirstRootBox()->LineTop()
                                         : LayoutUnit());
           new_logical_top +=
-              !GetLineLayoutItem().Style()->IsFlippedLinesWritingMode()
+              !GetLineLayoutItem().StyleRef().IsFlippedLinesWritingMode()
                   ? top_ruby_base_leading
                   : bottom_ruby_base_leading;
           box_height -= (top_ruby_base_leading + bottom_ruby_base_leading);
@@ -912,7 +912,7 @@
           std::max(line_bottom, line_bottom_including_margins);
     }
 
-    if (GetLineLayoutItem().Style()->IsFlippedLinesWritingMode())
+    if (GetLineLayoutItem().StyleRef().IsFlippedLinesWritingMode())
       FlipLinesInBlockDirection(line_top_including_margins,
                                 line_bottom_including_margins);
   }
@@ -1138,7 +1138,7 @@
   float measured_width = layout_text.Width(
       text->Start(), text->Len(), LayoutUnit(), text->Direction(), false,
       &fallback_fonts, &glyph_bounds);
-  const Font& font = layout_text.Style()->GetFont();
+  const Font& font = layout_text.StyleRef().GetFont();
   glyph_overflow.SetFromBounds(glyph_bounds, font, measured_width);
   if (!fallback_fonts.IsEmpty()) {
     GlyphOverflowAndFallbackFontsMap::ValueType* it =
@@ -1353,11 +1353,12 @@
                                       overflow_rect.Location()))
     return false;
 
-  if (GetLineLayoutItem().Style()->HasBorderRadius()) {
+  if (GetLineLayoutItem().StyleRef().HasBorderRadius()) {
     LayoutRect border_rect = LogicalFrameRect();
     border_rect.MoveBy(accumulated_offset);
-    FloatRoundedRect border = GetLineLayoutItem().Style()->GetRoundedBorderFor(
-        border_rect, IncludeLogicalLeftEdge(), IncludeLogicalRightEdge());
+    FloatRoundedRect border =
+        GetLineLayoutItem().StyleRef().GetRoundedBorderFor(
+            border_rect, IncludeLogicalLeftEdge(), IncludeLogicalRightEdge());
     if (!location_in_container.Intersects(border))
       return false;
   }
@@ -1402,7 +1403,8 @@
   // would be clipped out, so it has to be drawn separately).
   StyleImage* image = last_background_layer.GetImage();
   bool has_fill_image = image && image->CanRender();
-  return (!has_fill_image && !GetLineLayoutItem().Style()->HasBorderRadius()) ||
+  return (!has_fill_image &&
+          !GetLineLayoutItem().StyleRef().HasBorderRadius()) ||
          (!PrevForSameLayoutObject() && !NextForSameLayoutObject()) ||
          !Parent();
 }
@@ -1503,14 +1505,14 @@
 
     if (curr->GetLineLayoutItem().IsAtomicInlineLevel() &&
         curr->GetLineLayoutItem().IsRubyRun() &&
-        curr->GetLineLayoutItem().Style()->GetRubyPosition() ==
+        curr->GetLineLayoutItem().StyleRef().GetRubyPosition() ==
             RubyPosition::kBefore) {
       LineLayoutRubyRun ruby_run = LineLayoutRubyRun(curr->GetLineLayoutItem());
       LineLayoutRubyText ruby_text = ruby_run.RubyText();
       if (!ruby_text)
         continue;
 
-      if (!ruby_run.Style()->IsFlippedLinesWritingMode()) {
+      if (!ruby_run.StyleRef().IsFlippedLinesWritingMode()) {
         LayoutUnit top_of_first_ruby_text_line =
             ruby_text.LogicalTop() + (ruby_text.FirstRootBox()
                                           ? ruby_text.FirstRootBox()->LineTop()
@@ -1574,14 +1576,14 @@
 
     if (curr->GetLineLayoutItem().IsAtomicInlineLevel() &&
         curr->GetLineLayoutItem().IsRubyRun() &&
-        curr->GetLineLayoutItem().Style()->GetRubyPosition() ==
+        curr->GetLineLayoutItem().StyleRef().GetRubyPosition() ==
             RubyPosition::kAfter) {
       LineLayoutRubyRun ruby_run = LineLayoutRubyRun(curr->GetLineLayoutItem());
       LineLayoutRubyText ruby_text = ruby_run.RubyText();
       if (!ruby_text)
         continue;
 
-      if (ruby_run.Style()->IsFlippedLinesWritingMode()) {
+      if (ruby_run.StyleRef().IsFlippedLinesWritingMode()) {
         LayoutUnit top_of_first_ruby_text_line =
             ruby_text.LogicalTop() + (ruby_text.FirstRootBox()
                                           ? ruby_text.FirstRootBox()->LineTop()
@@ -1645,7 +1647,7 @@
     leaf_boxes_in_logical_order.push_back(leaf);
   }
 
-  if (GetLineLayoutItem().Style()->RtlOrdering() == EOrder::kVisual)
+  if (GetLineLayoutItem().StyleRef().RtlOrdering() == EOrder::kVisual)
     return;
 
   // Reverse of reordering of the line (L2 according to Bidi spec):
diff --git a/third_party/blink/renderer/core/layout/line/inline_flow_box.h b/third_party/blink/renderer/core/layout/line/inline_flow_box.h
index f49c483..d04be47 100644
--- a/third_party/blink/renderer/core/layout/line/inline_flow_box.h
+++ b/third_party/blink/renderer/core/layout/line/inline_flow_box.h
@@ -73,7 +73,7 @@
     // bullet list items.  Even when the list bullet is an image, the line is
     // still considered to be immune from the quirk.
     has_text_children_ =
-        line_layout_item.Style()->Display() == EDisplay::kListItem;
+        line_layout_item.StyleRef().Display() == EDisplay::kListItem;
     has_text_descendants_ = has_text_children_;
   }
 
diff --git a/third_party/blink/renderer/core/layout/line/inline_iterator.h b/third_party/blink/renderer/core/layout/line/inline_iterator.h
index f475497..52ecfc00 100644
--- a/third_party/blink/renderer/core/layout/line/inline_iterator.h
+++ b/third_party/blink/renderer/core/layout/line/inline_iterator.h
@@ -197,7 +197,7 @@
   if (!observer || !object || !object.IsLayoutInline())
     return;
 
-  UnicodeBidi unicode_bidi = object.Style()->GetUnicodeBidi();
+  UnicodeBidi unicode_bidi = object.StyleRef().GetUnicodeBidi();
   if (unicode_bidi == UnicodeBidi::kNormal)
     return;  // Nothing to do for unicode-bidi: normal
   if (TreatAsIsolated(object.StyleRef())) {
@@ -517,7 +517,7 @@
     return WTF::Unicode::Direction(c);
 
   if (line_layout_item_ && line_layout_item_.IsListMarker())
-    return line_layout_item_.Style()->IsLeftToRightDirection()
+    return line_layout_item_.StyleRef().IsLeftToRightDirection()
                ? WTF::Unicode::kLeftToRight
                : WTF::Unicode::kRightToLeft;
 
@@ -549,7 +549,7 @@
       character == kSoftHyphenCharacter)
     return true;
   if (character == '\n')
-    return !layout_text.Style()->PreserveNewline();
+    return !layout_text.StyleRef().PreserveNewline();
   return false;
 }
 
diff --git a/third_party/blink/renderer/core/layout/line/inline_text_box.cc b/third_party/blink/renderer/core/layout/line/inline_text_box.cc
index 0583fae..b36e91b 100644
--- a/third_party/blink/renderer/core/layout/line/inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/line/inline_text_box.cc
@@ -171,7 +171,7 @@
 
     // FIXME: Remove -webkit-line-break: LineBreakAfterWhiteSpace.
     int end_of_line_adjustment_for_css_line_break =
-        GetLineLayoutItem().Style()->GetLineBreak() ==
+        GetLineLayoutItem().StyleRef().GetLineBreak() ==
                 LineBreak::kAfterWhiteSpace
             ? -1
             : 0;
@@ -453,7 +453,7 @@
 
 bool InlineTextBox::IsLineBreak() const {
   return GetLineLayoutItem().IsBR() ||
-         (GetLineLayoutItem().Style()->PreserveNewline() && Len() == 1 &&
+         (GetLineLayoutItem().StyleRef().PreserveNewline() && Len() == 1 &&
           GetLineLayoutItem().GetText().length() > Start() &&
           (*GetLineLayoutItem().GetText().Impl())[Start()] == '\n');
 }
diff --git a/third_party/blink/renderer/core/layout/line/line_box_list.cc b/third_party/blink/renderer/core/layout/line/line_box_list.cc
index 68c362d..2b943ba 100644
--- a/third_party/blink/renderer/core/layout/line/line_box_list.cc
+++ b/third_party/blink/renderer/core/layout/line/line_box_list.cc
@@ -156,7 +156,7 @@
   LayoutUnit physical_extent = AbsoluteValue(physical_end - physical_start);
   physical_start = std::min(physical_start, physical_end);
 
-  if (layout_object.Style()->IsHorizontalWritingMode()) {
+  if (layout_object.StyleRef().IsHorizontalWritingMode()) {
     physical_start += offset.Y();
     return cull_rect.IntersectsVerticalRange(physical_start,
                                              physical_start + physical_extent);
diff --git a/third_party/blink/renderer/core/layout/line/line_breaker.cc b/third_party/blink/renderer/core/layout/line/line_breaker.cc
index c0362d8..4d6464b 100644
--- a/third_party/blink/renderer/core/layout/line/line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/line/line_breaker.cc
@@ -38,7 +38,7 @@
     if (line_layout_item.IsOutOfFlowPositioned()) {
       SetStaticPositions(block_, LineLayoutBox(line_layout_item),
                          width.IndentText());
-      if (line_layout_item.Style()->IsOriginalDisplayInlineType()) {
+      if (line_layout_item.StyleRef().IsOriginalDisplayInlineType()) {
         resolver.Runs().AddRun(
             CreateRun(0, 1, LineLayoutItem(line_layout_item), resolver));
         line_info.IncrementRunsFromLeadingWhitespace();
diff --git a/third_party/blink/renderer/core/layout/line/line_width.cc b/third_party/blink/renderer/core/layout/line/line_width.cc
index b1047e8..0be9101 100644
--- a/third_party/blink/renderer/core/layout/line/line_width.cc
+++ b/third_party/blink/renderer/core/layout/line/line_width.cc
@@ -87,7 +87,8 @@
         new_left = left_;
       }
     }
-    if (IndentText() == kIndentText && block_.Style()->IsLeftToRightDirection())
+    if (IndentText() == kIndentText &&
+        block_.StyleRef().IsLeftToRightDirection())
       new_left += FloorToInt(block_.TextIndentOffset());
     left_ = std::max(left_, new_left);
   } else {
@@ -102,7 +103,7 @@
       }
     }
     if (IndentText() == kIndentText &&
-        !block_.Style()->IsLeftToRightDirection())
+        !block_.StyleRef().IsLeftToRightDirection())
       new_right -= FloorToInt(block_.TextIndentOffset());
     right_ = std::min(right_, new_right);
   }
diff --git a/third_party/blink/renderer/core/layout/line/root_inline_box.cc b/third_party/blink/renderer/core/layout/line/root_inline_box.cc
index 603f56b..0167a842 100644
--- a/third_party/blink/renderer/core/layout/line/root_inline_box.cc
+++ b/third_party/blink/renderer/core/layout/line/root_inline_box.cc
@@ -307,7 +307,7 @@
 LayoutUnit RootInlineBox::BeforeAnnotationsAdjustment() const {
   LayoutUnit result;
 
-  if (!GetLineLayoutItem().Style()->IsFlippedLinesWritingMode()) {
+  if (!GetLineLayoutItem().StyleRef().IsFlippedLinesWritingMode()) {
     // Annotations under the previous line may push us down.
     if (PrevRootBox() && PrevRootBox()->HasAnnotationsAfter())
       result = PrevRootBox()->ComputeUnderAnnotationAdjustment(LineTop());
@@ -372,11 +372,11 @@
 LayoutUnit RootInlineBox::SelectionTop() const {
   LayoutUnit selection_top = line_top_;
   if (has_annotations_before_)
-    selection_top -= !GetLineLayoutItem().Style()->IsFlippedLinesWritingMode()
+    selection_top -= !GetLineLayoutItem().StyleRef().IsFlippedLinesWritingMode()
                          ? ComputeOverAnnotationAdjustment(line_top_)
                          : ComputeUnderAnnotationAdjustment(line_top_);
 
-  if (GetLineLayoutItem().Style()->IsFlippedLinesWritingMode() ||
+  if (GetLineLayoutItem().StyleRef().IsFlippedLinesWritingMode() ||
       !PrevRootBox())
     return selection_top;
 
@@ -390,11 +390,11 @@
 
   if (has_annotations_after_)
     selection_bottom +=
-        !GetLineLayoutItem().Style()->IsFlippedLinesWritingMode()
+        !GetLineLayoutItem().StyleRef().IsFlippedLinesWritingMode()
             ? ComputeUnderAnnotationAdjustment(line_bottom_)
             : ComputeOverAnnotationAdjustment(line_bottom_);
 
-  if (!GetLineLayoutItem().Style()->IsFlippedLinesWritingMode() ||
+  if (!GetLineLayoutItem().StyleRef().IsFlippedLinesWritingMode() ||
       !NextRootBox())
     return selection_bottom;
 
@@ -402,7 +402,7 @@
 }
 
 LayoutUnit RootInlineBox::BlockDirectionPointInLine() const {
-  return !Block().Style()->IsFlippedBlocksWritingMode()
+  return !Block().StyleRef().IsFlippedBlocksWritingMode()
              ? std::max(LineTop(), SelectionTop())
              : std::min(LineBottom(), SelectionBottom());
 }
@@ -670,15 +670,15 @@
   }
 
   LayoutUnit vertical_position;
-  EVerticalAlign vertical_align = box_model.Style()->VerticalAlign();
+  EVerticalAlign vertical_align = box_model.StyleRef().VerticalAlign();
   if (vertical_align == EVerticalAlign::kTop ||
       vertical_align == EVerticalAlign::kBottom)
     return LayoutUnit();
 
   LineLayoutItem parent = box_model.Parent();
   if (parent.IsLayoutInline() &&
-      parent.Style()->VerticalAlign() != EVerticalAlign::kTop &&
-      parent.Style()->VerticalAlign() != EVerticalAlign::kBottom)
+      parent.StyleRef().VerticalAlign() != EVerticalAlign::kTop &&
+      parent.StyleRef().VerticalAlign() != EVerticalAlign::kBottom)
     vertical_position = box->Parent()->LogicalTop();
 
   if (vertical_align != EVerticalAlign::kBaseline) {
@@ -726,12 +726,12 @@
       LayoutUnit line_height;
       // Per http://www.w3.org/TR/CSS21/visudet.html#propdef-vertical-align:
       // 'Percentages: refer to the 'line-height' of the element itself'.
-      if (box_model.Style()->GetVerticalAlignLength().IsPercentOrCalc())
-        line_height = LayoutUnit(box_model.Style()->ComputedLineHeight());
+      if (box_model.StyleRef().GetVerticalAlignLength().IsPercentOrCalc())
+        line_height = LayoutUnit(box_model.StyleRef().ComputedLineHeight());
       else
         line_height = box_model.LineHeight(first_line, line_direction);
       vertical_position -= ValueForLength(
-          box_model.Style()->GetVerticalAlignLength(), line_height);
+          box_model.StyleRef().GetVerticalAlignLength(), line_height);
     }
   }
 
diff --git a/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc b/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc
index 869820d..29fe8be9 100644
--- a/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc
+++ b/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc
@@ -243,7 +243,7 @@
   local_point.MoveBy(-column_rect.Location());
   if (!column_set_.IsHorizontalWritingMode()) {
     if (snap == kSnapToColumn) {
-      LayoutUnit column_start = column_set_.Style()->IsLeftToRightDirection()
+      LayoutUnit column_start = column_set_.StyleRef().IsLeftToRightDirection()
                                     ? LayoutUnit()
                                     : column_rect.Height();
       if (local_point.X() < 0)
@@ -255,7 +255,7 @@
                        local_point.Y());
   }
   if (snap == kSnapToColumn) {
-    LayoutUnit column_start = column_set_.Style()->IsLeftToRightDirection()
+    LayoutUnit column_start = column_set_.StyleRef().IsLeftToRightDirection()
                                   ? LayoutUnit()
                                   : column_rect.Width();
     if (local_point.Y() < 0)
@@ -425,7 +425,7 @@
   LayoutUnit column_gap = column_set_.ColumnGap();
 
   if (column_set_.MultiColumnFlowThread()->ProgressionIsInline()) {
-    if (column_set_.Style()->IsLeftToRightDirection())
+    if (column_set_.StyleRef().IsLeftToRightDirection())
       column_logical_left += column_index * (column_logical_width + column_gap);
     else
       column_logical_left += column_set_.ContentLogicalWidth() -
@@ -476,7 +476,7 @@
   // contents from a previous column in the overflow area of a following column.
   bool is_first_column_in_row = !column_index;
   bool is_last_column_in_row = column_index == ActualColumnCount() - 1;
-  bool is_ltr = column_set_.Style()->IsLeftToRightDirection();
+  bool is_ltr = column_set_.StyleRef().IsLeftToRightDirection();
   bool is_leftmost_column =
       is_ltr ? is_first_column_in_row : is_last_column_in_row;
   bool is_rightmost_column =
@@ -572,7 +572,7 @@
       is_horizontal_writing_mode == is_column_progression_inline
           ? visual_point.X()
           : visual_point.Y();
-  if (!column_set_.Style()->IsLeftToRightDirection() &&
+  if (!column_set_.StyleRef().IsLeftToRightDirection() &&
       is_column_progression_inline)
     offset_in_column_progression_direction =
         column_set_.LogicalWidth() - offset_in_column_progression_direction;
@@ -618,7 +618,7 @@
   bool is_column_progression_inline =
       column_set_.MultiColumnFlowThread()->ProgressionIsInline();
   bool is_flipped_column_progression =
-      !column_set_.Style()->IsLeftToRightDirection() &&
+      !column_set_.StyleRef().IsLeftToRightDirection() &&
       is_column_progression_inline;
   if (column_set_.IsHorizontalWritingMode() == is_column_progression_inline) {
     if (is_flipped_column_progression) {
diff --git a/third_party/blink/renderer/core/layout/order_iterator.cc b/third_party/blink/renderer/core/layout/order_iterator.cc
index c9671634..f239179 100644
--- a/third_party/blink/renderer/core/layout/order_iterator.cc
+++ b/third_party/blink/renderer/core/layout/order_iterator.cc
@@ -63,7 +63,7 @@
       current_child_ = current_child_->NextSiblingBox();
     }
   } while (!current_child_ ||
-           current_child_->Style()->Order() != *order_values_iterator_);
+           current_child_->StyleRef().Order() != *order_values_iterator_);
 
   return current_child_;
 }
@@ -79,7 +79,7 @@
 }
 
 void OrderIteratorPopulator::CollectChild(const LayoutBox* child) {
-  iterator_.order_values_.insert(child->Style()->Order());
+  iterator_.order_values_.insert(child->StyleRef().Order());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/scroll_anchor.cc b/third_party/blink/renderer/core/layout/scroll_anchor.cc
index af6c5f7..2f3ab2d 100644
--- a/third_party/blink/renderer/core/layout/scroll_anchor.cc
+++ b/third_party/blink/renderer/core/layout/scroll_anchor.cc
@@ -285,7 +285,7 @@
   if (!CandidateMayMoveWithScroller(candidate, scroller_))
     return ExamineResult(kSkip);
 
-  if (candidate->Style()->OverflowAnchor() == EOverflowAnchor::kNone)
+  if (candidate->StyleRef().OverflowAnchor() == EOverflowAnchor::kNone)
     return ExamineResult(kSkip);
 
   LayoutRect candidate_rect = RelativeBounds(candidate, scroller_);
diff --git a/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc b/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
index 7c9f0ec..f87c3ff3 100644
--- a/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
+++ b/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
@@ -52,7 +52,7 @@
     LayoutSize new_reference_box_logical_size) {
   const Document& document = layout_box_.GetDocument();
   bool is_horizontal_writing_mode =
-      layout_box_.ContainingBlock()->Style()->IsHorizontalWritingMode();
+      layout_box_.ContainingBlock()->StyleRef().IsHorizontalWritingMode();
 
   LayoutSize margin_box_for_use_counter = new_reference_box_logical_size;
   if (is_horizontal_writing_mode) {
@@ -63,7 +63,7 @@
                                       layout_box_.MarginWidth());
   }
 
-  switch (ReferenceBox(*layout_box_.Style()->ShapeOutside())) {
+  switch (ReferenceBox(*layout_box_.StyleRef().ShapeOutside())) {
     case CSSBoxType::kMargin:
       UseCounter::Count(document, WebFeature::kShapeOutsideMarginBox);
       if (is_horizontal_writing_mode)
@@ -176,7 +176,7 @@
     float margin) const {
   DCHECK(!style_image->IsPendingImage());
   const LayoutSize& image_size = RoundedLayoutSize(style_image->ImageSize(
-      layout_box_.GetDocument(), layout_box_.Style()->EffectiveZoom(),
+      layout_box_.GetDocument(), layout_box_.StyleRef().EffectiveZoom(),
       reference_box_logical_size_));
 
   const LayoutRect& margin_rect =
@@ -216,7 +216,7 @@
           : std::max(LayoutUnit(), containing_block.ContentWidth());
 
   float margin =
-      FloatValueForLength(layout_box_.Style()->ShapeMargin(),
+      FloatValueForLength(layout_box_.StyleRef().ShapeMargin(),
                           percentage_resolution_inline_size.ToFloat());
 
   float shape_image_threshold = style.ShapeImageThreshold();
@@ -285,7 +285,7 @@
 }
 
 LayoutUnit ShapeOutsideInfo::LogicalTopOffset() const {
-  switch (ReferenceBox(*layout_box_.Style()->ShapeOutside())) {
+  switch (ReferenceBox(*layout_box_.StyleRef().ShapeOutside())) {
     case CSSBoxType::kMargin:
       return -layout_box_.MarginBefore(layout_box_.ContainingBlock()->Style());
     case CSSBoxType::kBorder:
@@ -293,11 +293,11 @@
     case CSSBoxType::kPadding:
       return BorderBeforeInWritingMode(
           layout_box_,
-          layout_box_.ContainingBlock()->Style()->GetWritingMode());
+          layout_box_.ContainingBlock()->StyleRef().GetWritingMode());
     case CSSBoxType::kContent:
       return BorderAndPaddingBeforeInWritingMode(
           layout_box_,
-          layout_box_.ContainingBlock()->Style()->GetWritingMode());
+          layout_box_.ContainingBlock()->StyleRef().GetWritingMode());
     case CSSBoxType::kMissing:
       break;
   }
@@ -337,7 +337,7 @@
 }
 
 LayoutUnit ShapeOutsideInfo::LogicalLeftOffset() const {
-  switch (ReferenceBox(*layout_box_.Style()->ShapeOutside())) {
+  switch (ReferenceBox(*layout_box_.StyleRef().ShapeOutside())) {
     case CSSBoxType::kMargin:
       return -layout_box_.MarginStart(layout_box_.ContainingBlock()->Style());
     case CSSBoxType::kBorder:
@@ -357,7 +357,7 @@
 }
 
 bool ShapeOutsideInfo::IsEnabledFor(const LayoutBox& box) {
-  ShapeValue* shape_value = box.Style()->ShapeOutside();
+  ShapeValue* shape_value = box.StyleRef().ShapeOutside();
   if (!box.IsFloating() || !shape_value)
     return false;
 
@@ -401,7 +401,7 @@
           std::min(line_height, ShapeLogicalBottom() - border_box_line_top));
       if (segment.is_valid) {
         LayoutUnit logical_left_margin =
-            containing_block.Style()->IsLeftToRightDirection()
+            containing_block.StyleRef().IsLeftToRightDirection()
                 ? containing_block.MarginStartForChild(layout_box_)
                 : containing_block.MarginEndForChild(layout_box_);
         LayoutUnit raw_left_margin_box_delta =
@@ -410,7 +410,7 @@
             raw_left_margin_box_delta, LayoutUnit(), float_margin_box_width);
 
         LayoutUnit logical_right_margin =
-            containing_block.Style()->IsLeftToRightDirection()
+            containing_block.StyleRef().IsLeftToRightDirection()
                 ? containing_block.MarginEndForChild(layout_box_)
                 : containing_block.MarginStartForChild(layout_box_);
         LayoutUnit raw_right_margin_box_delta =
@@ -443,13 +443,13 @@
       ComputedShape().ShapeMarginLogicalBoundingBox();
   physical_bounding_box.SetX(physical_bounding_box.X() + LogicalLeftOffset());
 
-  if (layout_box_.Style()->IsFlippedBlocksWritingMode())
+  if (layout_box_.StyleRef().IsFlippedBlocksWritingMode())
     physical_bounding_box.SetY(layout_box_.LogicalHeight() -
                                physical_bounding_box.MaxY());
   else
     physical_bounding_box.SetY(physical_bounding_box.Y() + LogicalTopOffset());
 
-  if (!layout_box_.Style()->IsHorizontalWritingMode())
+  if (!layout_box_.StyleRef().IsHorizontalWritingMode())
     physical_bounding_box = physical_bounding_box.TransposedRect();
   else
     physical_bounding_box.SetY(physical_bounding_box.Y() + LogicalTopOffset());
@@ -460,15 +460,15 @@
 FloatPoint ShapeOutsideInfo::ShapeToLayoutObjectPoint(FloatPoint point) const {
   FloatPoint result = FloatPoint(point.X() + LogicalLeftOffset(),
                                  point.Y() + LogicalTopOffset());
-  if (layout_box_.Style()->IsFlippedBlocksWritingMode())
+  if (layout_box_.StyleRef().IsFlippedBlocksWritingMode())
     result.SetY(layout_box_.LogicalHeight() - result.Y());
-  if (!layout_box_.Style()->IsHorizontalWritingMode())
+  if (!layout_box_.StyleRef().IsHorizontalWritingMode())
     result = result.TransposedPoint();
   return result;
 }
 
 FloatSize ShapeOutsideInfo::ShapeToLayoutObjectSize(FloatSize size) const {
-  if (!layout_box_.Style()->IsHorizontalWritingMode())
+  if (!layout_box_.StyleRef().IsHorizontalWritingMode())
     return size.TransposedSize();
   return size;
 }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
index df0f405f..c34a72b 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
@@ -67,11 +67,12 @@
 
   if (IsBlendingAllowed()) {
     bool has_blend_mode_changed =
-        (old_style && old_style->HasBlendMode()) == !Style()->HasBlendMode();
-    if (Parent() && has_blend_mode_changed)
+        (old_style && old_style->HasBlendMode()) == !StyleRef().HasBlendMode();
+    if (Parent() && has_blend_mode_changed) {
       Parent()->DescendantIsolationRequirementsChanged(
-          Style()->HasBlendMode() ? kDescendantIsolationRequired
-                                  : kDescendantIsolationNeedsUpdate);
+          StyleRef().HasBlendMode() ? kDescendantIsolationRequired
+                                    : kDescendantIsolationNeedsUpdate);
+    }
   }
 
   LayoutBlock::StyleDidChange(diff, old_style);
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 3dda0b8..ee9bba3 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
@@ -85,7 +85,7 @@
   SVGResourcesCache::ClientWasAddedToTree(*child, child->StyleRef());
 
   bool should_isolate_descendants =
-      (child->IsBlendingAllowed() && child->Style()->HasBlendMode()) ||
+      (child->IsBlendingAllowed() && child->StyleRef().HasBlendMode()) ||
       child->HasNonIsolatedBlendingDescendants();
   if (should_isolate_descendants)
     DescendantIsolationRequirementsChanged(kDescendantIsolationRequired);
@@ -96,7 +96,7 @@
   LayoutSVGModelObject::RemoveChild(child);
 
   bool had_non_isolated_descendants =
-      (child->IsBlendingAllowed() && child->Style()->HasBlendMode()) ||
+      (child->IsBlendingAllowed() && child->StyleRef().HasBlendMode()) ||
       child->HasNonIsolatedBlendingDescendants();
   if (had_non_isolated_descendants)
     DescendantIsolationRequirementsChanged(kDescendantIsolationNeedsUpdate);
@@ -195,7 +195,7 @@
 
   // pointer-events: bounding-box makes it possible for containers to be direct
   // targets.
-  if (Style()->PointerEvents() == EPointerEvents::kBoundingBox) {
+  if (StyleRef().PointerEvents() == EPointerEvents::kBoundingBox) {
     // Check for a valid bounding box because it will be invalid for empty
     // containers.
     if (IsObjectBoundingBoxValid() &&
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc
index 10e0f346..2b0bad9 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc
@@ -75,7 +75,7 @@
 
   fill_bounding_box_ = FloatRect(center_ - radii_, radii_.ScaledBy(2));
   stroke_bounding_box_ = fill_bounding_box_;
-  if (Style()->SvgStyle().HasStroke())
+  if (StyleRef().SvgStyle().HasStroke())
     stroke_bounding_box_.Inflate(StrokeWidth() / 2);
 }
 
@@ -131,7 +131,7 @@
 }
 
 bool LayoutSVGEllipse::HasContinuousStroke() const {
-  const SVGComputedStyle& svg_style = Style()->SvgStyle();
+  const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
   return svg_style.StrokeDashArray()->IsEmpty();
 }
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
index 6af5862..d037cfa 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
@@ -69,7 +69,7 @@
   UpdateScaledFont();
 
   bool new_preserves =
-      Style() ? Style()->WhiteSpace() == EWhiteSpace::kPre : false;
+      Style() ? StyleRef().WhiteSpace() == EWhiteSpace::kPre : false;
   bool old_preserves =
       old_style ? old_style->WhiteSpace() == EWhiteSpace::kPre : false;
   if (old_preserves != new_preserves) {
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 4704f6d..8ba3124 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
@@ -134,11 +134,12 @@
 
   if (IsBlendingAllowed()) {
     bool has_blend_mode_changed =
-        (old_style && old_style->HasBlendMode()) == !Style()->HasBlendMode();
-    if (Parent() && has_blend_mode_changed)
+        (old_style && old_style->HasBlendMode()) == !StyleRef().HasBlendMode();
+    if (Parent() && has_blend_mode_changed) {
       Parent()->DescendantIsolationRequirementsChanged(
-          Style()->HasBlendMode() ? kDescendantIsolationRequired
-                                  : kDescendantIsolationNeedsUpdate);
+          StyleRef().HasBlendMode() ? kDescendantIsolationRequired
+                                    : kDescendantIsolationNeedsUpdate);
+    }
 
     if (has_blend_mode_changed)
       SetNeedsPaintPropertyUpdate();
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
index 81ab1129..aa88e85 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
@@ -117,7 +117,7 @@
 
 // Returns true if the stroke is continuous and definitely uses miter joins.
 bool LayoutSVGRect::DefinitelyHasSimpleStroke() const {
-  const SVGComputedStyle& svg_style = Style()->SvgStyle();
+  const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
 
   // The four angles of a rect are 90 degrees. Using the formula at:
   // http://www.w3.org/TR/SVG/painting.html#StrokeMiterlimitProperty
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
index 3aa0518c..bb916b86 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
@@ -66,7 +66,7 @@
   PaintRecordBuilder builder(nullptr, &context);
 
   ColorFilter mask_content_filter =
-      Style()->SvgStyle().ColorInterpolation() == CI_LINEARRGB
+      StyleRef().SvgStyle().ColorInterpolation() == CI_LINEARRGB
           ? kColorFilterSRGBToLinearRGB
           : kColorFilterNone;
   builder.Context().SetColorFilter(mask_content_filter);
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 6de0dd4..29f9a4d 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
@@ -147,7 +147,7 @@
     return ContainingBlock()->AvailableLogicalHeight(
         kIncludeMarginBorderPadding);
 
-  const Length& logical_height = Style()->LogicalHeight();
+  const Length& logical_height = StyleRef().LogicalHeight();
   if (IsDocumentElement() && logical_height.IsPercentOrCalc()) {
     return ValueForLength(
         logical_height,
@@ -242,9 +242,9 @@
   // clipped. When the svg is stand-alone (isDocumentElement() == true) the
   // viewport clipping should always be applied, noting that the window
   // scrollbars should be hidden if overflow=hidden.
-  return Style()->OverflowX() == EOverflow::kHidden ||
-         Style()->OverflowX() == EOverflow::kAuto ||
-         Style()->OverflowX() == EOverflow::kScroll || IsDocumentElement();
+  return StyleRef().OverflowX() == EOverflow::kHidden ||
+         StyleRef().OverflowX() == EOverflow::kAuto ||
+         StyleRef().OverflowX() == EOverflow::kScroll || IsDocumentElement();
 }
 
 LayoutRect LayoutSVGRoot::VisualOverflowRect() const {
@@ -326,7 +326,7 @@
   SVGResourcesCache::ClientWasAddedToTree(*child, child->StyleRef());
 
   bool should_isolate_descendants =
-      (child->IsBlendingAllowed() && child->Style()->HasBlendMode()) ||
+      (child->IsBlendingAllowed() && child->StyleRef().HasBlendMode()) ||
       child->HasNonIsolatedBlendingDescendants();
   if (should_isolate_descendants)
     DescendantIsolationRequirementsChanged(kDescendantIsolationRequired);
@@ -337,7 +337,7 @@
   LayoutReplaced::RemoveChild(child);
 
   bool had_non_isolated_descendants =
-      (child->IsBlendingAllowed() && child->Style()->HasBlendMode()) ||
+      (child->IsBlendingAllowed() && child->StyleRef().HasBlendMode()) ||
       child->HasNonIsolatedBlendingDescendants();
   if (had_non_isolated_descendants)
     DescendantIsolationRequirementsChanged(kDescendantIsolationNeedsUpdate);
@@ -411,7 +411,7 @@
   SVGTransformChangeDetector change_detector(local_to_border_box_transform_);
   SVGSVGElement* svg = ToSVGSVGElement(GetNode());
   DCHECK(svg);
-  float scale = Style()->EffectiveZoom();
+  float scale = StyleRef().EffectiveZoom();
   local_to_border_box_transform_ = svg->ViewBoxToViewTransform(
       ContentWidth() / scale, ContentHeight() / scale);
 
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 452e6ad..69fd4258 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
@@ -139,7 +139,7 @@
 }
 
 FloatRect LayoutSVGShape::HitTestStrokeBoundingBox() const {
-  if (Style()->SvgStyle().HasStroke())
+  if (StyleRef().SvgStyle().HasStroke())
     return stroke_bounding_box_;
 
   // Implementation of
@@ -360,7 +360,7 @@
 
   PointerEventsHitRules hit_rules(
       PointerEventsHitRules::SVG_GEOMETRY_HITTESTING,
-      result.GetHitTestRequest(), Style()->PointerEvents());
+      result.GetHitTestRequest(), StyleRef().PointerEvents());
   if (NodeAtFloatPointInternal(result.GetHitTestRequest(), local_point,
                                hit_rules)) {
     const LayoutPoint& local_layout_point = LayoutPoint(local_point);
@@ -406,7 +406,7 @@
   DCHECK(path_);
   FloatRect stroke_bounding_box = fill_bounding_box_;
 
-  if (Style()->SvgStyle().HasStroke()) {
+  if (StyleRef().SvgStyle().HasStroke()) {
     StrokeData stroke_data;
     SVGLayoutSupport::ApplyStrokeStyleToStrokeData(stroke_data, StyleRef(),
                                                    *this, DashScaleFactor());
@@ -430,7 +430,7 @@
 
 float LayoutSVGShape::StrokeWidth() const {
   SVGLengthContext length_context(GetElement());
-  return length_context.ValueForLength(Style()->SvgStyle().StrokeWidth());
+  return length_context.ValueForLength(StyleRef().SvgStyle().StrokeWidth());
 }
 
 LayoutSVGShapeRareData& LayoutSVGShape::EnsureRareData() const {
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 0daeb6b..c291ae4 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
@@ -86,7 +86,7 @@
   }
 
   bool HasNonScalingStroke() const {
-    return Style()->SvgStyle().VectorEffect() == VE_NON_SCALING_STROKE;
+    return StyleRef().SvgStyle().VectorEffect() == VE_NON_SCALING_STROKE;
   }
   const Path& NonScalingStrokePath() const {
     DCHECK(HasNonScalingStroke());
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 a27aece..0d720fe 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
@@ -378,7 +378,7 @@
 
 FloatRect LayoutSVGText::StrokeBoundingBox() const {
   FloatRect stroke_boundaries = ObjectBoundingBox();
-  const SVGComputedStyle& svg_style = Style()->SvgStyle();
+  const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
   if (!svg_style.HasStroke())
     return stroke_boundaries;
 
@@ -393,7 +393,7 @@
   FloatRect visual_rect = StrokeBoundingBox();
   SVGLayoutSupport::AdjustVisualRectWithResources(*this, visual_rect);
 
-  if (const ShadowList* text_shadow = Style()->TextShadow())
+  if (const ShadowList* text_shadow = StyleRef().TextShadow())
     text_shadow->AdjustRectForShadow(visual_rect);
 
   return visual_rect;
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 dbc43c7..8737a84c 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
@@ -216,7 +216,7 @@
     const LayoutObjectType* object) {
   for (LayoutObject* child = object->FirstChild(); child;
        child = child->NextSibling()) {
-    if (child->IsBlendingAllowed() && child->Style()->HasBlendMode())
+    if (child->IsBlendingAllowed() && child->StyleRef().HasBlendMode())
       return true;
     if (child->HasNonIsolatedBlendingDescendants() &&
         !WillIsolateBlendingDescendantsForObject(child))
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
index 3510f53ef..2cd2bea2 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
@@ -455,7 +455,7 @@
   LineLayoutSVGInlineText text_line_layout =
       LineLayoutSVGInlineText(text_box->GetLineLayoutItem());
 
-  const SVGComputedStyle& svg_style = text_line_layout.Style()->SvgStyle();
+  const SVGComputedStyle& svg_style = text_line_layout.StyleRef().SvgStyle();
   String text = text_box->GetLineLayoutItem().GetText();
 
   unsigned fragments_size = fragments.size();
@@ -471,7 +471,7 @@
     ts << "chunk 1 ";
     ETextAnchor anchor = svg_style.TextAnchor();
     bool is_vertical_text =
-        !text_line_layout.Style()->IsHorizontalWritingMode();
+        !text_line_layout.StyleRef().IsHorizontalWritingMode();
     if (anchor == TA_MIDDLE) {
       ts << "(middle anchor";
       if (is_vertical_text)
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc
index bbf32ba..c7824b10 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc
@@ -62,7 +62,7 @@
   DCHECK(text_line_layout);
   DCHECK(text_line_layout.Style());
 
-  const SVGComputedStyle& style = text_line_layout.Style()->SvgStyle();
+  const SVGComputedStyle& style = text_line_layout.StyleRef().SvgStyle();
 
   EDominantBaseline baseline = style.DominantBaseline();
   if (baseline == DB_AUTO) {
@@ -119,7 +119,7 @@
   DCHECK(text_line_layout_parent);
 
   EAlignmentBaseline baseline =
-      text_line_layout.Style()->SvgStyle().AlignmentBaseline();
+      text_line_layout.StyleRef().SvgStyle().AlignmentBaseline();
   if (baseline == AB_AUTO || baseline == AB_BASELINE) {
     baseline = DominantBaselineToAlignmentBaseline(is_vertical_text,
                                                    text_line_layout_parent);
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_query.cc b/third_party/blink/renderer/core/layout/svg/svg_text_query.cc
index b062998..236be0f 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_text_query.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_text_query.cc
@@ -108,7 +108,7 @@
       LineLayoutSVGInlineText(text_box->GetLineLayoutItem());
 
   query_data->is_vertical_text =
-      !query_data->text_line_layout.Style()->IsHorizontalWritingMode();
+      !query_data->text_line_layout.StyleRef().IsHorizontalWritingMode();
 
   // Loop over all text fragments in this text box, firing a callback for each.
   for (const SVGTextFragment& fragment : text_box->TextFragments()) {
diff --git a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
index 1a8efd8..7110087 100644
--- a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
+++ b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
@@ -170,9 +170,9 @@
   for (LayoutTableCol* column = table_->FirstColumn(); column;
        column = column->NextColumn()) {
     if (column->IsTableColumnGroupWithColumnChildren()) {
-      group_logical_width = column->Style()->LogicalWidth();
+      group_logical_width = column->StyleRef().LogicalWidth();
     } else {
-      Length col_logical_width = column->Style()->LogicalWidth();
+      Length col_logical_width = column->StyleRef().LogicalWidth();
       // FIXME: calc() on tables should be handled consistently with other
       // lengths. See bug: https://crbug.com/382725
       if (col_logical_width.IsCalculated() || col_logical_width.IsAuto())
@@ -242,19 +242,19 @@
   // A special case.  If this table is not fixed width and contained inside
   // a cell, then don't bloat the maxwidth by examining percentage growth.
   while (true) {
-    Length tw = table->Style()->Width();
+    Length tw = table->StyleRef().Width();
     if ((!tw.IsAuto() && !tw.IsPercentOrCalc()) ||
         table->IsOutOfFlowPositioned())
       return true;
     LayoutBlock* cb = table->ContainingBlock();
 
     while (!cb->IsLayoutView() && !cb->IsTableCell() &&
-           cb->Style()->Width().IsAuto() && !cb->IsOutOfFlowPositioned())
+           cb->StyleRef().Width().IsAuto() && !cb->IsOutOfFlowPositioned())
       cb = cb->ContainingBlock();
 
     // TODO(dgrogan): Should the second clause check for isFixed() instead?
-    if (!cb->IsTableCell() || (!cb->Style()->Width().IsAuto() &&
-                               !cb->Style()->Width().IsPercentOrCalc()))
+    if (!cb->IsTableCell() || (!cb->StyleRef().Width().IsAuto() &&
+                               !cb->StyleRef().Width().IsPercentOrCalc()))
       return true;
 
     LayoutTableCell* cell = ToLayoutTableCell(cb);
@@ -328,7 +328,7 @@
 void TableLayoutAlgorithmAuto::ApplyPreferredLogicalWidthQuirks(
     LayoutUnit& min_width,
     LayoutUnit& max_width) const {
-  Length table_logical_width = table_->Style()->LogicalWidth();
+  Length table_logical_width = table_->StyleRef().LogicalWidth();
   if (table_logical_width.IsFixed() && table_logical_width.IsPositive()) {
     // |minWidth| is the result of measuring the intrinsic content's size. Keep
     // it to make sure we are *never* smaller than the actual content.
@@ -339,7 +339,8 @@
     min_width = max_width = LayoutUnit(
         std::max<int>(min_width.Floor(), table_logical_width.Value()));
 
-    const Length& style_max_logical_width = table_->Style()->LogicalMaxWidth();
+    const Length& style_max_logical_width =
+        table_->StyleRef().LogicalMaxWidth();
     if (style_max_logical_width.IsFixed() &&
         !style_max_logical_width.IsNegative()) {
       min_width = LayoutUnit(
diff --git a/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc b/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
index 7057cd8..66cba73d 100644
--- a/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
+++ b/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
@@ -98,7 +98,7 @@
     if (col->IsTableColumnGroupWithColumnChildren())
       continue;
 
-    Length col_style_logical_width = col->Style()->LogicalWidth();
+    Length col_style_logical_width = col->StyleRef().LogicalWidth();
     int effective_col_width = 0;
     if (col_style_logical_width.IsFixed() &&
         col_style_logical_width.Value() > 0)
@@ -196,7 +196,7 @@
 void TableLayoutAlgorithmFixed::ApplyPreferredLogicalWidthQuirks(
     LayoutUnit& min_width,
     LayoutUnit& max_width) const {
-  Length table_logical_width = table_->Style()->LogicalWidth();
+  Length table_logical_width = table_->StyleRef().LogicalWidth();
   if (table_logical_width.IsFixed() && table_logical_width.IsPositive()) {
     min_width = max_width = LayoutUnit(
         max(min_width,
@@ -218,7 +218,7 @@
   // In this example, the two inner tables should be as large as the outer
   // table. We can achieve this effect by making the maxwidth of fixed tables
   // with percentage widths be infinite.
-  if (table_->Style()->LogicalWidth().IsPercentOrCalc() &&
+  if (table_->StyleRef().LogicalWidth().IsPercentOrCalc() &&
       max_width < kTableMaxWidth)
     max_width = LayoutUnit(kTableMaxWidth);
 }
diff --git a/third_party/blink/renderer/core/layout/text_autosizer.cc b/third_party/blink/renderer/core/layout/text_autosizer.cc
index 520cfbf..5e8973d8 100644
--- a/third_party/blink/renderer/core/layout/text_autosizer.cc
+++ b/third_party/blink/renderer/core/layout/text_autosizer.cc
@@ -101,7 +101,7 @@
   if (!layout_object->IsLayoutBlock())
     return false;
   if (layout_object->IsInline() &&
-      !layout_object->Style()->IsDisplayReplacedType())
+      !layout_object->StyleRef().IsDisplayReplacedType())
     return false;
   if (layout_object->IsListItemIncludingNG())
     return (layout_object->IsFloating() ||
@@ -120,9 +120,9 @@
          layout_object->IsFlexibleBoxIncludingDeprecated() ||
          (containing_block && containing_block->IsHorizontalWritingMode() !=
                                   layout_object->IsHorizontalWritingMode()) ||
-         layout_object->Style()->IsDisplayReplacedType() ||
+         layout_object->StyleRef().IsDisplayReplacedType() ||
          layout_object->IsTextArea() ||
-         layout_object->Style()->UserModify() != EUserModify::kReadOnly;
+         layout_object->StyleRef().UserModify() != EUserModify::kReadOnly;
 }
 
 static bool BlockIsRowOfLinks(const LayoutBlock* block) {
@@ -145,12 +145,12 @@
       if (!layout_object->IsInline() || layout_object->IsBR())
         return false;
     }
-    if (layout_object->Style()->IsLink()) {
+    if (layout_object->StyleRef().IsLink()) {
       link_count++;
       if (matching_font_size < 0)
-        matching_font_size = layout_object->Style()->SpecifiedFontSize();
+        matching_font_size = layout_object->StyleRef().SpecifiedFontSize();
       else if (matching_font_size !=
-               layout_object->Style()->SpecifiedFontSize())
+               layout_object->StyleRef().SpecifiedFontSize())
         return false;
 
       // Skip traversing descendants of the link.
@@ -211,7 +211,7 @@
 
   // Don't autosize block-level text that can't wrap (as it's likely to
   // expand sideways and break the page's layout).
-  if (!block->Style()->AutoWrap())
+  if (!block->StyleRef().AutoWrap())
     return true;
 
   if (BlockHeightConstrained(block))
@@ -223,7 +223,7 @@
 static bool HasExplicitWidth(const LayoutBlock* block) {
   // FIXME: This heuristic may need to be expanded to other ways a block can be
   // wider or narrower than its parent containing block.
-  return block->Style() && block->Style()->Width().IsSpecified();
+  return block->Style() && block->StyleRef().Width().IsSpecified();
 }
 
 static LayoutObject* GetParent(const LayoutObject* object) {
@@ -354,14 +354,14 @@
   // Cells in auto-layout tables are handled separately by inflateAutoTable.
   bool is_auto_table_cell =
       block->IsTableCell() &&
-      !ToLayoutTableCell(block)->Table()->Style()->IsFixedTableLayout();
+      !ToLayoutTableCell(block)->Table()->StyleRef().IsFixedTableLayout();
   if (!is_auto_table_cell && !cluster_stack_.IsEmpty())
     Inflate(block, layouter);
 }
 
 void TextAutosizer::InflateAutoTable(LayoutTable* table) {
   DCHECK(table);
-  DCHECK(!table->Style()->IsFixedTableLayout());
+  DCHECK(!table->StyleRef().IsFixedTableLayout());
   DCHECK(table->ContainingBlock());
 
   Cluster* cluster = CurrentCluster();
@@ -727,7 +727,7 @@
 
   // TextAreas and user-modifiable areas get a free pass to autosize regardless
   // of text content.
-  if (root->IsTextArea() || (root->Style() && root->Style()->UserModify() !=
+  if (root->IsTextArea() || (root->Style() && root->StyleRef().UserModify() !=
                                                   EUserModify::kReadOnly)) {
     cluster->has_enough_text_to_autosize_ = kHasEnoughText;
     return true;
@@ -763,7 +763,7 @@
       // layout. These values can be different.
       // Note: This is an approximation assuming each character is 1em wide.
       length += ToLayoutText(descendant)->GetText().StripWhiteSpace().length() *
-                descendant->Style()->SpecifiedFontSize();
+                descendant->StyleRef().SpecifiedFontSize();
 
       if (length >= minimum_text_length_to_autosize) {
         cluster->has_enough_text_to_autosize_ = kHasEnoughText;
@@ -988,7 +988,7 @@
     Length specified_width =
         block->IsTableCell()
             ? ToLayoutTableCell(block)->StyleOrColLogicalWidth()
-            : block->Style()->LogicalWidth();
+            : block->StyleRef().LogicalWidth();
     if (specified_width.IsFixed()) {
       if ((width = specified_width.Value()) > 0)
         return width;
diff --git a/third_party/blink/renderer/core/layout/text_autosizer_test.cc b/third_party/blink/renderer/core/layout/text_autosizer_test.cc
index 6bf81b4f..fde0c2e 100644
--- a/third_party/blink/renderer/core/layout/text_autosizer_test.cc
+++ b/third_party/blink/renderer/core/layout/text_autosizer_test.cc
@@ -78,11 +78,11 @@
   )HTML");
   Element* autosized = GetDocument().getElementById("autosized");
   EXPECT_FLOAT_EQ(16.f,
-                  autosized->GetLayoutObject()->Style()->SpecifiedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // (specified font-size = 16px) * (viewport width = 800px) /
   // (window width = 320px) = 40px.
   EXPECT_FLOAT_EQ(40.f,
-                  autosized->GetLayoutObject()->Style()->ComputedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, TextSizeAdjustDisablesAutosizing) {
@@ -121,16 +121,16 @@
   )HTML");
   LayoutObject* text_size_adjust_auto =
       GetDocument().getElementById("textSizeAdjustAuto")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, text_size_adjust_auto->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(40.f, text_size_adjust_auto->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust_auto->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(40.f, text_size_adjust_auto->StyleRef().ComputedFontSize());
   LayoutObject* text_size_adjust_none =
       GetDocument().getElementById("textSizeAdjustNone")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, text_size_adjust_none->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(16.f, text_size_adjust_none->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust_none->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust_none->StyleRef().ComputedFontSize());
   LayoutObject* text_size_adjust100 =
       GetDocument().getElementById("textSizeAdjust100")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, text_size_adjust100->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(16.f, text_size_adjust100->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust100->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust100->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, ParagraphWithChangingTextSizeAdjustment) {
@@ -154,37 +154,37 @@
   )HTML");
   Element* autosized_div = GetDocument().getElementById("autosized");
   EXPECT_FLOAT_EQ(
-      16.f, autosized_div->GetLayoutObject()->Style()->SpecifiedFontSize());
+      16.f, autosized_div->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   EXPECT_FLOAT_EQ(
-      40.f, autosized_div->GetLayoutObject()->Style()->ComputedFontSize());
+      40.f, autosized_div->GetLayoutObject()->StyleRef().ComputedFontSize());
 
   autosized_div->setAttribute(HTMLNames::classAttr, "none");
   GetDocument().View()->UpdateAllLifecyclePhases();
   EXPECT_FLOAT_EQ(
-      16.f, autosized_div->GetLayoutObject()->Style()->SpecifiedFontSize());
+      16.f, autosized_div->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   EXPECT_FLOAT_EQ(
-      16.f, autosized_div->GetLayoutObject()->Style()->ComputedFontSize());
+      16.f, autosized_div->GetLayoutObject()->StyleRef().ComputedFontSize());
 
   autosized_div->setAttribute(HTMLNames::classAttr, "small");
   GetDocument().View()->UpdateAllLifecyclePhases();
   EXPECT_FLOAT_EQ(
-      16.f, autosized_div->GetLayoutObject()->Style()->SpecifiedFontSize());
+      16.f, autosized_div->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   EXPECT_FLOAT_EQ(
-      8.f, autosized_div->GetLayoutObject()->Style()->ComputedFontSize());
+      8.f, autosized_div->GetLayoutObject()->StyleRef().ComputedFontSize());
 
   autosized_div->setAttribute(HTMLNames::classAttr, "large");
   GetDocument().View()->UpdateAllLifecyclePhases();
   EXPECT_FLOAT_EQ(
-      16.f, autosized_div->GetLayoutObject()->Style()->SpecifiedFontSize());
+      16.f, autosized_div->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   EXPECT_FLOAT_EQ(
-      24.f, autosized_div->GetLayoutObject()->Style()->ComputedFontSize());
+      24.f, autosized_div->GetLayoutObject()->StyleRef().ComputedFontSize());
 
   autosized_div->removeAttribute(HTMLNames::classAttr);
   GetDocument().View()->UpdateAllLifecyclePhases();
   EXPECT_FLOAT_EQ(
-      16.f, autosized_div->GetLayoutObject()->Style()->SpecifiedFontSize());
+      16.f, autosized_div->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   EXPECT_FLOAT_EQ(
-      40.f, autosized_div->GetLayoutObject()->Style()->ComputedFontSize());
+      40.f, autosized_div->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, ZeroTextSizeAdjustment) {
@@ -205,8 +205,8 @@
   )HTML");
   LayoutObject* text_size_adjust_zero =
       GetDocument().getElementById("textSizeAdjustZero")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, text_size_adjust_zero->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(0.f, text_size_adjust_zero->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust_zero->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(0.f, text_size_adjust_zero->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, NegativeTextSizeAdjustment) {
@@ -228,8 +228,9 @@
   LayoutObject* text_size_adjust_negative =
       GetDocument().getElementById("textSizeAdjustNegative")->GetLayoutObject();
   EXPECT_FLOAT_EQ(16.f,
-                  text_size_adjust_negative->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(40.f, text_size_adjust_negative->Style()->ComputedFontSize());
+                  text_size_adjust_negative->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(40.f,
+                  text_size_adjust_negative->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, TextSizeAdjustmentPixelUnits) {
@@ -250,8 +251,9 @@
       "</div>");
   LayoutObject* text_size_adjust_pixels =
       GetDocument().getElementById("textSizeAdjustPixels")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, text_size_adjust_pixels->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(40.f, text_size_adjust_pixels->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(16.f,
+                  text_size_adjust_pixels->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(40.f, text_size_adjust_pixels->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, NestedTextSizeAdjust) {
@@ -281,14 +283,14 @@
   )HTML");
   LayoutObject* text_size_adjust_a =
       GetDocument().getElementById("textSizeAdjustA")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, text_size_adjust_a->Style()->SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust_a->StyleRef().SpecifiedFontSize());
   // 16px * 47% = 7.52
-  EXPECT_FLOAT_EQ(7.52f, text_size_adjust_a->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(7.52f, text_size_adjust_a->StyleRef().ComputedFontSize());
   LayoutObject* text_size_adjust_b =
       GetDocument().getElementById("textSizeAdjustB")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, text_size_adjust_b->Style()->SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust_b->StyleRef().SpecifiedFontSize());
   // 16px * 53% = 8.48
-  EXPECT_FLOAT_EQ(8.48f, text_size_adjust_b->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(8.48f, text_size_adjust_b->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, PrefixedTextSizeAdjustIsAlias) {
@@ -309,10 +311,10 @@
   )HTML");
   LayoutObject* text_size_adjust =
       GetDocument().getElementById("textSizeAdjust")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, text_size_adjust->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(8.f, text_size_adjust->Style()->ComputedFontSize());
-  EXPECT_FLOAT_EQ(.5f,
-                  text_size_adjust->Style()->GetTextSizeAdjust().Multiplier());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(8.f, text_size_adjust->StyleRef().ComputedFontSize());
+  EXPECT_FLOAT_EQ(
+      .5f, text_size_adjust->StyleRef().GetTextSizeAdjust().Multiplier());
 }
 
 TEST_F(TextAutosizerTest, AccessibilityFontScaleFactor) {
@@ -334,11 +336,11 @@
   )HTML");
   Element* autosized = GetDocument().getElementById("autosized");
   EXPECT_FLOAT_EQ(16.f,
-                  autosized->GetLayoutObject()->Style()->SpecifiedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // 1.5 * (specified font-size = 16px) * (viewport width = 800px) /
   // (window width = 320px) = 60px.
   EXPECT_FLOAT_EQ(60.f,
-                  autosized->GetLayoutObject()->Style()->ComputedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, AccessibilityFontScaleFactorWithTextSizeAdjustNone) {
@@ -371,19 +373,19 @@
   )HTML");
   Element* autosized = GetDocument().getElementById("autosized");
   EXPECT_FLOAT_EQ(16.f,
-                  autosized->GetLayoutObject()->Style()->SpecifiedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // 1.5 * (specified font-size = 16px) = 24px.
   EXPECT_FLOAT_EQ(24.f,
-                  autosized->GetLayoutObject()->Style()->ComputedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().ComputedFontSize());
 
   // Because this does not autosize (due to the width), no accessibility font
   // scale factor should be applied.
   Element* not_autosized = GetDocument().getElementById("notAutosized");
   EXPECT_FLOAT_EQ(
-      16.f, not_autosized->GetLayoutObject()->Style()->SpecifiedFontSize());
+      16.f, not_autosized->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // specified font-size = 16px.
   EXPECT_FLOAT_EQ(
-      16.f, not_autosized->GetLayoutObject()->Style()->ComputedFontSize());
+      16.f, not_autosized->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, ChangingAccessibilityFontScaleFactor) {
@@ -405,21 +407,21 @@
   )HTML");
   Element* autosized = GetDocument().getElementById("autosized");
   EXPECT_FLOAT_EQ(16.f,
-                  autosized->GetLayoutObject()->Style()->SpecifiedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // 1.0 * (specified font-size = 16px) * (viewport width = 800px) /
   // (window width = 320px) = 40px.
   EXPECT_FLOAT_EQ(40.f,
-                  autosized->GetLayoutObject()->Style()->ComputedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().ComputedFontSize());
 
   GetDocument().GetSettings()->SetAccessibilityFontScaleFactor(2);
   GetDocument().View()->UpdateAllLifecyclePhases();
 
   EXPECT_FLOAT_EQ(16.f,
-                  autosized->GetLayoutObject()->Style()->SpecifiedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // 2.0 * (specified font-size = 16px) * (viewport width = 800px) /
   // (window width = 320px) = 80px.
   EXPECT_FLOAT_EQ(80.f,
-                  autosized->GetLayoutObject()->Style()->ComputedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, TextSizeAdjustDoesNotDisableAccessibility) {
@@ -452,21 +454,21 @@
       GetDocument().getElementById("textSizeAdjustNone");
   EXPECT_FLOAT_EQ(
       16.f,
-      text_size_adjust_none->GetLayoutObject()->Style()->SpecifiedFontSize());
+      text_size_adjust_none->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // 1.5 * (specified font-size = 16px) = 24px.
   EXPECT_FLOAT_EQ(
       24.f,
-      text_size_adjust_none->GetLayoutObject()->Style()->ComputedFontSize());
+      text_size_adjust_none->GetLayoutObject()->StyleRef().ComputedFontSize());
 
   Element* text_size_adjust_double =
       GetDocument().getElementById("textSizeAdjustDouble");
-  EXPECT_FLOAT_EQ(
-      16.f,
-      text_size_adjust_double->GetLayoutObject()->Style()->SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust_double->GetLayoutObject()
+                            ->StyleRef()
+                            .SpecifiedFontSize());
   // 1.5 * (specified font-size = 16px) * (text size adjustment = 2) = 48px.
-  EXPECT_FLOAT_EQ(
-      48.f,
-      text_size_adjust_double->GetLayoutObject()->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(48.f, text_size_adjust_double->GetLayoutObject()
+                            ->StyleRef()
+                            .ComputedFontSize());
 
   // Changing the accessibility font scale factor should change the adjusted
   // size.
@@ -475,19 +477,19 @@
 
   EXPECT_FLOAT_EQ(
       16.f,
-      text_size_adjust_none->GetLayoutObject()->Style()->SpecifiedFontSize());
+      text_size_adjust_none->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // 2.0 * (specified font-size = 16px) = 32px.
   EXPECT_FLOAT_EQ(
       32.f,
-      text_size_adjust_none->GetLayoutObject()->Style()->ComputedFontSize());
+      text_size_adjust_none->GetLayoutObject()->StyleRef().ComputedFontSize());
 
-  EXPECT_FLOAT_EQ(
-      16.f,
-      text_size_adjust_double->GetLayoutObject()->Style()->SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust_double->GetLayoutObject()
+                            ->StyleRef()
+                            .SpecifiedFontSize());
   // 2.0 * (specified font-size = 16px) * (text size adjustment = 2) = 64px.
-  EXPECT_FLOAT_EQ(
-      64.f,
-      text_size_adjust_double->GetLayoutObject()->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(64.f, text_size_adjust_double->GetLayoutObject()
+                            ->StyleRef()
+                            .ComputedFontSize());
 }
 
 // https://crbug.com/646237
@@ -506,10 +508,10 @@
 
   LayoutObject* text_size_adjust =
       GetDocument().getElementById("textSizeAdjust")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, text_size_adjust->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(24.f, text_size_adjust->Style()->ComputedFontSize());
-  EXPECT_FLOAT_EQ(1.5f,
-                  text_size_adjust->Style()->GetTextSizeAdjust().Multiplier());
+  EXPECT_FLOAT_EQ(16.f, text_size_adjust->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(24.f, text_size_adjust->StyleRef().ComputedFontSize());
+  EXPECT_FLOAT_EQ(
+      1.5f, text_size_adjust->StyleRef().GetTextSizeAdjust().Multiplier());
 }
 
 TEST_F(TextAutosizerTest, DeviceScaleAdjustmentWithViewport) {
@@ -536,23 +538,23 @@
 
   Element* autosized = GetDocument().getElementById("autosized");
   EXPECT_FLOAT_EQ(16.f,
-                  autosized->GetLayoutObject()->Style()->SpecifiedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // (specified font-size = 16px) * (viewport width = 800px) /
   // (window width = 320px) = 40px.
   // The device scale adjustment of 1.5 is ignored.
   EXPECT_FLOAT_EQ(40.f,
-                  autosized->GetLayoutObject()->Style()->ComputedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().ComputedFontSize());
 
   GetDocument().GetSettings()->SetViewportMetaEnabled(false);
   GetDocument().View()->UpdateAllLifecyclePhases();
 
   autosized = GetDocument().getElementById("autosized");
   EXPECT_FLOAT_EQ(16.f,
-                  autosized->GetLayoutObject()->Style()->SpecifiedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // (device scale adjustment = 1.5) * (specified font-size = 16px) *
   // (viewport width = 800px) / (window width = 320px) = 60px.
   EXPECT_FLOAT_EQ(60.f,
-                  autosized->GetLayoutObject()->Style()->ComputedFontSize());
+                  autosized->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, ChangingSuperClusterFirstText) {
@@ -590,14 +592,14 @@
 
   LayoutObject* long_text =
       GetDocument().getElementById("longText")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, long_text->Style()->SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(16.f, long_text->StyleRef().SpecifiedFontSize());
   //(specified font-size = 16px) * (block width = 560px) /
   // (window width = 320px) = 28px.
-  EXPECT_FLOAT_EQ(28.f, long_text->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(28.f, long_text->StyleRef().ComputedFontSize());
   LayoutObject* short_text =
       GetDocument().getElementById("shortText")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, short_text->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(28.f, short_text->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(16.f, short_text->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(28.f, short_text->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, ChangingSuperClusterSecondText) {
@@ -635,14 +637,14 @@
 
   LayoutObject* long_text =
       GetDocument().getElementById("longText")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, long_text->Style()->SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(16.f, long_text->StyleRef().SpecifiedFontSize());
   //(specified font-size = 16px) * (block width = 560px) /
   // (window width = 320px) = 28px.
-  EXPECT_FLOAT_EQ(28.f, long_text->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(28.f, long_text->StyleRef().ComputedFontSize());
   LayoutObject* short_text =
       GetDocument().getElementById("shortText")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, short_text->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(28.f, short_text->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(16.f, short_text->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(28.f, short_text->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, AddingSuperCluster) {
@@ -682,14 +684,14 @@
 
   LayoutObject* long_text =
       GetDocument().getElementById("longText")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, long_text->Style()->SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(16.f, long_text->StyleRef().SpecifiedFontSize());
   //(specified font-size = 16px) * (block width = 560px) /
   // (window width = 320px) = 28px.
-  EXPECT_FLOAT_EQ(28.f, long_text->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(28.f, long_text->StyleRef().ComputedFontSize());
   LayoutObject* short_text =
       GetDocument().getElementById("shortText")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, short_text->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(28.f, short_text->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(16.f, short_text->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(28.f, short_text->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, ChangingInheritedClusterTextInsideSuperCluster) {
@@ -728,14 +730,14 @@
 
   LayoutObject* long_text =
       GetDocument().getElementById("longText")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, long_text->Style()->SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(16.f, long_text->StyleRef().SpecifiedFontSize());
   //(specified font-size = 16px) * (block width = 560px) /
   // (window width = 320px) = 28px.
-  EXPECT_FLOAT_EQ(28.f, long_text->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(28.f, long_text->StyleRef().ComputedFontSize());
   LayoutObject* short_text =
       GetDocument().getElementById("shortText")->GetLayoutObject();
-  EXPECT_FLOAT_EQ(16.f, short_text->Style()->SpecifiedFontSize());
-  EXPECT_FLOAT_EQ(28.f, short_text->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(16.f, short_text->StyleRef().SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(28.f, short_text->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, AutosizeInnerContentOfRuby) {
@@ -777,20 +779,20 @@
   GetDocument().View()->UpdateAllLifecyclePhases();
 
   Element* ruby_inline = GetDocument().getElementById("rubyInline");
-  EXPECT_FLOAT_EQ(16.f,
-                  ruby_inline->GetLayoutObject()->Style()->SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(
+      16.f, ruby_inline->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // (specified font-size = 16px) * (viewport width = 800px) /
   // (window width = 320px) = 40px.
-  EXPECT_FLOAT_EQ(40.f,
-                  ruby_inline->GetLayoutObject()->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(
+      40.f, ruby_inline->GetLayoutObject()->StyleRef().ComputedFontSize());
 
   Element* ruby_block = GetDocument().getElementById("rubyBlock");
-  EXPECT_FLOAT_EQ(16.f,
-                  ruby_block->GetLayoutObject()->Style()->SpecifiedFontSize());
+  EXPECT_FLOAT_EQ(
+      16.f, ruby_block->GetLayoutObject()->StyleRef().SpecifiedFontSize());
   // (specified font-size = 16px) * (viewport width = 800px) /
   // (window width = 320px) = 40px.
   EXPECT_FLOAT_EQ(40.f,
-                  ruby_block->GetLayoutObject()->Style()->ComputedFontSize());
+                  ruby_block->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, ResizeAndGlyphOverflowChanged) {
@@ -868,7 +870,7 @@
   //(content width = 200px) / (window width = 320px) < 1.0f, multiplier = 1.0,
   // font-size = 16px;
   EXPECT_FLOAT_EQ(16.f,
-                  content->GetLayoutObject()->Style()->ComputedFontSize());
+                  content->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, LayoutViewWidthProvider) {
@@ -900,7 +902,7 @@
   // (specified font-size = 16px) * (viewport width = 800px) /
   // (window width = 320px) = 40px.
   EXPECT_FLOAT_EQ(40.f,
-                  content->GetLayoutObject()->Style()->ComputedFontSize());
+                  content->GetLayoutObject()->StyleRef().ComputedFontSize());
 
   GetDocument().getElementById("panel")->SetInnerHTMLFromString("insert text");
   content->SetInnerHTMLFromString(content->InnerHTMLAsString());
@@ -909,7 +911,7 @@
   // (specified font-size = 16px) * (viewport width = 800px) /
   // (window width = 320px) = 40px.
   EXPECT_FLOAT_EQ(40.f,
-                  content->GetLayoutObject()->Style()->ComputedFontSize());
+                  content->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, MultiColumns) {
@@ -942,7 +944,8 @@
   Element* target = GetDocument().getElementById("target");
   // (specified font-size = 16px) * ( thread flow layout width = 800px / 3) /
   // (window width = 320px) < 16px.
-  EXPECT_FLOAT_EQ(16.f, target->GetLayoutObject()->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(16.f,
+                  target->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, ScaledbyDSF) {
@@ -970,7 +973,7 @@
   // (specified font-size = 16px) * (thread flow layout width = 800px) /
   // (window width = 320px) * (device scale factor) = 40px * device_scale.
   EXPECT_FLOAT_EQ(40.0f * device_scale,
-                  target->GetLayoutObject()->Style()->ComputedFontSize());
+                  target->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, ClusterHasNotEnoughTextToAutosizeForZoomDSF) {
@@ -992,7 +995,8 @@
   // minimum_text_length_to_autosize < length. Thus, ClusterMultiplier()
   // returns 1 (not multiplied by the accessibility font scale factor).
   // computed font-size = specified font-size = 8px.
-  EXPECT_FLOAT_EQ(8.0f, target->GetLayoutObject()->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(8.0f,
+                  target->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 // TODO(jaebaek): Unit tests ClusterHasNotEnoughTextToAutosizeForZoomDSF and
@@ -1029,7 +1033,7 @@
   // ClusterHasEnoughTextToAutosize() returns true and both accessibility font
   // scale factor and device scale factor are multiplied.
   EXPECT_FLOAT_EQ(20.0f * device_scale,
-                  target->GetLayoutObject()->Style()->ComputedFontSize());
+                  target->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 
 TEST_F(TextAutosizerTest, AfterPrint) {
@@ -1051,11 +1055,12 @@
   )HTML");
   Element* target = GetDocument().getElementById("target");
   EXPECT_FLOAT_EQ(20.0f * device_scale,
-                  target->GetLayoutObject()->Style()->ComputedFontSize());
+                  target->GetLayoutObject()->StyleRef().ComputedFontSize());
   GetDocument().GetFrame()->StartPrinting(print_size, print_size, 1.0);
-  EXPECT_FLOAT_EQ(8.0f, target->GetLayoutObject()->Style()->ComputedFontSize());
+  EXPECT_FLOAT_EQ(8.0f,
+                  target->GetLayoutObject()->StyleRef().ComputedFontSize());
   GetDocument().GetFrame()->EndPrinting();
   EXPECT_FLOAT_EQ(20.0f * device_scale,
-                  target->GetLayoutObject()->Style()->ComputedFontSize());
+                  target->GetLayoutObject()->StyleRef().ComputedFontSize());
 }
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc
index 940d69d..d1e925ec 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -155,9 +155,9 @@
       } else {
         OriginAccessEntry access_entry(
             request.Url().Protocol(), request.Url().Host(),
-            OriginAccessEntry::kAllowRegisterableDomains);
+            network::cors::OriginAccessEntry::kAllowRegisterableDomains);
         if (access_entry.MatchesOrigin(*GetSecurityOrigin()) ==
-            OriginAccessEntry::kMatchesOrigin) {
+            network::cors::OriginAccessEntry::kMatchesOrigin) {
           site_value = "same-site";
         }
       }
diff --git a/third_party/blink/renderer/core/loader/link_loader.cc b/third_party/blink/renderer/core/loader/link_loader.cc
index c90c90bd..c9400a6 100644
--- a/third_party/blink/renderer/core/loader/link_loader.cc
+++ b/third_party/blink/renderer/core/loader/link_loader.cc
@@ -574,9 +574,13 @@
 
     ResourceRequest resource_request(params.href);
     resource_request.SetReferrerPolicy(params.referrer_policy);
-
     resource_request.SetFetchImportanceMode(
         GetFetchImportanceAttributeValue(params.importance));
+    if (RuntimeEnabledFeatures::SignedHTTPExchangeEnabled()) {
+      DEFINE_STATIC_LOCAL(const AtomicString, accept_prefetch,
+                          ("application/signed-exchange;v=b1;q=0.9,*/*;q=0.8"));
+      resource_request.SetHTTPAccept(accept_prefetch);
+    }
 
     ResourceLoaderOptions options;
     options.initiator_info.name = FetchInitiatorTypeNames::link;
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource.cc b/third_party/blink/renderer/core/loader/resource/image_resource.cc
index 86c73da..727f74f 100644
--- a/third_party/blink/renderer/core/loader/resource/image_resource.cc
+++ b/third_party/blink/renderer/core/loader/resource/image_resource.cc
@@ -24,7 +24,9 @@
 #include "third_party/blink/renderer/core/loader/resource/image_resource.h"
 
 #include <stdint.h>
+#include <algorithm>
 #include <memory>
+#include <utility>
 
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
@@ -74,7 +76,8 @@
   USING_GARBAGE_COLLECTED_MIXIN(ImageResourceInfoImpl);
 
  public:
-  ImageResourceInfoImpl(ImageResource* resource) : resource_(resource) {
+  explicit ImageResourceInfoImpl(ImageResource* resource)
+      : resource_(resource) {
     DCHECK(resource_);
   }
   void Trace(blink::Visitor* visitor) override {
@@ -139,7 +142,7 @@
   STACK_ALLOCATED();
 
  public:
-  ImageResourceFactory(const FetchParameters& fetch_params)
+  explicit ImageResourceFactory(const FetchParameters& fetch_params)
       : NonTextResourceFactory(Resource::kImage),
         fetch_params_(&fetch_params) {}
 
@@ -234,9 +237,8 @@
   Resource::OnMemoryDump(level_of_detail, memory_dump);
   const String name = GetMemoryDumpName() + "/image_content";
   auto* dump = memory_dump->CreateMemoryAllocatorDump(name);
-  size_t encoded_size =
-      content_->HasImage() ? content_->GetImage()->Data()->size() : 0;
-  dump->AddScalar("size", "bytes", encoded_size);
+  if (content_->HasImage() && content_->GetImage()->Data())
+    dump->AddScalar("size", "bytes", content_->GetImage()->Data()->size());
 }
 
 void ImageResource::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/mojo/mojo_handle.cc b/third_party/blink/renderer/core/mojo/mojo_handle.cc
index 9932560..a77ab76 100644
--- a/third_party/blink/renderer/core/mojo/mojo_handle.cc
+++ b/third_party/blink/renderer/core/mojo/mojo_handle.cc
@@ -221,10 +221,12 @@
   result_dict.setResult(result);
   if (result == MOJO_RESULT_OK) {
     WTF::ArrayBufferContents::DataHandle data_handle(
-        data, num_bytes, [](void* buffer) {
+        data, num_bytes,
+        [](void* buffer, size_t length, void* alloc_data) {
           MojoResult result = MojoUnmapBuffer(buffer);
           DCHECK_EQ(result, MOJO_RESULT_OK);
-        });
+        },
+        nullptr);
     WTF::ArrayBufferContents contents(std::move(data_handle),
                                       WTF::ArrayBufferContents::kNotShared);
     result_dict.setBuffer(DOMArrayBuffer::Create(contents));
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index b3351795..f346ef04 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -1176,8 +1176,8 @@
     UpdateFilters();
 
   if (!GetLayoutObject()
-           .Style()
-           ->IsRunningBackdropFilterAnimationOnCompositor())
+           .StyleRef()
+           .IsRunningBackdropFilterAnimationOnCompositor())
     UpdateBackdropFilters();
 
   IntRect local_compositing_bounds;
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc b/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
index 0f9721c..1e011f6df 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
@@ -203,11 +203,11 @@
            .StyleRef()
            .SubtreeWillChangeContents() &&
        squashing_layer.GetLayoutObject()
-           .Style()
-           ->IsRunningAnimationOnCompositor()) ||
+           .StyleRef()
+           .IsRunningAnimationOnCompositor()) ||
       squashing_layer.GetLayoutObject()
-          .Style()
-          ->ShouldCompositeForCurrentAnimations())
+          .StyleRef()
+          .ShouldCompositeForCurrentAnimations())
     return SquashingDisallowedReason::kSquashingLayerIsAnimating;
 
   if (layer->EnclosingPaginationLayer())
@@ -314,8 +314,8 @@
       if (ScrollingCoordinator* scrolling_coordinator =
               layer->GetScrollingCoordinator()) {
         if (layer->GetLayoutObject()
-                .Style()
-                ->HasViewportConstrainedPosition()) {
+                .StyleRef()
+                .HasViewportConstrainedPosition()) {
           scrolling_coordinator->FrameViewFixedObjectsDidChange(
               layer->GetLayoutObject().View()->GetFrameView());
         }
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
index 7918a5d..05e8195 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
@@ -192,7 +192,7 @@
   //
   // TODO(smcgruer): Only composite fixed if needed (http://crbug.com/742213)
   const bool ignore_lcd_text = true;
-  if (layer->GetLayoutObject().Style()->GetPosition() == EPosition::kFixed ||
+  if (layer->GetLayoutObject().StyleRef().GetPosition() == EPosition::kFixed ||
       compositing_reason_finder.RequiresCompositingForScrollDependentPosition(
           layer, ignore_lcd_text)) {
     subtree_reasons |=
diff --git a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
index c174e18a..44a593b 100644
--- a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
+++ b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
@@ -302,8 +302,8 @@
   bool ltr = inline_text_box_.IsLeftToRightDirection();
   bool flow_is_ltr = inline_text_box_.GetLineLayoutItem()
                          .ContainingBlock()
-                         .Style()
-                         ->IsLeftToRightDirection();
+                         .StyleRef()
+                         .IsLeftToRightDirection();
 
   const PaintOffsets& selection_offsets =
       ApplyTruncationToPaintOffsets({static_cast<unsigned>(selection_start),
@@ -451,8 +451,8 @@
   bool ltr = inline_text_box_.IsLeftToRightDirection();
   bool flow_is_ltr = inline_text_box_.GetLineLayoutItem()
                          .ContainingBlock()
-                         .Style()
-                         ->IsLeftToRightDirection();
+                         .StyleRef()
+                         .IsLeftToRightDirection();
 
   // truncation is relative to the start of the InlineTextBox, not the text
   // node.
@@ -647,8 +647,8 @@
 
     // Calculate start & width
     int delta_y = (inline_text_box_.GetLineLayoutItem()
-                           .Style()
-                           ->IsFlippedLinesWritingMode()
+                           .StyleRef()
+                           .IsFlippedLinesWritingMode()
                        ? inline_text_box_.Root().SelectionBottom() -
                              inline_text_box_.LogicalBottom()
                        : inline_text_box_.LogicalTop() -
@@ -690,8 +690,8 @@
   bool ltr = inline_text_box_.IsLeftToRightDirection();
   bool flow_is_ltr = inline_text_box_.GetLineLayoutItem()
                          .ContainingBlock()
-                         .Style()
-                         ->IsLeftToRightDirection();
+                         .StyleRef()
+                         .IsLeftToRightDirection();
   if (inline_text_box_.Truncation() != kCNoTruncation) {
     // In a mixed-direction flow the ellipsis is at the start of the text
     // so we need to start after it. Otherwise we just need to make sure
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 98010d2c..a7b76d96 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -360,8 +360,8 @@
         context_.current.should_flatten_inherited_transform;
 
     state.affected_by_outer_viewport_bounds_delta =
-        object_.Style()->GetPosition() == EPosition::kFixed &&
-        !object_.Style()->Bottom().IsAuto();
+        object_.StyleRef().GetPosition() == EPosition::kFixed &&
+        !object_.StyleRef().Bottom().IsAuto();
 
     if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
         RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
diff --git a/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc b/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
index 6a66bff..8fd02345 100644
--- a/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
+++ b/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
@@ -302,8 +302,8 @@
                                               TextDecoration decoration,
                                               const SVGTextFragment& fragment) {
   if (svg_inline_text_box_.GetLineLayoutItem()
-          .Style()
-          ->TextDecorationsInEffect() == TextDecoration::kNone)
+          .StyleRef()
+          .TextDecorationsInEffect() == TextDecoration::kNone)
     return;
 
   if (fragment.width <= 0)
diff --git a/third_party/blink/renderer/core/script/pending_script.cc b/third_party/blink/renderer/core/script/pending_script.cc
index bd8cdfb2..2a3901e 100644
--- a/third_party/blink/renderer/core/script/pending_script.cc
+++ b/third_party/blink/renderer/core/script/pending_script.cc
@@ -138,12 +138,16 @@
     return;
   }
 
-  // Do not execute module scripts if they are moved between documents.
-  // TODO(hiroshige): Also do not execute classic scripts. crbug.com/721914
-  if (OriginalContextDocument() != context_document &&
-      GetScriptType() == ScriptType::kModule) {
-    Dispose();
-    return;
+  if (OriginalContextDocument() != context_document) {
+    if (GetScriptType() == ScriptType::kModule) {
+      // Do not execute module scripts if they are moved between documents.
+      Dispose();
+      return;
+    }
+
+    // TODO(hiroshige): Also do not execute classic scripts.
+    // https://crbug.com/721914
+    UseCounter::Count(frame, WebFeature::kEvaluateScriptMovedBetweenDocuments);
   }
 
   Script* script = GetSource(document_url);
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image.cc b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
index cfbb9f3..e7da7c0 100644
--- a/third_party/blink/renderer/core/svg/graphics/svg_image.cc
+++ b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
@@ -187,7 +187,7 @@
     return container_size;
 
   // Assure that a container size is always given for a non-identity zoom level.
-  DCHECK_EQ(layout_object->Style()->EffectiveZoom(), 1);
+  DCHECK_EQ(layout_object->StyleRef().EffectiveZoom(), 1);
 
   // No set container size; use concrete object size.
   return intrinsic_size_;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
index 54ece7a..53b5eae 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
@@ -67,7 +67,7 @@
     DCHECK(layout_object);
     DCHECK(layout_object->Style());
     return diffuse_lighting->SetLightingColor(
-        layout_object->Style()->SvgStyle().LightingColor());
+        layout_object->StyleRef().SvgStyle().LightingColor());
   }
   if (attr_name == SVGNames::surfaceScaleAttr)
     return diffuse_lighting->SetSurfaceScale(
@@ -151,7 +151,7 @@
     return nullptr;
 
   DCHECK(layout_object->Style());
-  Color color = layout_object->Style()->SvgStyle().LightingColor();
+  Color color = layout_object->StyleRef().SvgStyle().LightingColor();
 
   const SVGFELightElement* light_node =
       SVGFELightElement::FindLightElement(*this);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
index 751caf8b..cc7cccdc 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
@@ -103,7 +103,7 @@
     return nullptr;
 
   DCHECK(layout_object->Style());
-  const SVGComputedStyle& svg_style = layout_object->Style()->SvgStyle();
+  const SVGComputedStyle& svg_style = layout_object->StyleRef().SvgStyle();
 
   Color color = svg_style.FloodColor();
   float opacity = svg_style.FloodOpacity();
diff --git a/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc b/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
index 5355841..0600bab19 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
@@ -56,7 +56,7 @@
     return nullptr;
 
   DCHECK(layout_object->Style());
-  const SVGComputedStyle& svg_style = layout_object->Style()->SvgStyle();
+  const SVGComputedStyle& svg_style = layout_object->StyleRef().SvgStyle();
 
   Color color = svg_style.FloodColor();
   float opacity = svg_style.FloodOpacity();
diff --git a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
index 8b665f73..88f88f9 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
@@ -77,7 +77,7 @@
     DCHECK(layout_object);
     DCHECK(layout_object->Style());
     return specular_lighting->SetLightingColor(
-        layout_object->Style()->SvgStyle().LightingColor());
+        layout_object->StyleRef().SvgStyle().LightingColor());
   }
   if (attr_name == SVGNames::surfaceScaleAttr)
     return specular_lighting->SetSurfaceScale(
@@ -164,7 +164,7 @@
     return nullptr;
 
   DCHECK(layout_object->Style());
-  Color color = layout_object->Style()->SvgStyle().LightingColor();
+  Color color = layout_object->StyleRef().SvgStyle().LightingColor();
 
   const SVGFELightElement* light_node =
       SVGFELightElement::FindLightElement(*this);
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 7096142..78b2eabe 100644
--- a/third_party/blink/renderer/core/svg/svg_geometry_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_geometry_element.cc
@@ -95,7 +95,7 @@
   HitTestRequest request(HitTestRequest::kReadOnly);
   PointerEventsHitRules hit_rules(
       PointerEventsHitRules::SVG_GEOMETRY_HITTESTING, request,
-      GetLayoutObject()->Style()->PointerEvents());
+      GetLayoutObject()->StyleRef().PointerEvents());
   hit_rules.can_hit_stroke = false;
   return ToLayoutSVGShape(GetLayoutObject())
       ->NodeAtFloatPointInternal(request, point->Target()->Value(), hit_rules);
@@ -112,7 +112,7 @@
   HitTestRequest request(HitTestRequest::kReadOnly);
   PointerEventsHitRules hit_rules(
       PointerEventsHitRules::SVG_GEOMETRY_HITTESTING, request,
-      GetLayoutObject()->Style()->PointerEvents());
+      GetLayoutObject()->StyleRef().PointerEvents());
   hit_rules.can_hit_fill = false;
   return ToLayoutSVGShape(GetLayoutObject())
       ->NodeAtFloatPointInternal(request, point->Target()->Value(), hit_rules);
@@ -124,7 +124,7 @@
 
   DCHECK(GetLayoutObject());
   DCHECK(GetLayoutObject()->Style());
-  path.SetWindRule(GetLayoutObject()->Style()->SvgStyle().ClipRule());
+  path.SetWindRule(GetLayoutObject()->StyleRef().SvgStyle().ClipRule());
   return path;
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_svg_element.cc b/third_party/blink/renderer/core/svg/svg_svg_element.cc
index 7a43561..f681199 100644
--- a/third_party/blink/renderer/core/svg/svg_svg_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_svg_element.cc
@@ -329,7 +329,7 @@
   LayoutObject* layout_object = element.GetLayoutObject();
   DCHECK(!layout_object || layout_object->Style());
   if (!layout_object ||
-      layout_object->Style()->PointerEvents() == EPointerEvents::kNone)
+      layout_object->StyleRef().PointerEvents() == EPointerEvents::kNone)
     return false;
 
   if (!IsIntersectionOrEnclosureTarget(layout_object))
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 91b0b66a..c359a8d 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -3054,7 +3054,7 @@
 ScriptPromise Internals::promiseCheck(ScriptState* script_state,
                                       long arg1,
                                       bool arg2,
-                                      const Dictionary& arg3,
+                                      const ScriptValue& arg3,
                                       const String& arg4,
                                       const Vector<String>& arg5,
                                       ExceptionState& exception_state) {
@@ -3068,7 +3068,7 @@
 
 ScriptPromise Internals::promiseCheckWithoutExceptionState(
     ScriptState* script_state,
-    const Dictionary& arg1,
+    const ScriptValue& arg1,
     const String& arg2,
     const Vector<String>& arg3) {
   return ScriptPromise::Cast(script_state,
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h
index 1f8fb70..804debac 100644
--- a/third_party/blink/renderer/core/testing/internals.h
+++ b/third_party/blink/renderer/core/testing/internals.h
@@ -49,7 +49,6 @@
 class DOMArrayBuffer;
 class DOMPoint;
 class DOMWindow;
-class Dictionary;
 class DictionaryTest;
 class Document;
 class DocumentMarker;
@@ -469,12 +468,12 @@
   ScriptPromise promiseCheck(ScriptState*,
                              long,
                              bool,
-                             const Dictionary&,
+                             const ScriptValue&,
                              const String&,
                              const Vector<String>&,
                              ExceptionState&);
   ScriptPromise promiseCheckWithoutExceptionState(ScriptState*,
-                                                  const Dictionary&,
+                                                  const ScriptValue&,
                                                   const String&,
                                                   const Vector<String>&);
   ScriptPromise promiseCheckRange(ScriptState*, long);
diff --git a/third_party/blink/renderer/core/testing/internals.idl b/third_party/blink/renderer/core/testing/internals.idl
index b4d63f2..fc81aaaa 100644
--- a/third_party/blink/renderer/core/testing/internals.idl
+++ b/third_party/blink/renderer/core/testing/internals.idl
@@ -310,8 +310,8 @@
     [CallWith=ScriptState] Promise createResolvedPromise(any value);
     [CallWith=ScriptState] Promise createRejectedPromise(any reason);
     [CallWith=ScriptState] Promise addOneToPromise(Promise promise);
-    [CallWith=ScriptState, RaisesException] Promise promiseCheck(long arg1, boolean arg2, Dictionary arg3, DOMString arg4, sequence<DOMString> arg5);
-    [CallWith=ScriptState] Promise promiseCheckWithoutExceptionState(Dictionary arg1, DOMString arg2, DOMString... variadic);
+    [CallWith=ScriptState, RaisesException] Promise promiseCheck(long arg1, boolean arg2, object arg3, DOMString arg4, sequence<DOMString> arg5);
+    [CallWith=ScriptState] Promise promiseCheckWithoutExceptionState(object arg1, DOMString arg2, DOMString... variadic);
     [CallWith=ScriptState] Promise promiseCheckRange([EnforceRange] octet arg1);
     [CallWith=ScriptState] Promise promiseCheckOverload(Location arg1);
     [CallWith=ScriptState] Promise promiseCheckOverload(Document arg1);
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
index 39ed2357..e5bc036 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
@@ -112,6 +112,7 @@
 
   if (registration) {
     DCHECK_EQ(error, mojom::blink::BackgroundFetchError::NONE);
+    DCHECK_EQ(registration->state(), "pending");
     registration->Initialize(GetSupplementable());
   }
 
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 abfb942cf..dbe549d 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
@@ -330,6 +330,11 @@
           script_state->GetIsolate(),
           "There already is a registration for the given id."));
       return;
+    case mojom::blink::BackgroundFetchError::PERMISSION_DENIED:
+      resolver->Reject(V8ThrowException::CreateTypeError(
+          script_state->GetIsolate(),
+          "This origin does not have permission to start a fetch."));
+      return;
     case mojom::blink::BackgroundFetchError::STORAGE_ERROR:
       DCHECK(!registration);
       resolver->Reject(V8ThrowException::CreateTypeError(
@@ -468,6 +473,7 @@
       return;
     case mojom::blink::BackgroundFetchError::DUPLICATED_DEVELOPER_ID:
     case mojom::blink::BackgroundFetchError::INVALID_ARGUMENT:
+    case mojom::blink::BackgroundFetchError::PERMISSION_DENIED:
     case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED:
       // Not applicable for this callback.
       break;
@@ -517,6 +523,7 @@
     case mojom::blink::BackgroundFetchError::DUPLICATED_DEVELOPER_ID:
     case mojom::blink::BackgroundFetchError::INVALID_ARGUMENT:
     case mojom::blink::BackgroundFetchError::INVALID_ID:
+    case mojom::blink::BackgroundFetchError::PERMISSION_DENIED:
     case mojom::blink::BackgroundFetchError::SERVICE_WORKER_UNAVAILABLE:
     case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED:
       // Not applicable for this callback.
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
index c639519..36200481 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h"
 
 #include "base/optional.h"
+#include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h"
 #include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
@@ -39,6 +40,21 @@
       state_(state),
       observer_binding_(this) {}
 
+BackgroundFetchRegistration::BackgroundFetchRegistration(
+    ServiceWorkerRegistration* registration,
+    const WebBackgroundFetchRegistration& web_registration)
+    : developer_id_(web_registration.developer_id),
+      unique_id_(web_registration.unique_id),
+      upload_total_(web_registration.upload_total),
+      uploaded_(web_registration.uploaded),
+      download_total_(web_registration.download_total),
+      downloaded_(web_registration.downloaded),
+      state_(web_registration.state),
+      observer_binding_(this) {
+  DCHECK(registration);
+  Initialize(registration);
+}
+
 BackgroundFetchRegistration::~BackgroundFetchRegistration() = default;
 
 void BackgroundFetchRegistration::Initialize(
@@ -226,6 +242,7 @@
     case mojom::blink::BackgroundFetchError::SERVICE_WORKER_UNAVAILABLE:
     case mojom::blink::BackgroundFetchError::DUPLICATED_DEVELOPER_ID:
     case mojom::blink::BackgroundFetchError::INVALID_ARGUMENT:
+    case mojom::blink::BackgroundFetchError::PERMISSION_DENIED:
     case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED:
       // Not applicable for this callback.
       break;
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h
index 7e7efc4..8366ed6 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h
@@ -21,6 +21,7 @@
 class ScriptState;
 class ServiceWorkerRegistration;
 class RequestOrUSVString;
+struct WebBackgroundFetchRegistration;
 
 // Represents an individual Background Fetch registration. Gives developers
 // access to its properties, options, and enables them to abort the fetch.
@@ -38,6 +39,11 @@
                               unsigned long long download_total,
                               unsigned long long downloaded,
                               mojom::BackgroundFetchState state);
+
+  BackgroundFetchRegistration(
+      ServiceWorkerRegistration* registration,
+      const WebBackgroundFetchRegistration& web_registration);
+
   ~BackgroundFetchRegistration() override;
 
   // Initializes the BackgroundFetchRegistration to be associated with the given
@@ -69,6 +75,9 @@
   unsigned long long uploaded() const;
   unsigned long long downloadTotal() const;
   unsigned long long downloaded() const;
+  const String state() const;
+
+  const String& unique_id() const { return unique_id_; }
 
   DEFINE_ATTRIBUTE_EVENT_LISTENER(progress);
 
@@ -78,9 +87,6 @@
   const AtomicString& InterfaceName() const override;
   ExecutionContext* GetExecutionContext() const override;
 
-  const String& unique_id() const { return unique_id_; }
-  const String state() const;
-
   void Dispose();
 
   void Trace(blink::Visitor* visitor) override;
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc
index b4b7d6d..27deb460 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc
@@ -23,7 +23,7 @@
       mojo_registration->developer_id, mojo_registration->unique_id,
       mojo_registration->upload_total, mojo_registration->uploaded,
       mojo_registration->download_total, mojo_registration->downloaded,
-      blink::mojom::BackgroundFetchState::PENDING);
+      mojo_registration->state);
 }
 
 blink::mojom::blink::BackgroundFetchOptionsPtr TypeConverter<
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc
index d1b219c..6df619e 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc
@@ -113,6 +113,7 @@
     case mojom::blink::BackgroundFetchError::DUPLICATED_DEVELOPER_ID:
     case mojom::blink::BackgroundFetchError::INVALID_ARGUMENT:
     case mojom::blink::BackgroundFetchError::SERVICE_WORKER_UNAVAILABLE:
+    case mojom::blink::BackgroundFetchError::PERMISSION_DENIED:
     case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED:
       // Not applicable for this callback.
       break;
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
index 9f399a23..863f1fd 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -154,8 +154,9 @@
 
   // TODO(crbug.com/803077): Avoid constructing an OriginAccessEntry just
   // for the IP address check.
-  OriginAccessEntry access_entry(origin->Protocol(), effective_domain,
-                                 blink::OriginAccessEntry::kAllowSubdomains);
+  OriginAccessEntry access_entry(
+      origin->Protocol(), effective_domain,
+      network::cors::OriginAccessEntry::MatchMode::kAllowSubdomains);
   if (effective_domain.IsEmpty() || access_entry.HostIsIPAddress()) {
     resolver->Reject(
         DOMException::Create(DOMExceptionCode::kSecurityError,
@@ -167,11 +168,12 @@
   // https://w3c.github.io/webauthn/#CreateCred-DetermineRpId and
   // https://w3c.github.io/webauthn/#GetAssn-DetermineRpId.
   if (!relying_party_id.IsNull()) {
-    OriginAccessEntry access_entry(origin->Protocol(), relying_party_id,
-                                   blink::OriginAccessEntry::kAllowSubdomains);
+    OriginAccessEntry access_entry(
+        origin->Protocol(), relying_party_id,
+        network::cors::OriginAccessEntry::kAllowSubdomains);
     if (relying_party_id.IsEmpty() ||
         access_entry.MatchesDomain(*origin) !=
-            blink::OriginAccessEntry::kMatchesOrigin) {
+            network::cors::OriginAccessEntry::kMatchesOrigin) {
       resolver->Reject(DOMException::Create(
           DOMExceptionCode::kSecurityError,
           "The relying party ID '" + relying_party_id +
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
index e6a4a40..464688b6 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -117,9 +117,7 @@
 
 void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchAbortEvent(
     int event_id,
-    const WebString& developer_id,
-    const WebString& unique_id,
-    blink::mojom::BackgroundFetchState state) {
+    const WebBackgroundFetchRegistration& registration) {
   DCHECK(WorkerGlobalScope()->IsContextThread());
   WaitUntilObserver* observer = WaitUntilObserver::Create(
       WorkerGlobalScope(), WaitUntilObserver::kBackgroundFetchAbort, event_id);
@@ -131,13 +129,10 @@
   // BackgroundFetchSettledFetches::Create which eventually calls ToV8.
   ScriptState::Scope scope(script_state);
 
-  // TODO(crbug.com/869918): Update to take a BackgroundFetchRegistration
-  // object, or all information required to build one.
-  BackgroundFetchRegistration* registration = new BackgroundFetchRegistration(
-      developer_id, unique_id, 0 /* upload_total */, 0 /* uploaded */,
-      0 /* download_total */, 0 /* downloaded */, state);
   BackgroundFetchEventInit init;
-  init.setRegistration(registration);
+  init.setRegistration(new BackgroundFetchRegistration(
+      WorkerGlobalScope()->registration() /* service_worker_registration */,
+      registration));
 
   BackgroundFetchEvent* event = BackgroundFetchEvent::Create(
       EventTypeNames::backgroundfetchabort, init, observer);
@@ -147,20 +142,15 @@
 
 void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchClickEvent(
     int event_id,
-    const WebString& developer_id,
-    const WebString& unique_id,
-    blink::mojom::BackgroundFetchState state) {
+    const WebBackgroundFetchRegistration& registration) {
   DCHECK(WorkerGlobalScope()->IsContextThread());
   WaitUntilObserver* observer = WaitUntilObserver::Create(
       WorkerGlobalScope(), WaitUntilObserver::kBackgroundFetchClick, event_id);
 
-  // TODO(crbug.com/869918): Update to take a BackgroundFetchRegistration
-  // object, or all information required to build one.
-  BackgroundFetchRegistration* registration = new BackgroundFetchRegistration(
-      developer_id, unique_id, 0 /* upload_total */, 0 /* uploaded */,
-      0 /* download_total */, 0 /* downloaded */, state);
   BackgroundFetchEventInit init;
-  init.setRegistration(registration);
+  init.setRegistration(new BackgroundFetchRegistration(
+      WorkerGlobalScope()->registration() /* service_worker_registration */,
+      registration));
 
   BackgroundFetchEvent* event = BackgroundFetchEvent::Create(
       EventTypeNames::backgroundfetchclick, init, observer);
@@ -170,9 +160,7 @@
 
 void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchFailEvent(
     int event_id,
-    const WebString& developer_id,
-    const WebString& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const WebBackgroundFetchRegistration& registration,
     const WebVector<WebBackgroundFetchSettledFetch>& fetches) {
   DCHECK(WorkerGlobalScope()->IsContextThread());
   WaitUntilObserver* observer = WaitUntilObserver::Create(
@@ -185,13 +173,10 @@
   // BackgroundFetchSettledFetches::Create which eventually calls ToV8.
   ScriptState::Scope scope(script_state);
 
-  // TODO(crbug.com/869918): Update to take a BackgroundFetchRegistration
-  // object, or all information required to build one.
-  BackgroundFetchRegistration* registration = new BackgroundFetchRegistration(
-      developer_id, unique_id, 0 /* upload_total */, 0 /* uploaded */,
-      0 /* download_total */, 0 /* downloaded */, state);
   BackgroundFetchEventInit init;
-  init.setRegistration(registration);
+  init.setRegistration(new BackgroundFetchRegistration(
+      WorkerGlobalScope()->registration() /* service_worker_registration */,
+      registration));
 
   BackgroundFetchUpdateUIEvent* event = BackgroundFetchUpdateUIEvent::Create(
       EventTypeNames::backgroundfetchfail, init, observer,
@@ -204,9 +189,7 @@
 
 void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchSuccessEvent(
     int event_id,
-    const WebString& developer_id,
-    const WebString& unique_id,
-    blink::mojom::BackgroundFetchState state,
+    const WebBackgroundFetchRegistration& registration,
     const WebVector<WebBackgroundFetchSettledFetch>& fetches) {
   DCHECK(WorkerGlobalScope()->IsContextThread());
   WaitUntilObserver* observer = WaitUntilObserver::Create(
@@ -220,13 +203,10 @@
   // BackgroundFetchSettledFetches::Create which eventually calls ToV8.
   ScriptState::Scope scope(script_state);
 
-  // TODO(crbug.com/869918): Update to take a BackgroundFetchRegistration
-  // object, or all information required to build one.
-  BackgroundFetchRegistration* registration = new BackgroundFetchRegistration(
-      developer_id, unique_id, 0 /* upload_total */, 0 /* uploaded */,
-      0 /* download_total */, 0 /* downloaded */, state);
   BackgroundFetchEventInit init;
-  init.setRegistration(registration);
+  init.setRegistration(new BackgroundFetchRegistration(
+      WorkerGlobalScope()->registration() /* service_worker_registration */,
+      registration));
 
   BackgroundFetchUpdateUIEvent* event = BackgroundFetchUpdateUIEvent::Create(
       EventTypeNames::backgroundfetchsuccess, init, observer,
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
index 22509a6d..7ca4e2a 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
@@ -83,25 +83,17 @@
   void DispatchActivateEvent(int) override;
   void DispatchBackgroundFetchAbortEvent(
       int event_id,
-      const WebString& developer_id,
-      const WebString& unique_id,
-      blink::mojom::BackgroundFetchState state) override;
+      const WebBackgroundFetchRegistration& registration) override;
   void DispatchBackgroundFetchClickEvent(
       int event_id,
-      const WebString& developer_id,
-      const WebString& unique_id,
-      blink::mojom::BackgroundFetchState state) override;
+      const WebBackgroundFetchRegistration& registration) override;
   void DispatchBackgroundFetchFailEvent(
       int event_id,
-      const WebString& developer_id,
-      const WebString& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const WebBackgroundFetchRegistration& registration,
       const WebVector<WebBackgroundFetchSettledFetch>& fetches) override;
   void DispatchBackgroundFetchSuccessEvent(
       int event_id,
-      const WebString& developer_id,
-      const WebString& unique_id,
-      blink::mojom::BackgroundFetchState state,
+      const WebBackgroundFetchRegistration& registration,
       const WebVector<WebBackgroundFetchSettledFetch>& fetches) override;
   void DispatchCookieChangeEvent(
       int event_id,
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 7a7e127..ef168b8b 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1829,7 +1829,6 @@
     "web_vector_test.cc",
     "weborigin/known_ports_test.cc",
     "weborigin/kurl_test.cc",
-    "weborigin/origin_access_entry_test.cc",
     "weborigin/scheme_registry_test.cc",
     "weborigin/security_origin_test.cc",
     "weborigin/security_policy_test.cc",
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
index 11e20df..c98c6ec 100644
--- a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
+++ b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
@@ -66,10 +66,13 @@
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     V8ContextSnapshotMode v8_context_snapshot_mode)
     : v8_context_snapshot_mode_(v8_context_snapshot_mode),
-      isolate_holder_(task_runner,
-                      gin::IsolateHolder::kSingleThread,
-                      IsMainThread() ? gin::IsolateHolder::kDisallowAtomicsWait
-                                     : gin::IsolateHolder::kAllowAtomicsWait),
+      isolate_holder_(
+          task_runner,
+          gin::IsolateHolder::kSingleThread,
+          IsMainThread() ? gin::IsolateHolder::kDisallowAtomicsWait
+                         : gin::IsolateHolder::kAllowAtomicsWait,
+          IsMainThread() ? gin::IsolateHolder::IsolateType::kBlinkMainThread
+                         : gin::IsolateHolder::IsolateType::kBlinkWorkerThread),
       interface_template_map_for_v8_context_snapshot_(GetIsolate()),
       string_cache_(std::make_unique<StringCache>(GetIsolate())),
       private_property_(V8PrivateProperty::Create()),
@@ -94,6 +97,7 @@
       isolate_holder_(Platform::Current()->MainThread()->GetTaskRunner(),
                       gin::IsolateHolder::kSingleThread,
                       gin::IsolateHolder::kAllowAtomicsWait,
+                      gin::IsolateHolder::IsolateType::kBlinkMainThread,
                       gin::IsolateHolder::IsolateCreationMode::kCreateSnapshot),
       interface_template_map_for_v8_context_snapshot_(GetIsolate()),
       string_cache_(std::make_unique<StringCache>(GetIsolate())),
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index c4b40a8..38a936d2 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -380,6 +380,10 @@
   RuntimeEnabledFeatures::SetSharedWorkerEnabled(enable);
 }
 
+void WebRuntimeFeatures::EnableSignedHTTPExchange(bool enable) {
+  RuntimeEnabledFeatures::SetSignedHTTPExchangeEnabled(enable);
+}
+
 void WebRuntimeFeatures::EnablePreciseMemoryInfo(bool enable) {
   RuntimeEnabledFeatures::SetPreciseMemoryInfoEnabled(enable);
 }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index c5bf2ad..5e61a7fb 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1123,6 +1123,9 @@
       status: "experimental",
     },
     {
+      name: "SignedHTTPExchange",
+    },
+    {
       name: "SlimmingPaintV2",
     },
     {
diff --git a/third_party/blink/renderer/platform/weborigin/DEPS b/third_party/blink/renderer/platform/weborigin/DEPS
index b33b9de..8dd4818 100644
--- a/third_party/blink/renderer/platform/weborigin/DEPS
+++ b/third_party/blink/renderer/platform/weborigin/DEPS
@@ -9,6 +9,7 @@
     # net/ includes should be allowed only in a limited set of directories,
     # so we have separate DEPS from platform's one.
     "+net/base",
+    "+services/network/public/cpp/cors/origin_access_entry.h",
     "+third_party/blink/renderer/platform/blob/blob_url.h",
     "+third_party/blink/renderer/platform/platform_export.h",
     "+third_party/blink/renderer/platform/runtime_enabled_features.h",
diff --git a/third_party/blink/renderer/platform/weborigin/origin_access_entry.cc b/third_party/blink/renderer/platform/weborigin/origin_access_entry.cc
index 37220fd5..9e729629 100644
--- a/third_party/blink/renderer/platform/weborigin/origin_access_entry.cc
+++ b/third_party/blink/renderer/platform/weborigin/origin_access_entry.cc
@@ -30,143 +30,32 @@
 
 #include "third_party/blink/renderer/platform/weborigin/origin_access_entry.h"
 
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
-#include "url/third_party/mozilla/url_parse.h"
-#include "url/url_canon.h"
 
 namespace blink {
 
-namespace {
+OriginAccessEntry::OriginAccessEntry(
+    const String& protocol,
+    const String& host,
+    network::cors::OriginAccessEntry::MatchMode match_mode)
+    : private_(std::string(protocol.Utf8().data()),
+               std::string(host.Utf8().data()),
+               match_mode) {}
 
-// TODO(mkwst): This basically replicates GURL::HostIsIPAddress. If/when
-// we re-evaluate everything after merging the Blink and Chromium
-// repositories, perhaps we can just use that directly.
-bool HostIsIPAddress(const String& host) {
-  if (host.IsEmpty())
-    return false;
+OriginAccessEntry::OriginAccessEntry(OriginAccessEntry&& from) = default;
 
-  String protocol("https://");
-  KURL url(NullURL(), protocol + host + "/");
-  if (!url.IsValid())
-    return false;
-
-  url::RawCanonOutputT<char, 128> ignored_output;
-  url::CanonHostInfo host_info;
-  url::Component host_component(0,
-                                static_cast<int>(url.Host().Utf8().length()));
-  url::CanonicalizeIPAddress(url.Host().Utf8().data(), host_component,
-                             &ignored_output, &host_info);
-  return host_info.IsIPAddress();
-}
-
-bool IsSubdomainOfHost(const String& subdomain, const String& host) {
-  if (subdomain.length() <= host.length())
-    return false;
-
-  if (subdomain[subdomain.length() - host.length() - 1] != '.')
-    return false;
-
-  if (!subdomain.EndsWith(host))
-    return false;
-
-  return true;
-}
-}  // namespace
-
-OriginAccessEntry::OriginAccessEntry(const String& protocol,
-                                     const String& host,
-                                     SubdomainSetting subdomain_setting)
-    : protocol_(protocol),
-      host_(host),
-      subdomain_settings_(subdomain_setting),
-      host_is_public_suffix_(false) {
-  DCHECK(subdomain_setting >= kAllowSubdomains ||
-         subdomain_setting <= kDisallowSubdomains);
-
-  host_is_ip_address_ = blink::HostIsIPAddress(host);
-
-  // Look for top-level domains, either with or without an additional dot.
-  if (!host_is_ip_address_) {
-    // Blink passes some things that aren't technically hosts like "*.foo", so
-    // use the permissive variant.
-    size_t public_suffix_length =
-        net::registry_controlled_domains::PermissiveGetHostRegistryLength(
-            StringUTF8Adaptor(host_).AsStringPiece(),
-            net::registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES,
-            net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
-    if (public_suffix_length == 0)
-      public_suffix_length = host_.length();
-
-    if (host_.length() <= public_suffix_length + 1) {
-      host_is_public_suffix_ = true;
-    } else if (subdomain_setting == kAllowRegisterableDomains &&
-               public_suffix_length) {
-      // The "2" in the next line is 1 for the '.', plus a 1-char minimum label
-      // length.
-      const size_t dot =
-          host_.ReverseFind('.', host_.length() - public_suffix_length - 2);
-      if (dot == kNotFound)
-        registerable_domain_ = host;
-      else
-        registerable_domain_ = host.Substring(dot + 1);
-    }
-  }
-}
-
-OriginAccessEntry::MatchResult OriginAccessEntry::MatchesOrigin(
+network::cors::OriginAccessEntry::MatchResult OriginAccessEntry::MatchesOrigin(
     const SecurityOrigin& origin) const {
-  if (protocol_ != origin.Protocol())
-    return kDoesNotMatchOrigin;
-
-  return MatchesDomain(origin);
+  return private_.MatchesOrigin(origin.ToUrlOrigin());
 }
 
-OriginAccessEntry::MatchResult OriginAccessEntry::MatchesDomain(
+network::cors::OriginAccessEntry::MatchResult OriginAccessEntry::MatchesDomain(
     const SecurityOrigin& origin) const {
-  // Special case: Include subdomains and empty host means "all hosts, including
-  // ip addresses".
-  if (subdomain_settings_ != kDisallowSubdomains && host_.IsEmpty())
-    return kMatchesOrigin;
+  return private_.MatchesDomain(origin.ToUrlOrigin());
+}
 
-  // Exact match.
-  if (host_ == origin.Host())
-    return kMatchesOrigin;
-
-  // Don't try to do subdomain matching on IP addresses.
-  if (host_is_ip_address_)
-    return kDoesNotMatchOrigin;
-
-  // Match subdomains.
-  switch (subdomain_settings_) {
-    case kDisallowSubdomains:
-      return kDoesNotMatchOrigin;
-
-    case kAllowSubdomains:
-      if (!IsSubdomainOfHost(origin.Host(), host_))
-        return kDoesNotMatchOrigin;
-      break;
-
-    case kAllowRegisterableDomains:
-      // Fall back to a simple subdomain check if no registerable domain could
-      // be found:
-      if (registerable_domain_.IsEmpty()) {
-        if (!IsSubdomainOfHost(origin.Host(), host_))
-          return kDoesNotMatchOrigin;
-      } else if (registerable_domain_ != origin.Host() &&
-                 !IsSubdomainOfHost(origin.Host(), registerable_domain_)) {
-        return kDoesNotMatchOrigin;
-      }
-      break;
-  };
-
-  if (host_is_public_suffix_)
-    return kMatchesOriginButIsPublicSuffix;
-
-  return kMatchesOrigin;
+bool OriginAccessEntry::HostIsIPAddress() const {
+  return private_.host_is_ip_address();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/weborigin/origin_access_entry.h b/third_party/blink/renderer/platform/weborigin/origin_access_entry.h
index 73212c78..037cae5 100644
--- a/third_party/blink/renderer/platform/weborigin/origin_access_entry.h
+++ b/third_party/blink/renderer/platform/weborigin/origin_access_entry.h
@@ -31,6 +31,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBORIGIN_ORIGIN_ACCESS_ENTRY_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBORIGIN_ORIGIN_ACCESS_ENTRY_H_
 
+#include "services/network/public/cpp/cors/origin_access_entry.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -39,67 +40,35 @@
 
 class SecurityOrigin;
 
+// A class to wrap network::cors::OriginAccessEntry to use with Blink types.
 class PLATFORM_EXPORT OriginAccessEntry {
   USING_FAST_MALLOC(OriginAccessEntry);
 
  public:
-  enum SubdomainSetting {
-    // 'www.example.com' matches an OriginAccessEntry for 'example.com'
-    kAllowSubdomains,
-
-    // 'www.example.com' matches an OriginAccessEntry for 'not-www.example.com'
-    kAllowRegisterableDomains,
-
-    // 'www.example.com' does not match an OriginAccessEntry for 'example.com'
-    kDisallowSubdomains
-  };
-
-  enum MatchResult {
-    kMatchesOrigin,
-    kMatchesOriginButIsPublicSuffix,
-    kDoesNotMatchOrigin
-  };
-
-  // If host is empty string and SubdomainSetting is not DisallowSubdomains, the
-  // entry will match all domains in the specified protocol.
+  // If host is empty string and MatchMode is not DisallowSubdomains, the entry
+  // will match all domains in the specified protocol.
   // IPv6 addresses must include brackets (e.g.
   // '[2001:db8:85a3::8a2e:370:7334]', not '2001:db8:85a3::8a2e:370:7334').
   OriginAccessEntry(const String& protocol,
                     const String& host,
-                    SubdomainSetting);
+                    network::cors::OriginAccessEntry::MatchMode);
+  OriginAccessEntry(OriginAccessEntry&& from);
 
   // 'matchesOrigin' requires a protocol match (e.g. 'http' != 'https').
   // 'matchesDomain' relaxes this constraint.
-  MatchResult MatchesOrigin(const SecurityOrigin&) const;
-  MatchResult MatchesDomain(const SecurityOrigin&) const;
+  network::cors::OriginAccessEntry::MatchResult MatchesOrigin(
+      const SecurityOrigin&) const;
+  network::cors::OriginAccessEntry::MatchResult MatchesDomain(
+      const SecurityOrigin&) const;
 
-  const String& Protocol() const { return protocol_; }
-  const String& Host() const { return host_; }
-  SubdomainSetting SubdomainSettings() const { return subdomain_settings_; }
-  bool HostIsIPAddress() const { return host_is_ip_address_; }
-  const String& Registerable() const { return registerable_domain_; }
+  bool HostIsIPAddress() const;
 
  private:
-  String protocol_;
-  String host_;
-  String registerable_domain_;
-  SubdomainSetting subdomain_settings_;
-  bool host_is_ip_address_;
-  bool host_is_public_suffix_;
+  network::cors::OriginAccessEntry private_;
+
+  DISALLOW_COPY_AND_ASSIGN(OriginAccessEntry);
 };
 
-PLATFORM_EXPORT inline bool operator==(const OriginAccessEntry& a,
-                                       const OriginAccessEntry& b) {
-  return EqualIgnoringASCIICase(a.Protocol(), b.Protocol()) &&
-         EqualIgnoringASCIICase(a.Host(), b.Host()) &&
-         a.SubdomainSettings() == b.SubdomainSettings();
-}
-
-PLATFORM_EXPORT inline bool operator!=(const OriginAccessEntry& a,
-                                       const OriginAccessEntry& b) {
-  return !(a == b);
-}
-
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBORIGIN_ORIGIN_ACCESS_ENTRY_H_
diff --git a/third_party/blink/renderer/platform/weborigin/security_policy.cc b/third_party/blink/renderer/platform/weborigin/security_policy.cc
index a61a1f9..fa157fa 100644
--- a/third_party/blink/renderer/platform/weborigin/security_policy.cc
+++ b/third_party/blink/renderer/platform/weborigin/security_policy.cc
@@ -85,8 +85,9 @@
   OriginAccessList* list = result.stored_value->value.get();
   list->push_back(OriginAccessEntry(
       destination_protocol, destination_domain,
-      allow_destination_subdomains ? OriginAccessEntry::kAllowSubdomains
-                                   : OriginAccessEntry::kDisallowSubdomains));
+      allow_destination_subdomains
+          ? network::cors::OriginAccessEntry::kAllowSubdomains
+          : network::cors::OriginAccessEntry::kDisallowSubdomains));
 }
 
 static void RemoveAllOriginAccessEntriesForOrigin(
@@ -106,7 +107,7 @@
   if (OriginAccessList* list = access_map.at(active_origin->ToString())) {
     for (size_t i = 0; i < list->size(); ++i) {
       if (list->at(i).MatchesOrigin(*target_origin) !=
-          OriginAccessEntry::kDoesNotMatchOrigin)
+          network::cors::OriginAccessEntry::kDoesNotMatchOrigin)
         return true;
     }
   }
diff --git a/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.cc b/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.cc
index 053babc..0640d2c6 100644
--- a/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.cc
+++ b/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.cc
@@ -128,12 +128,13 @@
 ArrayBufferContents::DataHandle ArrayBufferContents::CreateDataHandle(
     size_t size,
     InitializationPolicy policy) {
-  return DataHandle(ArrayBufferContents::AllocateMemoryOrNull(size, policy),
-                    size, FreeMemory);
+  return DataHandle(
+      ArrayBufferContents::AllocateMemoryOrNull(size, policy), size,
+      [](void* buffer, size_t, void*) { FreeMemory(buffer); }, nullptr);
 }
 
 ArrayBufferContents::DataHolder::DataHolder()
-    : data_(nullptr, 0, FreeMemory),
+    : data_(nullptr, 0, [](void*, size_t, void*) {}, nullptr),
       is_shared_(kNotShared),
       has_registered_external_allocation_(false) {}
 
diff --git a/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h b/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h
index 809229c..759a8df4 100644
--- a/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h
+++ b/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h
@@ -50,7 +50,7 @@
   // ArrayBufferContents::FreeMemory as the DataDeleter. Most clients would want
   // to use ArrayBufferContents::CreateDataHandle, which allocates memory and
   // specifies the correct deleter.
-  using DataDeleter = void (*)(void* data);
+  using DataDeleter = void (*)(void* data, size_t length, void* info);
 
   enum class AllocationKind { kNormal, kReservation };
 
@@ -58,25 +58,31 @@
     DISALLOW_COPY_AND_ASSIGN(DataHandle);
 
    public:
-    DataHandle(void* data, size_t length, DataDeleter deleter)
+    DataHandle(void* data,
+               size_t length,
+               DataDeleter deleter,
+               void* deleter_info)
         : allocation_base_(data),
           allocation_length_(length),
           data_(data),
           data_length_(length),
           kind_(AllocationKind::kNormal),
-          deleter_(deleter) {}
+          deleter_(deleter),
+          deleter_info_(deleter_info) {}
     DataHandle(void* allocation_base,
                size_t allocation_length,
                void* data,
                size_t data_length,
                AllocationKind kind,
-               DataDeleter deleter)
+               DataDeleter deleter,
+               void* deleter_info)
         : allocation_base_(allocation_base),
           allocation_length_(allocation_length),
           data_(data),
           data_length_(data_length),
           kind_(kind),
-          deleter_(deleter) {
+          deleter_(deleter),
+          deleter_info_(deleter_info) {
       DCHECK(reinterpret_cast<uintptr_t>(allocation_base_) <=
              reinterpret_cast<uintptr_t>(data_));
       DCHECK(reinterpret_cast<uintptr_t>(data_) + data_length_ <=
@@ -96,7 +102,7 @@
       switch (kind_) {
         case AllocationKind::kNormal:
           DCHECK(deleter_);
-          deleter_(data_);
+          deleter_(data_, data_length_, deleter_info_);
           return;
         case AllocationKind::kReservation:
           base::FreePages(allocation_base_, allocation_length_);
@@ -112,6 +118,7 @@
       data_length_ = other.data_length_;
       kind_ = other.kind_;
       deleter_ = other.deleter_;
+      deleter_info_ = other.deleter_info_;
       other.allocation_base_ = nullptr;
       return *this;
     }
@@ -137,6 +144,7 @@
 
     ArrayBufferContents::AllocationKind kind_;
     DataDeleter deleter_;
+    void* deleter_info_;
   };
 
   enum InitializationPolicy { kZeroInitialize, kDontInitialize };
diff --git a/third_party/blink/tools/audit_non_blink_usage.py b/third_party/blink/tools/audit_non_blink_usage.py
index 7b7df05..1c6f3ff3 100755
--- a/third_party/blink/tools/audit_non_blink_usage.py
+++ b/third_party/blink/tools/audit_non_blink_usage.py
@@ -286,6 +286,13 @@
         ],
     },
     {
+        'paths': ['third_party/blink/renderer/core/fetch/data_consumer_handle_test_util.cc'],
+        'allowed': [
+            # The existing code already contains gin::IsolateHolder.
+            'gin::IsolateHolder',
+        ],
+    },
+    {
         'paths': ['third_party/blink/renderer/core/paint'],
         'allowed': [
             # cc painting types.
diff --git a/third_party/feed/README.chromium b/third_party/feed/README.chromium
index 434cdf7..d6140ef 100644
--- a/third_party/feed/README.chromium
+++ b/third_party/feed/README.chromium
@@ -2,7 +2,7 @@
 Short name: feed
 URL: https://chromium.googlesource.com/feed
 Version: 0
-Revision: a4e91c7238e329ad11e48b068fe3b1e935c0de9b
+Revision: 831b51c0ac199fea3278ceb9de361c22486da935
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/feed/java_sources.gni b/third_party/feed/java_sources.gni
index bb0fdf11..9fd7083 100644
--- a/third_party/feed/java_sources.gni
+++ b/third_party/feed/java_sources.gni
@@ -8,6 +8,7 @@
   "src/src/main/java/com/google/android/libraries/feed/api/actionmanager/ActionManager.java",
   "src/src/main/java/com/google/android/libraries/feed/api/actionmanager/ActionReader.java",
   "src/src/main/java/com/google/android/libraries/feed/api/actionparser/ActionParser.java",
+  "src/src/main/java/com/google/android/libraries/feed/api/actionparser/ActionParserFactory.java",
   "src/src/main/java/com/google/android/libraries/feed/api/common/DismissActionWithSemanticProperties.java",
   "src/src/main/java/com/google/android/libraries/feed/api/common/MutationContext.java",
   "src/src/main/java/com/google/android/libraries/feed/api/common/PayloadWithId.java",
@@ -75,6 +76,7 @@
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/HeaderViewHolder.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/NoContentViewHolder.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/PietViewHolder.java",
+  "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/SwipeNotifier.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/SwipeableViewHolder.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/ViewHolderType.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/ZeroStateViewHolder.java",
@@ -88,6 +90,7 @@
   "src/src/main/java/com/google/android/libraries/feed/common/concurrent/TaskQueue.java",
   "src/src/main/java/com/google/android/libraries/feed/common/functional/Committer.java",
   "src/src/main/java/com/google/android/libraries/feed/common/functional/Consumer.java",
+  "src/src/main/java/com/google/android/libraries/feed/common/functional/Function.java",
   "src/src/main/java/com/google/android/libraries/feed/common/functional/Predicate.java",
   "src/src/main/java/com/google/android/libraries/feed/common/functional/SettableSupplier.java",
   "src/src/main/java/com/google/android/libraries/feed/common/functional/Supplier.java",
@@ -102,7 +105,8 @@
   "src/src/main/java/com/google/android/libraries/feed/common/ui/LayoutUtils.java",
   "src/src/main/java/com/google/android/libraries/feed/feedactionmanager/FeedActionManagerImpl.java",
   "src/src/main/java/com/google/android/libraries/feed/feedactionparser/FeedActionParser.java",
-  "src/src/main/java/com/google/android/libraries/feed/feedactionparser/internal/PietFeedActionPaylaodRetriever.java",
+  "src/src/main/java/com/google/android/libraries/feed/feedactionparser/FeedActionParserFactory.java",
+  "src/src/main/java/com/google/android/libraries/feed/feedactionparser/internal/PietFeedActionPayloadRetriever.java",
   "src/src/main/java/com/google/android/libraries/feed/feedactionreader/FeedActionReader.java",
   "src/src/main/java/com/google/android/libraries/feed/feedapplifecyclelistener/FeedAppLifecycleListener.java",
   "src/src/main/java/com/google/android/libraries/feed/feedapplifecyclelistener/FeedLifecycleListener.java",
@@ -117,6 +121,9 @@
   "src/src/main/java/com/google/android/libraries/feed/feedmodelprovider/internal/UpdatableModelFeature.java",
   "src/src/main/java/com/google/android/libraries/feed/feedmodelprovider/internal/UpdatableModelToken.java",
   "src/src/main/java/com/google/android/libraries/feed/feedprotocoladapter/FeedProtocolAdapter.java",
+  "src/src/main/java/com/google/android/libraries/feed/feedprotocoladapter/internal/transformers/ContentDataOperationTransformer.java",
+  "src/src/main/java/com/google/android/libraries/feed/feedprotocoladapter/internal/transformers/DataOperationTransformer.java",
+  "src/src/main/java/com/google/android/libraries/feed/feedprotocoladapter/internal/transformers/FeatureDataOperationTransformer.java",
   "src/src/main/java/com/google/android/libraries/feed/feedrequestmanager/FeedRequestManager.java",
   "src/src/main/java/com/google/android/libraries/feed/feedsessionmanager/FeedSessionManager.java",
   "src/src/main/java/com/google/android/libraries/feed/feedsessionmanager/FeedSessionManagerFactory.java",
diff --git a/third_party/feed/proto_sources.gni b/third_party/feed/proto_sources.gni
index b5c4743..afbe8fc 100644
--- a/third_party/feed/proto_sources.gni
+++ b/third_party/feed/proto_sources.gni
@@ -22,6 +22,7 @@
   "src/src/main/proto/search/now/ui/piet/shadows.proto",
   "src/src/main/proto/search/now/ui/piet/styles.proto",
   "src/src/main/proto/search/now/ui/piet/text.proto",
+  "src/src/main/proto/search/now/ui/stream/stream_offline_extension.proto",
   "src/src/main/proto/search/now/ui/stream/stream_structure.proto",
   "src/src/main/proto/search/now/ui/stream/stream_swipe_extension.proto",
   "src/src/main/proto/search/now/wire/feed/action_type.proto",
diff --git a/third_party/gvr-android-keyboard/OWNERS b/third_party/gvr-android-keyboard/OWNERS
index 60abf2a..de83b91 100644
--- a/third_party/gvr-android-keyboard/OWNERS
+++ b/third_party/gvr-android-keyboard/OWNERS
@@ -1,5 +1,4 @@
 acondor@chromium.org
-asimjour@chromium.org
 vollick@chromium.org
 
 # TEAM: xr-dev@chromium.org
diff --git a/third_party/robolectric/custom_asynctask/java/src/org/chromium/base/test/asynctask/ShadowAsyncTask.java b/third_party/robolectric/custom_asynctask/java/src/org/chromium/base/test/asynctask/ShadowAsyncTask.java
index d440264d..e4443e7 100644
--- a/third_party/robolectric/custom_asynctask/java/src/org/chromium/base/test/asynctask/ShadowAsyncTask.java
+++ b/third_party/robolectric/custom_asynctask/java/src/org/chromium/base/test/asynctask/ShadowAsyncTask.java
@@ -88,9 +88,7 @@
         return future.get(timeout, unit);
     }
 
-    @SuppressWarnings("unchecked")
-    @Implementation
-    public AsyncTask<Result> execute() {
+    public AsyncTask<Result> executeInRobolectric() {
         status = AsyncTask.Status.RUNNING;
         getBridge().onPreExecute();
 
diff --git a/third_party/tlslite/patches/tls13_intolerance.patch b/third_party/tlslite/patches/tls13_intolerance.patch
index 6f19571..ef50fed 100644
--- a/third_party/tlslite/patches/tls13_intolerance.patch
+++ b/third_party/tlslite/patches/tls13_intolerance.patch
@@ -6,7 +6,7 @@
      signed_cert_timestamps = 18  # RFC 6962
      extended_master_secret = 23  # RFC 7627
      token_binding = 24           # draft-ietf-tokbind-negotiation
-+    supported_versions = 43      # draft-ietf-tls-tls13-18
++    supported_versions = 43      # RFC 8446
      tack = 0xF300
      supports_npn = 13172
      channel_id = 30032
diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
index 8fb75d0..bac05c2f 100644
--- a/third_party/tlslite/tlslite/constants.py
+++ b/third_party/tlslite/tlslite/constants.py
@@ -58,7 +58,7 @@
     signed_cert_timestamps = 18  # RFC 6962
     extended_master_secret = 23  # RFC 7627
     token_binding = 24           # draft-ietf-tokbind-negotiation
-    supported_versions = 43      # draft-ietf-tls-tls13-18
+    supported_versions = 43      # RFC 8446
     tack = 0xF300
     supports_npn = 13172
     channel_id = 30032
diff --git a/tools/code_coverage/coverage_utils.py b/tools/code_coverage/coverage_utils.py
index db06248e..09b1e226 100644
--- a/tools/code_coverage/coverage_utils.py
+++ b/tools/code_coverage/coverage_utils.py
@@ -242,7 +242,9 @@
     """Initializes CoverageReportPostProcessor object."""
     # Caller provided parameters.
     self.output_dir = output_dir
-    self.src_root_dir = src_root_dir.rstrip(os.sep)
+    self.src_root_dir = os.path.normpath(GetFullPath(src_root_dir))
+    if not self.src_root_dir.endswith(os.sep):
+      self.src_root_dir += os.sep
     self.summary_data = json.loads(summary_data)
     assert len(self.summary_data['data']) == 1
     self.no_component_view = no_component_view
@@ -318,7 +320,7 @@
       while True:
         per_directory_coverage_summary[parent_dir].AddSummary(summary)
 
-        if parent_dir == self.src_root_dir:
+        if os.path.normpath(parent_dir) == os.path.normpath(self.src_root_dir):
           break
         parent_dir = os.path.dirname(parent_dir)
 
@@ -457,7 +459,7 @@
     per_file_coverage_summary = {}
     for file_coverage_data in files_coverage_data:
       file_path = file_coverage_data['filename']
-      assert file_path.startswith(self.src_root_dir + os.sep), (
+      assert file_path.startswith(self.src_root_dir), (
           'File path "%s" in coverage summary is outside source checkout.' %
           file_path)
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index dcc5612..361284c 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3096,6 +3096,9 @@
   <int value="2" label="Invalid argument"/>
   <int value="3" label="Invalid ID"/>
   <int value="4" label="Storage error"/>
+  <int value="5" label="Service Worker unavailable"/>
+  <int value="6" label="Quota exceeded"/>
+  <int value="7" label="Permission denied"/>
 </enum>
 
 <enum name="BackgroundFetchEventDispatchResult">
@@ -14242,6 +14245,7 @@
   <int value="465" label="PowerSmartDimEnabled"/>
   <int value="466" label="CoalesceH2ConnectionsWithClientCertificatesForHosts"/>
   <int value="467" label="NetBiosDiscoveryEnabled"/>
+  <int value="468" label="WebAppInstallForceList"/>
 </enum>
 
 <enum name="EnterprisePolicyInvalidations">
@@ -19820,6 +19824,10 @@
   <int value="2525" label="V8MediaStreamTrack_ContentHint_AttributeGetter"/>
   <int value="2526" label="V8MediaStreamTrack_ContentHint_AttributeSetter"/>
   <int value="2527" label="V8IDBFactory_Open_Method"/>
+  <int value="2528" label="EvaluateScriptMovedBetweenDocuments"/>
+  <int value="2529" label="ReportingObserver"/>
+  <int value="2530" label="DeprecationReport"/>
+  <int value="2531" label="InterventionReport"/>
 </enum>
 
 <enum name="FeedbackSource">
@@ -27706,6 +27714,7 @@
   <int value="1" label="Load failed - Invalid path"/>
   <int value="2" label="Load failed - File read error"/>
   <int value="3" label="Load failed - Ruleset verification error"/>
+  <int value="4" label="Load failed - Version mismatch"/>
 </enum>
 
 <enum name="LoadType">
diff --git a/tools/perf/benchmarks/loading.py b/tools/perf/benchmarks/loading.py
index 9de446e..61caa2c 100644
--- a/tools/perf/benchmarks/loading.py
+++ b/tools/perf/benchmarks/loading.py
@@ -18,6 +18,11 @@
 
   options = {'pageset_repeat': 2}
 
+  def SetExtraBrowserOptions(self, options):
+    options.AppendExtraBrowserArgs([
+        '--enable-features=TracingPerfettoBackend',
+    ])
+
   def CreateCoreTimelineBasedMeasurementOptions(self):
     tbm_options = timeline_based_measurement.Options()
     loading_metrics_category.AugmentOptionsForLoadingMetrics(tbm_options)
diff --git a/tools/perf/contrib/blink_layoutng_perf/OWNERS b/tools/perf/contrib/blink_layoutng_perf/OWNERS
new file mode 100644
index 0000000..d80a064
--- /dev/null
+++ b/tools/perf/contrib/blink_layoutng_perf/OWNERS
@@ -0,0 +1,2 @@
+eae@chromium.org
+cbiesinger@chromium.org
diff --git a/tools/perf/contrib/blink_layoutng_perf/__init__.py b/tools/perf/contrib/blink_layoutng_perf/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/perf/contrib/blink_layoutng_perf/__init__.py
diff --git a/tools/perf/contrib/blink_layoutng_perf/blink_layoutng_perf.py b/tools/perf/contrib/blink_layoutng_perf/blink_layoutng_perf.py
new file mode 100644
index 0000000..9c799cd49b
--- /dev/null
+++ b/tools/perf/contrib/blink_layoutng_perf/blink_layoutng_perf.py
@@ -0,0 +1,19 @@
+# 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.
+from benchmarks import blink_perf
+from telemetry import benchmark
+
+# pylint: disable=protected-access
+@benchmark.Info(emails=['cbiesinger@chromium.org'],
+                documentation_url='https://bit.ly/blink-perf-benchmarks')
+class BlinkPerfLayoutNg(blink_perf._BlinkPerfBenchmark):
+  subdir = 'layout'
+
+  def SetExtraBrowserOptions(self, options):
+    super(BlinkPerfLayoutNg, self).SetExtraBrowserOptions(options)
+    options.AppendExtraBrowserArgs('--enable-blink-features=LayoutNG')
+
+  @classmethod
+  def Name(cls):
+    return 'blink_perf.layout_ng'
diff --git a/tools/perf/core/perf_benchmark.py b/tools/perf/core/perf_benchmark.py
index 7a8ba55..77722d2 100644
--- a/tools/perf/core/perf_benchmark.py
+++ b/tools/perf/core/perf_benchmark.py
@@ -104,12 +104,6 @@
     # with the test results.
     options.AppendExtraBrowserArgs(
         '--disable-gpu-process-for-dx12-vulkan-info-collection')
-
-    # Switch Chrome to use Perfetto instead of TraceLog as the tracing backend,
-    # needed until the feature gets turned on by default everywhere.
-    if options.browser_type != 'reference':
-      options.AppendExtraBrowserArgs(
-          '--enable-features=TracingPerfettoBackend')
     self.SetExtraBrowserOptions(options)
 
   @staticmethod
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 2dc99c86..924c340 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -181,14 +181,6 @@
 crbug.com/873011 [ Android_Webview ] rasterize_and_record_micro.top_25/file://static_top_25/yahoonews.html [ Skip ]
 crbug.com/865400 [ Pixel_2 ] rasterize_and_record_micro.top_25/file://static_top_25/yahoonews.html [ Skip ]
 
-# Benchmark: smoothness.tough_pinch_zoom_cases
-crbug.com/875859 [ Nexus_5X ] smoothness.tough_pinch_zoom_cases/youtube_pinch_2018 [ Skip ]
-crbug.com/875859 [ Pixel_2 ] smoothness.tough_pinch_zoom_cases/youtube_pinch_2018 [ Skip ]
-
-# Benchmark: smoothness.gpu_rasterization.tough_pinch_zoom_cases
-crbug.com/875859 [ Nexus_5X ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/youtube_pinch_2018 [ Skip ]
-crbug.com/875859 [ Pixel_2 ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/youtube_pinch_2018 [ Skip ]
-
 # Benchmark: system_health.common_desktop
 crbug.com/828917 [ Mac ] system_health.common_desktop/multitab:misc:typical24 [ Skip ]
 crbug.com/874803 [ Win_10 ] system_health.common_desktop/multitab:misc:typical24 [ Skip ]
@@ -271,7 +263,6 @@
 crbug.com/805934 [ Mac_10.12 ] v8.browsing_desktop/browse:tech:discourse_infinite_scroll [ Skip ]
 crbug.com/839470 [ Win ] v8.browsing_desktop/browse:social:twitter_infinite_scroll [ Skip ]
 crbug.com/854239 [ Linux ] v8.browsing_desktop/browse:social:twitter_infinite_scroll [ Skip ]
-crbug.com/864718 [ Linux ] v8.browsing_desktop/browse:news:flipboard [ Skip ]
 crbug.com/875159 [ Win_10 ] v8.browsing_desktop/browse:social:facebook_infinite_scroll [ Skip ]
 crbug.com/875159 [ Win_10 ] v8.browsing_desktop/browse:media:imgur [ Skip ]
 crbug.com/875159 [ Win_10 ] v8.browsing_desktop/browse:media:tumblr [ Skip ]
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index 8218efe..08941cb0 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -754,6 +754,67 @@
     nullptr, nullptr};
 
 //
+// AtkText interface.
+//
+
+static gchar* ax_platform_node_auralinux_get_text(AtkText* atk_text,
+                                                  gint start_offset,
+                                                  gint end_offset) {
+  AtkObject* atk_object = ATK_OBJECT(atk_text);
+  ui::AXPlatformNodeAuraLinux* obj =
+      AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  if (!obj)
+    return nullptr;
+
+  std::string text = obj->GetTextForATK();
+  if (end_offset < 0)
+    end_offset = g_utf8_strlen(text.c_str(), -1);
+
+  return g_utf8_substring(text.c_str(), start_offset, end_offset);
+}
+
+static gint ax_platform_node_auralinux_get_character_count(AtkText* atk_text) {
+  AtkObject* atk_object = ATK_OBJECT(atk_text);
+  ui::AXPlatformNodeAuraLinux* obj =
+      AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  if (!obj)
+    return 0;
+
+  std::string text = obj->GetTextForATK();
+  return g_utf8_strlen(text.c_str(), -1);
+}
+
+static AtkAttributeSet* ax_platform_node_auralinux_get_run_attributes(
+    AtkText* atk_text,
+    gint offset,
+    gint* start_offset,
+    gint* end_offset) {
+  *start_offset = -1;
+  *end_offset = -1;
+
+  AtkObject* atk_object = ATK_OBJECT(atk_text);
+  ui::AXPlatformNodeAuraLinux* obj =
+      AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  if (!obj)
+    return nullptr;
+
+  *start_offset = 0;
+  *end_offset = ax_platform_node_auralinux_get_character_count(atk_text);
+
+  return nullptr;
+}
+
+static void ax_text_interface_base_init(AtkTextIface* iface) {
+  iface->get_text = ax_platform_node_auralinux_get_text;
+  iface->get_run_attributes = ax_platform_node_auralinux_get_run_attributes;
+  iface->get_character_count = ax_platform_node_auralinux_get_character_count;
+}
+
+static const GInterfaceInfo TextInfo = {
+    reinterpret_cast<GInterfaceInitFunc>(ax_text_interface_base_init), nullptr,
+    nullptr};
+
+//
 // The rest of the AXPlatformNodeAtk code, not specific to one
 // of the Atk* interfaces.
 //
@@ -879,6 +940,10 @@
   if (role == ATK_ROLE_LINK)
     interface_mask |= 1 << ATK_HYPERLINK_INTERFACE;
 
+  // Text interface
+  if (role == ATK_ROLE_TEXT)
+    interface_mask |= 1 << ATK_TEXT_INTERFACE;
+
   return interface_mask;
 }
 
@@ -916,6 +981,8 @@
   if (interface_mask_ & (1 << ATK_HYPERLINK_INTERFACE))
     g_type_add_interface_static(type, ATK_TYPE_HYPERLINK_IMPL,
                                 &HyperlinkImplInfo);
+  if (interface_mask_ & (1 << ATK_TEXT_INTERFACE))
+    g_type_add_interface_static(type, ATK_TYPE_TEXT, &TextInfo);
 
   return type;
 }
@@ -1732,4 +1799,12 @@
   *attributes = PrependAtkAttributeToAtkAttributeSet(name, value, *attributes);
 }
 
+std::string AXPlatformNodeAuraLinux::GetTextForATK() {
+  // Special case allows us to get text even in non-HTML case, e.g. browser UI.
+  if (IsPlainTextField())
+    return GetStringAttribute(ax::mojom::StringAttribute::kValue);
+
+  return AXPlatformNodeBase::GetText();
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.h b/ui/accessibility/platform/ax_platform_node_auralinux.h
index f7be935..9159e2a3 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.h
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -86,6 +86,8 @@
   void Init(AXPlatformNodeDelegate* delegate) override;
   int GetIndexInParent() override;
 
+  std::string GetTextForATK();
+
  protected:
   void AddAttributeToList(const char* name,
                           const char* value,
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
index 7dde4be7..c4dd25b 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -74,6 +74,18 @@
   atk_attribute_set_free(attributes);
 }
 
+static void SetStringAttributeOnNode(
+    AXNode* ax_node,
+    ax::mojom::StringAttribute attribute,
+    const char* attribute_value,
+    base::Optional<ax::mojom::Role> role = base::nullopt) {
+  AXNodeData new_data = AXNodeData();
+  new_data.role = role.value_or(ax::mojom::Role::kApplication);
+  new_data.id = ax_node->data().id;
+  new_data.AddStringAttribute(attribute, attribute_value);
+  ax_node->SetData(new_data);
+}
+
 static void TestAtkObjectIntAttribute(
     AXNode* ax_node,
     AtkObject* atk_object,
@@ -121,11 +133,7 @@
   };
 
   for (unsigned i = 0; i < G_N_ELEMENTS(tests); i++) {
-    AXNodeData new_data = AXNodeData();
-    new_data.role = role.value_or(ax::mojom::Role::kApplication);
-    new_data.id = ax_node->data().id;
-    new_data.AddStringAttribute(mojom_attribute, tests[i]);
-    ax_node->SetData(new_data);
+    SetStringAttributeOnNode(ax_node, mojom_attribute, tests[i], role);
     EnsureAtkObjectHasAttributeWithValue(atk_object, attribute_name, tests[i]);
   }
 }
@@ -849,4 +857,52 @@
   g_object_unref(root_obj);
 }
 
+//
+// AtkText interface
+//
+
+TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkText) {
+  AXNodeData root_data;
+  root_data.id = 1;
+  root_data.role = ax::mojom::Role::kStaticText;
+  Init(root_data);
+
+  AtkObject* root_atk_object(GetRootAtkObject());
+  ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
+  ASSERT_TRUE(ATK_IS_TEXT(root_atk_object));
+  g_object_ref(root_atk_object);
+
+  AtkText* atk_text = ATK_TEXT(root_atk_object);
+
+  auto verify_atk_text_contents = [&](const char* expected_text,
+                                      int start_offset, int end_offset) {
+    gchar* text = atk_text_get_text(atk_text, start_offset, end_offset);
+    EXPECT_STREQ(expected_text, text);
+    g_free(text);
+  };
+
+  AXNode* root = GetRootNode();
+  SetStringAttributeOnNode(root, ax::mojom::StringAttribute::kName, "Text",
+                           ax::mojom::Role::kStaticText);
+  verify_atk_text_contents("Text", 0, -1);
+
+  EXPECT_EQ(4, atk_text_get_character_count(atk_text));
+
+  SetStringAttributeOnNode(root, ax::mojom::StringAttribute::kName,
+                           "Longer String", ax::mojom::Role::kStaticText);
+  verify_atk_text_contents("Longer String", 0, -1);
+  verify_atk_text_contents("Longer ", 0, 7);
+  verify_atk_text_contents("String", 7, -1);
+  EXPECT_EQ(13, atk_text_get_character_count(atk_text));
+
+  SetStringAttributeOnNode(root, ax::mojom::StringAttribute::kName,
+                           "\xE2\x98\xBA", ax::mojom::Role::kStaticText);
+  verify_atk_text_contents("\xE2\x98\xBA", 0, -1);
+  verify_atk_text_contents("\xE2\x98\xBA", 0, 1);
+
+  EXPECT_EQ(1, atk_text_get_character_count(atk_text));
+
+  g_object_unref(root_atk_object);
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index 7b13246..cae47b1 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -294,11 +294,11 @@
          GetData().HasState(ax::mojom::State::kRichlyEditable);
 }
 
-base::string16 AXPlatformNodeBase::GetInnerText() {
+std::string AXPlatformNodeBase::GetInnerText() {
   if (IsTextOnlyObject())
-    return GetString16Attribute(ax::mojom::StringAttribute::kName);
+    return GetStringAttribute(ax::mojom::StringAttribute::kName);
 
-  base::string16 text;
+  std::string text;
   for (int i = 0; i < GetChildCount(); ++i) {
     gfx::NativeViewAccessible child_accessible = ChildAtIndex(i);
     AXPlatformNodeBase* child = FromNativeViewAccessible(child_accessible);
@@ -556,7 +556,7 @@
              GetIntAttribute(ax::mojom::IntAttribute::kScrollYMax);
 }
 
-base::string16 AXPlatformNodeBase::GetText() {
+std::string AXPlatformNodeBase::GetText() {
   return GetInnerText();
 }
 
@@ -575,7 +575,7 @@
   // value to be set in text fields with rich content, even though the same
   // information is available on the children.
   if (value.empty() && IsRichTextField())
-    return GetInnerText();
+    return base::UTF8ToUTF16(GetInnerText());
 
   return value;
 }
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index 10d6b1c..447d329 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -176,7 +176,7 @@
 
   bool HasFocus();
 
-  virtual base::string16 GetText();
+  virtual std::string GetText();
 
   virtual base::string16 GetValue();
 
@@ -212,7 +212,7 @@
 
   // |GetInnerText| recursively includes all the text from descendants such as
   // text found in any embedded object.
-  base::string16 GetInnerText();
+  std::string GetInnerText();
 
   // Cast a gfx::NativeViewAccessible to an AXPlatformNodeBase if it is one,
   // or return NULL if it's not an instance of this class.
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm
index 5e28513..7885fba 100644
--- a/ui/accessibility/platform/ax_platform_node_mac.mm
+++ b/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -389,13 +389,12 @@
     // the inner text.
     NSString* name =
         [self getStringAttribute:ax::mojom::StringAttribute::kName];
-    return [name length] > 0 ? name
-                             : base::SysUTF16ToNSString(node_->GetText());
+    return [name length] > 0 ? name : base::SysUTF8ToNSString(node_->GetText());
   } else if (eventType == ax::mojom::Event::kLiveRegionChanged &&
              node_->GetData().HasStringAttribute(
                  ax::mojom::StringAttribute::kContainerLiveStatus)) {
     // Live regions announce their inner text.
-    return base::SysUTF16ToNSString(node_->GetText());
+    return base::SysUTF8ToNSString(node_->GetText());
   }
   // Only alerts and live regions have something to announce.
   return nil;
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index acbea7d3..eff7262 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -536,9 +536,9 @@
   return -1;
 }
 
-base::string16 AXPlatformNodeWin::GetText() {
+base::string16 AXPlatformNodeWin::GetTextAsString16() {
   if (IsChildOfLeaf())
-    return AXPlatformNodeBase::GetText();
+    return base::UTF8ToUTF16(AXPlatformNodeBase::GetText());
 
   return hypertext_.hypertext;
 }
@@ -975,7 +975,7 @@
   }
 
   if (result.empty() && target->IsRichTextField())
-    result = target->GetInnerText();
+    result = base::UTF8ToUTF16(target->GetInnerText());
 
   *value = SysAllocString(result.c_str());
   DCHECK(*value);
@@ -5653,12 +5653,12 @@
   // Special case allows us to get text even in non-HTML case, e.g. browser UI.
   if (IsPlainTextField())
     return GetString16Attribute(ax::mojom::StringAttribute::kValue);
-  return GetText();
+  return GetTextAsString16();
 }
 
 void AXPlatformNodeWin::HandleSpecialTextOffset(LONG* offset) {
   if (*offset == IA2_TEXT_OFFSET_LENGTH) {
-    *offset = static_cast<LONG>(GetText().length());
+    *offset = static_cast<LONG>(GetTextAsString16().length());
   } else if (*offset == IA2_TEXT_OFFSET_CARET) {
     int selection_start, selection_end;
     GetSelectionOffsets(&selection_start, &selection_end);
@@ -5851,7 +5851,7 @@
           FromNativeViewAccessible(delegate_->ChildAtIndex(i)));
       DCHECK(sibling);
       if (sibling->IsTextOnlyObject())
-        hypertext_offset += (int32_t)sibling->GetText().size();
+        hypertext_offset += (int32_t)sibling->GetTextAsString16().size();
       else
         ++hypertext_offset;
     }
@@ -5948,7 +5948,7 @@
   if (endpoint_index_in_common_parent < index_in_common_parent)
     return 0;
   if (endpoint_index_in_common_parent > index_in_common_parent)
-    return (int32_t)GetText().size();
+    return (int32_t)GetTextAsString16().size();
 
   NOTREACHED();
   return -1;
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index 451b4c4..e88db88 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -285,9 +285,13 @@
   // AXPlatformNodeBase overrides.
   void Destroy() override;
   int GetIndexInParent() override;
-  base::string16 GetText() override;
   base::string16 GetValue() override;
 
+  // For the moment, we add a special version of this method which returns a
+  // base::string16, but once the hypertext generation code is shared between
+  // platforms we can just override AXPlatformNodeBase::GetText().
+  base::string16 GetTextAsString16();
+
   //
   // IAccessible methods.
   //
diff --git a/ui/aura/mus/input_method_mus.cc b/ui/aura/mus/input_method_mus.cc
index 7d1f500..030a132d 100644
--- a/ui/aura/mus/input_method_mus.cc
+++ b/ui/aura/mus/input_method_mus.cc
@@ -114,14 +114,21 @@
 void InputMethodMus::OnInputLocaleChanged() {
   // TODO(moshayedi): crbug.com/637418. Not supported in ChromeOS. Investigate
   // whether we want to support this or not.
+  NOTIMPLEMENTED_LOG_ONCE();
 }
 
 bool InputMethodMus::IsCandidatePopupOpen() const {
   // TODO(moshayedi): crbug.com/637416. Implement this properly when we have a
   // mean for displaying candidate list popup.
+  NOTIMPLEMENTED_LOG_ONCE();
   return false;
 }
 
+void InputMethodMus::ShowVirtualKeyboardIfEnabled() {
+  if (input_method_)
+    input_method_->ShowVirtualKeyboardIfEnabled();
+}
+
 ui::EventDispatchDetails InputMethodMus::SendKeyEventToInputMethod(
     const ui::KeyEvent& event,
     EventResultCallback ack_callback) {
diff --git a/ui/aura/mus/input_method_mus.h b/ui/aura/mus/input_method_mus.h
index f47be86..207aa202 100644
--- a/ui/aura/mus/input_method_mus.h
+++ b/ui/aura/mus/input_method_mus.h
@@ -47,6 +47,7 @@
   void CancelComposition(const ui::TextInputClient* client) override;
   void OnInputLocaleChanged() override;
   bool IsCandidatePopupOpen() const override;
+  void ShowVirtualKeyboardIfEnabled() override;
 
  private:
   friend class InputMethodMusTestApi;
diff --git a/ui/aura/mus/input_method_mus_unittest.cc b/ui/aura/mus/input_method_mus_unittest.cc
index c3c1bd6..c448bff6a 100644
--- a/ui/aura/mus/input_method_mus_unittest.cc
+++ b/ui/aura/mus/input_method_mus_unittest.cc
@@ -57,6 +57,9 @@
     process_key_event_callbacks_.push_back(std::move(callback));
   }
   void CancelComposition() override { was_cancel_composition_called_ = true; }
+  void ShowVirtualKeyboardIfEnabled() override {
+    was_show_virtual_keyboard_if_enabled_called_ = true;
+  }
 
   bool was_on_text_input_type_changed_called() {
     return was_on_text_input_type_changed_called_;
@@ -70,10 +73,15 @@
     return was_cancel_composition_called_;
   }
 
+  bool was_show_virtual_keyboard_if_enabled_called() {
+    return was_show_virtual_keyboard_if_enabled_called_;
+  }
+
  private:
   bool was_on_text_input_type_changed_called_ = false;
   bool was_on_caret_bounds_changed_called_ = false;
   bool was_cancel_composition_called_ = false;
+  bool was_show_virtual_keyboard_if_enabled_called_ = false;
   ProcessKeyEventCallbacks process_key_event_callbacks_;
 
   DISALLOW_COPY_AND_ASSIGN(TestInputMethod);
@@ -298,4 +306,15 @@
   EXPECT_FALSE(test_input_method.was_cancel_composition_called());
 }
 
+// Calling ShowVirtualKeyboardIfEnabled should notify the mus side.
+TEST_F(InputMethodMusTest, ShowVirtualKeyboardIfEnabled) {
+  TestInputMethodDelegate input_method_delegate;
+  InputMethodMus input_method_mus(&input_method_delegate, nullptr);
+  TestInputMethod test_input_method;
+  InputMethodMusTestApi::SetInputMethod(&input_method_mus, &test_input_method);
+  EXPECT_FALSE(test_input_method.was_show_virtual_keyboard_if_enabled_called());
+  input_method_mus.ShowVirtualKeyboardIfEnabled();
+  EXPECT_TRUE(test_input_method.was_show_virtual_keyboard_if_enabled_called());
+}
+
 }  // namespace aura
diff --git a/ui/base/ime/input_method_base.cc b/ui/base/ime/input_method_base.cc
index cf50411..df1e94c 100644
--- a/ui/base/ime/input_method_base.cc
+++ b/ui/base/ime/input_method_base.cc
@@ -142,9 +142,11 @@
 
 InputMethodKeyboardController*
 InputMethodBase::GetInputMethodKeyboardController() {
-  if (!keyboard_controller_)
+  if (!keyboard_controller_) {
+    NOTIMPLEMENTED() << "Using InputMethodKeyboardControllerStub";
     keyboard_controller_ =
         std::make_unique<InputMethodKeyboardControllerStub>();
+  }
   return keyboard_controller_.get();
 }
 
diff --git a/ui/file_manager/file_manager/common/images/icon128.png b/ui/file_manager/file_manager/common/images/icon128.png
index c5ed558..9e1f9a35 100644
--- a/ui/file_manager/file_manager/common/images/icon128.png
+++ b/ui/file_manager/file_manager/common/images/icon128.png
Binary files differ
diff --git a/ui/file_manager/file_manager/common/images/icon16.png b/ui/file_manager/file_manager/common/images/icon16.png
index 3884666..58d18283 100644
--- a/ui/file_manager/file_manager/common/images/icon16.png
+++ b/ui/file_manager/file_manager/common/images/icon16.png
Binary files differ
diff --git a/ui/file_manager/file_manager/common/images/icon192.png b/ui/file_manager/file_manager/common/images/icon192.png
new file mode 100644
index 0000000..111ec9f
--- /dev/null
+++ b/ui/file_manager/file_manager/common/images/icon192.png
Binary files differ
diff --git a/ui/file_manager/file_manager/common/images/icon256.png b/ui/file_manager/file_manager/common/images/icon256.png
deleted file mode 100644
index 631c951..0000000
--- a/ui/file_manager/file_manager/common/images/icon256.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/common/images/icon32.png b/ui/file_manager/file_manager/common/images/icon32.png
deleted file mode 100644
index 082d689..0000000
--- a/ui/file_manager/file_manager/common/images/icon32.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/common/images/icon48.png b/ui/file_manager/file_manager/common/images/icon48.png
index ec9ad58c..2bb8555 100644
--- a/ui/file_manager/file_manager/common/images/icon48.png
+++ b/ui/file_manager/file_manager/common/images/icon48.png
Binary files differ
diff --git a/ui/file_manager/file_manager/common/images/icon64.png b/ui/file_manager/file_manager/common/images/icon64.png
deleted file mode 100644
index bed4978..0000000
--- a/ui/file_manager/file_manager/common/images/icon64.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/file_manager/common/images/icon96.png b/ui/file_manager/file_manager/common/images/icon96.png
index 24ed0bfb..070057de 100644
--- a/ui/file_manager/file_manager/common/images/icon96.png
+++ b/ui/file_manager/file_manager/common/images/icon96.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
index 74beb84b..ddaef5dc 100644
--- a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
@@ -120,13 +120,15 @@
   fileSelectionHandler.addEventListener(
       FileSelectionHandler.EventType.CHANGE_THROTTLED,
       this.onFileSelectionChanged_.bind(this));
+  volumeManager.addEventListener(
+      'drive-connection-changed', this.updateOkButton_.bind(this));
 
   dialogFooter.initFileTypeFilter(
       this.fileTypes_, launchParam.includeAllFiles);
   this.onFileTypeFilterChanged_();
 
   this.newFolderCommand_ =
-      /** @type {cr.ui.Command} */ (document.getElementById('new-folder'));
+      /** @type {cr.ui.Command} */ ($('new-folder'));
   this.newFolderCommand_.addEventListener(
       'disabledChange', this.updateNewFolderButton_.bind(this));
 }
diff --git a/ui/file_manager/file_manager/foreground/js/file_selection.js b/ui/file_manager/file_manager/foreground/js/file_selection.js
index cbbb5d3..7003c59 100644
--- a/ui/file_manager/file_manager/foreground/js/file_selection.js
+++ b/ui/file_manager/file_manager/foreground/js/file_selection.js
@@ -252,9 +252,13 @@
     return;
 
   // Calculate all additional and heavy properties.
-  selection.computeAdditional(this.metadataModel_);
+  selection.computeAdditional(this.metadataModel_).then(() => {
+    if (this.selection !== selection)
+      return;
 
-  cr.dispatchSimpleEvent(this, FileSelectionHandler.EventType.CHANGE_THROTTLED);
+    cr.dispatchSimpleEvent(
+        this, FileSelectionHandler.EventType.CHANGE_THROTTLED);
+  });
 };
 
 /**
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json
index 68bd831..2de08b7 100644
--- a/ui/file_manager/file_manager/manifest.json
+++ b/ui/file_manager/file_manager/manifest.json
@@ -8,12 +8,10 @@
   "incognito" : "split",
   "icons": {
     "16": "common/images/icon16.png",
-    "32": "common/images/icon32.png",
     "48": "common/images/icon48.png",
-    "64": "common/images/icon64.png",
     "96": "common/images/icon96.png",
     "128": "common/images/icon128.png",
-    "256": "common/images/icon256.png"
+    "192": "common/images/icon192.png"
   },
   "permissions": [
     "chrome://extension-icon/",
diff --git a/ui/file_manager/file_manager_resources.grd b/ui/file_manager/file_manager_resources.grd
index 4d64bd53..1e37bbc 100644
--- a/ui/file_manager/file_manager_resources.grd
+++ b/ui/file_manager/file_manager_resources.grd
@@ -70,12 +70,10 @@
 
       <!-- Images referenced from the manifest or the code -->
       <include name="IDR_FILE_MANAGER_ICON_16" file="file_manager/common/images/icon16.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_ICON_32" file="file_manager/common/images/icon32.png" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_ICON_48" file="file_manager/common/images/icon48.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_ICON_64" file="file_manager/common/images/icon64.png" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_ICON_96" file="file_manager/common/images/icon96.png" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_ICON_128" file="file_manager/common/images/icon128.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_ICON_256" file="file_manager/common/images/icon256.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_ICON_192" file="file_manager/common/images/icon192.png" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_GALLERY_ICON_16" file="gallery/images/icon16.png" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_GALLERY_ICON_32" file="gallery/images/icon32.png" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_GALLERY_ICON_48" file="gallery/images/icon48.png" type="BINDATA" />
diff --git a/ui/file_manager/integration_tests/file_manager/create_new_folder.js b/ui/file_manager/integration_tests/file_manager/create_new_folder.js
index 3a1a545..ff7263fc 100644
--- a/ui/file_manager/integration_tests/file_manager/create_new_folder.js
+++ b/ui/file_manager/integration_tests/file_manager/create_new_folder.js
@@ -15,25 +15,25 @@
 /**
  * Selects the first item in the file list.
  *
- * @param {string} windowId The Files app windowId.
+ * @param {string} appId The Files app appId.
  * @return {Promise} Promise to be fulfilled on success.
  */
-function selectFirstFileListItem(windowId) {
+function selectFirstFileListItem(appId) {
   return Promise.resolve().then(function() {
     // Ensure no file list items are selected.
-    return remoteCall.waitForElementLost(windowId, ['#file-list [selected]']);
+    return remoteCall.waitForElementLost(appId, ['#file-list [selected]']);
   }).then(function() {
     // Press DownArrow key to select an item.
     const key = ['#file-list', 'ArrowDown', 'Down', false, false, false];
-    return remoteCall.callRemoteTestUtil('fakeKeyDown', windowId, key);
+    return remoteCall.callRemoteTestUtil('fakeKeyDown', appId, key);
   }).then(function(result) {
     chrome.test.assertTrue(result);
     // Await file list item selection.
-    return remoteCall.waitForElement(windowId, ['.table-row[selected]']);
+    return remoteCall.waitForElement(appId, ['.table-row[selected]']);
   }).then(function() {
     // Retrieve all selected items in the file list.
     return remoteCall.callRemoteTestUtil(
-        'queryAllElements', windowId, ['#file-list [selected]']);
+        'queryAllElements', appId, ['#file-list [selected]']);
   }).then(function(elements) {
     // Check: the first list item only should be selected.
     chrome.test.assertEq(1, elements.length);
@@ -44,42 +44,42 @@
 /**
  * Creates a new folder in the file list.
  *
- * @param {string} windowId The Files app windowId.
+ * @param {string} appId The Files app appId.
  * @param {Array<TestEntryInfo>} initialEntrySet Initial set of entries.
  * @param {string} selector Downloads or Drive directory tree item selector.
  * @return {Promise} Promise to be fulfilled on success.
  */
-function createNewFolder(windowId, initialEntrySet, selector) {
+function createNewFolder(appId, initialEntrySet, selector) {
   const textInput = '#file-list .table-row[renaming] input.rename';
 
   return new Promise(function(resolve) {
     // Focus the file-list.
-    remoteCall.callRemoteTestUtil('focus', windowId, ['#file-list'], resolve);
+    remoteCall.callRemoteTestUtil('focus', appId, ['#file-list'], resolve);
   }).then(function(result) {
     chrome.test.assertTrue(result);
     // Press Ctrl+E to create a new folder.
     const key = ['#file-list', 'e', 'U+0045', true, false, false];
-    return remoteCall.callRemoteTestUtil('fakeKeyDown', windowId, key);
+    return remoteCall.callRemoteTestUtil('fakeKeyDown', appId, key);
   }).then(function(result) {
     chrome.test.assertTrue(result);
     // Check: a new folder should be shown in the file list.
     const files = [['New Folder', '--', 'Folder', '']].concat(
         TestEntryInfo.getExpectedRows(initialEntrySet));
     return remoteCall.waitForFiles(
-        windowId, files, {ignoreLastModifiedTime: true});
+        appId, files, {ignoreLastModifiedTime: true});
   }).then(function() {
     // Check: a new folder should be present in the directory tree.
     const newSubtreeChildItem = selector +
         ' .tree-children .tree-item[entry-label="New Folder"]';
-    return remoteCall.waitForElement(windowId, newSubtreeChildItem);
+    return remoteCall.waitForElement(appId, newSubtreeChildItem);
   }).then(function() {
     // Check: the text input should be shown in the file list.
-    return remoteCall.waitForElement(windowId, textInput);
+    return remoteCall.waitForElement(appId, textInput);
   }).then(function() {
     // Get all file list rows that have attribute 'renaming'.
     const renamingFileListRows = ['#file-list .table-row[renaming]'];
     return remoteCall.callRemoteTestUtil(
-        'queryAllElements', windowId, renamingFileListRows);
+        'queryAllElements', appId, renamingFileListRows);
   }).then(function(elements) {
     // Check: the new folder only should be 'renaming'.
     chrome.test.assertEq(1, elements.length);
@@ -89,7 +89,7 @@
     // Get all file list rows that have attribute 'selected'.
     const selectedFileListRows = ['#file-list .table-row[selected]'];
     return remoteCall.callRemoteTestUtil(
-        'queryAllElements', windowId, selectedFileListRows);
+        'queryAllElements', appId, selectedFileListRows);
   }).then(function(elements) {
     // Check: the new folder only should be 'selected'.
     chrome.test.assertEq(1, elements.length);
@@ -98,32 +98,32 @@
   }).then(function() {
     // Type the test folder name.
     return remoteCall.callRemoteTestUtil(
-        'inputText', windowId, [textInput, 'Test Folder Name']);
+        'inputText', appId, [textInput, 'Test Folder Name']);
   }).then(function() {
     // Press the Enter key.
     const key = [textInput, 'Enter', 'Enter', false, false, false];
-    return remoteCall.callRemoteTestUtil('fakeKeyDown', windowId, key);
+    return remoteCall.callRemoteTestUtil('fakeKeyDown', appId, key);
   }).then(function(result) {
     chrome.test.assertTrue(result);
     // Wait until renaming is complete.
     const renamingItem = ['#file-list .table-row[renaming]'];
-    return remoteCall.waitForElementLost(windowId, renamingItem);
+    return remoteCall.waitForElementLost(appId, renamingItem);
   }).then(function() {
     // Check: the test folder should be shown in the file list.
     const files = [['Test Folder Name', '--', 'Folder', '']].concat(
         TestEntryInfo.getExpectedRows(initialEntrySet));
     return remoteCall.waitForFiles(
-        windowId, files, {ignoreLastModifiedTime: true});
+        appId, files, {ignoreLastModifiedTime: true});
   }).then(function(elements) {
     // Check: the test folder should be present in the directory tree.
     const testSubtreeChildItem = selector +
         ' .tree-children .tree-item[entry-label="Test Folder Name"]';
-    return remoteCall.waitForElement(windowId, testSubtreeChildItem);
+    return remoteCall.waitForElement(appId, testSubtreeChildItem);
   }).then(function() {
     // Get all file list rows that have attribute 'selected'.
     const selectedFileListRows = ['#file-list .table-row[selected]'];
     return remoteCall.callRemoteTestUtil(
-        'queryAllElements', windowId, selectedFileListRows);
+        'queryAllElements', appId, selectedFileListRows);
   }).then(function(elements) {
     // Check: the test folder only should be 'selected'.
     chrome.test.assertEq(1, elements.length);
@@ -135,7 +135,7 @@
  * Expands the directory tree item given by |selector| (Downloads or Drive)
  * to reveal its subtree child items.
  *
- * @param {string} appId The Files app windowId.
+ * @param {string} appId The Files app appId.
  * @param {string} selector Downloads or Drive directory tree item selector.
  * @return {Promise} Promise fulfilled on success.
  */
@@ -161,71 +161,71 @@
 }
 
 testcase.selectCreateFolderDownloads = function() {
-  let windowId;
+  let appId;
 
   const promise = new Promise(function(resolve) {
     setupAndWaitUntilReady(
         null, RootPath.DOWNLOADS, resolve, BASIC_LOCAL_ENTRY_SET, []);
   }).then(function(results) {
-    windowId = results.windowId;
-    return expandRoot(windowId, TREEITEM_DOWNLOADS);
+    appId = results.windowId;
+    return expandRoot(appId, TREEITEM_DOWNLOADS);
   }).then(function() {
-    return selectFirstFileListItem(windowId);
+    return selectFirstFileListItem(appId);
   }).then(function() {
-    return createNewFolder(windowId, BASIC_LOCAL_ENTRY_SET, TREEITEM_DOWNLOADS);
+    return createNewFolder(appId, BASIC_LOCAL_ENTRY_SET, TREEITEM_DOWNLOADS);
   });
 
   testPromise(promise);
 };
 
 testcase.createFolderDownloads = function() {
-  let windowId;
+  let appId;
 
   const promise = new Promise(function(resolve) {
     setupAndWaitUntilReady(
         null, RootPath.DOWNLOADS, resolve, BASIC_LOCAL_ENTRY_SET, []);
   }).then(function(results) {
-    windowId = results.windowId;
-    return expandRoot(windowId, TREEITEM_DOWNLOADS);
+    appId = results.windowId;
+    return expandRoot(appId, TREEITEM_DOWNLOADS);
   }).then(function() {
-    return createNewFolder(windowId, BASIC_LOCAL_ENTRY_SET, TREEITEM_DOWNLOADS);
+    return createNewFolder(appId, BASIC_LOCAL_ENTRY_SET, TREEITEM_DOWNLOADS);
   });
 
   testPromise(promise);
 };
 
 testcase.createFolderNestedDownloads = function() {
-  let windowId;
+  let appId;
 
   const promise = new Promise(function(resolve) {
     setupAndWaitUntilReady(
         null, RootPath.DOWNLOADS, resolve, BASIC_LOCAL_ENTRY_SET, []);
   }).then(function(results) {
-    windowId = results.windowId;
-    return expandRoot(windowId, TREEITEM_DOWNLOADS);
+    appId = results.windowId;
+    return expandRoot(appId, TREEITEM_DOWNLOADS);
   }).then(function() {
-    return navigateWithDirectoryTree(windowId, '/photos', 'Downloads');
+    return navigateWithDirectoryTree(appId, '/photos', 'Downloads');
   }).then(function() {
     return remoteCall.waitForFiles(
-        windowId, [], {ignoreLastModifiedTime: true});
+        appId, [], {ignoreLastModifiedTime: true});
   }).then(function() {
-    return createNewFolder(windowId, [], TREEITEM_DOWNLOADS);
+    return createNewFolder(appId, [], TREEITEM_DOWNLOADS);
   });
 
   testPromise(promise);
 };
 
 testcase.createFolderDrive = function() {
-  let windowId;
+  let appId;
 
   const promise = new Promise(function(resolve) {
     setupAndWaitUntilReady(
         null, RootPath.DRIVE, resolve, [], BASIC_DRIVE_ENTRY_SET);
   }).then(function(results) {
-    windowId = results.windowId;
-    return expandRoot(windowId, TREEITEM_DRIVE);
+    appId = results.windowId;
+    return expandRoot(appId, TREEITEM_DRIVE);
   }).then(function() {
-    return createNewFolder(windowId, BASIC_DRIVE_ENTRY_SET, TREEITEM_DRIVE);
+    return createNewFolder(appId, BASIC_DRIVE_ENTRY_SET, TREEITEM_DRIVE);
   });
 
   testPromise(promise);
diff --git a/ui/webui/resources/cr_components/certificate_manager/BUILD.gn b/ui/webui/resources/cr_components/certificate_manager/BUILD.gn
index 2c8a161a..59a88d5 100644
--- a/ui/webui/resources/cr_components/certificate_manager/BUILD.gn
+++ b/ui/webui/resources/cr_components/certificate_manager/BUILD.gn
@@ -46,6 +46,7 @@
   deps = [
     ":certificate_manager_types",
     ":certificates_browser_proxy",
+    "//ui/webui/resources/cr_elements/policy:cr_policy_indicator",
     "//ui/webui/resources/js:cr",
     "//ui/webui/resources/js:i18n_behavior",
   ]
@@ -105,6 +106,7 @@
     ":certificates_browser_proxy",
     "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
     "//ui/webui/resources/cr_elements/cr_lazy_render:cr_lazy_render",
+    "//ui/webui/resources/cr_elements/policy:cr_policy_indicator",
     "//ui/webui/resources/js:cr",
     "//ui/webui/resources/js:i18n_behavior",
   ]
diff --git a/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html b/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html
index 8dcb4409..aa89d1e 100644
--- a/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html
+++ b/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html
@@ -1,6 +1,7 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
 <link rel="import" href="certificate_shared_css.html">
@@ -20,6 +21,8 @@
     </style>
     <div class="expand-box">
       <div class="flex">[[model.id]]</div>
+      <cr-policy-indicator indicator-type="[[getPolicyIndicatorType_(model)]]">
+      </cr-policy-indicator>
       <cr-expand-button expanded="{{expanded_}}"
           alt="[[i18n('certificateManagerExpandA11yLabel')]]">
       </cr-expand-button>
diff --git a/ui/webui/resources/cr_components/certificate_manager/certificate_entry.js b/ui/webui/resources/cr_components/certificate_manager/certificate_entry.js
index bcd900e..f0124eb 100644
--- a/ui/webui/resources/cr_components/certificate_manager/certificate_entry.js
+++ b/ui/webui/resources/cr_components/certificate_manager/certificate_entry.js
@@ -11,7 +11,7 @@
   behaviors: [I18nBehavior],
 
   properties: {
-    /** @type {!Certificate} */
+    /** @type {!CertificatesOrgGroup} */
     model: Object,
 
     /** @type {!CertificateType} */
@@ -26,4 +26,9 @@
   isLast_: function(index) {
     return index == this.model.subnodes.length - 1;
   },
+
+  getPolicyIndicatorType_() {
+    return this.model.containsPolicyCerts ? CrPolicyIndicatorType.USER_POLICY :
+                                            CrPolicyIndicatorType.NONE;
+  },
 });
diff --git a/ui/webui/resources/cr_components/certificate_manager/certificate_list.js b/ui/webui/resources/cr_components/certificate_manager/certificate_list.js
index b2a1fe5..8bd3109 100644
--- a/ui/webui/resources/cr_components/certificate_manager/certificate_list.js
+++ b/ui/webui/resources/cr_components/certificate_manager/certificate_list.js
@@ -10,7 +10,7 @@
   is: 'certificate-list',
 
   properties: {
-    /** @type {!Array<!Certificate>} */
+    /** @type {!Array<!CertificatesOrgGroup>} */
     certificates: {
       type: Array,
       value: function() {
diff --git a/ui/webui/resources/cr_components/certificate_manager/certificate_manager.js b/ui/webui/resources/cr_components/certificate_manager/certificate_manager.js
index cb8da3e..9ef17af 100644
--- a/ui/webui/resources/cr_components/certificate_manager/certificate_manager.js
+++ b/ui/webui/resources/cr_components/certificate_manager/certificate_manager.js
@@ -17,7 +17,7 @@
       value: 0,
     },
 
-    /** @type {!Array<!Certificate>} */
+    /** @type {!Array<!CertificatesOrgGroup>} */
     personalCerts: {
       type: Array,
       value: function() {
@@ -25,7 +25,7 @@
       },
     },
 
-    /** @type {!Array<!Certificate>} */
+    /** @type {!Array<!CertificatesOrgGroup>} */
     serverCerts: {
       type: Array,
       value: function() {
@@ -33,7 +33,7 @@
       },
     },
 
-    /** @type {!Array<!Certificate>} */
+    /** @type {!Array<!CertificatesOrgGroup>} */
     caCerts: {
       type: Array,
       value: function() {
@@ -41,7 +41,7 @@
       },
     },
 
-    /** @type {!Array<!Certificate>} */
+    /** @type {!Array<!CertificatesOrgGroup>} */
     otherCerts: {
       type: Array,
       value: function() {
diff --git a/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html b/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html
index 409975b..2407809 100644
--- a/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html
+++ b/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html
@@ -2,6 +2,7 @@
 
 <link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
@@ -32,6 +33,8 @@
         [[i18n('certificateManagerUntrusted')]]
       </div>
       <div class="name">[[model.name]]</div>
+      <cr-policy-indicator indicator-type="[[getPolicyIndicatorType_(model)]]">
+      </cr-policy-indicator>
       <paper-icon-button-light class="icon-more-vert">
         <button id="dots" title="[[i18n('moreActions')]]" on-tap="onDotsTap_">
         </button>
diff --git a/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js b/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js
index 8467bd7..3f2c5423f 100644
--- a/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js
+++ b/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js
@@ -147,4 +147,10 @@
     var actionMenu = /** @type {!CrActionMenuElement} */ (this.$.menu.get());
     actionMenu.showAt(this.$.dots);
   },
+
+  /** @private */
+  getPolicyIndicatorType_: function(model) {
+    return model.policy ? CrPolicyIndicatorType.USER_POLICY :
+                          CrPolicyIndicatorType.NONE;
+  },
 });
diff --git a/ui/webui/resources/cr_components/certificate_manager/certificates_browser_proxy.js b/ui/webui/resources/cr_components/certificate_manager/certificates_browser_proxy.js
index bbf1d73f..826b4bb7 100644
--- a/ui/webui/resources/cr_components/certificate_manager/certificates_browser_proxy.js
+++ b/ui/webui/resources/cr_components/certificate_manager/certificates_browser_proxy.js
@@ -13,6 +13,7 @@
  *   id: string,
  *   name: string,
  *   policy: boolean,
+ *   webTrustAnchor: boolean,
  *   readonly: boolean,
  *   untrusted: boolean,
  * }}
@@ -30,14 +31,19 @@
 var NewCertificateSubNode;
 
 /**
+ * Top-level grouping node in a certificate list, representing an organization
+ * and containing certs that belong to the organization in |subnodes|. If a
+ * certificate does not have an organization name, it will be grouped under its
+ * own CertificatesOrgGroup with |name| set to its display name.
  * @typedef {{
  *   id: string,
  *   name: string,
+ *   containsPolicyCerts: boolean,
  *   subnodes: !Array<!CertificateSubnode>
  * }}
  * @see chrome/browser/ui/webui/settings/certificates_handler.cc
  */
-var Certificate;
+var CertificatesOrgGroup;
 
 /**
  * @typedef {{