diff --git a/DEPS b/DEPS
index 3c65961..cd8e5c1 100644
--- a/DEPS
+++ b/DEPS
@@ -206,11 +206,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': '1a364c273e289ebd3a318f92c122571875ec5daa',
+  'skia_revision': '56957d9ccfde015a603f55a589c74d55eae181b6',
   # 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': '35582ccb50705f34b3c89fc4e95ba9a3a10da681',
+  'v8_revision': 'ffc771df4710e998f73be031890f60ce2f69d513',
   # 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.
@@ -218,7 +218,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '3591997b58bfb1aab16a2d3d071529275bb84b05',
+  'angle_revision': '68b95b6330b48e05db7b4bcd1d1713951219c173',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -269,7 +269,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': 'e40e5df22e17fd2f9f50e408a349a1291c953370',
+  'catapult_revision': '22b0de95cd01b9ea77252ac0dc3c793cb07fe8d3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -368,7 +368,7 @@
   'ukey2_revision': '0275885d8e6038c39b8a8ca55e75d1d4d1727f47',
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'tint_revision': '62bbc6f6c0507b07c8d1057d8da4dc65afed4114',
+  'tint_revision': 'c8b2d23e9de73c2ff47635dd35de30a5a3049ab1',
 
   # TODO(crbug.com/941824): The values below need to be kept in sync
   # between //DEPS and //buildtools/DEPS, so if you're updating one,
@@ -784,7 +784,7 @@
           },
           {
               'package': 'chromium/third_party/android_sdk/public/cmdline-tools',
-              'version': 'ijpIFSitwBfaEdO9VXBGPqDHUVzPimXy_whw3aHTN9oC',
+              'version': 'V__2Ycej-H2-6AcXX5A3gi7sIk74SuN44PBm2uC_N1sC',
           },
       ],
       'condition': 'checkout_android_native_support',
@@ -1569,7 +1569,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b6d93e6c4293060b06c4f15d4cbd7f945e73c8d3',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@5e0515c39cc5229a05ce2fa82320757d0cbb07dd',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index ed7ba43..9f90298 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -388,9 +388,7 @@
   '^ios/chrome/',
   '^ios/web/',
   '^ios/web_view/',
-  '^media/blink/',
   '^media/cast/',
-  '^media/cdm/',
   '^media/filters/',
   '^media/gpu/',
   '^media/mojo/',
@@ -1414,6 +1412,42 @@
 def _IsProtoFile(input_api, file_path):
   return input_api.os_path.splitext(file_path)[1] == ".proto"
 
+
+def CheckNoUpstreamDepsOnClank(input_api, output_api):
+  """Prevent additions of dependencies from the upstream repo on //clank."""
+  # clank can depend on clank
+  if input_api.change.RepositoryRoot().endswith('clank'):
+    return []
+  build_file_patterns = [
+    r'(.+/)?BUILD\.gn',
+    r'.+\.gni',
+  ]
+  excluded_files = [
+    r'build[/\\]config[/\\]android[/\\]config\.gni'
+  ]
+  bad_pattern = input_api.re.compile(r'^[^#]*//clank')
+
+  error_message = 'Disallowed import on //clank in an upstream build file:'
+
+  def FilterFile(affected_file):
+    return input_api.FilterSourceFile(
+      affected_file,
+      files_to_check=build_file_patterns,
+      files_to_skip=excluded_files)
+
+  problems = []
+  for f in input_api.AffectedSourceFiles(FilterFile):
+    local_path = f.LocalPath()
+    for line_number, line in f.ChangedContents():
+      if (bad_pattern.search(line)):
+        problems.append(
+          '%s:%d\n    %s' % (local_path, line_number, line.strip()))
+  if problems:
+    return [output_api.PresubmitPromptOrNotify(error_message, problems)]
+  else:
+    return []
+
+
 def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
   """Attempts to prevent use of functions intended only for testing in
   non-testing code. For now this is just a best-effort implementation
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index 06ad9cb..a9b4047 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -1107,6 +1107,100 @@
                     'UsedDeprecatedSmokeAnnotation not found in errors')
 
 
+class CheckNoDownstreamDepsTest(unittest.TestCase):
+  def testInvalidDepFromUpstream(self):
+    mock_input_api = MockInputApi()
+    mock_output_api = MockOutputApi()
+
+    mock_input_api.files = [
+        MockAffectedFile('BUILD.gn', [
+          'deps = [',
+          '   "//clank/target:test",',
+          ']'
+        ]),
+        MockAffectedFile('chrome/android/BUILD.gn', [
+          'deps = [ "//clank/target:test" ]'
+        ]),
+        MockAffectedFile('chrome/chrome_java_deps.gni', [
+          'java_deps = [',
+          '   "//clank/target:test",',
+          ']'
+        ]),
+    ]
+    mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
+    msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(
+        mock_input_api, mock_output_api)
+    self.assertEqual(1, len(msgs),
+                     'Expected %d items, found %d: %s'
+                     % (1, len(msgs), msgs))
+    self.assertEqual(3, len(msgs[0].items),
+                     'Expected %d items, found %d: %s'
+                     % (3, len(msgs[0].items), msgs[0].items))
+    self.assertTrue(any('BUILD.gn:2' in item for item in msgs[0].items),
+                    'BUILD.gn not found in errors')
+    self.assertTrue(
+        any('chrome/android/BUILD.gn:1' in item for item in msgs[0].items),
+        'chrome/android/BUILD.gn:1 not found in errors')
+    self.assertTrue(
+        any('chrome/chrome_java_deps.gni:2' in item for item in msgs[0].items),
+        'chrome/chrome_java_deps.gni:2 not found in errors')
+
+  def testAllowsComments(self):
+    mock_input_api = MockInputApi()
+    mock_output_api = MockOutputApi()
+
+    mock_input_api.files = [
+        MockAffectedFile('BUILD.gn', [
+          '# real implementation in //clank/target:test',
+        ]),
+    ]
+    mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
+    msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(
+        mock_input_api, mock_output_api)
+    self.assertEqual(0, len(msgs),
+                     'Expected %d items, found %d: %s'
+                     % (0, len(msgs), msgs))
+
+  def testOnlyChecksBuildFiles(self):
+    mock_input_api = MockInputApi()
+    mock_output_api = MockOutputApi()
+
+    mock_input_api.files = [
+        MockAffectedFile('README.md', [
+          'DEPS = [ "//clank/target:test" ]'
+        ]),
+        MockAffectedFile('chrome/android/java/file.java', [
+          '//clank/ only function'
+        ]),
+    ]
+    mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
+    msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(
+        mock_input_api, mock_output_api)
+    self.assertEqual(0, len(msgs),
+                     'Expected %d items, found %d: %s'
+                     % (0, len(msgs), msgs))
+
+  def testValidDepFromDownstream(self):
+    mock_input_api = MockInputApi()
+    mock_output_api = MockOutputApi()
+
+    mock_input_api.files = [
+        MockAffectedFile('BUILD.gn', [
+          'DEPS = [',
+          '   "//clank/target:test",',
+          ']'
+        ]),
+        MockAffectedFile('java/BUILD.gn', [
+          'DEPS = [ "//clank/target:test" ]'
+        ]),
+    ]
+    mock_input_api.change.RepositoryRoot = lambda: 'chromium/src/clank'
+    msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(
+        mock_input_api, mock_output_api)
+    self.assertEqual(0, len(msgs),
+                     'Expected %d items, found %d: %s'
+                     % (0, len(msgs), msgs))
+
 class AndroidDeprecatedJUnitFrameworkTest(unittest.TestCase):
   def testCheckAndroidTestJUnitFramework(self):
     mock_input_api = MockInputApi()
diff --git a/android_webview/browser/cookie_manager.cc b/android_webview/browser/cookie_manager.cc
index 381c3703..3e666f3 100644
--- a/android_webview/browser/cookie_manager.cc
+++ b/android_webview/browser/cookie_manager.cc
@@ -52,8 +52,8 @@
 #include "url/url_constants.h"
 
 using base::WaitableEvent;
-using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertJavaStringToUTF16;
+using base::android::ConvertJavaStringToUTF8;
 using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
@@ -352,7 +352,8 @@
     // compatibility reasons.
     cookie_store_->SetCookieAccessDelegate(
         std::make_unique<network::CookieAccessDelegateImpl>(
-            network::mojom::CookieAccessDelegateType::ALWAYS_LEGACY));
+            network::mojom::CookieAccessDelegateType::ALWAYS_LEGACY,
+            nullptr /* preloaded_first_party_sets */));
   }
 
   return cookie_store_.get();
diff --git a/android_webview/browser/gfx/surfaces_instance.cc b/android_webview/browser/gfx/surfaces_instance.cc
index eb5bb936..94ce46c 100644
--- a/android_webview/browser/gfx/surfaces_instance.cc
+++ b/android_webview/browser/gfx/surfaces_instance.cc
@@ -237,7 +237,7 @@
                       gfx::Transform());
   viz::SharedQuadState* quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
+  quad_state->SetAll(gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect,
                      is_clipped, are_contents_opaque, 1.f,
                      SkBlendMode::kSrcOver, 0);
   viz::SolidColorDrawQuad* solid_quad =
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java
index ad98a3c4..ade8446 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java
@@ -451,7 +451,8 @@
     @Test
     @LargeTest
     @Feature({"AndroidWebView"})
-    public void testSingleFrame() throws Throwable {
+    @CommandLineFlags.Add({"disable-features=ContentCaptureConstantStreaming"})
+    public void testSingleFrameWithoutConstantStreaming() throws Throwable {
         final String response = "<html><head></head><body>"
                 + "<div id='place_holder'>"
                 + "<p style=\"height: 100vh\">Hello</p>"
@@ -510,6 +511,85 @@
     }
 
     @Test
+    @LargeTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add({"enable-features=ContentCaptureConstantStreaming"})
+    public void testSingleFrameWithConstantStreaming() throws Throwable {
+        final String response = "<html><head></head><body>"
+                + "<div id='place_holder'>"
+                + "<p style=\"height: 100vh\">Hello</p>"
+                + "<p>world</p>"
+                + "</body></html>";
+        final String url = mWebServer.setResponse(MAIN_FRAME_FILE, response, null);
+        runAndVerifyCallbacks(() -> {
+            loadUrlSync(url);
+        }, toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED));
+        Long frameId = null;
+        Set<Long> capturedContentIds = null;
+        // Verify only on-screen content is captured.
+        verifyCapturedContent(null, frameId, url, toStringSet("Hello"), capturedContentIds,
+                mConsumer.getParentFrame(), mConsumer.getCapturedContent());
+
+        // Scrolls to the bottom, the node that became invisible is removed, and the content
+        // at bottom is captured.
+        frameId = Long.valueOf(mConsumer.getCapturedContent().getId());
+        long contentHelloId = mConsumer.getCapturedContent().getChildren().get(0).getId();
+        capturedContentIds = mConsumer.cloneCaptureContentIds();
+        runAndVerifyCallbacks(()
+                                      -> { scrollToBottom(); },
+                toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED,
+                        TestAwContentCaptureConsumer.CONTENT_REMOVED));
+        verifyCapturedContent(null, frameId, url, toStringSet("world"), capturedContentIds,
+                mConsumer.getParentFrame(), mConsumer.getCapturedContent());
+        verifyRemovedContent(frameId, url, toLongSet(contentHelloId),
+                mConsumer.getCurrentFrameSession(), mConsumer.getRemovedIds());
+        long contentWorldId = mConsumer.getCapturedContent().getChildren().get(0).getId();
+        // Adds the new content at the beginning and scroll back, the newly visible content
+        // is captured and invisible content is removed.
+        final String newContentId = "new_content_id";
+        final String newContent = "new content";
+        capturedContentIds = mConsumer.cloneCaptureContentIds();
+        runAndVerifyCallbacks(
+                ()
+                        -> {
+                    insertElement(newContentId, newContent);
+                    scrollToTop();
+                },
+                toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED,
+                        TestAwContentCaptureConsumer.CONTENT_REMOVED));
+        verifyCapturedContent(null, frameId, url, toStringSet(newContent, "Hello"),
+                capturedContentIds, mConsumer.getParentFrame(), mConsumer.getCapturedContent());
+        verifyRemovedContent(frameId, url, toLongSet(contentWorldId),
+                mConsumer.getCurrentFrameSession(), mConsumer.getRemovedIds());
+
+        // Changed previous added element, this will trigger remove/capture events.
+        long removedContentId = mConsumer.getCapturedContent().getChildren().get(0).getId();
+        // The id is unordered, if the current one is "Hello", the next child must be "new content".
+        if (removedContentId == contentHelloId) {
+            removedContentId = mConsumer.getCapturedContent().getChildren().get(1).getId();
+        }
+        final String newContent2 = "new content 2";
+        capturedContentIds = mConsumer.cloneCaptureContentIds();
+        runAndVerifyCallbacks(()
+                                      -> { setInnerHTML(newContentId, newContent2); },
+                toIntArray(TestAwContentCaptureConsumer.CONTENT_REMOVED,
+                        TestAwContentCaptureConsumer.CONTENT_CAPTURED));
+        verifyRemovedContent(frameId, url, toLongSet(removedContentId),
+                mConsumer.getCurrentFrameSession(), mConsumer.getRemovedIds());
+        verifyCapturedContent(null, frameId, url, toStringSet(newContent2), capturedContentIds,
+                mConsumer.getParentFrame(), mConsumer.getCapturedContent());
+
+        // Remove the element.
+        removedContentId = mConsumer.getCapturedContent().getChildren().get(0).getId();
+        capturedContentIds = mConsumer.cloneCaptureContentIds();
+        runAndVerifyCallbacks(() -> {
+            removeElement(newContentId);
+        }, toIntArray(TestAwContentCaptureConsumer.CONTENT_REMOVED));
+        verifyRemovedContent(frameId, url, toLongSet(removedContentId),
+                mConsumer.getCurrentFrameSession(), mConsumer.getRemovedIds());
+    }
+
+    @Test
     @SmallTest
     @Feature({"AndroidWebView"})
     public void testChangeContent() throws Throwable {
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
index 28a5ec9..63b81b9 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
@@ -22,12 +22,12 @@
 
 import org.chromium.android_webview.test.util.JSUtils;
 import org.chromium.android_webview.test.util.JavascriptEventObserver;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.browser.test.util.TouchCommon;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
index 170f095..641a990 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
@@ -25,13 +25,13 @@
 import org.chromium.android_webview.test.util.CommonResources;
 import org.chromium.android_webview.test.util.JSUtils;
 import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.NavigationHistory;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnPageStartedHelper;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsGarbageCollectionTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsGarbageCollectionTest.java
index 5bbc3765..af65d78 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsGarbageCollectionTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsGarbageCollectionTest.java
@@ -29,13 +29,13 @@
 import org.chromium.android_webview.AwContents;
 import org.chromium.android_webview.gfx.AwGLFunctor;
 import org.chromium.android_webview.test.AwActivityTestRule.TestDependencyFactory;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.content_public.browser.ImeAdapter;
 import org.chromium.content_public.browser.WebContentsAccessibility;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.common.ContentUrlConstants;
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
index 2fb68cf..ee75e96 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
@@ -26,12 +26,12 @@
 import org.chromium.android_webview.test.TestAwContentsClient.ShouldInterceptRequestHelper;
 import org.chromium.android_webview.test.util.CommonResources;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.browser.MessagePort;
 import org.chromium.content_public.browser.SelectionPopupController;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
index 7e649a8d..8df4a6c 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
@@ -47,6 +47,7 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.InMemorySharedPreferences;
@@ -55,7 +56,6 @@
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.common.ContentUrlConstants;
 import org.chromium.net.test.EmbeddedTestServer;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java b/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java
index 72d9d27..dc81e96 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java
@@ -10,10 +10,10 @@
 import org.junit.Assert;
 
 import org.chromium.android_webview.AwContents;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper;
 import org.chromium.content_public.browser.test.util.WebContentsUtils;
 
diff --git a/ash/ambient/ambient_controller.cc b/ash/ambient/ambient_controller.cc
index f8f2e19..28713ab 100644
--- a/ash/ambient/ambient_controller.cc
+++ b/ash/ambient/ambient_controller.cc
@@ -89,9 +89,19 @@
 
 // Returns true if the device is currently connected to a charger.
 bool IsChargerConnected() {
-  return (PowerStatus::Get()->IsBatteryCharging() ||
-          PowerStatus::Get()->IsBatteryFull()) &&
-         PowerStatus::Get()->IsLinePowerConnected();
+  DCHECK(PowerStatus::IsInitialized());
+  auto* power_status = PowerStatus::Get();
+  if (power_status->IsBatteryPresent()) {
+    // If battery is full or battery is charging, that implies power is
+    // connected. Also return true if a power source is connected and
+    // battery is not discharging.
+    return power_status->IsBatteryCharging() || power_status->IsBatteryFull() ||
+           (power_status->IsLinePowerConnected() &&
+            !power_status->IsBatteryDischargingOnLinePower());
+  } else {
+    // Chromeboxes have no battery.
+    return power_status->IsLinePowerConnected();
+  }
 }
 
 bool IsUiHidden(AmbientUiVisibility visibility) {
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index f7ca6307..5877915 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -2857,7 +2857,7 @@
         Get the <ph name="intent">$1<ex>definition</ex></ph> for "<ph name="query">$2<ex>unfathomable</ex></ph>"
       </message>
       <message name="IDS_ASH_QUICK_ANSWERS_USER_NOTICE_VIEW_DESC_TEXT" desc="Description in the dialog that opens up to seek user-consent for the Quick Answers feature.">
-        With a right-click or a long press, Assistant shows info such as the definition or unit conversion for your selection.
+        With a right-click or a long press, Assistant shows info such as the definition, translation or unit conversion for your selection.
       </message>
       <message name="IDS_ASH_QUICK_ANSWERS_USER_NOTICE_VIEW_MANAGE_SETTINGS_BUTTON" desc="Display text on the Manage-Settings button in the dialog that opens up to seek user-consent for the Quick Answers feature.">
         Manage Settings
diff --git a/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_USER_NOTICE_VIEW_DESC_TEXT.png.sha1 b/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_USER_NOTICE_VIEW_DESC_TEXT.png.sha1
index 23178262..e3fc638 100644
--- a/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_USER_NOTICE_VIEW_DESC_TEXT.png.sha1
+++ b/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_USER_NOTICE_VIEW_DESC_TEXT.png.sha1
@@ -1 +1 @@
-e512771795e84328ecc069b5e40f56541d5b7eb9
\ No newline at end of file
+20dca11d54463f196ec212bfcb5884d398e7eb9d
\ No newline at end of file
diff --git a/ash/child_accounts/parent_access_controller_impl.cc b/ash/child_accounts/parent_access_controller_impl.cc
index cb4dbe1f..451bb0cf 100644
--- a/ash/child_accounts/parent_access_controller_impl.cc
+++ b/ash/child_accounts/parent_access_controller_impl.cc
@@ -9,8 +9,10 @@
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "base/bind.h"
+#include "base/check.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string16.h"
+#include "components/session_manager/session_manager_types.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace ash {
@@ -171,6 +173,16 @@
   if (PinRequestWidget::Get())
     return false;
 
+  // When there is no logged in user we should accept parent access code for any
+  // of child account added to the device.
+  const auto session_state =
+      Shell::Get()->session_controller()->GetSessionState();
+  const bool user_in_session =
+      session_state == session_manager::SessionState::LOGGED_IN_NOT_ACTIVE ||
+      session_state == session_manager::SessionState::ACTIVE ||
+      session_state == session_manager::SessionState::LOCKED;
+  DCHECK(user_in_session || child_account_id.empty());
+
   account_id_ = child_account_id;
   action_ = action;
   validation_time_ = validation_time;
diff --git a/ash/child_accounts/parent_access_controller_impl_unittest.cc b/ash/child_accounts/parent_access_controller_impl_unittest.cc
index 7948ea6..158f833c 100644
--- a/ash/child_accounts/parent_access_controller_impl_unittest.cc
+++ b/ash/child_accounts/parent_access_controller_impl_unittest.cc
@@ -12,7 +12,10 @@
 #include "ash/login/ui/views_utils.h"
 #include "ash/public/cpp/child_accounts/parent_access_controller.h"
 #include "base/bind.h"
+#include "base/dcheck_is_on.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "components/account_id/account_id.h"
+#include "components/session_manager/session_manager_types.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/views/controls/button/label_button.h"
 
@@ -22,10 +25,13 @@
 
 using ::testing::_;
 
+AccountId GetChildAccountId() {
+  return AccountId::FromUserEmail("child@gmail.com");
+}
+
 class ParentAccessControllerImplTest : public LoginTestBase {
  protected:
-  ParentAccessControllerImplTest()
-      : account_id_(AccountId::FromUserEmail("child@gmail.com")) {}
+  ParentAccessControllerImplTest() : account_id_(GetChildAccountId()) {}
   ~ParentAccessControllerImplTest() override = default;
 
   // LoginScreenTest:
@@ -55,11 +61,23 @@
     access_granted ? ++successful_validation_ : ++back_action_;
   }
 
-  void StartParentAccess(
-      SupervisedAction action = SupervisedAction::kUnlockTimeLimits) {
+  // Starts parent access validation.
+  // Use this overloaded method if session state and supervised action are not
+  // relevant.
+  void StartParentAccess() {
+    GetSessionControllerClient()->SetSessionState(
+        session_manager::SessionState::LOCKED);
+    StartParentAccess(account_id_, SupervisedAction::kUnlockTimeLimits);
+  }
+
+  // Starts parent access validation with supervised |action|.
+  // Session state should be configured accordingly to the |action|.
+  void StartParentAccess(SupervisedAction action) {
     StartParentAccess(account_id_, action);
   }
 
+  // Starts parent access validation with supervised |action| and |account_id|.
+  // Session state should be configured accordingly to the |action|.
   void StartParentAccess(const AccountId& account_id, SupervisedAction action) {
     validation_time_ = base::Time::Now();
     ash::ParentAccessController::Get()->ShowWidget(
@@ -137,6 +155,8 @@
 
 // Tests correct UMA reporting for parent access.
 TEST_F(ParentAccessControllerImplTest, ParentAccessUMARecording) {
+  GetSessionControllerClient()->SetSessionState(
+      session_manager::SessionState::LOCKED);
   StartParentAccess(SupervisedAction::kUnlockTimeLimits);
   histogram_tester_.ExpectBucketCount(
       ParentAccessControllerImpl::kUMAParentAccessCodeUsage,
@@ -145,6 +165,8 @@
   ExpectUMAActionReported(
       ParentAccessControllerImpl::UMAAction::kCanceledByUser, 1, 1);
 
+  GetSessionControllerClient()->SetSessionState(
+      session_manager::SessionState::ACTIVE);
   StartParentAccess(SupervisedAction::kUpdateTimezone);
   histogram_tester_.ExpectBucketCount(
       ParentAccessControllerImpl::kUMAParentAccessCodeUsage,
@@ -153,7 +175,6 @@
   ExpectUMAActionReported(
       ParentAccessControllerImpl::UMAAction::kCanceledByUser, 2, 2);
 
-  // The below usage depends on the session state.
   GetSessionControllerClient()->SetSessionState(
       session_manager::SessionState::ACTIVE);
   StartParentAccess(SupervisedAction::kUpdateClock);
@@ -166,7 +187,7 @@
 
   GetSessionControllerClient()->SetSessionState(
       session_manager::SessionState::LOGIN_PRIMARY);
-  StartParentAccess(SupervisedAction::kUpdateClock);
+  StartParentAccess(EmptyAccountId(), SupervisedAction::kUpdateClock);
   histogram_tester_.ExpectBucketCount(
       ParentAccessControllerImpl::kUMAParentAccessCodeUsage,
       ParentAccessControllerImpl::UMAUsage::kTimeChangeLoginScreen, 1);
@@ -186,7 +207,7 @@
 
   GetSessionControllerClient()->SetSessionState(
       session_manager::SessionState::LOGIN_PRIMARY);
-  StartParentAccess(SupervisedAction::kReauth);
+  StartParentAccess(EmptyAccountId(), SupervisedAction::kReauth);
   histogram_tester_.ExpectBucketCount(
       ParentAccessControllerImpl::kUMAParentAccessCodeUsage,
       ParentAccessControllerImpl::UMAUsage::kReauhLoginScreen, 1);
@@ -238,5 +259,26 @@
       ParentAccessControllerImpl::UMAAction::kCanceledByUser, 1, 3);
 }
 
+#if DCHECK_IS_ON()
+// Tests that on login screen we check parent access code against all accounts.
+TEST_F(ParentAccessControllerImplTest, EnforceNoAccountSpecifiedOnLogin) {
+  GetSessionControllerClient()->SetSessionState(
+      session_manager::SessionState::LOGIN_PRIMARY);
+  EXPECT_DEATH_IF_SUPPORTED(
+      StartParentAccess(GetChildAccountId(), SupervisedAction::kReauth), "");
+
+  GetSessionControllerClient()->SetSessionState(
+      session_manager::SessionState::LOGIN_PRIMARY);
+  EXPECT_DEATH_IF_SUPPORTED(
+      StartParentAccess(GetChildAccountId(), SupervisedAction::kAddUser), "");
+
+  GetSessionControllerClient()->SetSessionState(
+      session_manager::SessionState::LOGIN_PRIMARY);
+  EXPECT_DEATH_IF_SUPPORTED(
+      StartParentAccess(GetChildAccountId(), SupervisedAction::kUpdateClock),
+      "");
+}
+#endif
+
 }  // namespace
 }  // namespace ash
diff --git a/ash/fast_ink/fast_ink_host.cc b/ash/fast_ink/fast_ink_host.cc
index 93e2eba0..ba041e1 100644
--- a/ash/fast_ink/fast_ink_host.cc
+++ b/ash/fast_ink/fast_ink_host.cc
@@ -408,7 +408,7 @@
       buffer_to_target_transform,
       /*quad_layer_rect=*/output_rect,
       /*visible_quad_layer_rect=*/output_rect,
-      /*rounded_corner_bounds=*/gfx::RRectF(),
+      /*mask_filter_info=*/gfx::MaskFilterInfo(),
       /*clip_rect=*/gfx::Rect(),
       /*is_clipped=*/false, /*are_contents_opaque=*/false, /*opacity=*/1.f,
       /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
diff --git a/ash/fast_ink/view_tree_host_root_view.cc b/ash/fast_ink/view_tree_host_root_view.cc
index dd05502..9bb359c8 100644
--- a/ash/fast_ink/view_tree_host_root_view.cc
+++ b/ash/fast_ink/view_tree_host_root_view.cc
@@ -452,7 +452,7 @@
       buffer_to_target_transform,
       /*quad_layer_rect=*/output_rect,
       /*visible_quad_layer_rect=*/output_rect,
-      /*rounded_corner_bounds=*/gfx::RRectF(),
+      /*mask_filter_info=*/gfx::MaskFilterInfo(),
       /*clip_rect=*/gfx::Rect(),
       /*is_clipped=*/false, /*are_contents_opaque=*/false, /*opacity=*/1.f,
       /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
diff --git a/ash/hud_display/cpu_status.cc b/ash/hud_display/cpu_status.cc
index cec1858..a55260c2 100644
--- a/ash/hud_display/cpu_status.cc
+++ b/ash/hud_display/cpu_status.cc
@@ -20,9 +20,6 @@
 constexpr char kProcStatFile[] = "/proc/stat";
 
 std::string ReadProcFile(const base::FilePath& path) {
-  // Synchronously reading files in /proc and /sys are safe.
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
-
   std::string result;
   base::ReadFileToString(path, &result);
   return result;
diff --git a/ash/hud_display/cpu_status.h b/ash/hud_display/cpu_status.h
index efa57a9..adc1f6f 100644
--- a/ash/hud_display/cpu_status.h
+++ b/ash/hud_display/cpu_status.h
@@ -35,6 +35,7 @@
 };
 
 // Parses current /proc/stat and restuns current values.
+// Must be called on io-enabled thread.
 CpuStats GetProcStatCPU();
 
 }  // namespace hud_display
diff --git a/ash/hud_display/data_source.h b/ash/hud_display/data_source.h
index 0844250..7eec37be 100644
--- a/ash/hud_display/data_source.h
+++ b/ash/hud_display/data_source.h
@@ -58,6 +58,7 @@
   DataSource& operator=(const DataSource&) = delete;
   ~DataSource();
 
+  // This must be called on io-enabled thread.
   Snapshot GetSnapshotAndReset();
 
  private:
diff --git a/ash/hud_display/graphs_container_view.cc b/ash/hud_display/graphs_container_view.cc
index a77b353..2dd33b5 100644
--- a/ash/hud_display/graphs_container_view.cc
+++ b/ash/hud_display/graphs_container_view.cc
@@ -12,6 +12,7 @@
 #include "ash/hud_display/memory_graph_page_view.h"
 #include "base/bind.h"
 #include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/metadata/metadata_impl_macros.h"
 
@@ -21,7 +22,13 @@
 
 // UI refresh interval.
 constexpr base::TimeDelta kGraphsDataRefreshInterval =
-    base::TimeDelta::FromMilliseconds(1000);
+    base::TimeDelta::FromMilliseconds(500);
+
+void GetDataSnapshotOnThreadPool(DataSource* data_source,
+                                 DataSource::Snapshot* out_snapshot) {
+  // This is run on the ThreadPool.
+  *out_snapshot = data_source->GetSnapshotAndReset();
+}
 
 }  // namespace
 
@@ -31,38 +38,78 @@
 BEGIN_METADATA(GraphsContainerView, views::View)
 END_METADATA
 
-GraphsContainerView::GraphsContainerView() {
+GraphsContainerView::GraphsContainerView()
+    : start_time_(base::TimeTicks::Now()),
+      file_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
+      data_source_(new DataSource,
+                   base::OnTaskRunnerDeleter(file_task_runner_)) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
 
   // Make all graph pages take the whole view and make sure that only one
   // is shown at a time.
   SetLayoutManager(std::make_unique<views::FillLayout>());
 
-  refresh_timer_.Start(FROM_HERE, kGraphsDataRefreshInterval, this,
-                       &GraphsContainerView::UpdateData);
-
   // Adds another graphs page.
   AddChildView(
-      std::make_unique<MemoryGraphPageView>(refresh_timer_.GetCurrentDelay()))
+      std::make_unique<MemoryGraphPageView>(kGraphsDataRefreshInterval))
       ->SetID(static_cast<int>(DisplayMode::MEMORY_DISPLAY));
-  AddChildView(
-      std::make_unique<CpuGraphPageView>(refresh_timer_.GetCurrentDelay()))
+  AddChildView(std::make_unique<CpuGraphPageView>(kGraphsDataRefreshInterval))
       ->SetID(static_cast<int>(DisplayMode::CPU_DISPLAY));
-  AddChildView(
-      std::make_unique<FPSGraphPageView>(refresh_timer_.GetCurrentDelay()))
+  AddChildView(std::make_unique<FPSGraphPageView>(kGraphsDataRefreshInterval))
       ->SetID(static_cast<int>(DisplayMode::FPS_DISPLAY));
+
+  RequestDataUpdate();
 }
 
 GraphsContainerView::~GraphsContainerView() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
 }
 
-void GraphsContainerView::UpdateData() {
-  const DataSource::Snapshot snapshot = data_source_.GetSnapshotAndReset();
-  for (auto* child : children())
-    static_cast<GraphPageViewBase*>(child)->UpdateData(snapshot);
+void GraphsContainerView::RequestDataUpdate() {
+  std::unique_ptr<DataSource::Snapshot> snapshot_container =
+      std::make_unique<DataSource::Snapshot>();
+  DataSource::Snapshot* snapshot = snapshot_container.get();
+  file_task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&GetDataSnapshotOnThreadPool,
+                     base::Unretained(data_source_.get()), snapshot),
+      base::BindOnce(&GraphsContainerView::UpdateData,
+                     weak_factory_.GetWeakPtr(),
+                     std::move(snapshot_container)));
+}
+
+void GraphsContainerView::UpdateData(
+    std::unique_ptr<DataSource::Snapshot> snapshot) {
+  // Adjust for any missing data.
+  const off_t expected_updates =
+      (base::TimeTicks::Now() - start_time_) / kGraphsDataRefreshInterval;
+  const unsigned intervals =
+      expected_updates > static_cast<off_t>(data_update_count_)
+          ? expected_updates - data_update_count_
+          : 1;
+  data_update_count_ += intervals;
+
+  for (auto* child : children()) {
+    // Insert missing points.
+    for (unsigned j = 0; j < intervals; ++j)
+      static_cast<GraphPageViewBase*>(child)->UpdateData(*snapshot);
+  }
 
   SchedulePaint();
+
+  const base::TimeTicks next_start_time =
+      start_time_ + kGraphsDataRefreshInterval * data_update_count_;
+  const base::TimeTicks now = base::TimeTicks::Now();
+  if (next_start_time <= now) {
+    RequestDataUpdate();
+  } else {
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(&GraphsContainerView::RequestDataUpdate,
+                       weak_factory_.GetWeakPtr()),
+        next_start_time - now);
+  }
 }
 
 void GraphsContainerView::SetMode(DisplayMode mode) {
diff --git a/ash/hud_display/graphs_container_view.h b/ash/hud_display/graphs_container_view.h
index faad9a7..5e08227 100644
--- a/ash/hud_display/graphs_container_view.h
+++ b/ash/hud_display/graphs_container_view.h
@@ -7,8 +7,11 @@
 
 #include "ash/hud_display/data_source.h"
 #include "ash/hud_display/graph_page_view_base.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
-#include "base/timer/timer.h"
+#include "base/sequenced_task_runner.h"
+#include "base/time/time.h"
 #include "ui/views/view.h"
 
 namespace ash {
@@ -26,20 +29,28 @@
   GraphsContainerView& operator=(const GraphsContainerView&) = delete;
   ~GraphsContainerView() override;
 
-  // Synchrnously reads system counters and updates data.
-  void UpdateData();
 
   // Updates graphs display to match given mode.
   void SetMode(DisplayMode mode);
 
+  // Schedules new data update on the thread pool.
+  void RequestDataUpdate();
+
+  // Update graphs data from the given snapshot.
+  void UpdateData(std::unique_ptr<DataSource::Snapshot> snapshot);
+
  private:
-  // HUD is updatd with new data every tick.
-  base::RepeatingTimer refresh_timer_;
+  // This helps detect missing data intervals.
+  const base::TimeTicks start_time_;
+  size_t data_update_count_{0};
 
   // Source of graphs data.
-  DataSource data_source_;
+  scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
+  std::unique_ptr<DataSource, base::OnTaskRunnerDeleter> data_source_;
 
   SEQUENCE_CHECKER(ui_sequence_checker_);
+
+  base::WeakPtrFactory<GraphsContainerView> weak_factory_{this};
 };
 
 }  // namespace hud_display
diff --git a/ash/hud_display/memory_status.cc b/ash/hud_display/memory_status.cc
index e465ae5..5937e1bc 100644
--- a/ash/hud_display/memory_status.cc
+++ b/ash/hud_display/memory_status.cc
@@ -37,9 +37,6 @@
 }
 
 std::string ReadProcFile(const base::FilePath& path) {
-  // Synchronously reading files in /proc and /sys are safe.
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
-
   std::string result;
   ReadFileToString(path, &result);
   return result;
diff --git a/ash/hud_display/memory_status.h b/ash/hud_display/memory_status.h
index 87d9c8bf..bacbf486 100644
--- a/ash/hud_display/memory_status.h
+++ b/ash/hud_display/memory_status.h
@@ -17,6 +17,7 @@
 // Should run on the file thread.
 class MemoryStatus {
  public:
+  // Must be created on io-enabled thread.
   MemoryStatus();
   MemoryStatus(const MemoryStatus&) = delete;
   MemoryStatus& operator=(const MemoryStatus&) = delete;
diff --git a/ash/login/ui/access_code_input.cc b/ash/login/ui/access_code_input.cc
index 4c6cda4..9273a93 100644
--- a/ash/login/ui/access_code_input.cc
+++ b/ash/login/ui/access_code_input.cc
@@ -30,14 +30,13 @@
 
 constexpr int kAccessCodeInputFieldWidthDp = 24;
 constexpr int kAccessCodeBetweenInputFieldsGapDp = 8;
-
-constexpr SkColor kTextColor = SK_ColorWHITE;
 }  // namespace
 
 FlexCodeInput::FlexCodeInput(OnInputChange on_input_change,
                              OnEnter on_enter,
                              OnEscape on_escape,
-                             bool obscure_pin)
+                             bool obscure_pin,
+                             SkColor text_color)
     : on_input_change_(std::move(on_input_change)),
       on_enter_(std::move(on_enter)),
       on_escape_(std::move(on_escape)) {
@@ -54,7 +53,7 @@
       kAccessCodeFontSizeDeltaDp, gfx::Font::FontStyle::NORMAL,
       gfx::Font::Weight::NORMAL));
   code_field_->SetBorder(views::CreateSolidSidedBorder(
-      0, 0, kAccessCodeFlexUnderlineThicknessDp, 0, kTextColor));
+      0, 0, kAccessCodeFlexUnderlineThicknessDp, 0, text_color));
   code_field_->SetBackgroundColor(SK_ColorTRANSPARENT);
   code_field_->SetFocusBehavior(FocusBehavior::ALWAYS);
   code_field_->SetPreferredSize(
@@ -190,7 +189,8 @@
                                            OnInputChange on_input_change,
                                            OnEnter on_enter,
                                            OnEscape on_escape,
-                                           bool obscure_pin)
+                                           bool obscure_pin,
+                                           SkColor text_color)
     : on_input_change_(std::move(on_input_change)),
       on_enter_(std::move(on_enter)),
       on_escape_(std::move(on_escape)),
@@ -217,12 +217,12 @@
     } else {
       field->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
     }
-    field->SetTextColor(kTextColor);
+    field->SetTextColor(text_color);
     field->SetFontList(views::Textfield::GetDefaultFontList().Derive(
         kAccessCodeFontSizeDeltaDp, gfx::Font::FontStyle::NORMAL,
         gfx::Font::Weight::NORMAL));
     field->SetBorder(views::CreateSolidSidedBorder(
-        0, 0, kAccessCodeInputFieldUnderlineThicknessDp, 0, kTextColor));
+        0, 0, kAccessCodeInputFieldUnderlineThicknessDp, 0, text_color));
     field->SetGroup(kFixedLengthInputGroup);
 
     // Ignores the a11y focus of |field| because the a11y needs to focus to the
diff --git a/ash/login/ui/access_code_input.h b/ash/login/ui/access_code_input.h
index 7c3c9cad..0bde3d9 100644
--- a/ash/login/ui/access_code_input.h
+++ b/ash/login/ui/access_code_input.h
@@ -63,7 +63,8 @@
   FlexCodeInput(OnInputChange on_input_change,
                 OnEnter on_enter,
                 OnEscape on_escape,
-                bool obscure_pin);
+                bool obscure_pin,
+                SkColor text_color);
 
   FlexCodeInput(const FlexCodeInput&) = delete;
   FlexCodeInput& operator=(const FlexCodeInput&) = delete;
@@ -165,7 +166,8 @@
                        OnInputChange on_input_change,
                        OnEnter on_enter,
                        OnEscape on_escape,
-                       bool obscure_pin);
+                       bool obscure_pin,
+                       SkColor text_color);
 
   ~FixedLengthCodeInput() override;
   FixedLengthCodeInput(const FixedLengthCodeInput&) = delete;
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 22061ab..26fc561 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -1022,7 +1022,7 @@
       callbacks.on_easy_unlock_icon_hovered,
       callbacks.on_easy_unlock_icon_tapped);
 
-  auto pin_input_view = std::make_unique<LoginPinInputView>();
+  auto pin_input_view = std::make_unique<LoginPinInputView>(palette);
   pin_input_view_ = pin_input_view.get();
   pin_input_view->Init(base::BindRepeating(&LoginAuthUserView::OnAuthSubmit,
                                            base::Unretained(this)),
diff --git a/ash/login/ui/login_palette.cc b/ash/login/ui/login_palette.cc
index e1a84b08..2d0682a7 100644
--- a/ash/login/ui/login_palette.cc
+++ b/ash/login/ui/login_palette.cc
@@ -30,7 +30,9 @@
        .pin_ink_drop_highlight_color =
            SkColorSetA(ripple_attributes.base_color, highlight_opacity),
        .pin_ink_drop_ripple_color =
-           SkColorSetA(ripple_attributes.base_color, inkdrop_opacity)});
+           SkColorSetA(ripple_attributes.base_color, inkdrop_opacity),
+       .pin_input_text_color = AshColorProvider::Get()->GetContentLayerColor(
+           AshColorProvider::ContentLayerType::kTextColorPrimary)});
 }
 
 LoginPalette CreateInSessionAuthPalette() {
@@ -41,7 +43,8 @@
        .button_enabled_color = SK_ColorDKGRAY,
        .button_annotation_color = SK_ColorDKGRAY,
        .pin_ink_drop_highlight_color = SkColorSetA(SK_ColorDKGRAY, 0x0A),
-       .pin_ink_drop_ripple_color = SkColorSetA(SK_ColorDKGRAY, 0x0F)});
+       .pin_ink_drop_ripple_color = SkColorSetA(SK_ColorDKGRAY, 0x0F),
+       .pin_input_text_color = SK_ColorDKGRAY});
 }
 
 }  // namespace ash
diff --git a/ash/login/ui/login_palette.h b/ash/login/ui/login_palette.h
index e35c44c..d18bf8a7 100644
--- a/ash/login/ui/login_palette.h
+++ b/ash/login/ui/login_palette.h
@@ -22,6 +22,7 @@
   SkColor button_annotation_color;
   SkColor pin_ink_drop_highlight_color;
   SkColor pin_ink_drop_ripple_color;
+  SkColor pin_input_text_color;
 };
 
 // For login screen and lock screen.
diff --git a/ash/login/ui/login_pin_input_view.cc b/ash/login/ui/login_pin_input_view.cc
index e872f60..ceeafbc2 100644
--- a/ash/login/ui/login_pin_input_view.cc
+++ b/ash/login/ui/login_pin_input_view.cc
@@ -37,6 +37,7 @@
 class LoginPinInput : public FixedLengthCodeInput {
  public:
   LoginPinInput(int length,
+                const LoginPalette& palette,
                 LoginPinInputView::OnPinSubmit on_submit,
                 LoginPinInputView::OnPinChanged on_changed);
 
@@ -61,6 +62,7 @@
 };
 
 LoginPinInput::LoginPinInput(int length,
+                             const LoginPalette& palette,
                              LoginPinInputView::OnPinSubmit on_submit,
                              LoginPinInputView::OnPinChanged on_changed)
     : FixedLengthCodeInput(length,
@@ -69,7 +71,8 @@
                                                base::Unretained(this)),
                            /*on_enter*/ base::DoNothing(),
                            /*on_escape*/ base::DoNothing(),
-                           /*obscure_pin*/ true),
+                           /*obscure_pin*/ true,
+                           /*text_color*/ palette.pin_input_text_color),
       length_(length),
       on_submit_(on_submit),
       on_changed_(on_changed) {
@@ -147,11 +150,12 @@
   return view_->code_input_;
 }
 
-LoginPinInputView::LoginPinInputView() : length_(kDefaultLength) {
+LoginPinInputView::LoginPinInputView(const LoginPalette& palette)
+    : length_(kDefaultLength), palette_(palette) {
   SetLayoutManager(std::make_unique<views::FillLayout>());
 
   code_input_ = AddChildView(std::make_unique<LoginPinInput>(
-      length_,
+      length_, palette_,
       base::BindRepeating(&LoginPinInputView::SubmitPin,
                           base::Unretained(this)),
       base::BindRepeating(&LoginPinInputView::OnChanged,
@@ -192,7 +196,7 @@
   RemoveChildView(code_input_);
   delete code_input_;
   code_input_ = AddChildView(std::make_unique<LoginPinInput>(
-      pin_length,
+      pin_length, palette_,
       base::BindRepeating(&LoginPinInputView::SubmitPin,
                           base::Unretained(this)),
       base::BindRepeating(&LoginPinInputView::OnChanged,
diff --git a/ash/login/ui/login_pin_input_view.h b/ash/login/ui/login_pin_input_view.h
index 848893d4..38a4c772 100644
--- a/ash/login/ui/login_pin_input_view.h
+++ b/ash/login/ui/login_pin_input_view.h
@@ -7,6 +7,7 @@
 
 #include "ash/ash_export.h"
 #include "ash/login/ui/access_code_input.h"
+#include "ash/login/ui/login_palette.h"
 #include "ash/login/ui/non_accessible_view.h"
 #include "ui/views/view.h"
 
@@ -47,7 +48,7 @@
     LoginPinInputView* const view_;
   };
 
-  LoginPinInputView();
+  explicit LoginPinInputView(const LoginPalette& palette);
   LoginPinInputView& operator=(const LoginPinInputView&) = delete;
   LoginPinInputView(const LoginPinInputView&) = delete;
   ~LoginPinInputView() override;
@@ -90,6 +91,9 @@
   // Current field length.
   size_t length_ = kDefaultLength;
 
+  // Palette for the instance.
+  LoginPalette palette_;
+
   // Whether the field is read only.
   bool is_read_only_ = false;
 
@@ -105,4 +109,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_LOGIN_UI_LOGIN_PIN_INPUT_VIEW_H_
\ No newline at end of file
+#endif  // ASH_LOGIN_UI_LOGIN_PIN_INPUT_VIEW_H_
diff --git a/ash/login/ui/login_pin_input_view_unittest.cc b/ash/login/ui/login_pin_input_view_unittest.cc
index 27a9ae1..94bcc82 100644
--- a/ash/login/ui/login_pin_input_view_unittest.cc
+++ b/ash/login/ui/login_pin_input_view_unittest.cc
@@ -5,6 +5,7 @@
 #include "ash/login/ui/login_pin_input_view.h"
 #include <memory>
 #include <string>
+#include "ash/login/ui/login_palette.h"
 #include "ash/login/ui/login_test_base.h"
 #include "base/bind.h"
 #include "base/optional.h"
@@ -32,7 +33,7 @@
 
   void SetUp() override {
     LoginTestBase::SetUp();
-    view_ = new LoginPinInputView();
+    view_ = new LoginPinInputView(CreateDefaultLoginPalette());
     view_->Init(base::BindRepeating(&LoginPinInputViewTest::OnPinSubmit,
                                     base::Unretained(this)),
                 base::BindRepeating(&LoginPinInputViewTest::OnPinChanged,
diff --git a/ash/login/ui/pin_request_view.cc b/ash/login/ui/pin_request_view.cc
index ee74711..82bdd18 100644
--- a/ash/login/ui/pin_request_view.cc
+++ b/ash/login/ui/pin_request_view.cc
@@ -311,6 +311,8 @@
 
   add_spacer(kDescriptionToAccessCodeDistanceDp);
 
+  LoginPalette palette = CreateDefaultLoginPalette();
+
   // Access code input view.
   if (request.pin_length.has_value()) {
     CHECK_GT(request.pin_length.value(), 0);
@@ -321,7 +323,7 @@
         base::BindRepeating(&PinRequestView::SubmitCode,
                             base::Unretained(this)),
         base::BindRepeating(&PinRequestView::OnBack, base::Unretained(this)),
-        request.obscure_pin));
+        request.obscure_pin, palette.pin_input_text_color));
     access_code_view_->SetFocusBehavior(FocusBehavior::ALWAYS);
   } else {
     auto flex_code_input = std::make_unique<FlexCodeInput>(
@@ -330,7 +332,7 @@
         base::BindRepeating(&PinRequestView::SubmitCode,
                             base::Unretained(this)),
         base::BindRepeating(&PinRequestView::OnBack, base::Unretained(this)),
-        request.obscure_pin);
+        request.obscure_pin, palette.pin_input_text_color);
     flex_code_input->SetAccessibleName(default_accessible_title_);
     access_code_view_ = AddChildView(std::move(flex_code_input));
   }
diff --git a/ash/quick_answers/ui/user_notice_view.cc b/ash/quick_answers/ui/user_notice_view.cc
index 2ff5fc2f..6b3fac5 100644
--- a/ash/quick_answers/ui/user_notice_view.cc
+++ b/ash/quick_answers/ui/user_notice_view.cc
@@ -68,8 +68,8 @@
 // Accept button.
 constexpr SkColor kAcceptButtonTextColor = gfx::kGoogleGrey200;
 constexpr char kA11yAcceptButtonDescText[] =
-    "Let Assistant show info such as definition or unit conversion for your "
-    "selection.";
+    "Let Assistant show info such as definition, translation or unit "
+    "conversion for your selection.";
 
 // Dogfood button.
 constexpr int kDogfoodButtonMarginDip = 4;
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index abba70ad..d059ad8 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -36,6 +36,7 @@
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
 #include "ash/strings/grit/ash_strings.h"
+#include "ash/style/ash_color_provider.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/wm/desks/desks_util.h"
 #include "ash/wm/mru_window_tracker.h"
@@ -100,9 +101,6 @@
 
 namespace {
 
-// White with ~20% opacity.
-constexpr SkColor kSeparatorColor = SkColorSetARGB(0x32, 0xFF, 0xFF, 0xFF);
-
 // The dimensions, in pixels, of the separator between pinned and unpinned
 // items.
 constexpr int kSeparatorSize = 20;
@@ -400,7 +398,8 @@
       IconAnimationType::kFadeOutAnimation);
 
   separator_ = new views::Separator();
-  separator_->SetColor(kSeparatorColor);
+  separator_->SetColor(AshColorProvider::Get()->GetContentLayerColor(
+      AshColorProvider::ContentLayerType::kSeparatorColor));
   separator_->SetPreferredHeight(kSeparatorSize);
   separator_->SetVisible(false);
   ConfigureChildView(separator_, ui::LAYER_TEXTURED);
diff --git a/ash/system/privacy_screen/privacy_screen_toast_controller.cc b/ash/system/privacy_screen/privacy_screen_toast_controller.cc
index e641314..b516595 100644
--- a/ash/system/privacy_screen/privacy_screen_toast_controller.cc
+++ b/ash/system/privacy_screen/privacy_screen_toast_controller.cc
@@ -57,7 +57,9 @@
   init_params.translucent = true;
 
   bubble_view_ = new TrayBubbleView(init_params);
-  toast_view_ = new PrivacyScreenToastView(this);
+  toast_view_ = new PrivacyScreenToastView(
+      this, base::BindRepeating(&PrivacyScreenToastController::ButtonPressed,
+                                base::Unretained(this)));
   bubble_view_->AddChildView(toast_view_);
 
   bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_view_);
@@ -143,8 +145,7 @@
   }
 }
 
-void PrivacyScreenToastController::ButtonPressed(views::Button* sender,
-                                                 const ui::Event& event) {
+void PrivacyScreenToastController::ButtonPressed() {
   auto* privacy_screen_controller = Shell::Get()->privacy_screen_controller();
   privacy_screen_controller->SetEnabled(
       !privacy_screen_controller->GetEnabled(),
diff --git a/ash/system/privacy_screen/privacy_screen_toast_controller.h b/ash/system/privacy_screen/privacy_screen_toast_controller.h
index c45382d1..8d79766 100644
--- a/ash/system/privacy_screen/privacy_screen_toast_controller.h
+++ b/ash/system/privacy_screen/privacy_screen_toast_controller.h
@@ -19,8 +19,7 @@
 // privacy screen is toggled on/off.
 class ASH_EXPORT PrivacyScreenToastController
     : public TrayBubbleView::Delegate,
-      public PrivacyScreenController::Observer,
-      public views::ButtonListener {
+      public PrivacyScreenController::Observer {
  public:
   explicit PrivacyScreenToastController(UnifiedSystemTray* tray);
   ~PrivacyScreenToastController() override;
@@ -46,6 +45,8 @@
   // Updates the toast UI with the current privacy screen state.
   void UpdateToastView();
 
+  void ButtonPressed();
+
   // TrayBubbleView::Delegate:
   void BubbleViewDestroyed() override;
   void OnMouseEnteredView() override;
@@ -55,9 +56,6 @@
   // PrivacyScreenController::Observer:
   void OnPrivacyScreenSettingChanged(bool enabled) override;
 
-  // views::ButtonListener:
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
-
   UnifiedSystemTray* const tray_;
   TrayBubbleView* bubble_view_ = nullptr;
   views::Widget* bubble_widget_ = nullptr;
diff --git a/ash/system/privacy_screen/privacy_screen_toast_view.cc b/ash/system/privacy_screen/privacy_screen_toast_view.cc
index 03cfb1e..1d8a0f0 100644
--- a/ash/system/privacy_screen/privacy_screen_toast_view.cc
+++ b/ash/system/privacy_screen/privacy_screen_toast_view.cc
@@ -111,7 +111,8 @@
 };
 
 PrivacyScreenToastView::PrivacyScreenToastView(
-    PrivacyScreenToastController* controller)
+    PrivacyScreenToastController* controller,
+    views::Button::PressedCallback callback)
     : controller_(controller) {
   auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kHorizontal, kPrivacyScreenToastInsets,
@@ -119,7 +120,8 @@
   layout->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::kCenter);
 
-  button_ = new FeaturePodIconButton(controller, /*is_togglable=*/true);
+  button_ =
+      new FeaturePodIconButton(std::move(callback), /*is_togglable=*/true);
   button_->SetVectorIcon(kPrivacyScreenIcon);
   button_->SetToggled(false);
   button_->AddObserver(this);
diff --git a/ash/system/privacy_screen/privacy_screen_toast_view.h b/ash/system/privacy_screen/privacy_screen_toast_view.h
index 3a0672a3..841f687 100644
--- a/ash/system/privacy_screen/privacy_screen_toast_view.h
+++ b/ash/system/privacy_screen/privacy_screen_toast_view.h
@@ -20,7 +20,8 @@
 class ASH_EXPORT PrivacyScreenToastView : public views::View,
                                           public views::ViewObserver {
  public:
-  explicit PrivacyScreenToastView(PrivacyScreenToastController* controller);
+  PrivacyScreenToastView(PrivacyScreenToastController* controller,
+                         views::Button::PressedCallback callback);
   ~PrivacyScreenToastView() override;
   PrivacyScreenToastView(PrivacyScreenToastView&) = delete;
   PrivacyScreenToastView operator=(PrivacyScreenToastView&) = delete;
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 3e44373..d8ef814 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -3871,6 +3871,7 @@
       "test/android/javatests/src/org/chromium/base/test/util/CallbackHelper.java",
       "test/android/javatests/src/org/chromium/base/test/util/CloseableOnMainThread.java",
       "test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java",
+      "test/android/javatests/src/org/chromium/base/test/util/CriteriaNotSatisfiedException.java",
       "test/android/javatests/src/org/chromium/base/test/util/DisableIf.java",
       "test/android/javatests/src/org/chromium/base/test/util/DisableIfSkipCheck.java",
       "test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java",
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/CriteriaNotSatisfiedException.java b/base/test/android/javatests/src/org/chromium/base/test/util/CriteriaNotSatisfiedException.java
new file mode 100644
index 0000000..0d5bffcc
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/CriteriaNotSatisfiedException.java
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+/**
+ * Exception indicating that a Criteria did not match expectations.
+ */
+public class CriteriaNotSatisfiedException extends AssertionError {
+    /**
+     * @param msg The reason the criteria was not met.
+     */
+    public CriteriaNotSatisfiedException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @param cause The underlying exception that prevented the Criteria.
+     */
+    public CriteriaNotSatisfiedException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/base/trace_event/interned_args_helper.h b/base/trace_event/interned_args_helper.h
index 2f8f5bb..ac85c19 100644
--- a/base/trace_event/interned_args_helper.h
+++ b/base/trace_event/interned_args_helper.h
@@ -44,7 +44,7 @@
 namespace std {
 
 template <>
-struct ::std::hash<base::trace_event::TraceSourceLocation> {
+struct hash<base::trace_event::TraceSourceLocation> {
   std::size_t operator()(
       const base::trace_event::TraceSourceLocation& loc) const {
     static_assert(sizeof(base::trace_event::TraceSourceLocation) ==
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 02f11ef..3ee99cc 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20201029.0.1
+0.20201029.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 02f11ef..3ee99cc 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20201029.0.1
+0.20201029.2.1
diff --git a/cc/base/math_util.cc b/cc/base/math_util.cc
index d9b43f4..486974d 100644
--- a/cc/base/math_util.cc
+++ b/cc/base/math_util.cc
@@ -804,6 +804,22 @@
   res->EndArray();
 }
 
+void MathUtil::AddCornerRadiiToTracedValue(
+    const char* name,
+    const gfx::RRectF& rect,
+    base::trace_event::TracedValue* res) {
+  res->BeginArray(name);
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kUpperLeft).x());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kUpperLeft).y());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kUpperRight).x());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kUpperRight).y());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kLowerRight).x());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kLowerRight).y());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kLowerLeft).x());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kLowerLeft).y());
+  res->EndArray();
+}
+
 double MathUtil::AsDoubleSafely(double value) {
   return std::min(value, std::numeric_limits<double>::max());
 }
diff --git a/cc/base/math_util.h b/cc/base/math_util.h
index 1368c9c1..8cb8c386 100644
--- a/cc/base/math_util.h
+++ b/cc/base/math_util.h
@@ -16,6 +16,7 @@
 #include "ui/gfx/geometry/box_f.h"
 #include "ui/gfx/geometry/point3_f.h"
 #include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rounded_corners_f.h"
 #include "ui/gfx/geometry/scroll_offset.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/transform.h"
@@ -303,6 +304,9 @@
   static void AddToTracedValue(const char* name,
                                const gfx::RRectF& rect,
                                base::trace_event::TracedValue* res);
+  static void AddCornerRadiiToTracedValue(const char* name,
+                                          const gfx::RRectF& rect,
+                                          base::trace_event::TracedValue* res);
 
   // Returns a base::Value representation of the floating point value.
   // If the value is inf, returns max double/float representation.
diff --git a/cc/layers/draw_properties.h b/cc/layers/draw_properties.h
index d5a0a7d8..d5efc6d 100644
--- a/cc/layers/draw_properties.h
+++ b/cc/layers/draw_properties.h
@@ -11,7 +11,7 @@
 
 #include "cc/trees/occlusion.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/rrect_f.h"
+#include "ui/gfx/mask_filter_info.h"
 #include "ui/gfx/transform.h"
 
 namespace cc {
@@ -61,9 +61,9 @@
   // value is used to avoid unnecessarily changing GL scissor state.
   gfx::Rect clip_rect;
 
-  // Contains a rounded corner rect to clip this layer when drawing. This rrect
-  // is in the target space of the layer.
-  gfx::RRectF rounded_corner_bounds;
+  // Contains a mask information applied to the layer. The coordinates is in the
+  // target space of the layer.
+  gfx::MaskFilterInfo mask_filter_info;
 };
 
 }  // namespace cc
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 957f458a..5249bbd 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -551,8 +551,8 @@
         effect_tree_index() != EffectTree::kInvalidNodeId) {
       if (EffectNode* node =
               property_trees->effect_tree.Node(effect_tree_index())) {
-        node->rounded_corner_bounds =
-            gfx::RRectF(effective_clip_rect, corner_radii());
+        node->mask_filter_info =
+            gfx::MaskFilterInfo(effective_clip_rect, corner_radii());
         node->effect_changed = true;
         property_trees->effect_tree.set_needs_update(true);
       }
@@ -658,8 +658,8 @@
   EffectNode* node = nullptr;
   if (property_trees && effect_tree_index() != EffectTree::kInvalidNodeId &&
       (node = property_trees->effect_tree.Node(effect_tree_index()))) {
-    node->rounded_corner_bounds =
-        gfx::RRectF(EffectiveClipRect(), corner_radii);
+    node->mask_filter_info =
+        gfx::MaskFilterInfo(EffectiveClipRect(), corner_radii);
     node->effect_changed = true;
     property_trees->effect_tree.set_needs_update(true);
   } else {
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index b29796f9..460019a 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -142,9 +142,9 @@
   EffectNode* effect_node = GetEffectTree().Node(effect_tree_index_);
   state->SetAll(draw_properties_.target_space_transform, gfx::Rect(bounds()),
                 draw_properties_.visible_layer_rect,
-                draw_properties_.rounded_corner_bounds,
-                draw_properties_.clip_rect, draw_properties_.is_clipped,
-                contents_opaque, draw_properties_.opacity,
+                draw_properties_.mask_filter_info, draw_properties_.clip_rect,
+                draw_properties_.is_clipped, contents_opaque,
+                draw_properties_.opacity,
                 effect_node->HasRenderSurface() ? SkBlendMode::kSrcOver
                                                 : effect_node->blend_mode,
                 GetSortingContextId());
@@ -178,9 +178,9 @@
 
   EffectNode* effect_node = GetEffectTree().Node(effect_tree_index_);
   state->SetAll(scaled_draw_transform, content_rect, visible_content_rect,
-                draw_properties().rounded_corner_bounds,
-                draw_properties().clip_rect, draw_properties().is_clipped,
-                contents_opaque, draw_properties().opacity,
+                draw_properties().mask_filter_info, draw_properties().clip_rect,
+                draw_properties().is_clipped, contents_opaque,
+                draw_properties().opacity,
                 effect_node->HasRenderSurface() ? SkBlendMode::kSrcOver
                                                 : effect_node->blend_mode,
                 GetSortingContextId());
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index b483fc7..2b7d4d69 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -1811,15 +1811,15 @@
       layer_5->effect_tree_index());
 
   EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners),
-            node_1->rounded_corner_bounds);
+            node_1->mask_filter_info.rounded_corner_bounds());
   EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners),
-            node_2->rounded_corner_bounds);
+            node_2->mask_filter_info.rounded_corner_bounds());
   EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners),
-            node_3->rounded_corner_bounds);
+            node_3->mask_filter_info.rounded_corner_bounds());
   EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners),
-            node_4->rounded_corner_bounds);
+            node_4->mask_filter_info.rounded_corner_bounds());
   EXPECT_EQ(gfx::RRectF(gfx::RectF(gfx::Rect(kLayerSize)), kRoundedCorners),
-            node_5->rounded_corner_bounds);
+            node_5->mask_filter_info.rounded_corner_bounds());
 
   // Setting clip to layer bounds.
   layer_1->SetMasksToBounds(true);
@@ -1850,18 +1850,18 @@
   EXPECT_EQ(gfx::RRectF(gfx::RectF(gfx::IntersectRects(gfx::Rect(kLayerSize),
                                                        kClipRect)),
                         kUpdatedRoundedCorners),
-            node_1->rounded_corner_bounds);
+            node_1->mask_filter_info.rounded_corner_bounds());
   EXPECT_EQ(gfx::RRectF(gfx::RectF(gfx::IntersectRects(gfx::Rect(kLayerSize),
                                                        kClipRect)),
                         kUpdatedRoundedCorners),
-            node_2->rounded_corner_bounds);
+            node_2->mask_filter_info.rounded_corner_bounds());
   EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kUpdatedRoundedCorners),
-            node_3->rounded_corner_bounds);
+            node_3->mask_filter_info.rounded_corner_bounds());
   EXPECT_EQ(gfx::RRectF(gfx::RectF(kUpdatedClipRect), kRoundedCorners),
-            node_4->rounded_corner_bounds);
+            node_4->mask_filter_info.rounded_corner_bounds());
   EXPECT_EQ(
       gfx::RRectF(gfx::RectF(gfx::Rect(kLayerSize)), kUpdatedRoundedCorners),
-      node_5->rounded_corner_bounds);
+      node_5->mask_filter_info.rounded_corner_bounds());
 }
 
 }  // namespace
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc
index ac3f7c28..a1eb58c 100644
--- a/cc/layers/render_surface_impl.cc
+++ b/cc/layers/render_surface_impl.cc
@@ -399,7 +399,7 @@
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(
-      draw_transform(), content_rect(), content_rect(), rounded_corner_bounds(),
+      draw_transform(), content_rect(), content_rect(), mask_filter_info(),
       draw_properties_.clip_rect, draw_properties_.is_clipped, contents_opaque,
       draw_properties_.draw_opacity, BlendMode(), sorting_context_id);
 
diff --git a/cc/layers/render_surface_impl.h b/cc/layers/render_surface_impl.h
index 115b49a..0dc3766 100644
--- a/cc/layers/render_surface_impl.h
+++ b/cc/layers/render_surface_impl.h
@@ -20,6 +20,7 @@
 #include "components/viz/common/quads/shared_quad_state.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/mask_filter_info.h"
 #include "ui/gfx/transform.h"
 
 namespace cc {
@@ -54,11 +55,11 @@
   }
   float draw_opacity() const { return draw_properties_.draw_opacity; }
 
-  void SetRoundedCornerRRect(const gfx::RRectF& rounded_corner_bounds) {
-    draw_properties_.rounded_corner_bounds = rounded_corner_bounds;
+  void SetMaskFilterInfo(const gfx::MaskFilterInfo& mask_filter_info) {
+    draw_properties_.mask_filter_info = mask_filter_info;
   }
-  const gfx::RRectF& rounded_corner_bounds() const {
-    return draw_properties_.rounded_corner_bounds;
+  const gfx::MaskFilterInfo& mask_filter_info() const {
+    return draw_properties_.mask_filter_info;
   }
 
   SkBlendMode BlendMode() const;
@@ -241,10 +242,10 @@
     // True if the surface needs to be clipped by clip_rect.
     bool is_clipped : 1;
 
-    // Contains a rounded corner rect to clip this render surface by when
-    // drawing. This rrect is in the target space of the render surface.  The
-    // root render surface will never have this set.
-    gfx::RRectF rounded_corner_bounds;
+    // Contains a mask information applied to the layer. The coordinates is in
+    // the target space of the render surface. The root render surface will
+    // never have this set.
+    gfx::MaskFilterInfo mask_filter_info;
   };
 
   DrawProperties draw_properties_;
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc
index 3767b58a..824dd4a 100644
--- a/cc/layers/video_layer_impl.cc
+++ b/cc/layers/video_layer_impl.cc
@@ -163,10 +163,10 @@
   if (visible_quad_rect.IsEmpty())
     return;
 
-  updater_->AppendQuads(
-      render_pass, frame_, transform, quad_rect, visible_quad_rect,
-      draw_properties().rounded_corner_bounds, clip_rect(), is_clipped(),
-      contents_opaque(), draw_opacity(), GetSortingContextId());
+  updater_->AppendQuads(render_pass, frame_, transform, quad_rect,
+                        visible_quad_rect, draw_properties().mask_filter_info,
+                        clip_rect(), is_clipped(), contents_opaque(),
+                        draw_opacity(), GetSortingContextId());
 }
 
 void VideoLayerImpl::DidDraw(viz::ClientResourceProvider* resource_provider) {
diff --git a/cc/test/render_pass_test_utils.cc b/cc/test/render_pass_test_utils.cc
index 3809da1..3232fdc 100644
--- a/cc/test/render_pass_test_utils.cc
+++ b/cc/test/render_pass_test_utils.cc
@@ -112,8 +112,8 @@
                                         const gfx::Rect& rect,
                                         SkColor color) {
   viz::SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect, true,
-                       false, 1, SkBlendMode::kSrcOver, 0);
+  shared_state->SetAll(gfx::Transform(), rect, rect, gfx::MaskFilterInfo(),
+                       rect, true, false, 1, SkBlendMode::kSrcOver, 0);
   auto* quad = pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
   quad->SetNew(shared_state, rect, rect, color, false);
   return quad;
@@ -124,8 +124,8 @@
                                             SkColor color,
                                             const gfx::Transform& transform) {
   viz::SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(transform, rect, rect, gfx::RRectF(), rect, false, false,
-                       1,
+  shared_state->SetAll(transform, rect, rect, gfx::MaskFilterInfo(), rect,
+                       false, false, 1,
 
                        SkBlendMode::kSrcOver, 0);
   auto* quad = pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
@@ -140,7 +140,7 @@
   viz::SharedQuadState* shared_state =
       to_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(gfx::Transform(), output_rect, output_rect,
-                       gfx::RRectF(), output_rect, false, false, 1,
+                       gfx::MaskFilterInfo(), output_rect, false, false, 1,
                        SkBlendMode::kSrcOver, 0);
   auto* quad = to_pass->template CreateAndAppendDrawQuad<QuadType>();
   quad->SetNew(shared_state, output_rect, output_rect, contributing_pass->id, 0,
@@ -170,8 +170,9 @@
   gfx::Rect output_rect = contributing_pass->output_rect;
   viz::SharedQuadState* shared_state =
       to_pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(transform, output_rect, output_rect, gfx::RRectF(),
-                       output_rect, false, false, 1, blend_mode, 0);
+  shared_state->SetAll(transform, output_rect, output_rect,
+                       gfx::MaskFilterInfo(), output_rect, false, false, 1,
+                       blend_mode, 0);
   auto* quad =
       to_pass->CreateAndAppendDrawQuad<viz::AggregatedRenderPassDrawQuad>();
   gfx::Size arbitrary_nonzero_size(1, 1);
@@ -217,8 +218,8 @@
 
   viz::SharedQuadState* shared_state =
       to_pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect, false,
-                       false, 1, SkBlendMode::kSrcOver, 0);
+  shared_state->SetAll(gfx::Transform(), rect, rect, gfx::MaskFilterInfo(),
+                       rect, false, false, 1, SkBlendMode::kSrcOver, 0);
 
   auto* debug_border_quad =
       to_pass->CreateAndAppendDrawQuad<viz::DebugBorderDrawQuad>();
@@ -278,8 +279,8 @@
 
   viz::SharedQuadState* shared_state2 =
       to_pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect, false,
-                       false, 1, SkBlendMode::kSrcOver, 0);
+  shared_state->SetAll(gfx::Transform(), rect, rect, gfx::MaskFilterInfo(),
+                       rect, false, false, 1, SkBlendMode::kSrcOver, 0);
 
   auto* tile_quad = to_pass->CreateAndAppendDrawQuad<viz::TileDrawQuad>();
   tile_quad->SetNew(shared_state2, rect, visible_rect, needs_blending,
@@ -394,8 +395,8 @@
 
   viz::SharedQuadState* shared_state =
       to_pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect, false,
-                       false, 1, SkBlendMode::kSrcOver, 0);
+  shared_state->SetAll(gfx::Transform(), rect, rect, gfx::MaskFilterInfo(),
+                       rect, false, false, 1, SkBlendMode::kSrcOver, 0);
 
   viz::DebugBorderDrawQuad* debug_border_quad =
       to_pass->CreateAndAppendDrawQuad<viz::DebugBorderDrawQuad>();
@@ -455,8 +456,8 @@
 
   viz::SharedQuadState* shared_state2 =
       to_pass->CreateAndAppendSharedQuadState();
-  shared_state2->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
-                        false, false, 1, SkBlendMode::kSrcOver, 0);
+  shared_state2->SetAll(gfx::Transform(), rect, rect, gfx::MaskFilterInfo(),
+                        rect, false, false, 1, SkBlendMode::kSrcOver, 0);
 
   viz::TileDrawQuad* tile_quad =
       to_pass->CreateAndAppendDrawQuad<viz::TileDrawQuad>();
diff --git a/cc/test/render_pass_test_utils.h b/cc/test/render_pass_test_utils.h
index 54a8d59..0c4b5001 100644
--- a/cc/test/render_pass_test_utils.h
+++ b/cc/test/render_pass_test_utils.h
@@ -72,8 +72,8 @@
                                         const gfx::Rect& rect,
                                         SkColor color) {
   viz::SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect, false,
-                       false, 1, SkBlendMode::kSrcOver, 0);
+  shared_state->SetAll(gfx::Transform(), rect, rect, gfx::MaskFilterInfo(),
+                       rect, false, false, 1, SkBlendMode::kSrcOver, 0);
   auto* quad =
       pass->template CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
   quad->SetNew(shared_state, rect, rect, color, false);
diff --git a/cc/trees/draw_properties_unittest.cc b/cc/trees/draw_properties_unittest.cc
index cd040c96..d461d6a 100644
--- a/cc/trees/draw_properties_unittest.cc
+++ b/cc/trees/draw_properties_unittest.cc
@@ -8122,12 +8122,12 @@
   UpdateMainDrawProperties();
   CommitAndActivate();
 
-  EXPECT_FALSE(
-      GetRenderSurfaceImpl(child_1)->rounded_corner_bounds().IsEmpty());
-  EXPECT_FALSE(
-      GetRenderSurfaceImpl(child_2)->rounded_corner_bounds().IsEmpty());
-  EXPECT_FALSE(
-      GetRenderSurfaceImpl(child_3)->rounded_corner_bounds().IsEmpty());
+  EXPECT_TRUE(
+      GetRenderSurfaceImpl(child_1)->mask_filter_info().HasRoundedCorners());
+  EXPECT_TRUE(
+      GetRenderSurfaceImpl(child_2)->mask_filter_info().HasRoundedCorners());
+  EXPECT_TRUE(
+      GetRenderSurfaceImpl(child_3)->mask_filter_info().HasRoundedCorners());
 }
 
 }  // namespace
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 1e007fd..c2e79fc 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -706,27 +706,28 @@
                                 layer->clip_tree_index(), target_node->id);
 }
 
-std::pair<gfx::RRectF, bool> GetRoundedCornerRRect(
+std::pair<gfx::MaskFilterInfo, bool> GetMaskFilterInfoPair(
     const PropertyTrees* property_trees,
     int effect_tree_index,
     bool for_render_surface) {
-  static const std::pair<gfx::RRectF, bool> kEmptyRoundedCornerInfo(
-      gfx::RRectF(), false);
+  static const std::pair<gfx::MaskFilterInfo, bool> kEmptyMaskFilterInfoPair =
+      std::make_pair(gfx::MaskFilterInfo(), false);
+
   const EffectTree* effect_tree = &property_trees->effect_tree;
   const EffectNode* effect_node = effect_tree->Node(effect_tree_index);
   const int target_id = effect_node->target_id;
 
-  // Return empty rrect if this node has a render surface but the function call
-  // was made for a non render surface.
+  // Return empty mask info if this node has a render surface but the function
+  // call was made for a non render surface.
   if (effect_node->HasRenderSurface() && !for_render_surface)
-    return kEmptyRoundedCornerInfo;
+    return kEmptyMaskFilterInfoPair;
 
   // Traverse the parent chain up to the render target to find a node which has
   // a rounded corner bounds set.
   const EffectNode* node = effect_node;
   bool found_rounded_corner = false;
   while (node) {
-    if (!node->rounded_corner_bounds.IsEmpty()) {
+    if (node->mask_filter_info.HasRoundedCorners()) {
       found_rounded_corner = true;
       break;
     }
@@ -749,17 +750,17 @@
   // While traversing up the parent chain we did not find any node with a
   // rounded corner.
   if (!node || !found_rounded_corner)
-    return kEmptyRoundedCornerInfo;
+    return kEmptyMaskFilterInfoPair;
 
   gfx::Transform to_target;
   if (!property_trees->GetToTarget(node->transform_id, target_id, &to_target))
-    return kEmptyRoundedCornerInfo;
+    return kEmptyMaskFilterInfoPair;
 
   auto result =
-      std::make_pair(node->rounded_corner_bounds, node->is_fast_rounded_corner);
+      std::make_pair(node->mask_filter_info, node->is_fast_rounded_corner);
 
-  if (!to_target.TransformRRectF(&result.first))
-    return kEmptyRoundedCornerInfo;
+  if (!result.first.Transform(to_target))
+    return kEmptyMaskFilterInfoPair;
 
   return result;
 }
@@ -839,9 +840,9 @@
   SetSurfaceDrawOpacity(property_trees->effect_tree, render_surface);
   SetSurfaceDrawTransform(property_trees, render_surface);
 
-  render_surface->SetRoundedCornerRRect(
-      GetRoundedCornerRRect(property_trees, render_surface->EffectTreeIndex(),
-                            /*for_render_surface*/ true)
+  render_surface->SetMaskFilterInfo(
+      GetMaskFilterInfoPair(property_trees, render_surface->EffectTreeIndex(),
+                            /*for_render_surface=*/true)
           .first);
   render_surface->SetScreenSpaceTransform(
       property_trees->ToScreenSpaceTransformWithoutSurfaceContentsScale(
@@ -1142,12 +1143,12 @@
         layer, property_trees->transform_tree, property_trees->effect_tree);
     layer->draw_properties().screen_space_transform_is_animating =
         transform_node->to_screen_is_potentially_animated;
-    auto rounded_corner_info =
-        GetRoundedCornerRRect(property_trees, layer->effect_tree_index(),
-                              /*from_render_surface*/ false);
-    layer->draw_properties().rounded_corner_bounds = rounded_corner_info.first;
+    auto mask_filter_info_pair =
+        GetMaskFilterInfoPair(property_trees, layer->effect_tree_index(),
+                              /*from_render_surface=*/false);
+    layer->draw_properties().mask_filter_info = mask_filter_info_pair.first;
     layer->draw_properties().is_fast_rounded_corner =
-        rounded_corner_info.second;
+        mask_filter_info_pair.second;
   }
 
   // Compute effects and determine if render surfaces have contributing layers
diff --git a/cc/trees/effect_node.cc b/cc/trees/effect_node.cc
index de8b74ca..fa07fea5 100644
--- a/cc/trees/effect_node.cc
+++ b/cc/trees/effect_node.cc
@@ -60,7 +60,7 @@
          backdrop_filters == other.backdrop_filters &&
          backdrop_filter_bounds == other.backdrop_filter_bounds &&
          backdrop_mask_element_id == other.backdrop_mask_element_id &&
-         rounded_corner_bounds == other.rounded_corner_bounds &&
+         mask_filter_info == other.mask_filter_info &&
          is_fast_rounded_corner == other.is_fast_rounded_corner &&
          node_or_ancestor_has_filters == other.node_or_ancestor_has_filters &&
          affected_by_backdrop_filter == other.affected_by_backdrop_filter &&
@@ -158,12 +158,18 @@
   if (!backdrop_filters.IsEmpty())
     value->SetString("backdrop_filters", backdrop_filters.ToString());
   value->SetDouble("backdrop_filter_quality", backdrop_filter_quality);
-  value->SetBoolean("is_fast_rounded_corner", is_fast_rounded_corner);
   value->SetBoolean("node_or_ancestor_has_filters",
                     node_or_ancestor_has_filters);
-  if (!rounded_corner_bounds.IsEmpty()) {
-    MathUtil::AddToTracedValue("rounded_corner_bounds", rounded_corner_bounds,
+  if (!mask_filter_info.IsEmpty()) {
+    MathUtil::AddToTracedValue("mask_filter_bounds", mask_filter_info.bounds(),
                                value);
+    if (mask_filter_info.HasRoundedCorners()) {
+      MathUtil::AddCornerRadiiToTracedValue(
+          "mask_filter_rounded_corner_raii",
+          mask_filter_info.rounded_corner_bounds(), value);
+      value->SetBoolean("mask_filter_is_fast_rounded_corner",
+                        is_fast_rounded_corner);
+    }
   }
   value->SetString("blend_mode", SkBlendMode_Name(blend_mode));
   value->SetBoolean("cache_render_surface", cache_render_surface);
diff --git a/cc/trees/effect_node.h b/cc/trees/effect_node.h
index 4834773c..2a2541d1 100644
--- a/cc/trees/effect_node.h
+++ b/cc/trees/effect_node.h
@@ -11,6 +11,7 @@
 #include "third_party/skia/include/core/SkBlendMode.h"
 #include "ui/gfx/geometry/point_f.h"
 #include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/mask_filter_info.h"
 #include "ui/gfx/rrect_f.h"
 
 namespace base {
@@ -80,9 +81,10 @@
   // image.
   ElementId backdrop_mask_element_id;
 
-  // Bounds of rounded corner rrect in the space of the transform node
-  // associated with this effect node.
-  gfx::RRectF rounded_corner_bounds;
+  // The mask filter information applied to this effect node. The coordinates of
+  // in the mask info is in the space of the transform node associated with this
+  // effect node.
+  gfx::MaskFilterInfo mask_filter_info;
 
   SkBlendMode blend_mode;
 
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 84f938e..5378cf4 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1053,9 +1053,9 @@
   viz::SharedQuadState* shared_quad_state =
       target_render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(gfx::Transform(), root_target_rect,
-                            root_target_rect, gfx::RRectF(), root_target_rect,
-                            false, are_contents_opaque, opacity,
-                            SkBlendMode::kSrcOver, sorting_context_id);
+                            root_target_rect, gfx::MaskFilterInfo(),
+                            root_target_rect, false, are_contents_opaque,
+                            opacity, SkBlendMode::kSrcOver, sorting_context_id);
 
   for (gfx::Rect screen_space_rect : fill_region) {
     gfx::Rect visible_screen_space_rect = screen_space_rect;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 4cd91ba97..399d69bb 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -18123,8 +18123,8 @@
 
   // Add rounded corners to the layer, which are unable to be hit tested by the
   // simple quad-based logic.
-  CreateEffectNode(rounded_frame_layer).rounded_corner_bounds =
-      gfx::RRectF(25, 25, 50, 50, 5);
+  CreateEffectNode(rounded_frame_layer).mask_filter_info =
+      gfx::MaskFilterInfo(gfx::RRectF(25, 25, 50, 50, 5));
 
   UpdateDrawProperties(host_impl_->active_tree());
 
diff --git a/cc/trees/occlusion_tracker.cc b/cc/trees/occlusion_tracker.cc
index 7a6bf206..b3ed41e 100644
--- a/cc/trees/occlusion_tracker.cc
+++ b/cc/trees/occlusion_tracker.cc
@@ -350,7 +350,7 @@
   if (layer->Is3dSorted())
     return;
 
-  if (!layer->draw_properties().rounded_corner_bounds.IsEmpty())
+  if (!layer->draw_properties().mask_filter_info.IsEmpty())
     return;
 
   SimpleEnclosedRegion opaque_layer_region = layer->VisibleOpaqueRegion();
diff --git a/cc/trees/occlusion_tracker_unittest.cc b/cc/trees/occlusion_tracker_unittest.cc
index c2dafbd..ebe12ad 100644
--- a/cc/trees/occlusion_tracker_unittest.cc
+++ b/cc/trees/occlusion_tracker_unittest.cc
@@ -924,8 +924,8 @@
     filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
     GetEffectNode(opacity_layer)->filters = filters;
 
-    CreateEffectNode(rounded_corner_layer).rounded_corner_bounds =
-        gfx::RRectF(1, 2, 3, 4, 5, 6);
+    CreateEffectNode(rounded_corner_layer).mask_filter_info =
+        gfx::MaskFilterInfo(gfx::RRectF(1, 2, 3, 4, 5, 6));
 
     this->CalcDrawEtc();
     EXPECT_TRUE(rounded_corner_layer->contributes_to_drawn_render_surface());
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index a4a770d1..d9da2f9 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -344,6 +344,11 @@
   gfx::Vector2dF ancestor_sticky_box_offset;
   if (sticky_data->nearest_node_shifting_sticky_box !=
       TransformTree::kInvalidNodeId) {
+    // TODO(crbug.com/1128479): Investigate why there would be an invalid index
+    // passed in. Early return for now.
+    if (sticky_data->nearest_node_shifting_sticky_box >=
+        static_cast<int>(property_trees()->transform_tree.size()))
+      return gfx::Vector2dF();
     const StickyPositionNodeData* ancestor_sticky_data =
         GetStickyPositionData(sticky_data->nearest_node_shifting_sticky_box);
     DCHECK(ancestor_sticky_data);
@@ -354,6 +359,11 @@
   gfx::Vector2dF ancestor_containing_block_offset;
   if (sticky_data->nearest_node_shifting_containing_block !=
       TransformTree::kInvalidNodeId) {
+    // TODO(crbug.com/1128479): Investigate why there would be an invalid index
+    // passed in. Early return for now.
+    if (sticky_data->nearest_node_shifting_containing_block >=
+        static_cast<int>(property_trees()->transform_tree.size()))
+      return gfx::Vector2dF();
     const StickyPositionNodeData* ancestor_sticky_data = GetStickyPositionData(
         sticky_data->nearest_node_shifting_containing_block);
     DCHECK(ancestor_sticky_data);
@@ -1137,7 +1147,7 @@
   const EffectNode* effect_node = Node(effect_id);
   for (; effect_node->id != kContentsRootNodeId;
        effect_node = Node(effect_node->parent_id)) {
-    if (!effect_node->rounded_corner_bounds.IsEmpty() ||
+    if (!effect_node->mask_filter_info.IsEmpty() ||
         effect_node->has_masking_child)
       return true;
   }
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index ab2eb2f..d0f5851 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -7,7 +7,9 @@
 #include <stddef.h>
 
 #include <map>
+#include <memory>
 #include <set>
+#include <utility>
 
 #include "base/auto_reset.h"
 #include "cc/base/math_util.h"
@@ -165,10 +167,6 @@
          !layer->clip_rect().IsEmpty();
 }
 
-gfx::RRectF RoundedCornerBounds(Layer* layer) {
-  return gfx::RRectF(layer->EffectiveClipRect(), layer->corner_radii());
-}
-
 void PropertyTreeBuilderContext::AddClipNodeIfNeeded(
     const DataForRecursion& data_from_ancestor,
     Layer* layer,
@@ -491,7 +489,8 @@
     // This is currently in the local space of the layer and hence in an invalid
     // space. Once we have the associated transform node for this effect node,
     // we will update this to the transform node's coordinate space.
-    node->rounded_corner_bounds = RoundedCornerBounds(layer);
+    node->mask_filter_info =
+        gfx::MaskFilterInfo(layer->EffectiveClipRect(), layer->corner_radii());
     node->is_fast_rounded_corner = layer->is_fast_rounded_corner();
   }
 
@@ -557,7 +556,8 @@
 
   EffectNode* effect_node =
       effect_tree_.Node(data_for_children->effect_tree_parent);
-  const bool has_rounded_corner = !effect_node->rounded_corner_bounds.IsEmpty();
+  const bool has_rounded_corner =
+      effect_node->mask_filter_info.HasRoundedCorners();
 
   // Having a rounded corner should trigger a transform node.
   if (has_rounded_corner)
diff --git a/cc/trees/property_tree_builder_unittest.cc b/cc/trees/property_tree_builder_unittest.cc
index 243de40..c824607 100644
--- a/cc/trees/property_tree_builder_unittest.cc
+++ b/cc/trees/property_tree_builder_unittest.cc
@@ -859,7 +859,8 @@
   // Since this effect node has no descendants that draw and no descendant that
   // has a rounded corner, it does not need a render surface.
   const EffectNode* effect_node = GetEffectNode(rounded_corner_layer_1.get());
-  gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_1 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_FALSE(effect_node->HasRenderSurface());
   EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(),
                   kRoundedCorner1Radius);
@@ -869,7 +870,8 @@
   // Since this node has descendants with roudned corners, it needs a render
   // surface. It also has 2 descendants that draw.
   effect_node = GetEffectNode(rounded_corner_layer_2.get());
-  gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_2 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(effect_node->HasRenderSurface());
   EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(),
                   kRoundedCorner2Radius);
@@ -879,7 +881,8 @@
   // Since this node has a descendant that has a rounded corner, it will trigger
   // the creation of a render surface.
   effect_node = GetEffectNode(rounded_corner_layer_3.get());
-  gfx::RRectF rounded_corner_bounds_3 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_3 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(effect_node->HasRenderSurface());
   EXPECT_FLOAT_EQ(rounded_corner_bounds_3.GetSimpleRadius(),
                   kRoundedCorner3Radius);
@@ -889,7 +892,8 @@
   // Since this node has no descendants that draw nor any descendant that has a
   // rounded corner, it does not need a render surface.
   effect_node = GetEffectNode(rounded_corner_layer_4.get());
-  gfx::RRectF rounded_corner_bounds_4 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_4 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_FALSE(effect_node->HasRenderSurface());
   EXPECT_FLOAT_EQ(rounded_corner_bounds_4.GetSimpleRadius(),
                   kRoundedCorner4Radius);
@@ -918,7 +922,8 @@
   // scale factor is 1.6 thus giving the target space origin of [24, 24]. The
   // corner radius is also scaled by a factor of 1.6.
   const gfx::RRectF actual_rrect_1 =
-      rounded_corner_layer_1_impl->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_1_impl->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   EXPECT_EQ(actual_rrect_1.rect(), bounds_in_target_space);
@@ -931,13 +936,16 @@
   // scale factor is 1.6 thus giving the target space origin of [64, 64]. The
   // corner radius is also scaled by a factor of 1.6.
   const gfx::RRectF actual_self_rrect_2 =
-      rounded_corner_layer_2_impl->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_2_impl->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(actual_self_rrect_2.IsEmpty());
 
   bounds_in_target_space = kRoundedCornerLayer2Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   const gfx::RRectF actual_render_target_rrect_2 =
-      rounded_corner_layer_2_impl->render_target()->rounded_corner_bounds();
+      rounded_corner_layer_2_impl->render_target()
+          ->mask_filter_info()
+          .rounded_corner_bounds();
   EXPECT_EQ(actual_render_target_rrect_2.rect(), bounds_in_target_space);
   EXPECT_FLOAT_EQ(actual_render_target_rrect_2.GetSimpleRadius(),
                   kRoundedCorner2Radius * kDeviceScale);
@@ -948,7 +956,8 @@
   // device scale factor is 1.6 thus giving the target space origin of [64, 88].
   // The corner radius is also scaled by a factor of 1.6 * transform scale.
   const gfx::RRectF actual_self_rrect_3 =
-      rounded_corner_layer_3_impl->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_3_impl->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(actual_self_rrect_3.IsEmpty());
 
   bounds_in_target_space = kRoundedCornerLayer3Bound;
@@ -960,7 +969,9 @@
   bounds_in_target_space.set_size(transformed_size);
 
   const gfx::RRectF actual_render_target_rrect_3 =
-      rounded_corner_layer_3_impl->render_target()->rounded_corner_bounds();
+      rounded_corner_layer_3_impl->render_target()
+          ->mask_filter_info()
+          .rounded_corner_bounds();
   EXPECT_EQ(actual_render_target_rrect_3.rect(), bounds_in_target_space);
   EXPECT_FLOAT_EQ(actual_render_target_rrect_3.GetSimpleRadius(),
                   kRoundedCorner3Radius * kDeviceScale * kRoundedCorner3Scale);
@@ -972,7 +983,8 @@
   // rigin of [3.2, 3.2].
   // The corner radius is also scaled by a factor of 3.2.
   const gfx::RRectF actual_rrect_4 =
-      rounded_corner_layer_4_impl->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_4_impl->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   bounds_in_target_space = kRoundedCornerLayer4Bound;
   bounds_in_target_space.Scale(kDeviceScale * kRoundedCorner3Scale);
   EXPECT_EQ(actual_rrect_4.rect(), bounds_in_target_space);
@@ -1042,7 +1054,8 @@
   // that has a rounded corner before the render surface, it does not need a
   // render surface.
   const EffectNode* effect_node = GetEffectNode(rounded_corner_layer_1.get());
-  gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_1 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_FALSE(effect_node->HasRenderSurface());
   EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(),
                   kRoundedCorner1Radius);
@@ -1052,7 +1065,8 @@
   // Since this effect node has no descendants that draw and no descendant that
   // has a rounded corner, it does not need a render surface.
   effect_node = GetEffectNode(rounded_corner_layer_2.get());
-  gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_2 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_FALSE(effect_node->HasRenderSurface());
   EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(),
                   kRoundedCorner2Radius);
@@ -1077,7 +1091,8 @@
   // scale factor is 1.6 thus giving the target space origin of [96, 0]. The
   // corner radius is also scaled by a factor of 1.6.
   const gfx::RRectF actual_rrect_1 =
-      rounded_corner_layer_1_impl->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_1_impl->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   EXPECT_EQ(actual_rrect_1.rect(), bounds_in_target_space);
@@ -1088,7 +1103,8 @@
   // The render target for this layer is |render_surface|.
   // The offset from the origin of the render target is [0, 0].
   const gfx::RRectF actual_rrect_2 =
-      rounded_corner_layer_2_impl->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_2_impl->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   bounds_in_target_space = kRoundedCornerLayer2Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   EXPECT_EQ(actual_rrect_2.rect(), bounds_in_target_space);
@@ -1157,7 +1173,8 @@
   // Since this effect node has 1 descendant with a rounded corner without a
   // render surface along the chain, it need a render surface.
   const EffectNode* effect_node = GetEffectNode(rounded_corner_layer_1.get());
-  gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_1 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(effect_node->HasRenderSurface());
   EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(),
                   kRoundedCorner1Radius);
@@ -1167,7 +1184,8 @@
   // Since this effect node has no descendants that draw and no descendant that
   // has a rounded corner, it does not need a render surface.
   effect_node = GetEffectNode(rounded_corner_layer_2.get());
-  gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_2 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_FALSE(effect_node->HasRenderSurface());
   EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(),
                   kRoundedCorner2Radius);
@@ -1192,13 +1210,16 @@
   // scale factor is 1.6 thus giving the target space origin of [0, 96]. The
   // corner radius is also scaled by a factor of 1.6.
   const gfx::RRectF actual_self_rrect_1 =
-      rounded_corner_layer_1_impl->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_1_impl->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(actual_self_rrect_1.IsEmpty());
 
   gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   const gfx::RRectF actual_render_target_rrect_1 =
-      rounded_corner_layer_1_impl->render_target()->rounded_corner_bounds();
+      rounded_corner_layer_1_impl->render_target()
+          ->mask_filter_info()
+          .rounded_corner_bounds();
   EXPECT_EQ(actual_render_target_rrect_1.rect(), bounds_in_target_space);
   EXPECT_FLOAT_EQ(actual_render_target_rrect_1.GetSimpleRadius(),
                   kRoundedCorner1Radius * kDeviceScale);
@@ -1207,7 +1228,8 @@
   // The render target for this layer is |render_surface|.
   // The offset from the origin of the render target is [0, 0].
   const gfx::RRectF actual_rrect_2 =
-      rounded_corner_layer_2_impl->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_2_impl->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   bounds_in_target_space = kRoundedCornerLayer2Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   EXPECT_EQ(actual_rrect_2.rect(), bounds_in_target_space);
@@ -1297,7 +1319,8 @@
   // surface even though it has 2 layers in the subtree that draws content.
   const EffectNode* effect_node =
       GetEffectNode(fast_rounded_corner_layer.get());
-  gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_1 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_FALSE(effect_node->HasRenderSurface());
   EXPECT_TRUE(effect_node->is_fast_rounded_corner);
   EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(),
@@ -1307,7 +1330,8 @@
 
   // Since this node has 2 descendants that draw, it will have a rounded corner.
   effect_node = GetEffectNode(rounded_corner_layer.get());
-  gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_2 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(effect_node->HasRenderSurface());
   EXPECT_FALSE(effect_node->is_fast_rounded_corner);
   EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(),
@@ -1336,7 +1360,8 @@
   // The offset from the origin of the render target is [0, 0] and the device
   // scale factor is 1.6.
   const gfx::RRectF actual_rrect_1 =
-      fast_rounded_corner_layer_impl->draw_properties().rounded_corner_bounds;
+      fast_rounded_corner_layer_impl->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   EXPECT_EQ(actual_rrect_1.rect(), bounds_in_target_space);
@@ -1347,9 +1372,9 @@
   // This should have the same rounded corner boudns as fast rounded corner
   // layer.
   const gfx::RRectF layer_1_rrect =
-      layer_1_impl->draw_properties().rounded_corner_bounds;
+      layer_1_impl->draw_properties().mask_filter_info.rounded_corner_bounds();
   const gfx::RRectF layer_2_rrect =
-      layer_2_impl->draw_properties().rounded_corner_bounds;
+      layer_2_impl->draw_properties().mask_filter_info.rounded_corner_bounds();
   EXPECT_EQ(actual_rrect_1, layer_1_rrect);
   EXPECT_EQ(actual_rrect_1, layer_2_rrect);
 
@@ -1359,13 +1384,16 @@
   // scale factor is 1.6 thus giving the target space origin of [64, 64]. The
   // corner radius is also scaled by a factor of 1.6.
   const gfx::RRectF actual_self_rrect_2 =
-      rounded_corner_layer_impl->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_impl->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(actual_self_rrect_2.IsEmpty());
 
   bounds_in_target_space = kRoundedCornerLayer2Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   const gfx::RRectF actual_render_target_rrect_2 =
-      rounded_corner_layer_impl->render_target()->rounded_corner_bounds();
+      rounded_corner_layer_impl->render_target()
+          ->mask_filter_info()
+          .rounded_corner_bounds();
   EXPECT_EQ(actual_render_target_rrect_2.rect(), bounds_in_target_space);
   EXPECT_FLOAT_EQ(actual_render_target_rrect_2.GetSimpleRadius(),
                   kRoundedCorner2Radius * kDeviceScale);
@@ -1373,9 +1401,9 @@
   // Layer 3 and layer 4 should have no rounded corner bounds set as their
   // parent is a render surface.
   const gfx::RRectF layer_3_rrect =
-      layer_3_impl->draw_properties().rounded_corner_bounds;
+      layer_3_impl->draw_properties().mask_filter_info.rounded_corner_bounds();
   const gfx::RRectF layer_4_rrect =
-      layer_4_impl->draw_properties().rounded_corner_bounds;
+      layer_4_impl->draw_properties().mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(layer_3_rrect.IsEmpty());
   EXPECT_TRUE(layer_4_rrect.IsEmpty());
 }
@@ -1462,7 +1490,8 @@
   // Since this layer has a descendant that has rounded corner, this node will
   // require a render surface.
   const EffectNode* effect_node = GetEffectNode(rounded_corner_layer_1.get());
-  gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_1 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(effect_node->HasRenderSurface());
   EXPECT_FALSE(effect_node->is_fast_rounded_corner);
   EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(),
@@ -1473,7 +1502,8 @@
   // Since this layer has no descendant with rounded corner or drawable, it will
   // not have a render surface.
   effect_node = GetEffectNode(fast_rounded_corner_layer_2.get());
-  gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_2 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_FALSE(effect_node->HasRenderSurface());
   EXPECT_TRUE(effect_node->is_fast_rounded_corner);
   EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(),
@@ -1484,7 +1514,8 @@
   // Since this layer has 1 descendant with a rounded corner, it should have a
   // render surface.
   effect_node = GetEffectNode(rounded_corner_layer_3.get());
-  gfx::RRectF rounded_corner_bounds_3 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_3 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(effect_node->HasRenderSurface());
   EXPECT_FALSE(effect_node->is_fast_rounded_corner);
   EXPECT_FLOAT_EQ(rounded_corner_bounds_3.GetSimpleRadius(),
@@ -1494,7 +1525,8 @@
 
   // Since this layer no descendants, it would no thave a render pass.
   effect_node = GetEffectNode(rounded_corner_layer_4.get());
-  gfx::RRectF rounded_corner_bounds_4 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_4 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_FALSE(effect_node->HasRenderSurface());
   EXPECT_FALSE(effect_node->is_fast_rounded_corner);
   EXPECT_FLOAT_EQ(rounded_corner_bounds_4.GetSimpleRadius(),
@@ -1523,13 +1555,16 @@
   // The offset from the origin of the render target is [5, 5] and the device
   // scale factor is 1.6 giving a total offset of [8, 8].
   const gfx::RRectF actual_self_rrect_1 =
-      rounded_corner_layer_impl_1->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_impl_1->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(actual_self_rrect_1.IsEmpty());
 
   gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   const gfx::RRectF actual_render_target_rrect_1 =
-      rounded_corner_layer_impl_1->render_target()->rounded_corner_bounds();
+      rounded_corner_layer_impl_1->render_target()
+          ->mask_filter_info()
+          .rounded_corner_bounds();
   EXPECT_EQ(actual_render_target_rrect_1.rect(), bounds_in_target_space);
   EXPECT_FLOAT_EQ(actual_render_target_rrect_1.GetSimpleRadius(),
                   kRoundedCorner1Radius * kDeviceScale);
@@ -1539,7 +1574,8 @@
   // The offset from the origin of the render target is [0, 0] and the device
   // scale factor is 1.6. The corner radius is also scaled by a factor of 1.6.
   const gfx::RRectF actual_self_rrect_2 =
-      fast_rounded_corner_layer_impl_2->draw_properties().rounded_corner_bounds;
+      fast_rounded_corner_layer_impl_2->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   bounds_in_target_space = kRoundedCornerLayer2Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   EXPECT_EQ(actual_self_rrect_2.rect(), bounds_in_target_space);
@@ -1552,13 +1588,16 @@
   // scale factor is 1.6 thus giving the target space origin of [64, 64]. The
   // corner radius is also scaled by a factor of 1.6.
   const gfx::RRectF actual_self_rrect_3 =
-      rounded_corner_layer_impl_3->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_impl_3->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(actual_self_rrect_3.IsEmpty());
 
   bounds_in_target_space = kRoundedCornerLayer3Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   const gfx::RRectF actual_render_target_rrect_3 =
-      rounded_corner_layer_impl_3->render_target()->rounded_corner_bounds();
+      rounded_corner_layer_impl_3->render_target()
+          ->mask_filter_info()
+          .rounded_corner_bounds();
   EXPECT_EQ(actual_render_target_rrect_3.rect(), bounds_in_target_space);
   EXPECT_FLOAT_EQ(actual_render_target_rrect_3.GetSimpleRadius(),
                   kRoundedCorner3Radius * kDeviceScale);
@@ -1569,7 +1608,8 @@
   // scale factor is 1.6 thus giving the target space origin of [48, 0]. The
   // corner radius is also scaled by a factor of 1.6.
   const gfx::RRectF actual_self_rrect_4 =
-      rounded_corner_layer_impl_4->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_impl_4->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   bounds_in_target_space = kRoundedCornerLayer4Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   EXPECT_EQ(actual_self_rrect_4.rect(), bounds_in_target_space);
@@ -1658,7 +1698,8 @@
   // surface.
   const EffectNode* effect_node =
       GetEffectNode(fast_rounded_corner_layer_1.get());
-  gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_1 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(effect_node->HasRenderSurface());
   EXPECT_TRUE(effect_node->is_fast_rounded_corner);
   EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(),
@@ -1669,7 +1710,8 @@
   // Since this layer has no descendant with rounded corner or drawable, it will
   // not have a render surface.
   effect_node = GetEffectNode(rounded_corner_layer_1.get());
-  gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_2 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_FALSE(effect_node->HasRenderSurface());
   EXPECT_FALSE(effect_node->is_fast_rounded_corner);
   EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(),
@@ -1680,7 +1722,8 @@
   // Since this layer has a descendant with rounded corner, it should have a
   // render surface.
   effect_node = GetEffectNode(rounded_corner_layer_2.get());
-  gfx::RRectF rounded_corner_bounds_3 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_3 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(effect_node->HasRenderSurface());
   EXPECT_FALSE(effect_node->is_fast_rounded_corner);
   EXPECT_FLOAT_EQ(rounded_corner_bounds_3.GetSimpleRadius(),
@@ -1690,7 +1733,8 @@
 
   // Since this layer has no descendant, it does not need a render surface.
   effect_node = GetEffectNode(rounded_corner_layer_3.get());
-  gfx::RRectF rounded_corner_bounds_4 = effect_node->rounded_corner_bounds;
+  gfx::RRectF rounded_corner_bounds_4 =
+      effect_node->mask_filter_info.rounded_corner_bounds();
   EXPECT_FALSE(effect_node->HasRenderSurface());
   EXPECT_FALSE(effect_node->is_fast_rounded_corner);
   EXPECT_FLOAT_EQ(rounded_corner_bounds_4.GetSimpleRadius(),
@@ -1719,14 +1763,16 @@
   // The offset from the origin of the render target is [5, 5] and the device
   // scale factor is 1.6.
   const gfx::RRectF actual_self_rrect_1 =
-      fast_rounded_corner_layer_impl_1->draw_properties().rounded_corner_bounds;
+      fast_rounded_corner_layer_impl_1->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(actual_self_rrect_1.IsEmpty());
 
   gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   const gfx::RRectF actual_render_target_rrect_1 =
       fast_rounded_corner_layer_impl_1->render_target()
-          ->rounded_corner_bounds();
+          ->mask_filter_info()
+          .rounded_corner_bounds();
   EXPECT_EQ(actual_render_target_rrect_1.rect(), bounds_in_target_space);
   EXPECT_FLOAT_EQ(actual_render_target_rrect_1.GetSimpleRadius(),
                   kRoundedCorner1Radius * kDeviceScale);
@@ -1736,7 +1782,8 @@
   // The offset from the origin of the render target is [0, 0] and the device
   // scale factor is 1.6. The corner radius is also scaled by a factor of 1.6.
   const gfx::RRectF actual_self_rrect_2 =
-      rounded_corner_layer_impl_1->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_impl_1->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   bounds_in_target_space = kRoundedCornerLayer2Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   EXPECT_EQ(actual_self_rrect_2.rect(), bounds_in_target_space);
@@ -1749,13 +1796,16 @@
   // scale factor is 1.6 thus giving the target space origin of [8, 8]. The
   // corner radius is also scaled by a factor of 1.6.
   const gfx::RRectF actual_self_rrect_3 =
-      rounded_corner_layer_impl_2->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_impl_2->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   EXPECT_TRUE(actual_self_rrect_3.IsEmpty());
 
   bounds_in_target_space = kRoundedCornerLayer3Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   const gfx::RRectF actual_render_target_rrect_3 =
-      rounded_corner_layer_impl_2->render_target()->rounded_corner_bounds();
+      rounded_corner_layer_impl_2->render_target()
+          ->mask_filter_info()
+          .rounded_corner_bounds();
   EXPECT_EQ(actual_render_target_rrect_3.rect(), bounds_in_target_space);
   EXPECT_FLOAT_EQ(actual_render_target_rrect_3.GetSimpleRadius(),
                   kRoundedCorner3Radius * kDeviceScale);
@@ -1766,7 +1816,8 @@
   // scale factor is 1.6 thus giving the target space origin of [0, 8]. The
   // corner radius is also scaled by a factor of 1.6.
   const gfx::RRectF actual_self_rrect_4 =
-      rounded_corner_layer_impl_3->draw_properties().rounded_corner_bounds;
+      rounded_corner_layer_impl_3->draw_properties()
+          .mask_filter_info.rounded_corner_bounds();
   bounds_in_target_space = kRoundedCornerLayer4Bound;
   bounds_in_target_space.Scale(kDeviceScale);
   EXPECT_EQ(actual_self_rrect_4.rect(), bounds_in_target_space);
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 64479694..2d7885f8 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1369,10 +1369,10 @@
       "//chrome/browser/resources:nearby_share_dialog_resources",
       "//chrome/browser/resources:nearby_shared_resources",
       "//chrome/browser/resources:nearby_shared_resources_v3",
-      "//chrome/browser/resources:os_settings_resources",
       "//chrome/browser/resources/chromeos:cellular_setup_resources",
       "//chrome/browser/resources/chromeos:multidevice_setup_resources",
       "//chrome/browser/resources/chromeos/accessibility:build",
+      "//chrome/browser/resources/settings/chromeos:os_settings_resources",
       "//third_party/ink:ink_resources",
     ]
   }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 1cb45779..f6843a2 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -820,6 +820,7 @@
     "//chrome/browser/image_fetcher:java",
     "//chrome/browser/omaha/android:java",
     "//chrome/browser/performance_hints/android:java",
+    "//chrome/browser/policy/android:java",
     "//chrome/browser/preferences:java",
     "//chrome/browser/preferences:preferences_junit_tests",
     "//chrome/browser/profiles/android:java",
@@ -1034,6 +1035,7 @@
     "//chrome/browser/omaha/android:java",
     "//chrome/browser/optimization_guide/android:javatests",
     "//chrome/browser/paint_preview/android:java",
+    "//chrome/browser/paint_preview/android:javatests",
     "//chrome/browser/password_check:public_java",
     "//chrome/browser/password_manager/android:java",
     "//chrome/browser/password_manager/android_test_helpers:test_support_java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 22709e35..92dcc52 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -725,6 +725,7 @@
   "java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java",
   "java/src/org/chromium/chrome/browser/firstrun/FreIntentCreator.java",
   "java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java",
+  "java/src/org/chromium/chrome/browser/firstrun/PolicyLoadListener.java",
   "java/src/org/chromium/chrome/browser/firstrun/SigninFirstRunFragment.java",
   "java/src/org/chromium/chrome/browser/firstrun/TabbedModeFirstRunActivity.java",
   "java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java",
@@ -1191,7 +1192,7 @@
   "java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java",
   "java/src/org/chromium/chrome/browser/page_info/ChromePermissionParamsListBuilderDelegate.java",
   "java/src/org/chromium/chrome/browser/page_info/SiteSettingsHelper.java",
-  "java/src/org/chromium/chrome/browser/paint_preview/PaintPreviewHelper.java",
+  "java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelper.java",
   "java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmark.java",
   "java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksFaviconThrottle.java",
   "java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksProviderIterator.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index d73ee7e..8565961 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -100,6 +100,7 @@
   "junit/src/org/chromium/chrome/browser/firstrun/FirstRunAppRestrictionInfoTest.java",
   "junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java",
   "junit/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationUnitTest.java",
+  "junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java",
   "junit/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManagerUnitTest.java",
   "junit/src/org/chromium/chrome/browser/gcore/GoogleApiClientHelperTest.java",
   "junit/src/org/chromium/chrome/browser/gsa/GSAStateUnitTest.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 8a3d855..b6e458cd 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -352,10 +352,6 @@
   "javatests/src/org/chromium/chrome/browser/page_info/CookieControlsViewTest.java",
   "javatests/src/org/chromium/chrome/browser/page_info/PageInfoControllerTest.java",
   "javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java",
-  "javatests/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreviewTest.java",
-  "javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewTest.java",
-  "javatests/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewTest.java",
-  "javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java",
   "javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationIntegrationTestRule.java",
   "javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTestRule.java",
   "javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizationsUnitTest.java",
diff --git a/chrome/android/expectations/OWNERS b/chrome/android/expectations/OWNERS
index c48c0d0..0581b52 100644
--- a/chrome/android/expectations/OWNERS
+++ b/chrome/android/expectations/OWNERS
@@ -1,4 +1,5 @@
-# Anyone can approve expectation updates. These expectation files exist to
-# prevent changing them without knowing, and to provide a git history of
-# changes to these important aggregated files.
+# Many expectation updates are trivial in nature, and so global ownership
+# is used here.
+# If you are unsure whether or not changes make sense, please request a
+# knowledgeable reviewer (e.g. from //chrome/android/OWNERS).
 *
diff --git a/chrome/android/expectations/README.md b/chrome/android/expectations/README.md
index 04bbadb0..35c8e65 100644
--- a/chrome/android/expectations/README.md
+++ b/chrome/android/expectations/README.md
@@ -26,15 +26,11 @@
 ### Why do we care about Proguard flag discrepancies?
 
 Some configs are explicitly added ([ex](proguard.flags)) while others are pulled
-in implicitly by GN deps (ex. `aar_prebuilt()` deps). In the later case, these
-config changes aren't reviewed and can sometimes result in crashes and/or size
-regressions. Example of where this has happened before:
+in implicitly by GN deps (ex. `aar_prebuilt()` deps, or any target that specifies
+`proguard_configs = [...]`). 
 
-  * Updating a prebuilt that supplies a Proguard config with a rule that is
-    too broad (i.e. a rule that matches more classes than the intended ones)
-
-Having checked-in versions of the Proguard configs used allows us to identify
-and address these issues earlier.
+Since proguard configs are global in nature, it is important that all configs go
+through code review. We use these `.expected` files to ensure that they do.
 
 ## AndroidManifest.xml
 
@@ -43,8 +39,8 @@
 
 ### What are `*.AndroidManifest.expected` files?
 
-They contain the contents of the final merged manifest used when building their
-associated targets.
+They contain the pretty-printed contents of the final merged manifest used when
+building their associated targets.
 
 ### What are `*.AndroidManifest.diff.expected` files?
 For internal targets, we don't want to check that the generated manifest are
@@ -67,6 +63,9 @@
 changes, manifest entries that are pulled in via. deps (through manifest
 merging) can cause real bugs (permissions issues, security vulnerabilities).
 
+`AndroidManfiest.xml` entries create a contract between Chrome and Android,
+and so its important that all changes to this contract go through code review.
+
 ## Native Libraries and Assets
 Some of our apk and aab files contain native library files (under lib/) and
 assets files (under assets/).
diff --git a/chrome/android/expectations/lint-baseline.xml b/chrome/android/expectations/lint-baseline.xml
index 8cc2dcb..01d093b 100644
--- a/chrome/android/expectations/lint-baseline.xml
+++ b/chrome/android/expectations/lint-baseline.xml
@@ -1,5 +1,16 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.0.1" client="cli" variant="all" version="4.0.1">
+<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+
+    <issue
+        id="UnsupportedChromeOsCameraSystemFeature"
+        message="You should look for any camera available on the device, not just the rear"
+        errorLine1="        boolean hasCamera = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);"
+        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="../../base/android/java/src/org/chromium/base/SysUtils.java"
+            line="160"
+            column="29"/>
+    </issue>
 
     <issue
         id="VisibleForTests"
@@ -118,7 +129,7 @@
         errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="477"
+            line="475"
             column="30"/>
     </issue>
 
@@ -129,7 +140,7 @@
         errorLine2="                                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java"
-            line="144"
+            line="145"
             column="63"/>
     </issue>
 
@@ -140,7 +151,7 @@
         errorLine2="        ~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../android_webview/java/src/org/chromium/android_webview/AwContents.java"
-            line="1284"
+            line="1347"
             column="9"/>
     </issue>
 
@@ -151,7 +162,7 @@
         errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../android_webview/java/src/org/chromium/android_webview/AwContents.java"
-            line="1285"
+            line="1348"
             column="17"/>
     </issue>
 
@@ -162,7 +173,7 @@
         errorLine2="                                             ~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../android_webview/java/src/org/chromium/android_webview/AwContents.java"
-            line="1781"
+            line="1844"
             column="46"/>
     </issue>
 
@@ -173,7 +184,7 @@
         errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../android_webview/java/src/org/chromium/android_webview/AwContents.java"
-            line="2780"
+            line="2843"
             column="22"/>
     </issue>
 
@@ -404,7 +415,7 @@
         errorLine2="                                                      ~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/ui/BottomSheetManager.java"
-            line="215"
+            line="224"
             column="55"/>
     </issue>
 
@@ -415,7 +426,7 @@
         errorLine2="                                               ~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/ui/BottomSheetManager.java"
-            line="219"
+            line="228"
             column="48"/>
     </issue>
 
@@ -426,7 +437,7 @@
         errorLine2="                                                        ~~~~~~~~~~~~">
         <location
             file="../../weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java"
-            line="285"
+            line="301"
             column="57"/>
     </issue>
 
@@ -437,7 +448,7 @@
         errorLine2="                                                                            ~~~~~~~~~~~~">
         <location
             file="../../weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java"
-            line="409"
+            line="412"
             column="77"/>
     </issue>
 
@@ -448,7 +459,7 @@
         errorLine2="                                                                                   ~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java"
-            line="362"
+            line="368"
             column="84"/>
     </issue>
 
@@ -459,7 +470,7 @@
         errorLine2="                      ~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java"
-            line="731"
+            line="757"
             column="23"/>
     </issue>
 
@@ -481,7 +492,7 @@
         errorLine2="                                                                  ~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java"
-            line="770"
+            line="783"
             column="67"/>
     </issue>
 
@@ -503,7 +514,7 @@
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java"
-            line="259"
+            line="260"
             column="36"/>
     </issue>
 
@@ -514,7 +525,7 @@
         errorLine2="                    ~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionServiceImpl.java"
-            line="107"
+            line="104"
             column="21"/>
     </issue>
 
@@ -576,17 +587,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="        return FeedConfiguration.getFeedServerEndpoint();"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedDebuggingBridge.java"
-            line="24"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="                            ImageFetcher.resizeImage(bitmap, params.width, params.height));"
         errorLine2="                                         ~~~~~~~~~~~">
         <location
@@ -598,12 +598,12 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="                                IncognitoNotificationService.getRemoveAllIncognitoTabsIntent("
-        errorLine2="                                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="                                IncognitoNotificationServiceImpl.getRemoveAllIncognitoTabsIntent("
+        errorLine2="                                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationManager.java"
             line="56"
-            column="62"/>
+            column="66"/>
     </issue>
 
     <issue
@@ -646,7 +646,7 @@
         errorLine2="                   ~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java"
-            line="108"
+            line="112"
             column="20"/>
     </issue>
 
@@ -657,7 +657,7 @@
         errorLine2="                                         ~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java"
-            line="127"
+            line="131"
             column="42"/>
     </issue>
 
@@ -668,7 +668,7 @@
         errorLine2="                   ~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java"
-            line="141"
+            line="145"
             column="20"/>
     </issue>
 
@@ -712,7 +712,7 @@
         errorLine2="                                  ~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java"
-            line="328"
+            line="302"
             column="35"/>
     </issue>
 
@@ -734,7 +734,7 @@
         errorLine2="                                   ~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java"
-            line="322"
+            line="321"
             column="36"/>
     </issue>
 
@@ -745,7 +745,7 @@
         errorLine2="                                                 ~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java"
-            line="350"
+            line="349"
             column="50"/>
     </issue>
 
@@ -800,7 +800,7 @@
         errorLine2="                     ~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java"
-            line="523"
+            line="522"
             column="22"/>
     </issue>
 
@@ -877,7 +877,7 @@
         errorLine2="                   ~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java"
-            line="318"
+            line="325"
             column="20"/>
     </issue>
 
@@ -888,7 +888,7 @@
         errorLine2="                        ~~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java"
-            line="63"
+            line="64"
             column="25"/>
     </issue>
 
@@ -899,7 +899,7 @@
         errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilder.java"
-            line="202"
+            line="212"
             column="25"/>
     </issue>
 
@@ -1053,7 +1053,7 @@
         errorLine2="                                                                         ~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java"
-            line="1568"
+            line="1554"
             column="74"/>
     </issue>
 
@@ -1064,7 +1064,7 @@
         errorLine2="                              ~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java"
-            line="604"
+            line="634"
             column="31"/>
     </issue>
 
@@ -1086,7 +1086,7 @@
         errorLine2="                                                                     ~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivityCoordinator.java"
-            line="54"
+            line="56"
             column="70"/>
     </issue>
 
@@ -1097,7 +1097,7 @@
         errorLine2="                                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java"
-            line="968"
+            line="972"
             column="58"/>
     </issue>
 
@@ -1108,7 +1108,7 @@
         errorLine2="                            ~~~~~~~~~~~~~~">
         <location
             file="../../android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java"
-            line="1824"
+            line="1828"
             column="29"/>
     </issue>
 
@@ -1130,7 +1130,7 @@
         errorLine2="                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java"
-            line="164"
+            line="70"
             column="18"/>
     </issue>
 
@@ -1141,7 +1141,7 @@
         errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java"
-            line="188"
+            line="88"
             column="30"/>
     </issue>
 
@@ -1152,7 +1152,7 @@
         errorLine2="                 ^">
         <location
             file="../../components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java"
-            line="243"
+            line="143"
             column="18"/>
     </issue>
 
@@ -1225,23 +1225,23 @@
     <issue
         id="Autofill"
         message="Missing `autofillHints` attribute"
-        errorLine1="        &lt;EditText"
-        errorLine2="         ~~~~~~~~">
+        errorLine1="            &lt;EditText"
+        errorLine2="             ~~~~~~~~">
         <location
             file="../../chrome/browser/password_check/android/java/res/layout/password_check_edit_fragment.xml"
-            line="27"
-            column="10"/>
+            line="31"
+            column="14"/>
     </issue>
 
     <issue
         id="Autofill"
         message="Missing `autofillHints` attribute"
-        errorLine1="        &lt;EditText"
-        errorLine2="         ~~~~~~~~">
+        errorLine1="            &lt;EditText"
+        errorLine2="             ~~~~~~~~">
         <location
             file="../../chrome/browser/password_check/android/java/res/layout/password_check_edit_fragment.xml"
-            line="47"
-            column="10"/>
+            line="52"
+            column="14"/>
     </issue>
 
     <issue
@@ -1251,7 +1251,7 @@
         errorLine2="                   ~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/AccessibilityTabModelListItem.java"
-            line="453"
+            line="456"
             column="20"/>
     </issue>
 
@@ -1262,7 +1262,7 @@
         errorLine2="                                             ^">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java"
-            line="215"
+            line="193"
             column="46"/>
     </issue>
 
@@ -1339,7 +1339,7 @@
         errorLine2="                   ~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java"
-            line="639"
+            line="652"
             column="20"/>
     </issue>
 
@@ -1356,17 +1356,6 @@
 
     <issue
         id="ClickableViewAccessibility"
-        message="Custom view `InterceptTouchLayout` overrides `onTouchEvent` but not `performClick`"
-        errorLine1="        public boolean onTouchEvent(MotionEvent event) {"
-        errorLine2="                       ~~~~~~~~~~~~">
-        <location
-            file="../../chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java"
-            line="126"
-            column="24"/>
-    </issue>
-
-    <issue
-        id="ClickableViewAccessibility"
         message="Custom view ``ImageButton`` has `setOnTouchListener` called on it but does not override `performClick`"
         errorLine1="        menuBtn.setOnTouchListener(menuPopupButtonHelper);"
         errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -1482,7 +1471,7 @@
         errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/toolbar/menu_button/MenuButton.java"
-            line="76"
+            line="77"
             column="9"/>
     </issue>
 
@@ -1548,7 +1537,7 @@
         errorLine2="                   ~~~~~~~~~~~~">
         <location
             file="../../components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameView.java"
-            line="108"
+            line="107"
             column="20"/>
     </issue>
 
@@ -1565,17 +1554,6 @@
 
     <issue
         id="ClickableViewAccessibility"
-        message="Custom view `ScrollingBottomViewResourceFrameLayout` overrides `onTouchEvent` but not `performClick`"
-        errorLine1="    public boolean onTouchEvent(MotionEvent event) {"
-        errorLine2="                   ~~~~~~~~~~~~">
-        <location
-            file="../../chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewResourceFrameLayout.java"
-            line="63"
-            column="20"/>
-    </issue>
-
-    <issue
-        id="ClickableViewAccessibility"
         message="`onTouch` lambda should call `View#performClick` when a click is detected"
         errorLine1="        mEmptyViewWrapper.setOnTouchListener((v, event) -> true);"
         errorLine2="                                             ~~~~~~~~~~~~~~~~~~">
@@ -1587,23 +1565,12 @@
 
     <issue
         id="ClickableViewAccessibility"
-        message="Custom view ``ImageButton`` has `setOnTouchListener` called on it but does not override `performClick`"
-        errorLine1="        mMenuButton.getImageButton().setOnTouchListener(appMenuButtonHelper);"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTPhone.java"
-            line="188"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="ClickableViewAccessibility"
         message="Custom view `TextEditorHandleView` overrides `onTouchEvent` but not `performClick`"
         errorLine1="    public boolean onTouchEvent(MotionEvent event) {"
         errorLine2="                   ~~~~~~~~~~~~">
         <location
             file="../../clank/browser/image_editor/internal/java/src/org/chromium/chrome/browser/image_editor/text/TextEditorHandleView.java"
-            line="151"
+            line="181"
             column="20"/>
     </issue>
 
@@ -1625,7 +1592,7 @@
         errorLine2="                   ~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java"
-            line="505"
+            line="499"
             column="20"/>
     </issue>
 
@@ -1669,7 +1636,7 @@
         errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../components/browser_ui/contacts_picker/android/java/res/layout/contacts_list_item_view.xml"
-            line="48"
+            line="49"
             column="17"/>
     </issue>
 
@@ -1680,7 +1647,7 @@
         errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../components/browser_ui/contacts_picker/android/java/res/layout/contacts_list_item_view.xml"
-            line="72"
+            line="73"
             column="17"/>
     </issue>
 
@@ -1691,7 +1658,7 @@
         errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../components/browser_ui/contacts_picker/android/java/res/layout/contacts_list_item_view.xml"
-            line="96"
+            line="97"
             column="17"/>
     </issue>
 
@@ -1797,12 +1764,12 @@
     <issue
         id="KeyboardInaccessibleWidget"
         message="&apos;clickable&apos; attribute found, please also add &apos;focusable&apos;"
-        errorLine1="        android:clickable=&quot;true&quot;"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="    android:clickable=&quot;true&quot;"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../clank/browser/image_editor/internal/java/res/layout/line_tool_color_item.xml"
-            line="16"
-            column="9"/>
+            line="17"
+            column="5"/>
     </issue>
 
     <issue
@@ -1812,7 +1779,7 @@
         errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../components/browser_ui/photo_picker/android/java/res/layout/photo_picker_dialog.xml"
-            line="36"
+            line="38"
             column="9"/>
     </issue>
 
@@ -1834,7 +1801,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="../../chrome/android/java/res/layout/share_sheet_item.xml"
-            line="10"
+            line="9"
             column="5"/>
     </issue>
 
diff --git a/chrome/android/expectations/lint-suppressions.xml b/chrome/android/expectations/lint-suppressions.xml
index b4e81f2f..b0da7b0 100644
--- a/chrome/android/expectations/lint-suppressions.xml
+++ b/chrome/android/expectations/lint-suppressions.xml
@@ -135,6 +135,8 @@
   <issue id="PrivateApi" severity="ignore"/>
   <!-- Chrome is a system app. -->
   <issue id="ProtectedPermissions" severity="ignore"/>
+  <!-- Android 11+ package visibility: g.co/dev/packagevisibility -->
+  <issue id="QueryAllPackagesPermission" severity="ignore"/>
   <issue id="RestrictedApi">
     <!-- Chrome uses these GMS core APIs. -->
     <ignore regexp="is marked as internal and should not be accessed from apps"/>
@@ -145,6 +147,8 @@
   <issue id="RtlCompat" severity="ignore"/>
   <issue id="RtlEnabled" severity="ignore"/>
   <issue id="RtlSymmetry" severity="ignore"/>
+  <!-- Android 10+ WRITE_EXTERNAL_STORAGE changed meaning. -->
+  <issue id="ScopedStorage" severity="ignore"/>
   <issue id="SetJavaScriptEnabled" severity="ignore"/>
   <issue id="SignatureOrSystemPermissions" severity="ignore"/>
   <issue id="StaticFieldLeak">
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn
index 638b800..e02f60d2 100644
--- a/chrome/android/features/autofill_assistant/BUILD.gn
+++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -350,6 +350,7 @@
     "java/res/drawable/ic_grocery_black_24dp.xml",
     "java/res/drawable/ic_local_dining_black_24dp.xml",
     "java/res/drawable/ic_logo_assistant_24dp.xml",
+    "java/res/drawable/ic_overflow_black_24dp.xml",
     "java/res/drawable/ic_payment_black_24dp.xml",
     "java/res/drawable/ic_refresh_black_24dp.xml",
     "java/res/drawable/ic_remove_outline_white_24dp.xml",
diff --git a/chrome/android/features/autofill_assistant/java/res/drawable/ic_overflow_black_24dp.xml b/chrome/android/features/autofill_assistant/java/res/drawable/ic_overflow_black_24dp.xml
new file mode 100644
index 0000000..fcb47d7
--- /dev/null
+++ b/chrome/android/features/autofill_assistant/java/res/drawable/ic_overflow_black_24dp.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    tools:targetApi="21">
+    <path
+        android:fillColor="@color/default_icon_color"
+        android:pathData="M12 8c1.1 0 2 -0.9 2 -2s-0.9 -2 -2 -2 -2 0.9 -2 2 0.9 2 2 2zm0 2c-1.1 0 -2 0.9 -2 2s0.9 2 2 2 2 -0.9 2 -2 -0.9 -2 -2 -2zm0 6c-1.1 0 -2 0.9 -2 2s0.9 2 2 2 2 -0.9 2 -2 -0.9 -2 -2 -2z"/>
+</vector>
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChip.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChip.java
index 1e517c5..0a638ca9 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChip.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChip.java
@@ -26,7 +26,7 @@
 
     /**
      * An icon that should be displayed next to the text. This is the java version of the ChipIcon
-     * enum in //components/autofill_assistant/browser/service.proto. DO NOT change this without
+     * enum in //components/autofill_assistant/browser/model.proto. DO NOT change this without
      * adapting that proto enum.
      */
     @IntDef({Icon.NONE, Icon.CLEAR, Icon.DONE, Icon.REFRESH})
@@ -34,14 +34,17 @@
     public @interface Icon {
         int NONE = 0;
 
-        // https://icons.googleplex.com/#icon=ic_clear
+        // https://icons.googleplex.com/#icon=clear
         int CLEAR = 1;
 
-        // https://icons.googleplex.com/#icon=ic_done
+        // https://icons.googleplex.com/#icon=done
         int DONE = 2;
 
-        // https://icons.googleplex.com/#icon=ic_refresh
+        // https://icons.googleplex.com/#icon=refresh
         int REFRESH = 3;
+
+        // https://icons.googleplex.com/#icon=more_vert
+        int OVERFLOW = 4;
     }
 
     /**
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java
index 9410b2d2..8634ac34 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java
@@ -97,6 +97,10 @@
                 iconResource = R.drawable.ic_refresh_black_24dp;
                 iconDescriptionResource = R.string.menu_refresh;
                 break;
+            case AssistantChip.Icon.OVERFLOW:
+                iconResource = R.drawable.ic_overflow_black_24dp;
+                iconDescriptionResource = R.string.autofill_assistant_overflow_options;
+                break;
             default:
                 iconResource = ButtonView.INVALID_ICON_ID;
                 break;
diff --git a/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd b/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd
index 1f9d8c9..add935b4 100644
--- a/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd
+++ b/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd
@@ -245,6 +245,9 @@
       <message name="IDS_AUTOFILL_ASSISTANT_DECREASE_VALUE" desc="Text announced when the '-' button of a counter is highlighted by TalkBack.">
         Decrease value
       </message>
+      <message name="IDS_AUTOFILL_ASSISTANT_OVERFLOW_OPTIONS" desc="Content description for the overflow icon displayed in the first prompt, which will open a popup menu with additional options.">
+        Preferences
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings_grd/IDS_AUTOFILL_ASSISTANT_OVERFLOW_OPTIONS.png.sha1 b/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings_grd/IDS_AUTOFILL_ASSISTANT_OVERFLOW_OPTIONS.png.sha1
new file mode 100644
index 0000000..d2d987d7
--- /dev/null
+++ b/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings_grd/IDS_AUTOFILL_ASSISTANT_OVERFLOW_OPTIONS.png.sha1
@@ -0,0 +1 @@
+5b4aa0d63b975373972c59e624b7e841f7f21497
\ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java
index b97e0ea..71bfebdf 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java
@@ -50,6 +50,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.Callback;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
@@ -61,7 +62,6 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.browser.test.util.TestTouchUtils;
diff --git a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java
index 204efd32..1591c0e 100644
--- a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java
+++ b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java
@@ -107,37 +107,18 @@
     }
 
     public CableAuthenticator(Context context, CableAuthenticatorUI ui, long networkContext,
-            long instanceIdDriver, String activityClassName, boolean isFcmNotification,
+            long registration, String activityClassName, boolean isFcmNotification,
             UsbAccessory accessory) {
         mContext = context;
         mUi = ui;
         mCallback = ui;
 
-        SharedPreferences prefs =
-                mContext.getSharedPreferences(STATE_FILE_NAME, Context.MODE_PRIVATE);
-        byte[] stateBytes;
-        try {
-            stateBytes = Base64.decode(prefs.getString(STATE_VALUE_NAME, ""), Base64.DEFAULT);
-        } catch (IllegalArgumentException e) {
-            Log.w(TAG, "Ignoring corrupt state");
-            stateBytes = new byte[0];
-        }
-
         // networkContext can only be used from the UI thread, therefore all
         // short-lived work is done on that thread.
         mTaskRunner = PostTask.createSingleThreadTaskRunner(UiThreadTaskTraits.USER_VISIBLE);
         assert mTaskRunner.belongsToCurrentThread();
 
-        byte[] newStateBytes = CableAuthenticatorJni.get().setup(
-                instanceIdDriver, activityClassName, networkContext, stateBytes);
-        if (newStateBytes.length > 0) {
-            Log.i(TAG, "Writing updated state");
-            prefs.edit()
-                    .putString(STATE_VALUE_NAME,
-                            Base64.encodeToString(
-                                    newStateBytes, Base64.NO_WRAP | Base64.NO_PADDING))
-                    .apply();
-        }
+        setup(registration, activityClassName, networkContext);
 
         if (accessory != null) {
             // USB mode can start immediately.
@@ -153,6 +134,32 @@
         // Otherwise wait for a QR scan.
     }
 
+    // setup initialises the native code. This is idempotent.
+    private static void setup(long registration, String activityClassName, long networkContext) {
+        // SharedPreferences in Chromium is loaded and cached at startup, and
+        // applying changes is done asynchronously. Thus it's ok to do here, on
+        // the UI thread.
+        SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
+        byte[] stateBytes;
+        try {
+            stateBytes = Base64.decode(prefs.getString(STATE_VALUE_NAME, ""), Base64.DEFAULT);
+        } catch (IllegalArgumentException e) {
+            Log.w(TAG, "Ignoring corrupt state");
+            stateBytes = new byte[0];
+        }
+
+        byte[] newStateBytes = CableAuthenticatorJni.get().setup(
+                registration, activityClassName, networkContext, stateBytes);
+        if (newStateBytes.length > 0) {
+            Log.i(TAG, "Writing updated state");
+            prefs.edit()
+                    .putString(STATE_VALUE_NAME,
+                            Base64.encodeToString(
+                                    newStateBytes, Base64.NO_WRAP | Base64.NO_PADDING))
+                    .apply();
+        }
+    }
+
     // Calls from native code.
 
     @CalledByNative
@@ -457,6 +464,15 @@
     }
 
     /**
+     * onCloudMessage is called by {@link CableAuthenticatorUI} when a GCM message is received.
+     */
+    public static void onCloudMessage(
+            long event, long systemNetworkContext, long registration, String activityClassName) {
+        setup(registration, activityClassName, systemNetworkContext);
+        CableAuthenticatorJni.get().onCloudMessage(event);
+    }
+
+    /**
      * showNotification is called by the C++ code to show an Android
      * notification. When pressed, the notification will activity the given
      * Activity and Fragment.
@@ -518,7 +534,7 @@
          * ignored. It returns an empty byte array if the given state is valid, or the new contents
          * of the persisted state otherwise.
          */
-        byte[] setup(long instanceIdDriver, String activityClassName, long networkContext,
+        byte[] setup(long registration, String activityClassName, long networkContext,
                 byte[] stateBytes);
 
         /**
@@ -548,6 +564,13 @@
         void stop();
 
         /**
+         * Called when a GCM message is received. The argument is a pointer to a
+         * |device::cablev2::authenticator::Registration::Event| object that the native code takes
+         * ownership of.
+         */
+        void onCloudMessage(long event);
+
+        /**
          * Called to alert native code of a response to a makeCredential request.
          */
         void onAuthenticatorAttestationResponse(
diff --git a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java
index eab2cfe4..3904dbaa 100644
--- a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java
+++ b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java
@@ -58,8 +58,8 @@
         mCreatedByUsbIntent = (accessory != null);
         final long networkContext = arguments.getLong(
                 "org.chromium.chrome.modules.cablev2_authenticator.NetworkContext");
-        final long instanceIdDriver = arguments.getLong(
-                "org.chromium.chrome.modules.cablev2_authenticator.InstanceIDDriver");
+        final long registration =
+                arguments.getLong("org.chromium.chrome.modules.cablev2_authenticator.Registration");
         final String activityClassName = arguments.getString(
                 "org.chromium.chrome.modules.cablev2_authenticator.ActivityClassName");
         final boolean isFcmNotification =
@@ -67,8 +67,8 @@
 
         mPermissionDelegate = new ActivityAndroidPermissionDelegate(
                 new WeakReference<Activity>((Activity) context));
-        mAuthenticator = new CableAuthenticator(getContext(), this, networkContext,
-                instanceIdDriver, activityClassName, isFcmNotification, accessory);
+        mAuthenticator = new CableAuthenticator(getContext(), this, networkContext, registration,
+                activityClassName, isFcmNotification, accessory);
     }
 
     @Override
@@ -222,4 +222,14 @@
     public void onComplete() {
         getActivity().runOnUiThread(() -> { getActivity().finish(); });
     }
+
+    /**
+     * onCloudMessage is called by {@link CableAuthenticatorModuleProvider} when a GCM message is
+     * received.
+     */
+    public static void onCloudMessage(
+            long event, long systemNetworkContext, long registration, String activityClassName) {
+        CableAuthenticator.onCloudMessage(
+                event, systemNetworkContext, registration, activityClassName);
+    }
 }
diff --git a/chrome/android/features/cablev2_authenticator/native/cablev2_authenticator_android.cc b/chrome/android/features/cablev2_authenticator/native/cablev2_authenticator_android.cc
index aa4b5fe..e1d468e4 100644
--- a/chrome/android/features/cablev2_authenticator/native/cablev2_authenticator_android.cc
+++ b/chrome/android/features/cablev2_authenticator/native/cablev2_authenticator_android.cc
@@ -29,6 +29,7 @@
 using base::android::ConvertUTF8ToJavaString;
 using base::android::JavaByteArrayToByteVector;
 using base::android::JavaParamRef;
+using base::android::JavaRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::ToJavaArrayOfByteArray;
@@ -94,8 +95,9 @@
   std::array<uint8_t, device::cablev2::kRootSecretSize> root_secret;
   network::mojom::NetworkContext* network_context = nullptr;
 
-  // registration owns the object that handles cloud messages.
-  std::unique_ptr<device::cablev2::authenticator::Registration> registration;
+  // registration is a non-owning pointer to the global |Registration|.
+  device::cablev2::authenticator::Registration* registration = nullptr;
+
   // activity_class_name is the name of a Java class that should be the target
   // of any notifications shown.
   std::string activity_class_name;
@@ -135,20 +137,6 @@
   return *global_data;
 }
 
-// OnContactEvent is called when the tunnel service alerts us to a tunnel
-// request from a paired device.
-void OnContactEvent(
-    std::unique_ptr<device::cablev2::authenticator::Registration::Event>
-        event) {
-  GlobalData& global_data = GetGlobalData();
-
-  global_data.last_event = std::move(event);
-
-  Java_CableAuthenticator_showNotification(
-      global_data.env, ConvertUTF8ToJavaString(
-                           global_data.env, global_data.activity_class_name));
-}
-
 // AndroidBLEAdvert wraps a Java |BLEAdvert| object so that
 // |authenticator::Platform| can hold it.
 class AndroidBLEAdvert
@@ -178,7 +166,7 @@
 // implementation of FIDO operations.
 class AndroidPlatform : public device::cablev2::authenticator::Platform {
  public:
-  AndroidPlatform(JNIEnv* env, const JavaParamRef<jobject>& cable_authenticator)
+  AndroidPlatform(JNIEnv* env, const JavaRef<jobject>& cable_authenticator)
       : env_(env), cable_authenticator_(cable_authenticator) {
     DCHECK(env_->IsInstanceOf(
         cable_authenticator_.obj(),
@@ -318,7 +306,7 @@
 
 static ScopedJavaLocalRef<jbyteArray> JNI_CableAuthenticator_Setup(
     JNIEnv* env,
-    jlong instance_id_driver_long,
+    jlong registration_long,
     const JavaParamRef<jstring>& activity_class_name,
     jlong network_context_long,
     const JavaParamRef<jbyteArray>& state_bytes) {
@@ -349,10 +337,10 @@
       ConvertJavaStringToUTF8(activity_class_name);
 
   static_assert(sizeof(jlong) >= sizeof(void*), "");
-  auto* instance_id_driver =
-      reinterpret_cast<instance_id::InstanceIDDriver*>(instance_id_driver_long);
-  global_data.registration = device::cablev2::authenticator::Register(
-      instance_id_driver, base::BindRepeating(OnContactEvent));
+  global_data.registration =
+      reinterpret_cast<device::cablev2::authenticator::Registration*>(
+          registration_long);
+  global_data.registration->PrepareContactID();
 
   global_data.network_context =
       reinterpret_cast<network::mojom::NetworkContext*>(network_context_long);
@@ -430,6 +418,21 @@
   ResetGlobalData();
 }
 
+static void JNI_CableAuthenticator_OnCloudMessage(JNIEnv* env,
+                                                  jlong event_long) {
+  static_assert(sizeof(jlong) >= sizeof(void*), "");
+  std::unique_ptr<device::cablev2::authenticator::Registration::Event> event(
+      reinterpret_cast<device::cablev2::authenticator::Registration::Event*>(
+          event_long));
+
+  GlobalData& global_data = GetGlobalData();
+  global_data.last_event = std::move(event);
+
+  Java_CableAuthenticator_showNotification(
+      global_data.env, ConvertUTF8ToJavaString(
+                           global_data.env, global_data.activity_class_name));
+}
+
 static void JNI_CableAuthenticator_OnAuthenticatorAttestationResponse(
     JNIEnv* env,
     jint ctap_status,
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
index 2aa29a70..7f030f99 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
@@ -52,6 +52,7 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -72,7 +73,6 @@
 import org.chromium.components.feature_engagement.TriggerState;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.DeferredViewStubInflationProvider;
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/v1/FeedNewTabPageCardRenderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/v1/FeedNewTabPageCardRenderTest.java
index d476a7a2..3cc610a0 100644
--- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/v1/FeedNewTabPageCardRenderTest.java
+++ b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/v1/FeedNewTabPageCardRenderTest.java
@@ -59,6 +59,7 @@
     ChromeFeatureList.OMNIBOX_SEARCH_ENGINE_LOGO})
 @Features.DisableFeatures({ChromeFeatureList.REPORT_FEED_USER_ACTIONS,
     ChromeFeatureList.QUERY_TILES, ChromeFeatureList.VIDEO_TUTORIALS,
+    ChromeFeatureList.ENHANCED_PROTECTION_PROMO_CARD,
     ChromeFeatureList.INTEREST_FEED_V2})
 public class FeedNewTabPageCardRenderTest {
     // clang-format on
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 1bec234..a332d41 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -108,7 +108,7 @@
 import org.chromium.chrome.browser.ntp.NewTabPageUma;
 import org.chromium.chrome.browser.ntp.cards.promo.HomepagePromoVariationManager;
 import org.chromium.chrome.browser.omnibox.OmniboxFocusReason;
-import org.chromium.chrome.browser.paint_preview.PaintPreviewHelper;
+import org.chromium.chrome.browser.paint_preview.StartupPaintPreviewHelper;
 import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -949,7 +949,7 @@
         // Paint Preview should follow the same logic as startup UMA histograms as the feature
         // should only run on cold startup of Chrome when the user is unable to interact before
         // entering a tab.
-        PaintPreviewHelper.setShouldShowOnRestore(shouldTrackColdStartupMetrics);
+        StartupPaintPreviewHelper.setShouldShowOnRestore(shouldTrackColdStartupMetrics);
     }
 
     private void setInitialOverviewState() {
@@ -1542,7 +1542,8 @@
 
         mInactivityTracker = new ChromeInactivityTracker(
                 ChromePreferenceKeys.TABBED_ACTIVITY_LAST_BACKGROUNDED_TIME_MS_PREF);
-        PaintPreviewHelper.initialize(this, getTabModelSelector(), shouldShowTabSwitcherOnStart(),
+        StartupPaintPreviewHelper.initialize(this, getTabModelSelector(),
+                shouldShowTabSwitcherOnStart(),
                 ()
                         -> getToolbarManager() == null
                         ? null
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/DEPS
index e3589a9..e8fe000 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DEPS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DEPS
@@ -263,7 +263,7 @@
   "AutocompleteMediator\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
-  "PaintPreviewHelper\.java": [
+  "StartupPaintPreviewHelper\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
   "AutoSigninSnackbarController\.java": [
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
index 19c27fe4..0148f48 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
@@ -449,6 +449,7 @@
         InputMethodManager imm =
                 (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
         View view = mShouldRequestExpirationDate ? mMonthInput : mCardUnmaskInput;
+        view.requestFocus();
         imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
         view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         if (sObserverForTest != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/BrowserServicesIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/BrowserServicesIntentDataProvider.java
index 3fa18c8c..c65d0748 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/BrowserServicesIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/BrowserServicesIntentDataProvider.java
@@ -512,4 +512,11 @@
     public boolean shouldHideOmniboxSuggestionsForCctVisits() {
         return false;
     }
+
+    /**
+     * Returns true if visits from cct should be hidden.
+     */
+    public boolean shouldHideCctVisits() {
+        return false;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 4a5990ea..f61095f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -101,6 +101,9 @@
                 if (mIntentDataProvider.shouldHideOmniboxSuggestionsForCctVisits()) {
                     tab.setAddApi2TransitionToFutureNavigations(true);
                 }
+                if (mIntentDataProvider.shouldHideCctVisits()) {
+                    tab.setHideFutureNavigations(true);
+                }
             }
         });
 
@@ -189,7 +192,10 @@
             if (mNavigationController.openCurrentUrlInBrowser(false)) {
                 RecordUserAction.record("CustomTabsMenuOpenInChrome");
                 WebContents webContents = tab == null ? null : tab.getWebContents();
-                if (tab != null) tab.setAddApi2TransitionToFutureNavigations(false);
+                if (tab != null) {
+                    tab.setAddApi2TransitionToFutureNavigations(false);
+                    tab.setHideFutureNavigations(false);
+                }
                 mConnection.notifyOpenInBrowser(mSession, webContents);
             }
             return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 5bcf750..668bb69 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -46,6 +46,7 @@
 import org.chromium.chrome.browser.flags.ActivityType;
 import org.chromium.chrome.browser.flags.CachedFeatureFlags;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.gsa.GSAState;
 import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.browser_ui.widget.TintedDrawable;
@@ -148,6 +149,13 @@
             "androidx.browser.customtabs.extra.HIDE_OMNIBOX_SUGGESTIONS_FROM_CCT";
 
     /**
+     * Extra that, if set, results in marking visits from cct as hidden. The value is
+     * a boolean, and is only considered if the feature kCCTHideVisits is enabled.
+     */
+    public static final String EXTRA_HIDE_VISITS_FROM_CCT =
+            "androidx.browser.customtabs.extra.HIDE_VISITS_FROM_CCT";
+
+    /**
      * Extra used to provide a PendingIntent that we can launch to focus the client.
      * TODO(peconn): Move to AndroidX.
      */
@@ -601,7 +609,6 @@
     }
 
     @Override
-    @Nullable
     public Intent getIntent() {
         return mIntent;
     }
@@ -886,4 +893,18 @@
     public boolean shouldHideOmniboxSuggestionsForCctVisits() {
         return shouldHideOmniboxSuggestionsForCctVisits(mIntent);
     }
+
+    @Override
+    public boolean shouldHideCctVisits() {
+        if (!ChromeFeatureList.isEnabled(
+                    ChromeFeatureList.HIDE_FROM_API_3_TRANSITIONS_FROM_HISTORY)) {
+            return false;
+        }
+
+        // Only 1p apps are allowed to hide visits.
+        String clientPackageName =
+                CustomTabsConnection.getInstance().getClientPackageNameForSession(getSession());
+        if (!GSAState.isGsaPackageName(clientPackageName)) return false;
+        return IntentUtils.safeGetBooleanExtra(mIntent, EXTRA_HIDE_VISITS_FROM_CCT, false);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
index 9d6069bc..7dec0fb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
@@ -185,6 +185,10 @@
             tab.setAddApi2TransitionToFutureNavigations(true);
         }
 
+        if (mIntentDataProvider.shouldHideCctVisits()) {
+            tab.setHideFutureNavigations(true);
+        }
+
         tab.loadUrl(params);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/PolicyLoadListener.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/PolicyLoadListener.java
new file mode 100644
index 0000000..7e1f483
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/PolicyLoadListener.java
@@ -0,0 +1,126 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.firstrun;
+
+import androidx.annotation.Nullable;
+
+import org.chromium.base.Callback;
+import org.chromium.base.CallbackController;
+import org.chromium.base.supplier.OneshotSupplier;
+import org.chromium.base.supplier.OneshotSupplierImpl;
+import org.chromium.components.policy.PolicyService;
+import org.chromium.components.policy.PolicyService.Observer;
+
+/**
+ * Class that is responsible for listening to signals before policy service is fully initialized in
+ * C++. The value it supplies will be ready when a decision about *whether reading policy value is
+ * necessary*.
+ *
+ * The signals this class observes are policy service initialization and Android app restrictions.
+ * If no app restrictions are found before the policy service is initialized, early out of the
+ * loading process and inform the listeners.
+ *
+ * To be more specific:
+ *
+ *  - Supplies [True] if policy service is initialized and policy might be applied;
+ *  - Supplies [False] if no app restriction is found, thus no polices will be found on device.
+ */
+public class PolicyLoadListener implements OneshotSupplier<Boolean> {
+    private final CallbackController mCallbackController;
+    private final OneshotSupplierImpl<Boolean> mMightHavePoliciesSupplier;
+    private final OneshotSupplier<PolicyService> mPolicyServiceSupplier;
+
+    private PolicyService.Observer mPolicyServiceObserver;
+
+    /**
+     * Whether app restriction is found on the device. This can be null when this information is not
+     * ready yet.
+     */
+    private @Nullable Boolean mHasRestriction;
+
+    /**
+     * Create the instance and start listening to signals from policy service and app restrictions.
+     * @param appRestrictionInfo Class that provides whether app restriction is found on device.
+     * @param policyServiceSupplier Supplier of PolicyService that this class listened to.
+     */
+    public PolicyLoadListener(FirstRunAppRestrictionInfo appRestrictionInfo,
+            OneshotSupplier<PolicyService> policyServiceSupplier) {
+        mCallbackController = new CallbackController();
+        mMightHavePoliciesSupplier = new OneshotSupplierImpl<>();
+
+        mPolicyServiceSupplier = policyServiceSupplier;
+
+        appRestrictionInfo.getHasAppRestriction(
+                mCallbackController.makeCancelable(this::onAppRestrictionDetected));
+        policyServiceSupplier.onAvailable(
+                mCallbackController.makeCancelable(this::onPolicyServiceAvailable));
+    }
+
+    /**
+     * Cancel all unfinished callback and remove observer for policy service if any.
+     */
+    public void destroy() {
+        mCallbackController.destroy();
+        if (mPolicyServiceObserver != null) {
+            mPolicyServiceSupplier.get().removeObserver(mPolicyServiceObserver);
+            mPolicyServiceObserver = null;
+        }
+    }
+
+    @Override
+    public void onAvailable(Callback<Boolean> callback) {
+        mMightHavePoliciesSupplier.onAvailable(callback);
+    }
+
+    @Override
+    public Boolean get() {
+        return mMightHavePoliciesSupplier.get();
+    }
+
+    /**
+     * Check status for internal signals. If loading completes, mark loading is finished.
+     */
+    private void setSupplierIfDecidable() {
+        // Early return if policy value has been set.
+        if (mMightHavePoliciesSupplier.get() != null) return;
+
+        boolean confirmedNoAppRestriction = mHasRestriction != null && !mHasRestriction;
+        boolean policyServiceInitialized = (mPolicyServiceSupplier.get() != null
+                && mPolicyServiceSupplier.get().isInitializationComplete());
+        if (confirmedNoAppRestriction) {
+            // No app restriction is found.
+            mMightHavePoliciesSupplier.set(false);
+        } else if (policyServiceInitialized) {
+            // Policies are ready to be read,
+            mMightHavePoliciesSupplier.set(true);
+        }
+    }
+
+    private void onAppRestrictionDetected(boolean hasAppRestriction) {
+        mHasRestriction = hasAppRestriction;
+        setSupplierIfDecidable();
+    }
+
+    private void onPolicyServiceAvailable(PolicyService policyService) {
+        // Ignore the signal if loading is no longer necessary.
+        if (mMightHavePoliciesSupplier.get() != null) return;
+
+        assert policyService != null;
+
+        if (policyService.isInitializationComplete()) {
+            setSupplierIfDecidable();
+        } else {
+            mPolicyServiceObserver = new Observer() {
+                @Override
+                public void onPolicyServiceInitialized() {
+                    policyService.removeObserver(mPolicyServiceObserver);
+                    mPolicyServiceObserver = null;
+                    setSupplierIfDecidable();
+                }
+            };
+            policyService.addObserver(mPolicyServiceObserver);
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/PaintPreviewHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelper.java
similarity index 92%
rename from chrome/android/java/src/org/chromium/chrome/browser/paint_preview/PaintPreviewHelper.java
rename to chrome/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelper.java
index 736c92fa..adc07ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/PaintPreviewHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelper.java
@@ -32,9 +32,9 @@
 import java.util.Map;
 
 /**
- * Handles initialization of the Paint Preview tab observers.
+ * Glue code for the Paint Preview show-on-startup feature.
  */
-public class PaintPreviewHelper {
+public class StartupPaintPreviewHelper {
     /**
      * Tracks whether a paint preview should be shown on tab restore. We use this to only attempt
      * to display a paint preview on the first tab restoration that happens on Chrome startup when
@@ -44,11 +44,11 @@
 
     /**
      * A map for keeping Activity-specific variables and classes. New entries are added on calls to
-     * {@link #initialize(ChromeActivity, TabModelSelector)}. Entries are automatically removed when
-     * their respective Activity is destroyed.
+     * {@link #initialize}. Entries are automatically removed when their respective Activity is
+     * destroyed.
      */
-    private static Map<WindowAndroid, PaintPreviewWindowAndroidHelper> sWindowAndroidHelperMap =
-            new HashMap<>();
+    private static final Map<WindowAndroid, PaintPreviewWindowAndroidHelper>
+            sWindowAndroidHelperMap = new HashMap<>();
 
     /**
      * Sets whether a Paint Preview should attempt to be shown on restoration of a tab. If the
@@ -162,10 +162,10 @@
         /**
          * Tracks the activity creation time in ms from {@link SystemClock#elapsedRealtime}.
          */
-        private long mActivityCreationTime;
-        private WindowAndroid mWindowAndroid;
-        private BrowserControlsManager mBrowserControlsManager;
-        private Supplier<LoadProgressCoordinator> mProgressBarCoordinatorSupplier;
+        private final long mActivityCreationTime;
+        private final WindowAndroid mWindowAndroid;
+        private final BrowserControlsManager mBrowserControlsManager;
+        private final Supplier<LoadProgressCoordinator> mProgressBarCoordinatorSupplier;
 
         PaintPreviewWindowAndroidHelper(ChromeActivity<?> chromeActivity,
                 Supplier<LoadProgressCoordinator> progressBarCoordinatorSupplier) {
@@ -197,5 +197,5 @@
         }
     }
 
-    private PaintPreviewHelper() {}
+    private StartupPaintPreviewHelper() {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/policy/EnterpriseInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/policy/EnterpriseInfo.java
index 646da05..5af63ac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/policy/EnterpriseInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/policy/EnterpriseInfo.java
@@ -84,6 +84,7 @@
     /**
      * Returns, via callback, whether the device has a device owner or a profile owner.
      */
+    @SuppressWarnings("QueryPermissionsNeeded")
     public void getDeviceEnterpriseInfo(Callback<OwnedState> callback) {
         // AsyncTask requires being called from UI thread.
         ThreadUtils.assertOnUiThread();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
index 03eb6c0..f8371cb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.settings;
 
+import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
@@ -345,12 +346,15 @@
         mManageSync.setIcon(SyncSettingsUtils.getSyncStatusIcon(getActivity()));
         mManageSync.setSummary(SyncSettingsUtils.getSyncStatusSummary(getActivity()));
         mManageSync.setOnPreferenceClickListener(pref -> {
-            if (isSyncConsentAvailable) {
+            Context context = getContext();
+            if (ProfileSyncService.get().isSyncDisabledByEnterprisePolicy()) {
+                SyncSettingsUtils.showSyncDisabledByAdministratorToast(context);
+            } else if (isSyncConsentAvailable) {
                 SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
-                settingsLauncher.launchSettingsActivity(getContext(), ManageSyncSettings.class);
+                settingsLauncher.launchSettingsActivity(context, ManageSyncSettings.class);
             } else {
                 SigninActivityLauncherImpl.get().launchActivityForPromoDefaultFlow(
-                        getContext(), SigninAccessPoint.SETTINGS, primaryAccountName);
+                        context, SigninAccessPoint.SETTINGS, primaryAccountName);
             }
             return true;
         });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncSettingsUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncSettingsUtils.java
index 9090649c..4c3ff07 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncSettingsUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncSettingsUtils.java
@@ -42,6 +42,7 @@
 import org.chromium.components.sync.KeyRetrievalTriggerForUMA;
 import org.chromium.components.sync.StopSource;
 import org.chromium.ui.UiUtils;
+import org.chromium.ui.widget.Toast;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -426,4 +427,15 @@
                             Log.e(TAG, "Error opening key retrieval dialog: ", exception);
                         });
     }
+
+    /**
+     * Shows a toast indicating that sync is disabled for the account by the system administrator.
+     *
+     * @param context The context where the toast will be shown.
+     */
+    public static void showSyncDisabledByAdministratorToast(Context context) {
+        Toast.makeText(context, context.getString(R.string.sync_is_disabled_by_administrator),
+                     Toast.LENGTH_LONG)
+                .show();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
index 7c3b2545..1b62a1cb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -57,7 +57,7 @@
     "+chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePage.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageAssassin.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java",
-    "+chrome/android/java/src/org/chromium/chrome/browser/paint_preview/PaintPreviewHelper.java",
+    "+chrome/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelper.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/night_mode",
     "+chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/UrlConstants.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBuilder.java
index 6b99d84a..5cdb278 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBuilder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBuilder.java
@@ -173,8 +173,13 @@
         // |onInitialized| of TabObserver they register.
         tab.initialize(mParent, mCreationType, mLoadUrlParams, mWebContents, mDelegateFactory,
                 mInitiallyHidden, mTabState, mSerializedCriticalPersistedTabData);
-        if (mParent != null && mParent.getAddApi2TransitionToFutureNavigations()) {
-            tab.setAddApi2TransitionToFutureNavigations(true);
+        if (mParent != null) {
+            if (mParent.getAddApi2TransitionToFutureNavigations()) {
+                tab.setAddApi2TransitionToFutureNavigations(true);
+            }
+            if (mParent.getHideFutureNavigations()) {
+                tab.setHideFutureNavigations(true);
+            }
         }
 
         return tab;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
index 8bb989f..3229e9e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -35,7 +35,7 @@
 import org.chromium.chrome.browser.native_page.NativePageAssassin;
 import org.chromium.chrome.browser.night_mode.NightModeUtils;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
-import org.chromium.chrome.browser.paint_preview.PaintPreviewHelper;
+import org.chromium.chrome.browser.paint_preview.StartupPaintPreviewHelper;
 import org.chromium.chrome.browser.rlz.RevenueStats;
 import org.chromium.chrome.browser.tab.state.CriticalPersistedTabData;
 import org.chromium.chrome.browser.ui.TabObscuringHandler;
@@ -729,6 +729,19 @@
                 && TabImplJni.get().getAddApi2TransitionToFutureNavigations(mNativeTabAndroid);
     }
 
+    @Override
+    public void setHideFutureNavigations(boolean hide) {
+        if (mNativeTabAndroid != 0) {
+            TabImplJni.get().setHideFutureNavigations(mNativeTabAndroid, hide);
+        }
+    }
+
+    @Override
+    public boolean getHideFutureNavigations() {
+        return (mNativeTabAndroid != 0)
+                && TabImplJni.get().getHideFutureNavigations(mNativeTabAndroid);
+    }
+
     // TabObscuringHandler.Observer
 
     @Override
@@ -1374,7 +1387,7 @@
     private final void restoreIfNeeded() {
         // Attempts to display the Paint Preview representation of this Tab. Please note that this
         // is behind an experimental flag (crbug.com/1008520).
-        if (isFrozen()) PaintPreviewHelper.showPaintPreviewOnRestore(this);
+        if (isFrozen()) StartupPaintPreviewHelper.showPaintPreviewOnRestore(this);
 
         try {
             TraceEvent.begin("Tab.restoreIfNeeded");
@@ -1533,5 +1546,7 @@
         void loadOriginalImage(long nativeTabAndroid, TabImpl caller);
         void setAddApi2TransitionToFutureNavigations(long nativeTabAndroid, boolean shouldAdd);
         boolean getAddApi2TransitionToFutureNavigations(long nativeTabAndroid);
+        void setHideFutureNavigations(long nativeTabAndroid, boolean hide);
+        boolean getHideFutureNavigations(long nativeTabAndroid);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkHandlerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkHandlerDelegate.java
index 2c9607d..0e7d5e5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkHandlerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkHandlerDelegate.java
@@ -56,6 +56,7 @@
      * Calls the native WebApkHandlerDelegate with information for each installed WebAPK.
      */
     @CalledByNative
+    @SuppressWarnings("QueryPermissionsNeeded")
     public void retrieveWebApks() {
         if (mNativePointer == 0) {
             return;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
index 95e1f10..8a7680a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
@@ -24,6 +24,7 @@
 
 import org.chromium.base.BaseSwitches;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.UrlUtils;
@@ -39,7 +40,6 @@
 import org.chromium.chrome.test.util.browser.contextmenu.RevampedContextMenuUtils;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java
index 2bd5160..afe6eab 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java
@@ -18,6 +18,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -27,7 +28,6 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.media.MediaSwitches;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
index ee7a6868..f5b6eec5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
@@ -29,6 +29,7 @@
 import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.FlakyTest;
@@ -47,7 +48,6 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.TestInputMethodManagerWrapper;
 import org.chromium.content_public.browser.test.util.TouchCommon;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedPromoRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedPromoRenderTest.java
index 83c02bc..4aa618d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedPromoRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedPromoRenderTest.java
@@ -27,12 +27,15 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.BookmarkTestRule;
+import org.chromium.chrome.test.util.BookmarkTestUtil;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
 import org.chromium.components.signin.test.util.FakeProfileDataSource;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.test.util.NightModeTestUtils;
 import org.chromium.ui.test.util.UiDisableIf;
 
@@ -80,6 +83,11 @@
         // Native side needs to loaded before signing in test account.
         mActivityTestRule.startMainActivityOnBlankPage();
         mAccountManagerTestRule.addTestAccountThenSigninAndEnableSync();
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            BookmarkModel bookmarkModel = new BookmarkModel(Profile.getLastUsedRegularProfile());
+            bookmarkModel.loadFakePartnerBookmarkShimForTesting();
+        });
+        BookmarkTestUtil.waitForBookmarkModelLoaded();
     }
 
     @After
@@ -107,7 +115,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "crbug.com/1136534")
     @Feature("RenderTest")
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
     public void testPersonalizedSyncPromoInBookmarkPage(boolean nightModeEnabled) throws Exception {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 7d4ebd3..5d38c97 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -75,6 +75,7 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
@@ -135,7 +136,6 @@
 import org.chromium.content_public.browser.test.util.ClickUtils;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -2417,6 +2417,120 @@
         Assert.assertEquals(0, getVisibleEntryTransitionType() & PageTransition.FROM_API_2);
     }
 
+    @Test
+    @SmallTest
+    @EnableFeatures({ChromeFeatureList.HIDE_FROM_API_3_TRANSITIONS_FROM_HISTORY})
+    public void testHideVisitsFromCctDefaultsToFalse() throws Exception {
+        // Start CCT.
+        Context context = InstrumentationRegistry.getInstrumentation()
+                                  .getTargetContext()
+                                  .getApplicationContext();
+        Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage);
+        mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
+
+        Assert.assertFalse(mCustomTabActivityTestRule.getActivity()
+                                   .getActivityTab()
+                                   .getHideFutureNavigations());
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures({ChromeFeatureList.HIDE_FROM_API_3_TRANSITIONS_FROM_HISTORY})
+    public void testHideVisitsFromCctNotAvailableTo3p() throws Exception {
+        // Start CCT.
+        Context context = InstrumentationRegistry.getInstrumentation()
+                                  .getTargetContext()
+                                  .getApplicationContext();
+        Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage);
+        intent.putExtra(CustomTabIntentDataProvider.EXTRA_HIDE_VISITS_FROM_CCT, true);
+        mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
+
+        // Value of EXTRA_HIDE_VISITS_FROM_CCT is ignored for non-1ps.
+        Assert.assertFalse(mCustomTabActivityTestRule.getActivity()
+                                   .getActivityTab()
+                                   .getHideFutureNavigations());
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures({ChromeFeatureList.HIDE_FROM_API_3_TRANSITIONS_FROM_HISTORY})
+    public void testHideVisitsFromCctRemovedWhenOpenInBrowser() throws Exception {
+        // Augment the CustomTabsSession to catch open in browser.
+        CallbackHelper callbackTriggered = new CallbackHelper();
+        CustomTabsSession session =
+                CustomTabsTestUtils
+                        .bindWithCallback(new CustomTabsCallback() {
+                            @Override
+                            public void extraCallback(String callbackName, Bundle args) {
+                                if (callbackName.equals(
+                                            CustomTabsConnection.OPEN_IN_BROWSER_CALLBACK)) {
+                                    callbackTriggered.notifyCalled();
+                                }
+                            }
+                        })
+                        .session;
+
+        // Start CCT.
+        Intent intent = new CustomTabsIntent.Builder(session).build().intent;
+        intent.setData(Uri.parse(mTestPage));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(CustomTabIntentDataProvider.EXTRA_HIDE_VISITS_FROM_CCT, true);
+        CustomTabsSessionToken token = CustomTabsSessionToken.getSessionTokenFromIntent(intent);
+        CustomTabsConnection connection = CustomTabsConnection.getInstance();
+        connection.newSession(token);
+        connection.overridePackageNameForSessionForTesting(
+                token, "com.google.android.googlequicksearchbox");
+
+        mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
+        Assert.assertTrue(mCustomTabActivityTestRule.getActivity()
+                                  .getActivityTab()
+                                  .getHideFutureNavigations());
+
+        // Trigger open in browser.
+        IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW);
+        filter.addDataScheme(Uri.parse(mTestServer.getURL("/")).getScheme());
+        final ActivityMonitor monitor =
+                InstrumentationRegistry.getInstrumentation().addMonitor(filter, null, false);
+        openAppMenuAndAssertMenuShown();
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+            MenuItem item =
+                    AppMenuTestSupport.getMenu(mCustomTabActivityTestRule.getAppMenuCoordinator())
+                            .findItem(R.id.open_in_browser_id);
+            Assert.assertNotNull(item);
+            getActivity().onMenuOrKeyboardAction(R.id.open_in_browser_id, false);
+        });
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            return InstrumentationRegistry.getInstrumentation().checkMonitorHit(monitor, 1);
+        });
+        callbackTriggered.waitForCallback(0);
+        Assert.assertFalse(mCustomTabActivityTestRule.getActivity()
+                                   .getActivityTab()
+                                   .getHideFutureNavigations());
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures({ChromeFeatureList.HIDE_FROM_API_3_TRANSITIONS_FROM_HISTORY})
+    public void testHideVisitsFromCctPreloadDisabled() throws Exception {
+        Context context = InstrumentationRegistry.getInstrumentation()
+                                  .getTargetContext()
+                                  .getApplicationContext();
+        Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage);
+        intent.setData(Uri.parse(mTestPage));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra("org.chromium.chrome.browser.init.DISABLE_STARTUP_TAB_PRELOADER", true);
+        intent.putExtra(CustomTabIntentDataProvider.EXTRA_HIDE_VISITS_FROM_CCT, true);
+        CustomTabsSessionToken token = CustomTabsSessionToken.getSessionTokenFromIntent(intent);
+        CustomTabsConnection connection = CustomTabsConnection.getInstance();
+        connection.newSession(token);
+        connection.overridePackageNameForSessionForTesting(
+                token, "com.google.android.googlequicksearchbox");
+        mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
+        Assert.assertTrue(mCustomTabActivityTestRule.getActivity()
+                                  .getActivityTab()
+                                  .getHideFutureNavigations());
+    }
+
     /**
      * The following test that history only has a single final page after speculation,
      * whether it was a hit or a miss.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTestRule.java
index 8ef380f..b72286c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTestRule.java
@@ -17,6 +17,7 @@
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.fullscreen.FullscreenOptions;
@@ -26,7 +27,6 @@
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java
index cd29d51..832260a8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java
@@ -47,6 +47,7 @@
 
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
@@ -73,7 +74,6 @@
 import org.chromium.components.infobars.InfoBar;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.net.NetworkChangeNotifier;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MediaRouterIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MediaRouterIntegrationTest.java
index 7c4248a9..331fd13 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MediaRouterIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MediaRouterIntegrationTest.java
@@ -22,6 +22,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -34,7 +35,6 @@
 import org.chromium.content_public.browser.test.util.ClickUtils;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.common.ContentSwitches;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/multiwindow/MultiWindowTestHelper.java b/chrome/android/javatests/src/org/chromium/chrome/browser/multiwindow/MultiWindowTestHelper.java
index df35231..4722f68 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/multiwindow/MultiWindowTestHelper.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/multiwindow/MultiWindowTestHelper.java
@@ -20,13 +20,13 @@
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.ChromeTabbedActivity2;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.util.concurrent.atomic.AtomicReference;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java
index 4d09a26..15280e9a1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java
@@ -32,6 +32,7 @@
 import org.chromium.base.ActivityState;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
@@ -54,7 +55,6 @@
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.browser.test.util.TestTouchUtils;
 import org.chromium.net.test.EmbeddedTestServer;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
index 9f3493d..f8c958e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
@@ -25,6 +25,7 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.autofill.CardUnmaskPrompt;
@@ -48,7 +49,6 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.payments.mojom.PaymentDetailsModifier;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
index 2e9c037..f723918 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
@@ -40,6 +40,7 @@
 import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
@@ -75,7 +76,6 @@
 import org.chromium.components.search_engines.TemplateUrl;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.KeyUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.browser.test.util.TestTouchUtils;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java
index cbe8e85..1802b91d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java
@@ -18,6 +18,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -27,7 +28,6 @@
 import org.chromium.components.sync.protocol.EntitySpecifics;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
index d3bb632..252dfd5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
@@ -18,6 +18,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -29,7 +30,6 @@
 import org.chromium.components.sync.protocol.BookmarkSpecifics;
 import org.chromium.components.sync.protocol.SyncEntity;
 import org.chromium.content_public.browser.test.util.Criteria;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.util.ArrayList;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
index 16cb08c3..9a8dd04 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
@@ -19,6 +19,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -33,7 +34,6 @@
 import org.chromium.components.sync.protocol.SyncEnums;
 import org.chromium.components.sync.protocol.TabNavigation;
 import org.chromium.content_public.browser.test.util.Criteria;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.util.ArrayList;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
index 5471161..62f853a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
@@ -18,6 +18,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -29,7 +30,6 @@
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.base.PageTransition;
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java
new file mode 100644
index 0000000..64c8ca15
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java
@@ -0,0 +1,169 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.firstrun;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.never;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowProcess;
+
+import org.chromium.base.Callback;
+import org.chromium.base.supplier.OneshotSupplierImpl;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.components.policy.PolicyService;
+
+/** Unit tests for PolicyLoadListener. */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, shadows = {ShadowProcess.class})
+public class PolicyLoadListenerUnitTest {
+    private static final String LOADED_POLICY_READY = "Policy service should be ready to read.";
+    private static final String LOADED_NO_POLICY = "Policy should not exist.";
+    private static final String LOADING_NOT_FINISHED =
+            "Whether policy might exist should be not decided yet.";
+
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Spy
+    public OneshotSupplierImpl<PolicyService> mTestPolicyServiceSupplier =
+            new OneshotSupplierImpl<>();
+    @Spy
+    public Callback<Boolean> mListener;
+    @Mock
+    public PolicyService mPolicyService;
+    @Mock
+    public FirstRunAppRestrictionInfo mTestAppRestrictionInfo;
+
+    private PolicyService.Observer mPolicyServiceObserver;
+    private Callback<Boolean> mAppRestrictionsCallback;
+    private PolicyLoadListener mPolicyLoadListener;
+
+    @Before
+    public void setUp() {
+        Mockito.doAnswer(invocation -> {
+                   mPolicyServiceObserver = invocation.getArgument(0);
+                   return null;
+               })
+                .when(mPolicyService)
+                .addObserver(any());
+        Mockito.doAnswer(invocation -> {
+                   mAppRestrictionsCallback = invocation.getArgument(0);
+                   return null;
+               })
+                .when(mTestAppRestrictionInfo)
+                .getHasAppRestriction(any());
+
+        mPolicyLoadListener =
+                new PolicyLoadListener(mTestAppRestrictionInfo, mTestPolicyServiceSupplier);
+        Assert.assertNull(LOADING_NOT_FINISHED, mPolicyLoadListener.get());
+
+        Mockito.verify(mTestAppRestrictionInfo).getHasAppRestriction(mAppRestrictionsCallback);
+        Mockito.verify(mTestPolicyServiceSupplier).onAvailable(any());
+    }
+
+    @Test
+    public void testAppRestrictionNotFound() {
+        mPolicyLoadListener.onAvailable(mListener);
+
+        mAppRestrictionsCallback.onResult(false);
+        Assert.assertFalse(LOADED_NO_POLICY, mPolicyLoadListener.get());
+        Mockito.verify(mListener).onResult(false);
+    }
+
+    @Test
+    public void testAppRestrictionFoundAndPolicyLoaded() {
+        mPolicyLoadListener.onAvailable(mListener);
+
+        mAppRestrictionsCallback.onResult(true);
+        Assert.assertNull(LOADING_NOT_FINISHED, mPolicyLoadListener.get());
+        Mockito.verify(mListener, never()).onResult(any());
+
+        mTestPolicyServiceSupplier.set(mPolicyService);
+        Assert.assertNull(LOADING_NOT_FINISHED, mPolicyLoadListener.get());
+        Mockito.verify(mListener, never()).onResult(any());
+
+        setPolicyServiceInitialized();
+        Assert.assertTrue(LOADED_POLICY_READY, mPolicyLoadListener.get());
+        Mockito.verify(mListener).onResult(true);
+    }
+
+    @Test
+    public void testPolicyInitializedWithoutAppRestriction() {
+        mPolicyLoadListener.onAvailable(mListener);
+
+        mTestPolicyServiceSupplier.set(mPolicyService);
+        Assert.assertNull(LOADING_NOT_FINISHED, mPolicyLoadListener.get());
+        Mockito.verify(mListener, never()).onResult(any());
+
+        setPolicyServiceInitialized();
+        Assert.assertTrue(LOADED_POLICY_READY, mPolicyLoadListener.get());
+        Mockito.verify(mListener).onResult(true);
+    }
+
+    @Test
+    public void testPolicyInitializedBeforeSupplied() {
+        setPolicyServiceInitialized();
+        Assert.assertNull(LOADING_NOT_FINISHED, mPolicyLoadListener.get());
+
+        mTestPolicyServiceSupplier.set(mPolicyService);
+        Assert.assertTrue(LOADED_POLICY_READY, mPolicyLoadListener.get());
+    }
+
+    @Test
+    public void testAddListenerAfterFinished() {
+        mAppRestrictionsCallback.onResult(false);
+        Assert.assertFalse(LOADED_NO_POLICY, mPolicyLoadListener.get());
+
+        mPolicyLoadListener.onAvailable(mListener);
+        Mockito.verify(mListener).onResult(false);
+    }
+
+    @Test
+    public void testDestroyAfterStart_AppRestrictions() {
+        mPolicyLoadListener.onAvailable(mListener);
+
+        mPolicyLoadListener.destroy();
+        Assert.assertNull(LOADING_NOT_FINISHED, mPolicyLoadListener.get());
+        Mockito.verify(mListener, never()).onResult(anyBoolean());
+
+        // Even when no app restrictions were found, listeners will not be informed after #destroy,
+        // and the state for PolicyLoadListener should stay at not finished.
+        mAppRestrictionsCallback.onResult(false);
+        Assert.assertNull(LOADING_NOT_FINISHED, mPolicyLoadListener.get());
+        Mockito.verify(mListener, never()).onResult(anyBoolean());
+    }
+
+    @Test
+    public void testDestroyAfterStart_PolicyInitialized() {
+        mPolicyLoadListener.onAvailable(mListener);
+
+        mPolicyLoadListener.destroy();
+        Assert.assertNull(LOADING_NOT_FINISHED, mPolicyLoadListener.get());
+        Mockito.verify(mListener, never()).onResult(anyBoolean());
+
+        // Even when policy service is initialized, listeners will not be informed after #destroy,
+        // and the state for PolicyLoadListener should stay at not finished.
+        mTestPolicyServiceSupplier.set(mPolicyService);
+        Assert.assertNull(LOADING_NOT_FINISHED, mPolicyLoadListener.get());
+        Mockito.verify(mListener, never()).onResult(anyBoolean());
+    }
+
+    private void setPolicyServiceInitialized() {
+        Mockito.when(mPolicyService.isInitializationComplete()).thenReturn(true);
+        if (mPolicyServiceObserver != null) mPolicyServiceObserver.onPolicyServiceInitialized();
+    }
+}
diff --git a/chrome/android/modules/cablev2_authenticator/internal/java/src/org/chromium/chrome/modules/cablev2_authenticator/ModuleImpl.java b/chrome/android/modules/cablev2_authenticator/internal/java/src/org/chromium/chrome/modules/cablev2_authenticator/ModuleImpl.java
index 5a0acda0..2e0514c 100644
--- a/chrome/android/modules/cablev2_authenticator/internal/java/src/org/chromium/chrome/modules/cablev2_authenticator/ModuleImpl.java
+++ b/chrome/android/modules/cablev2_authenticator/internal/java/src/org/chromium/chrome/modules/cablev2_authenticator/ModuleImpl.java
@@ -20,4 +20,11 @@
     public Fragment getFragment() {
         return new CableAuthenticatorUI();
     }
+
+    @Override
+    public void onCloudMessage(
+            long event, long systemNetworkContext, long registration, String activityClassName) {
+        CableAuthenticatorUI.onCloudMessage(
+                event, systemNetworkContext, registration, activityClassName);
+    }
 }
diff --git a/chrome/android/modules/cablev2_authenticator/public/java/src/org/chromium/chrome/modules/cablev2_authenticator/Module.java b/chrome/android/modules/cablev2_authenticator/public/java/src/org/chromium/chrome/modules/cablev2_authenticator/Module.java
index 90ac8697..c87278f 100644
--- a/chrome/android/modules/cablev2_authenticator/public/java/src/org/chromium/chrome/modules/cablev2_authenticator/Module.java
+++ b/chrome/android/modules/cablev2_authenticator/public/java/src/org/chromium/chrome/modules/cablev2_authenticator/Module.java
@@ -20,4 +20,8 @@
 public interface Module {
     /** Returns a {@link Fragment} that contains the authenticator UI. */
     public Fragment getFragment();
+
+    /** Handle a message from the tunnel service. */
+    public void onCloudMessage(
+            long event, long systemNetworkContext, long registration, String activityClassName);
 }
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index b2582509..aa24559 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -3733,99 +3733,6 @@
   <message name="IDS_NETWORK_HEALTH_STATE_ONLINE" desc="Network State - Online. This state is when a network device is connected to a network and can access the internet.">
     Online
   </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_LAN_CONNECTIVITY" desc="Label for Network diagnostics `LAN connectivity` test. This test determines if the device is connected to a Local Area Network (LAN)">
-    Lan Connectivity
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH" desc="Label for Network diagnostics `signal strength` test. This test ensures that a WiFi signal is strong enough for a stable connection.">
-    Signal Strength
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED" desc="Label for Network diagnostics `gateway can be pinged` test. This test ensures that there is a connection to the network gateway.">
-    Gateway can be Pinged
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_HAS_SECURE_WIFI_CONNECTION" desc="Label for Network diagnostics `has secure WiFi connection` test. This test ensures that the WiFi connection is properly secure.">
-    Secure WiFi Connection
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PRESENT" desc="Label for Network diagnostics `DNS resolver present` test. This test ensures that the Domain Name Service (DNS) exists.">
-    DNS Resolver Present
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY" desc="Label for Network diagnostics `DNS latency` test. This test makes sure the latency between the device and the Domain Name Server (DNS) is acceptable.">
-    DNS Latency
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION" desc="Label for Network diagnostics `DNS resolution` test. This test ensures that the Domain Name Server (DNS) can resolve network requests.">
-    DNS Resolution
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_PASSED" desc="Label shown when a Network diagnostics routine passed">
-    Passed
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_FAILED" desc="Label shown when a Network diagnostics routine failed">
-    Failed
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_NOT_RUN" desc="Label shown when a Network diagnostics routine did not run">
-    Not Run
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_RUN" desc="Label for Network diagnostics run routine button">
-    Run
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_RUN_ALL" desc="Label for Network diagnostics run all routines button">
-    Run All Routines
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_SEND_FEEDBACK" desc="Label for Network diagnostics send feedback report button">
-    Send Feedback Report
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_NOT_FOUND" desc="Error message shown when a WiFi signal could not be detected">
-    Signal not found
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_WEAK" desc="Error message shown when a only a weak WiFi signal could be detected">
-    Weak signal
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_UNREACHABLE" desc="Error message shown when a network gateway is not reachable">
-    Gateway is unreachable
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_DEFAULT_FAILED" desc="Error message shown when the default network gateway cannot be pinged">
-    Failed to ping the default network gateway
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_DEFAULT_ABOVE_LATENCY" desc="Error message shown when the latency of the default network gateway is too high">
-    Default network above latency threshold
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_NON_DEFAULT_FAILED" desc="Error message shown when the non-default network gateway cannot be pinged">
-    Failed to ping the non-default network gateway
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_NON_DEFAULT_ABOVE_LATENCY" desc="Error message shown when the latency of the non-default network gateway is too high">
-    Non-default network above latency threshold
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_NOT_SECURE" desc="Error message shown when the current WiFi network is not secure">
-    WiFi network is not secure
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_8021x" desc="Error message shown when the current WiFi network is secured with the weak protocol WEP 802.1x">
-    WiFi network is secured with weak protocol WEP 802.1x
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_PSK" desc="Error message shown when the current WiFi network is secured with the weak protocol WEP PSK">
-    WiFi network is secured with weak protocol WEP PSK
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_UNKNOWN" desc="Error message shown when the current WiFi network is secured with an unknown protocol">
-    Unknown WiFi security protocol
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_NO_NAME_SERVERS" desc="Error message shown when the no domain name servers (DNS) are found">
-    No name servers found
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_MALFORMED_NAME_SERVERS" desc="Error message shown when the domain name servers (DNS) are malformed">
-    Malformed name servers
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_EMPTY_NAME_SERVERS" desc="Error message shown when the domain name servers (DNS) are empty">
-    Empty name servers
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_FAILED_TO_RESOLVE_ALL_HOSTS" desc="Error message shown when the domain name servers (DNS) failed to resolve all hosts">
-    Failed to resolve all hosts
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SLIGHTLY_ABOVE_THRESHOLD" desc="Error message shown when the latency for the domain name server (DNS) is slightly above an allowable threshold">
-    DNS latency slightly above allowable threshold
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SIGNIFICANTLY_ABOVE_THRESHOLD" desc="Error message shown when the latency for the domain name server (DNS) is significantly above an allowable threshold">
-    DNS latency significantly above allowable threshold
-  </message>
-  <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION_PROBLEM_FAILED_TO_RESOLVE_HOST" desc="Error message shown when the domain name server (DNS) failed to resolve a host">
-    Failed to resolve host
-  </message>
 
   <!-- Set time/date UI display strings -->
   <message name="IDS_SET_TIME_TITLE" desc="Title of the set time/date UI.">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f9d33ab..ca30357 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1490,8 +1490,6 @@
     "resource_coordinator/utils.h",
     "resources_util.cc",
     "resources_util.h",
-    "search/ntp_features.cc",
-    "search/ntp_features.h",
     "search/search.cc",
     "search/search.h",
     "search/suggestions/suggestions_service_factory.cc",
@@ -2351,6 +2349,9 @@
       ]
     }
   }
+  if (is_linux || is_chromeos) {
+    deps += [ "//chrome/browser/error_reporting" ]
+  }
   if (use_ozone) {
     deps += [
       "//ui/events/ozone",
@@ -3211,6 +3212,7 @@
       "//components/translate/core/language_detection",
       "//components/ukm/content",
       "//components/viz/common",
+      "//device/fido:cablev2_registration",
       "//ipc:param_traits",
       "//media/mojo/clients",
       "//rlz:rlz_utils",
@@ -6742,8 +6744,6 @@
     sources += [
       "safe_browsing/certificate_reporting_service_test_utils.cc",
       "safe_browsing/certificate_reporting_service_test_utils.h",
-      "safe_browsing/mock_report_sender.cc",
-      "safe_browsing/mock_report_sender.h",
     ]
     deps += [
       "//chrome/browser/safe_browsing",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 9b80893..1a3da83 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -16,6 +16,7 @@
   "+chrome/android/modules",
   "+chrome/android/test_support_jni_headers",
   "+chrome/app",
+  "+chrome/browser/error_reporting",
   "+chrome/browser/flags/android",
   "+chrome/browser/preferences/android",
   "+chrome/browser/profiles/android/jni_headers",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 944d5b901..a51a294 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -47,7 +47,6 @@
 #include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_features.h"
 #include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_params.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/sharing/click_to_call/feature.h"
 #include "chrome/browser/sharing/features.h"
 #include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
@@ -113,6 +112,7 @@
 #include "components/query_tiles/switches.h"
 #include "components/reading_list/features/reading_list_switches.h"
 #include "components/safe_browsing/core/features.h"
+#include "components/search/ntp_features.h"
 #include "components/security_interstitials/content/stateful_ssl_host_state_delegate.h"
 #include "components/security_interstitials/core/features.h"
 #include "components/security_state/core/features.h"
@@ -4411,7 +4411,7 @@
 
     {"screen-capture-android", flag_descriptions::kUserMediaScreenCapturingName,
      flag_descriptions::kUserMediaScreenCapturingDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kUserMediaScreenCapturing)},
+     FEATURE_VALUE_TYPE(features::kUserMediaScreenCapturing)},
 #endif
 
 #if defined(OS_ANDROID)
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index d1aac75a..2d671441 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/android/tab_web_contents_delegate_android.h"
 #include "chrome/browser/browser_about_handler.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/history/history_tab_helper.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_android.h"
@@ -263,6 +264,8 @@
 
   AttachTabHelpers(web_contents_.get());
 
+  PropagateHideFutureNavigationsToHistoryTabHelper();
+
   SetWindowSessionID(session_window_id_);
 
   ContextMenuHelper::FromWebContents(web_contents())
@@ -475,11 +478,26 @@
   return devtools_host_;
 }
 
+void TabAndroid::SetHideFutureNavigations(JNIEnv* env, jboolean hide) {
+  if (hide_future_navigations_ == hide)
+    return;
+  hide_future_navigations_ = hide;
+  PropagateHideFutureNavigationsToHistoryTabHelper();
+}
+
 void TabAndroid::SetDevToolsAgentHost(
     scoped_refptr<content::DevToolsAgentHost> host) {
   devtools_host_ = std::move(host);
 }
 
+void TabAndroid::PropagateHideFutureNavigationsToHistoryTabHelper() {
+  if (!web_contents())
+    return;
+  auto* history_tab_helper = HistoryTabHelper::FromWebContents(web_contents());
+  if (history_tab_helper)
+    history_tab_helper->set_hide_all_navigations(hide_future_navigations_);
+}
+
 base::android::ScopedJavaLocalRef<jobject> JNI_TabImpl_FromWebContents(
     JNIEnv* env,
     const JavaParamRef<jobject>& jweb_contents) {
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index 6db2b0e0..6aa3eb9 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -182,12 +182,20 @@
   jboolean GetAddApi2TransitionToFutureNavigations(JNIEnv* env) {
     return should_add_api2_transition_to_future_navigations_;
   }
+  void SetHideFutureNavigations(JNIEnv* env, jboolean hide);
+  jboolean GetHideFutureNavigations(JNIEnv* env) {
+    return hide_future_navigations_;
+  }
 
   scoped_refptr<content::DevToolsAgentHost> GetDevToolsAgentHost();
 
   void SetDevToolsAgentHost(scoped_refptr<content::DevToolsAgentHost> host);
 
  private:
+  // Calls set_hide_future_navigations() on the HistoryTabHelper associated
+  // with |web_contents_|.
+  void PropagateHideFutureNavigationsToHistoryTabHelper();
+
   JavaObjectWeakGlobalRef weak_java_tab_;
 
   // Identifier of the window the tab is in.
@@ -201,6 +209,7 @@
   scoped_refptr<content::DevToolsAgentHost> devtools_host_;
   std::unique_ptr<browser_sync::SyncedTabDelegateAndroid> synced_tab_delegate_;
   bool should_add_api2_transition_to_future_navigations_ = false;
+  bool hide_future_navigations_ = false;
 
   base::ObserverList<Observer> observers_;
 
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index d6f2ec1a..37a643a 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -196,6 +196,10 @@
 #include "components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h"
 #endif
 
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#include "chrome/browser/error_reporting/chrome_js_error_report_processor.h"  // nogncheck
+#endif
+
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
 #include "chrome/browser/component_updater/supervised_user_whitelist_installer.h"
 #endif
@@ -1150,6 +1154,10 @@
   ApplyMetricsReportingPolicy();
 #endif
 
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+  ChromeJsErrorReportProcessor::Create();
+#endif
+
 #if BUILDFLAG(ENABLE_PLUGINS)
   auto* plugin_service = content::PluginService::GetInstance();
   plugin_service->SetFilter(ChromePluginServiceFilter::GetInstance());
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 0f269dc6..86c92f8 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -110,7 +110,6 @@
 #include "chrome/browser/payments/payment_credential_factory.h"
 #include "chrome/browser/payments/payment_request_factory.h"
 #include "chrome/browser/promo_browser_command/promo_browser_command.mojom.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/task_module/task_module.mojom.h"
 #include "chrome/browser/speech/speech_recognition_client_browser_interface.h"
 #include "chrome/browser/speech/speech_recognition_client_browser_interface_factory.h"
@@ -118,6 +117,7 @@
 #include "chrome/browser/speech/speech_recognition_service_factory.h"
 #include "chrome/browser/ui/webui/downloads/downloads.mojom.h"
 #include "chrome/browser/ui/webui/downloads/downloads_ui.h"
+#include "components/search/ntp_features.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #if !defined(OFFICIAL_BUILD)
 #include "chrome/browser/ui/webui/new_tab_page/foo/foo.mojom.h"  // nogncheck crbug.com/1125897
diff --git a/chrome/browser/chrome_browser_main_android.cc b/chrome/browser/chrome_browser_main_android.cc
index 65092b08..218ec43 100644
--- a/chrome/browser/chrome_browser_main_android.cc
+++ b/chrome/browser/chrome_browser_main_android.cc
@@ -15,12 +15,14 @@
 #include "chrome/browser/android/seccomp_support_detector.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/webauthn/android/cable_module_android.h"
 #include "components/crash/content/browser/child_exit_observer_android.h"
 #include "components/crash/content/browser/child_process_crash_observer_android.h"
 #include "components/metrics/stability_metrics_helper.h"
 #include "content/public/browser/android/compositor.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/main_function_params.h"
+#include "device/fido/features.h"
 #include "net/base/network_change_notifier.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/resource/resource_bundle_android.h"
@@ -60,6 +62,14 @@
   // Start watching the preferences that need to be backed up backup using
   // Android backup, so that we create a new backup if they change.
   backup_watcher_.reset(new android::ChromeBackupWatcher(profile()));
+
+  // The GCM driver can be used at this point because the primary profile has
+  // been created. Register non-profile-specific things that use GCM so that no
+  // messages can be processed (and dropped) because the handler wasn't
+  // installed in time.
+  if (base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport)) {
+    webauthn::authenticator::RegisterForCloudMessages();
+  }
 }
 
 int ChromeBrowserMainPartsAndroid::PreEarlyInitialization() {
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
index 39f6536..cbbf736 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
@@ -9,6 +9,7 @@
 
 #include "ash/public/cpp/child_accounts/parent_access_controller.h"
 #include "base/check.h"
+#include "base/logging.h"
 #include "base/no_destructor.h"
 #include "base/timer/timer.h"
 #include "chrome/common/chrome_features.h"
@@ -26,13 +27,30 @@
 
 // Returns true when the device owner is a child.
 bool IsDeviceOwnedByChild() {
+  // TODO(crbug.com/1143369): Owner id might not be available early after
+  // startup. Wait for it to be ready.
   AccountId owner_account_id =
       user_manager::UserManager::Get()->GetOwnerAccountId();
-  if (owner_account_id.empty())
+  if (owner_account_id.empty()) {
+    LOG(ERROR) << "Device owner could not be determined - will skip parent "
+                  "code validation";
     return false;
+  }
+
   const user_manager::User* device_owner =
       user_manager::UserManager::Get()->FindUser(owner_account_id);
-  CHECK(device_owner);
+
+  // It looks like reading users from Local State might be failing sometimes.
+  // Default to false if ownership is not known to avoid crash.
+  // TODO(agawronska): Investigate if it can be improved. Defaulting to false
+  // could sometimes lead to skipping parent code validation when child is the
+  // device owner.
+  if (!device_owner) {
+    LOG(ERROR) << "Device owner could not be determined - will skip parent "
+                  "code validation";
+    return false;
+  }
+
   return device_owner->IsChild();
 }
 
diff --git a/chrome/browser/chromeos/net/network_health/network_health_localized_strings.cc b/chrome/browser/chromeos/net/network_health/network_health_localized_strings.cc
index be551f3..ae14585c6 100644
--- a/chrome/browser/chromeos/net/network_health/network_health_localized_strings.cc
+++ b/chrome/browser/chromeos/net/network_health/network_health_localized_strings.cc
@@ -24,62 +24,6 @@
     {"NetworkHealthStatePortal", IDS_NETWORK_HEALTH_STATE_PORTAL},
     {"NetworkHealthStateConnected", IDS_NETWORK_HEALTH_STATE_CONNECTED},
     {"NetworkHealthStateOnline", IDS_NETWORK_HEALTH_STATE_ONLINE},
-
-    // Network Diagnostics Strings
-    {"NetworkDiagnosticsLanConnectivity",
-     IDS_NETWORK_DIAGNOSTICS_LAN_CONNECTIVITY},
-    {"NetworkDiagnosticsSignalStrength",
-     IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH},
-    {"NetworkDiagnosticsGatewayCanBePinged",
-     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED},
-    {"NetworkDiagnosticsHasSecureWiFiConnection",
-     IDS_NETWORK_DIAGNOSTICS_HAS_SECURE_WIFI_CONNECTION},
-    {"NetworkDiagnosticsDnsResolverPresent",
-     IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PRESENT},
-    {"NetworkDiagnosticsDnsLatency", IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY},
-    {"NetworkDiagnosticsDnsResolution", IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION},
-    {"NetworkDiagnosticsPassed", IDS_NETWORK_DIAGNOSTICS_PASSED},
-    {"NetworkDiagnosticsFailed", IDS_NETWORK_DIAGNOSTICS_FAILED},
-    {"NetworkDiagnosticsNotRun", IDS_NETWORK_DIAGNOSTICS_NOT_RUN},
-    {"NetworkDiagnosticsRun", IDS_NETWORK_DIAGNOSTICS_RUN},
-    {"NetworkDiagnosticsRunAll", IDS_NETWORK_DIAGNOSTICS_RUN_ALL},
-    {"NetworkDiagnosticsSendFeedback", IDS_NETWORK_DIAGNOSTICS_SEND_FEEDBACK},
-    {"SignalStrengthProblem_NotFound",
-     IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_NOT_FOUND},
-    {"SignalStrengthProblem_Weak",
-     IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_WEAK},
-    {"GatewayPingProblem_Unreachable",
-     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_UNREACHABLE},
-    {"GatewayPingProblem_NoDefaultPing",
-     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_DEFAULT_FAILED},
-    {"GatewayPingProblem_DefaultLatency",
-     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_DEFAULT_ABOVE_LATENCY},
-    {"GatewayPingProblem_NoNonDefaultPing",
-     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_NON_DEFAULT_FAILED},
-    {"GatewayPingProblem_NonDefaultLatency",
-     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_NON_DEFAULT_ABOVE_LATENCY},
-    {"SecureWifiProblem_None",
-     IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_NOT_SECURE},
-    {"SecureWifiProblem_8021x",
-     IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_8021x},
-    {"SecureWifiProblem_PSK",
-     IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_PSK},
-    {"SecureWifiProblem_Unknown",
-     IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_UNKNOWN},
-    {"DnsResolverProblem_NoNameServers",
-     IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_NO_NAME_SERVERS},
-    {"DnsResolverProblem_MalformedNameServers",
-     IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_MALFORMED_NAME_SERVERS},
-    {"DnsResolverProblem_EmptyNameServers",
-     IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_EMPTY_NAME_SERVERS},
-    {"DnsLatencyProblem_FailedResolveHosts",
-     IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_FAILED_TO_RESOLVE_ALL_HOSTS},
-    {"DnsLatencyProblem_LatencySlightlyAbove",
-     IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SLIGHTLY_ABOVE_THRESHOLD},
-    {"DnsLatencyProblem_LatencySignificantlyAbove",
-     IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SIGNIFICANTLY_ABOVE_THRESHOLD},
-    {"DnsResolutionProblem_FailedResolve",
-     IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION_PROBLEM_FAILED_TO_RESOLVE_HOST},
 };
 
 }  // namespace
diff --git a/chrome/browser/chromeos/policy/active_directory_policy_manager.cc b/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
index ef9a225..17728f3 100644
--- a/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
+++ b/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
@@ -97,6 +97,17 @@
   return true;
 }
 
+bool ActiveDirectoryPolicyManager::IsFirstPolicyLoadComplete(
+    PolicyDomain domain) const {
+  if (domain == POLICY_DOMAIN_CHROME)
+    return store()->first_policies_loaded();
+  if (domain == extension_policy_domain_) {
+    return extension_policy_service_ &&
+           extension_policy_service_->policy() != nullptr;
+  }
+  return true;
+}
+
 void ActiveDirectoryPolicyManager::RefreshPolicies() {
   scheduler_->ScheduleTaskNow();
 }
diff --git a/chrome/browser/chromeos/policy/active_directory_policy_manager.h b/chrome/browser/chromeos/policy/active_directory_policy_manager.h
index b29b2cf..d83919d 100644
--- a/chrome/browser/chromeos/policy/active_directory_policy_manager.h
+++ b/chrome/browser/chromeos/policy/active_directory_policy_manager.h
@@ -45,6 +45,7 @@
   void Init(SchemaRegistry* registry) override;
   void Shutdown() override;
   bool IsInitializationComplete(PolicyDomain domain) const override;
+  bool IsFirstPolicyLoadComplete(PolicyDomain domain) const override;
   void RefreshPolicies() override;
 
   // CloudPolicyStore::Observer:
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc b/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
index 508122d..c99e51b 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
@@ -90,6 +90,11 @@
   return true;
 }
 
+bool DeviceLocalAccountPolicyProvider::IsFirstPolicyLoadComplete(
+    PolicyDomain domain) const {
+  return IsInitializationComplete(domain);
+}
+
 void DeviceLocalAccountPolicyProvider::RefreshPolicies() {
   DeviceLocalAccountPolicyBroker* broker = GetBroker();
   if (broker && broker->core()->service()) {
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_provider.h b/chrome/browser/chromeos/policy/device_local_account_policy_provider.h
index 84db045f..bfe124c 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_provider.h
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_provider.h
@@ -48,6 +48,7 @@
 
   // ConfigurationPolicyProvider:
   bool IsInitializationComplete(PolicyDomain domain) const override;
+  bool IsFirstPolicyLoadComplete(PolicyDomain domain) const override;
   void RefreshPolicies() override;
 
   // DeviceLocalAccountPolicyService::Observer:
diff --git a/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc b/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
index a3feb1a..79a69c7 100644
--- a/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
+++ b/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
@@ -379,6 +379,45 @@
   }
 }
 
+// Helper function to convert extensions::ManifestInvalidError to the
+// ExtensionInstallReportLogEvent::ManifestInvalidError proto.
+em::ExtensionInstallReportLogEvent_ManifestInvalidError
+ConvertManifestInvalidErrorToProto(extensions::ManifestInvalidError error) {
+  using ManifestError = extensions::ManifestInvalidError;
+  switch (error) {
+    case ManifestError::XML_PARSING_FAILED:
+      return em::ExtensionInstallReportLogEvent::XML_PARSING_FAILED;
+    case ManifestError::INVALID_XLMNS_ON_GUPDATE_TAG:
+      return em::ExtensionInstallReportLogEvent::INVALID_XLMNS_ON_GUPDATE_TAG;
+    case ManifestError::MISSING_GUPDATE_TAG:
+      return em::ExtensionInstallReportLogEvent::MISSING_GUPDATE_TAG;
+    case ManifestError::INVALID_PROTOCOL_ON_GUPDATE_TAG:
+      return em::ExtensionInstallReportLogEvent::
+          INVALID_PROTOCOL_ON_GUPDATE_TAG;
+    case ManifestError::MISSING_APP_ID:
+      return em::ExtensionInstallReportLogEvent::MISSING_APP_ID;
+    case ManifestError::MISSING_UPDATE_CHECK_TAGS:
+      return em::ExtensionInstallReportLogEvent::MISSING_UPDATE_CHECK_TAGS;
+    case ManifestError::MULTIPLE_UPDATE_CHECK_TAGS:
+      return em::ExtensionInstallReportLogEvent::MULTIPLE_UPDATE_CHECK_TAGS;
+    case ManifestError::INVALID_PRODVERSION_MIN:
+      return em::ExtensionInstallReportLogEvent::INVALID_PRODVERSION_MIN;
+    case ManifestError::EMPTY_CODEBASE_URL:
+      return em::ExtensionInstallReportLogEvent::EMPTY_CODEBASE_URL;
+    case ManifestError::INVALID_CODEBASE_URL:
+      return em::ExtensionInstallReportLogEvent::INVALID_CODEBASE_URL;
+    case ManifestError::MISSING_VERSION_FOR_UPDATE_CHECK:
+      return em::ExtensionInstallReportLogEvent::
+          MISSING_VERSION_FOR_UPDATE_CHECK;
+    case ManifestError::INVALID_VERSION:
+      return em::ExtensionInstallReportLogEvent::INVALID_VERSION;
+    case ManifestError::BAD_UPDATE_SPECIFICATION:
+      return em::ExtensionInstallReportLogEvent::BAD_UPDATE_SPECIFICATION;
+    case ManifestError::BAD_APP_STATUS:
+      return em::ExtensionInstallReportLogEvent::BAD_APP_STATUS;
+  }
+}
+
 }  // namespace
 
 ExtensionInstallEventLogCollector::ExtensionInstallEventLogCollector(
@@ -477,6 +516,12 @@
     event->set_unpacker_failure_reason(ConvertUnpackerFailureReasonToProto(
         data.unpacker_failure_reason.value()));
   }
+  // Manifest invalid error is only reported if the extension failed due to
+  // failure reason MANIFEST_INVALID.
+  if (data.manifest_invalid_error) {
+    event->set_manifest_invalid_error(ConvertManifestInvalidErrorToProto(
+        data.manifest_invalid_error.value()));
+  }
   extensions::ForceInstalledTracker* force_installed_tracker =
       extensions::ExtensionSystem::Get(profile_)
           ->extension_service()
diff --git a/chrome/browser/chromeos/policy/extension_install_event_log_collector_unittest.cc b/chrome/browser/chromeos/policy/extension_install_event_log_collector_unittest.cc
index afab6c0..42a1a68 100644
--- a/chrome/browser/chromeos/policy/extension_install_event_log_collector_unittest.cc
+++ b/chrome/browser/chromeos/policy/extension_install_event_log_collector_unittest.cc
@@ -508,6 +508,30 @@
             delegate()->last_request().event.unpacker_failure_reason());
 }
 
+// Verifies that a new event is created when the extension failed due to
+// MANIFEST_INVALID failure reason.
+TEST_F(ExtensionInstallEventLogCollectorTest,
+       ExtensionInstallFailedWitManifestInvalid) {
+  auto collector = std::make_unique<ExtensionInstallEventLogCollector>(
+      registry(), delegate(), profile());
+
+  extensions::InstallStageTracker* tracker =
+      extensions::InstallStageTracker::Get(profile());
+
+  // One extension failed.
+  extensions::ExtensionDownloaderDelegate::FailureData data(
+      extensions::ManifestInvalidError::MISSING_APP_ID);
+  tracker->ReportManifestInvalidFailure(kExtensionId1, data);
+  ASSERT_TRUE(VerifyEventAddedSuccessfully(1 /*expected_add_count*/,
+                                           0 /*expected_add_all_count*/));
+  EXPECT_EQ(em::ExtensionInstallReportLogEvent::INSTALLATION_FAILED,
+            delegate()->last_request().event.event_type());
+  EXPECT_EQ(em::ExtensionInstallReportLogEvent::MANIFEST_INVALID,
+            delegate()->last_request().event.failure_reason());
+  EXPECT_EQ(em::ExtensionInstallReportLogEvent::MISSING_APP_ID,
+            delegate()->last_request().event.manifest_invalid_error());
+}
+
 TEST_F(ExtensionInstallEventLogCollectorTest, InstallExtension) {
   std::unique_ptr<ExtensionInstallEventLogCollector> collector =
       std::make_unique<ExtensionInstallEventLogCollector>(
diff --git a/chrome/browser/chromeos/policy/install_event_log_util.cc b/chrome/browser/chromeos/policy/install_event_log_util.cc
index 13299cf..6a411566 100644
--- a/chrome/browser/chromeos/policy/install_event_log_util.cc
+++ b/chrome/browser/chromeos/policy/install_event_log_util.cc
@@ -51,6 +51,7 @@
 constexpr char kInstallCreationStage[] = "installCreationStage";
 constexpr char kDownloadCacheStatus[] = "downloadCacheStatus";
 constexpr char kUnpackerFailureReason[] = "unpackerFailureReason";
+constexpr char kManifestInvalidError[] = "manifestInvalidError";
 
 // Calculates hash for the given |event| and |context|, and stores the hash in
 // |hash|. Returns true if |event| and |context| are json serializable and
@@ -221,6 +222,12 @@
         extension_install_report_log_event.unpacker_failure_reason());
   }
 
+  if (extension_install_report_log_event.has_manifest_invalid_error()) {
+    event.SetIntKey(
+        kManifestInvalidError,
+        extension_install_report_log_event.manifest_invalid_error());
+  }
+
   base::Value wrapper(base::Value::Type::DICTIONARY);
   wrapper.SetKey(kExtensionInstallEvent, std::move(event));
 
diff --git a/chrome/browser/chromeos/policy/install_event_log_util_unittest.cc b/chrome/browser/chromeos/policy/install_event_log_util_unittest.cc
index 696f5a2..6004ffa7 100644
--- a/chrome/browser/chromeos/policy/install_event_log_util_unittest.cc
+++ b/chrome/browser/chromeos/policy/install_event_log_util_unittest.cc
@@ -50,6 +50,7 @@
 constexpr char kInstallCreationStage[] = "installCreationStage";
 constexpr char kDownloadCacheStatus[] = "downloadCacheStatus";
 constexpr char kUnpackerFailureReason[] = "unpackerFailureReason";
+constexpr char kManifestInvalidError[] = "manifestInvalidError";
 
 void ConvertToValueAndVerify(const em::ExtensionInstallReportLogEvent& event,
                              const std::vector<std::string>& keys) {
@@ -115,6 +116,22 @@
                            kStatefulTotal, kStatefulFree});
 }
 
+// Verifies that an event reporting update manifest invalid error is
+// successfully parsed.
+TEST_F(ExtensionInstallEventLogUtilTest, ManifestInvalidFailureReasonEvent) {
+  event_.set_event_type(
+      em::ExtensionInstallReportLogEvent::INSTALLATION_FAILED);
+  event_.set_failure_reason(
+      em::ExtensionInstallReportLogEvent::MANIFEST_INVALID);
+  event_.set_manifest_invalid_error(
+      em::ExtensionInstallReportLogEvent::XML_PARSING_FAILED);
+  event_.set_stateful_total(kDiskSpaceTotalBytes);
+  event_.set_stateful_free(kDiskSpaceFreeBytes);
+  ConvertToValueAndVerify(event_,
+                          {kEventType, kFailureReason, kManifestInvalidError,
+                           kStatefulTotal, kStatefulFree});
+}
+
 // Verifies that an event reporting extension installation stage is successfully
 // parsed.
 TEST_F(ExtensionInstallEventLogUtilTest, InstallationStageEvent) {
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
index 66201c0..19c5917 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
@@ -344,6 +344,8 @@
 
     EXPECT_CALL(provider_, IsInitializationComplete(_))
         .WillRepeatedly(Return(false));
+    EXPECT_CALL(provider_, IsFirstPolicyLoadComplete(_))
+        .WillRepeatedly(Return(false));
     provider_.Init();
     PolicyServiceImpl::Providers providers;
     providers.push_back(&provider_);
@@ -398,6 +400,8 @@
     Mock::VerifyAndClearExpectations(&provider_);
     EXPECT_CALL(provider_, IsInitializationComplete(_))
         .WillRepeatedly(Return(true));
+    EXPECT_CALL(provider_, IsFirstPolicyLoadComplete(_))
+        .WillRepeatedly(Return(true));
     provider_.SetAutoRefresh();
     provider_.RefreshPolicies();
     base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/chromeos/web_applications/media_app_integration_browsertest.cc b/chrome/browser/chromeos/web_applications/media_app_integration_browsertest.cc
index c1ea8d67..68a6af0 100644
--- a/chrome/browser/chromeos/web_applications/media_app_integration_browsertest.cc
+++ b/chrome/browser/chromeos/web_applications/media_app_integration_browsertest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/chromeos/file_manager/file_manager_test_util.h"
 #include "chrome/browser/chromeos/file_manager/web_file_tasks.h"
 #include "chrome/browser/chromeos/web_applications/system_web_app_integration_test.h"
+#include "chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/browser.h"
@@ -283,6 +284,7 @@
 IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest,
                        TrustedContextReportsConsoleErrors) {
   MockCrashEndpoint endpoint(embedded_test_server());
+  ScopedMockChromeJsErrorReportProcessor processor(endpoint);
 
   WaitForTestSystemAppInstall();
   content::WebContents* web_ui = LaunchApp(web_app::SystemAppType::MEDIA);
@@ -304,6 +306,7 @@
 IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest,
                        TrustedContextReportsDomExceptions) {
   MockCrashEndpoint endpoint(embedded_test_server());
+  ScopedMockChromeJsErrorReportProcessor processor(endpoint);
 
   WaitForTestSystemAppInstall();
   content::WebContents* web_ui = LaunchApp(web_app::SystemAppType::MEDIA);
@@ -320,6 +323,7 @@
 IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest,
                        UntrustedContextReportsDomExceptions) {
   MockCrashEndpoint endpoint(embedded_test_server());
+  ScopedMockChromeJsErrorReportProcessor processor(endpoint);
 
   WaitForTestSystemAppInstall();
   content::WebContents* app = LaunchApp(web_app::SystemAppType::MEDIA);
@@ -336,6 +340,7 @@
 IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest,
                        TrustedContextReportsUnhandledExceptions) {
   MockCrashEndpoint endpoint(embedded_test_server());
+  ScopedMockChromeJsErrorReportProcessor processor(endpoint);
 
   WaitForTestSystemAppInstall();
   content::WebContents* web_ui = LaunchApp(web_app::SystemAppType::MEDIA);
@@ -352,6 +357,7 @@
 IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest,
                        UntrustedContextReportsUnhandledExceptions) {
   MockCrashEndpoint endpoint(embedded_test_server());
+  ScopedMockChromeJsErrorReportProcessor processor(endpoint);
 
   WaitForTestSystemAppInstall();
   content::WebContents* app = LaunchApp(web_app::SystemAppType::MEDIA);
@@ -367,6 +373,7 @@
 IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest,
                        TrustedContextReportsTypeErrors) {
   MockCrashEndpoint endpoint(embedded_test_server());
+  ScopedMockChromeJsErrorReportProcessor processor(endpoint);
 
   WaitForTestSystemAppInstall();
   content::WebContents* web_ui = LaunchApp(web_app::SystemAppType::MEDIA);
@@ -384,6 +391,7 @@
 IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest,
                        UntrustedContextReportsTypeErrors) {
   MockCrashEndpoint endpoint(embedded_test_server());
+  ScopedMockChromeJsErrorReportProcessor processor(endpoint);
 
   WaitForTestSystemAppInstall();
   content::WebContents* app = LaunchApp(web_app::SystemAppType::MEDIA);
diff --git a/chrome/browser/component_updater/soda_component_installer.cc b/chrome/browser/component_updater/soda_component_installer.cc
index 80da745..d6684ec 100644
--- a/chrome/browser/component_updater/soda_component_installer.cc
+++ b/chrome/browser/component_updater/soda_component_installer.cc
@@ -133,10 +133,12 @@
                            PrefService* prefs,
                            base::OnceClosure callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!base::FeatureList::IsEnabled(media::kLiveCaption))
-    return;
 
   if (base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) {
+    if (!prefs->GetBoolean(prefs::kLiveCaptionEnabled) ||
+        !base::FeatureList::IsEnabled(media::kLiveCaption)) {
+      return;
+    }
     auto installer = base::MakeRefCounted<ComponentInstaller>(
         std::make_unique<SODAComponentInstallerPolicy>(base::BindRepeating(
             [](ComponentUpdateService* cus, PrefService* prefs,
@@ -148,32 +150,16 @@
             },
             cus, prefs)));
 
-    if (prefs->GetBoolean(prefs::kLiveCaptionEnabled)) {
       installer->Register(cus, std::move(callback));
-    } else {
-      // Register and uninstall the SODA component to delete the previously
-      // installed SODA files.
-      if (!prefs->GetFilePath(prefs::kSodaBinaryPath).empty()) {
-        installer->Register(
-            cus,
-            base::BindOnce(
-                [](ComponentUpdateService* cus, PrefService* prefs) {
-                  if (component_updater::UninstallSODAComponent(cus, prefs)) {
-                    prefs->SetFilePath(prefs::kSodaBinaryPath,
-                                       base::FilePath());
-                    prefs->SetFilePath(prefs::kSodaEnUsConfigPath,
-                                       base::FilePath());
-                  }
-                },
-                cus, prefs));
-      }
-    }
   }
 }
 
 void RegisterSodaLanguageComponent(ComponentUpdateService* cus,
                                    PrefService* prefs) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  // TODO(crbug.com/1143753): Clean up this component if the Live Caption
+  // feature hasn't been used for some time.
   if (base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) {
     speech::LanguageCode language = speech::GetLanguageCode(
         prefs->GetString(prefs::kLiveCaptionLanguageCode));
@@ -197,8 +183,4 @@
   }
 }
 
-bool UninstallSODAComponent(ComponentUpdateService* cus, PrefService* prefs) {
-  return cus->UnregisterComponent(
-      SODAComponentInstallerPolicy::GetExtensionId());
-}
 }  // namespace component_updater
diff --git a/chrome/browser/component_updater/soda_component_installer.h b/chrome/browser/component_updater/soda_component_installer.h
index 7929bcc..99db6a6 100644
--- a/chrome/browser/component_updater/soda_component_installer.h
+++ b/chrome/browser/component_updater/soda_component_installer.h
@@ -63,8 +63,6 @@
 void RegisterSodaLanguageComponent(ComponentUpdateService* cus,
                                    PrefService* prefs);
 
-bool UninstallSODAComponent(ComponentUpdateService* cus, PrefService* prefs);
-
 }  // namespace component_updater
 
 #endif  // CHROME_BROWSER_COMPONENT_UPDATER_SODA_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/component_updater/soda_en_us_component_installer.cc b/chrome/browser/component_updater/soda_en_us_component_installer.cc
index 2e3c6510..2d46bde 100644
--- a/chrome/browser/component_updater/soda_en_us_component_installer.cc
+++ b/chrome/browser/component_updater/soda_en_us_component_installer.cc
@@ -135,6 +135,9 @@
                                PrefService* prefs,
                                base::OnceClosure callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  // TODO(crbug.com/1143753): Clean up this component if the Live Caption
+  // feature hasn't been used for some time.
   if (base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) {
     if (!prefs->GetBoolean(prefs::kLiveCaptionEnabled) ||
         !base::FeatureList::IsEnabled(media::kLiveCaption)) {
@@ -156,9 +159,4 @@
   }
 }
 
-bool UninstallSodaEnUsComponent(ComponentUpdateService* cus,
-                                PrefService* prefs) {
-  return cus->UnregisterComponent(
-      SodaEnUsComponentInstallerPolicy::GetExtensionId());
-}
 }  // namespace component_updater
diff --git a/chrome/browser/component_updater/soda_en_us_component_installer.h b/chrome/browser/component_updater/soda_en_us_component_installer.h
index d914aa7..a25dce5b 100644
--- a/chrome/browser/component_updater/soda_en_us_component_installer.h
+++ b/chrome/browser/component_updater/soda_en_us_component_installer.h
@@ -62,9 +62,6 @@
                                PrefService* prefs,
                                base::OnceClosure callback);
 
-bool UninstallSodaEnUsComponent(ComponentUpdateService* cus,
-                                PrefService* prefs);
-
 }  // namespace component_updater
 
 #endif  // CHROME_BROWSER_COMPONENT_UPDATER_SODA_EN_US_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/component_updater/soda_ja_jp_component_installer.cc b/chrome/browser/component_updater/soda_ja_jp_component_installer.cc
index 3ba3273..f07187a0 100644
--- a/chrome/browser/component_updater/soda_ja_jp_component_installer.cc
+++ b/chrome/browser/component_updater/soda_ja_jp_component_installer.cc
@@ -135,6 +135,9 @@
                                PrefService* prefs,
                                base::OnceClosure callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  // TODO(crbug.com/1143753): Clean up this component if the Live Caption
+  // feature hasn't been used for some time.
   if (base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) {
     if (!prefs->GetBoolean(prefs::kLiveCaptionEnabled) ||
         !base::FeatureList::IsEnabled(media::kLiveCaption)) {
@@ -156,9 +159,4 @@
   }
 }
 
-bool UninstallSodaJaJpComponent(ComponentUpdateService* cus,
-                                PrefService* prefs) {
-  return cus->UnregisterComponent(
-      SodaJaJpComponentInstallerPolicy::GetExtensionId());
-}
 }  // namespace component_updater
diff --git a/chrome/browser/component_updater/soda_ja_jp_component_installer.h b/chrome/browser/component_updater/soda_ja_jp_component_installer.h
index 589345b..df42190b 100644
--- a/chrome/browser/component_updater/soda_ja_jp_component_installer.h
+++ b/chrome/browser/component_updater/soda_ja_jp_component_installer.h
@@ -62,9 +62,6 @@
                                PrefService* prefs,
                                base::OnceClosure callback);
 
-bool UninstallSodaJaJpComponent(ComponentUpdateService* cus,
-                                PrefService* prefs);
-
 }  // namespace component_updater
 
 #endif  // CHROME_BROWSER_COMPONENT_UPDATER_SODA_JA_JP_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/content_settings/content_settings_browsertest.cc b/chrome/browser/content_settings/content_settings_browsertest.cc
index 6ba517e..326d6fd6 100644
--- a/chrome/browser/content_settings/content_settings_browsertest.cc
+++ b/chrome/browser/content_settings/content_settings_browsertest.cc
@@ -662,6 +662,55 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_P(CookieSettingsTest, BlockCookiesAlsoBlocksFileSystem) {
+  ui_test_utils::NavigateToURL(browser(), GetPageURL());
+  content_settings::CookieSettings* settings =
+      CookieSettingsFactory::GetForProfile(browser()->profile()).get();
+  settings->SetCookieSetting(GetPageURL(), CONTENT_SETTING_BLOCK);
+
+  const char kBaseExpected[] = "%s - %s";
+
+  const char kBaseScript[] = R"(
+      (async function() {
+        const name = `%s`;
+        try {
+          await %s;
+        } catch(e) {
+          return `${name} - ${e.toString()}`;
+        }
+        return `${name} - success`;
+      }())
+  )";
+
+  struct TestOp {
+    const char* name;
+    const char* code;
+    const char* error;
+  };
+
+  const TestOp kTestOps[] = {
+      {.name = "navigator.storage.getDirectory()",
+       .code = "navigator.storage.getDirectory()",
+       .error = "SecurityError: Storage directory access is denied."},
+      {.name = "window.webkitRequestFileSystem()",
+       .code = "new Promise((resolve, reject) => { "
+               " window.webkitRequestFileSystem(window.TEMPORARY,"
+               " 5*1024, () => resolve(),"
+               " (e) => reject(e));"
+               "});",
+       .error = "AbortError: An ongoing operation was aborted, typically with "
+                "a call to abort()."},
+  };
+
+  content::WebContents* tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  for (auto& op : kTestOps) {
+    EXPECT_EQ(base::StringPrintf(kBaseExpected, op.name, op.error),
+              EvalJs(tab, base::StringPrintf(kBaseScript, op.name, op.code)));
+  }
+}
+
 INSTANTIATE_TEST_SUITE_P(
     All,
     CookieSettingsTest,
diff --git a/chrome/browser/enterprise/connectors/content_analysis_delegate_unittest.cc b/chrome/browser/enterprise/connectors/content_analysis_delegate_unittest.cc
index 54c16454..3e4dfa5c 100644
--- a/chrome/browser/enterprise/connectors/content_analysis_delegate_unittest.cc
+++ b/chrome/browser/enterprise/connectors/content_analysis_delegate_unittest.cc
@@ -897,7 +897,13 @@
   EXPECT_TRUE(called);
 }
 
-TEST_F(ContentAnalysisDelegateAuditOnlyTest, FileIsEncrypted_PolicyAllows) {
+// Flaky on Mac: https://crbug.com/1143782:
+#if defined(OS_MAC)
+#define MAYBE_FileIsEncrypted_PolicyAllows DISABLED_FileIsEncrypted_PolicyAllows
+#else
+#define MAYBE_FileIsEncrypted_PolicyAllows FileIsEncrypted_PolicyAllows
+#endif
+TEST_F(ContentAnalysisDelegateAuditOnlyTest, MAYBE_FileIsEncrypted_PolicyAllows) {
   content::InProcessUtilityThreadHelper in_process_utility_thread_helper;
 
   SetScanPolicies(/*dlp=*/true, /*malware=*/true);
diff --git a/chrome/browser/error_reporting/BUILD.gn b/chrome/browser/error_reporting/BUILD.gn
new file mode 100644
index 0000000..4115d4b
--- /dev/null
+++ b/chrome/browser/error_reporting/BUILD.gn
@@ -0,0 +1,55 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# TODO(crbug.com/1129544) This is currently disabled due to Windows DLL
+# thunking issues. Fix & re-enable.
+assert(is_linux || is_chromeos)
+
+static_library("error_reporting") {
+  sources = [
+    "chrome_js_error_report_processor.cc",
+    "chrome_js_error_report_processor.h",
+  ]
+  deps = [
+    "//base",
+    "//components/crash/content/browser/error_reporting",
+    "//components/crash/core/app",
+    "//components/feedback",
+    "//components/startup_metric_utils/browser",
+    "//content/public/browser",
+    "//net",
+    "//services/network:network_service",
+    "//services/network/public/cpp",
+  ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "mock_chrome_js_error_report_processor.cc",
+    "mock_chrome_js_error_report_processor.h",
+  ]
+  deps = [
+    ":error_reporting",
+    "//base",
+    "//components/crash/content/browser/error_reporting:mock_crash_endpoint",
+  ]
+}
+
+source_set("unit_test") {
+  testonly = true
+  sources = [ "chrome_js_error_report_processor_unittest.cc" ]
+  deps = [
+    ":error_reporting",
+    ":test_support",
+    "//base",
+    "//chrome/test:test_support",
+    "//components/crash/content/browser/error_reporting",
+    "//components/crash/content/browser/error_reporting:mock_crash_endpoint",
+    "//components/crash/core/app",
+    "//content/test:test_support",
+    "//net:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/browser/error_reporting/OWNERS b/chrome/browser/error_reporting/OWNERS
new file mode 100644
index 0000000..708f882
--- /dev/null
+++ b/chrome/browser/error_reporting/OWNERS
@@ -0,0 +1,3 @@
+file://components/crash/content/browser/error_reporting/OWNERS
+
+# COMPONENT: Internals>CrashReporting
diff --git a/components/crash/content/browser/error_reporting/send_javascript_error_report.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor.cc
similarity index 72%
rename from components/crash/content/browser/error_reporting/send_javascript_error_report.cc
rename to chrome/browser/error_reporting/chrome_js_error_report_processor.cc
index abc0436..bf17734d 100644
--- a/components/crash/content/browser/error_reporting/send_javascript_error_report.cc
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor.cc
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/crash/content/browser/error_reporting/send_javascript_error_report.h"
+#include "chrome/browser/error_reporting/chrome_js_error_report_processor.h"
 
-#include <memory>
-#include <string>
 #include <tuple>
 #include <utility>
 #include <vector>
@@ -14,7 +12,6 @@
 #include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/no_destructor.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
@@ -34,49 +31,7 @@
 
 namespace {
 
-#if defined(GOOGLE_CHROME_BUILD)
 constexpr char kCrashEndpointUrl[] = "https://clients2.google.com/cr/report";
-#else
-constexpr char kCrashEndpointUrl[] = "";
-#endif
-
-std::string& GetCrashEndpoint() {
-  static base::NoDestructor<std::string> crash_endpoint(kCrashEndpointUrl);
-  return *crash_endpoint;
-}
-
-struct OsVersionOverride {
-  OsVersionOverride(int32_t major_override,
-                    int32_t minor_override,
-                    int32_t bugfix_override)
-      : major(major_override), minor(minor_override), bugfix(bugfix_override) {}
-  int32_t major;
-  int32_t minor;
-  int32_t bugfix;
-};
-
-// If return value is set, use that as the major/minor/bugfix OS version
-// numbers. This is used as dependency injection during testing.
-base::Optional<OsVersionOverride>& GetOsVersionOverrides() {
-  static base::NoDestructor<base::Optional<OsVersionOverride>> testing_override;
-  return *testing_override;
-}
-
-// TODO(crbug.com/1129544) This is currently disabled due to Windows DLL
-// thunking issues. Fix & re-enable.
-#if !defined(OS_WIN)
-
-void OnRequestComplete(std::unique_ptr<network::SimpleURLLoader> url_loader,
-                       base::ScopedClosureRunner callback_runner,
-                       std::unique_ptr<std::string> response_body) {
-  if (response_body) {
-    // TODO(iby): Update the crash log (uploads.log)
-    DVLOG(1) << "Uploaded crash report. ID: " << *response_body;
-  } else {
-    LOG(ERROR) << "Failed to upload crash report";
-  }
-  // callback_runner will implicitly run the callback when we reach this line.
-}
 
 // Sometimes, the stack trace will contain an error message as the first line,
 // which confuses the Crash server. This function deletes it if it is present.
@@ -104,10 +59,41 @@
       .Redact(message);
 }
 
+using ParameterMap = std::map<std::string, std::string>;
+
+std::string BuildPostRequestQueryString(const ParameterMap& params) {
+  std::vector<std::string> query_parts;
+  for (const auto& kv : params) {
+    query_parts.push_back(base::StrCat(
+        {kv.first, "=",
+         net::EscapeQueryParamValue(kv.second, /*use_plus=*/false)}));
+  }
+  return base::JoinString(query_parts, "&");
+}
+
+}  // namespace
+
+ChromeJsErrorReportProcessor::ChromeJsErrorReportProcessor() = default;
+ChromeJsErrorReportProcessor::~ChromeJsErrorReportProcessor() = default;
+
+void ChromeJsErrorReportProcessor::OnRequestComplete(
+    std::unique_ptr<network::SimpleURLLoader> url_loader,
+    base::ScopedClosureRunner callback_runner,
+    std::unique_ptr<std::string> response_body) {
+  if (response_body) {
+    // TODO(iby): Update the crash log (uploads.log)
+    VLOG(1) << "Uploaded crash report. ID: " << *response_body;
+  } else {
+    LOG(ERROR) << "Failed to upload crash report";
+  }
+  // callback_runner will implicitly run the callback when we reach this line.
+}
+
 // Returns the redacted, fixed-up error report if the user consented to have it
 // sent. Returns base::nullopt if the user did not consent or we otherwise
 // should not send the report. All the MayBlock work should be done in here.
-base::Optional<JavaScriptErrorReport> CheckConsentAndRedact(
+base::Optional<JavaScriptErrorReport>
+ChromeJsErrorReportProcessor::CheckConsentAndRedact(
     JavaScriptErrorReport error_report) {
   if (!crash_reporter::GetClientCollectStatsConsent()) {
     return base::nullopt;
@@ -126,57 +112,37 @@
   return error_report;
 }
 
-using ParameterMap = std::map<std::string, std::string>;
-
-std::string BuildPostRequestQueryString(const ParameterMap& params) {
-  std::vector<std::string> query_parts;
-  for (const auto& kv : params) {
-    query_parts.push_back(base::StrCat(
-        {kv.first, "=",
-         net::EscapeQueryParamValue(kv.second, /*use_plus=*/false)}));
-  }
-  return base::JoinString(query_parts, "&");
-}
-
-struct PlatformInfo {
+struct ChromeJsErrorReportProcessor::PlatformInfo {
   std::string product_name;
   std::string version;
   std::string channel;
   std::string os_version;
 };
 
-PlatformInfo GetPlatformInfo() {
+ChromeJsErrorReportProcessor::PlatformInfo
+ChromeJsErrorReportProcessor::GetPlatformInfo() {
   PlatformInfo info;
 
   // TODO(https://crbug.com/1121816): Get correct product_name for non-POSIX
   // platforms.
-#if defined(OS_POSIX) && !defined(OS_APPLE)
+#if defined(OS_POSIX)
   crash_reporter::GetClientProductNameAndVersion(&info.product_name,
                                                  &info.version, &info.channel);
 #endif
   int32_t os_major_version = 0;
   int32_t os_minor_version = 0;
   int32_t os_bugfix_version = 0;
-  const base::Optional<OsVersionOverride>& version_override =
-      GetOsVersionOverrides();
-  if (version_override) {
-    os_major_version = version_override->major;
-    os_minor_version = version_override->minor;
-    os_bugfix_version = version_override->bugfix;
-  } else {
-    base::SysInfo::OperatingSystemVersionNumbers(
-        &os_major_version, &os_minor_version, &os_bugfix_version);
-  }
-
+  GetOsVersion(os_major_version, os_minor_version, os_bugfix_version);
   info.os_version = base::StringPrintf("%d.%d.%d", os_major_version,
                                        os_minor_version, os_bugfix_version);
   return info;
 }
 
-void SendReport(const GURL& url,
-                const std::string& body,
-                base::ScopedClosureRunner callback_runner,
-                network::SharedURLLoaderFactory* loader_factory) {
+void ChromeJsErrorReportProcessor::SendReport(
+    const GURL& url,
+    const std::string& body,
+    base::ScopedClosureRunner callback_runner,
+    network::SharedURLLoaderFactory* loader_factory) {
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->method = "POST";
   resource_request->url = url;
@@ -215,7 +181,7 @@
         }
       })");
 
-  DVLOG(1) << "Sending crash report: " << resource_request->url;
+  VLOG(1) << "Sending crash report: " << resource_request->url;
 
   auto url_loader = network::SimpleURLLoader::Create(
       std::move(resource_request), traffic_annotation);
@@ -228,13 +194,13 @@
   network::SimpleURLLoader* loader = url_loader.get();
   loader->DownloadToString(
       loader_factory,
-      base::BindOnce(&OnRequestComplete, std::move(url_loader),
-                     std::move(callback_runner)),
+      base::BindOnce(&ChromeJsErrorReportProcessor::OnRequestComplete, this,
+                     std::move(url_loader), std::move(callback_runner)),
       kCrashEndpointResponseMaxSizeInBytes);
 }
 
 // Finishes sending process once the MayBlock processing is done. On UI thread.
-void OnConsentCheckCompleted(
+void ChromeJsErrorReportProcessor::OnConsentCheckCompleted(
     base::ScopedClosureRunner callback_runner,
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
     base::TimeDelta browser_process_uptime,
@@ -245,13 +211,7 @@
     return;
   }
 
-  std::string& crash_endpoint_string = GetCrashEndpoint();
-  if (crash_endpoint_string.empty()) {
-    LOG(WARNING) << "Not sending error reports to Google for browsers that are "
-                    "not Google Chrome";
-    return;
-  }
-
+  std::string crash_endpoint_string = GetCrashEndpoint();
   // TODO(https://crbug.com/986166): Use crash_reporter for Chrome OS.
   const auto platform = GetPlatformInfo();
 
@@ -299,17 +259,22 @@
   SendReport(url, body, std::move(callback_runner), loader_factory.get());
 }
 
-#endif  // !defined(OS_WIN)
+// static
+void ChromeJsErrorReportProcessor::Create() {
+  // Google only wants error reports from official builds. Don't install a
+  // processor for other builds.
+#if defined(GOOGLE_CHROME_BUILD)
+  DCHECK(JsErrorReportProcessor::Get() == nullptr)
+      << "Attempted to create multiple ChromeJsErrorReportProcessors";
+  JsErrorReportProcessor::SetDefault(
+      base::AdoptRef(new ChromeJsErrorReportProcessor));
+#endif  // defined(GOOGLE_CHROME_BUILD)
+}
 
-}  // namespace
-
-// TODO(crbug.com/1129544) This is currently disabled due to Windows DLL
-// thunking issues. Fix & re-enable.
-#if !defined(OS_WIN)
-
-void SendJavaScriptErrorReport(JavaScriptErrorReport error_report,
-                               base::OnceClosure completion_callback,
-                               content::BrowserContext* browser_context) {
+void ChromeJsErrorReportProcessor::SendErrorReport(
+    JavaScriptErrorReport error_report,
+    base::OnceClosure completion_callback,
+    content::BrowserContext* browser_context) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   base::ScopedClosureRunner callback_runner(std::move(completion_callback));
 
@@ -329,26 +294,20 @@
   // this thread (the UI thread) to use the loader_factory.
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::MayBlock()},
-      base::BindOnce(&CheckConsentAndRedact, std::move(error_report)),
-      base::BindOnce(&OnConsentCheckCompleted, std::move(callback_runner),
+      base::BindOnce(&ChromeJsErrorReportProcessor::CheckConsentAndRedact, this,
+                     std::move(error_report)),
+      base::BindOnce(&ChromeJsErrorReportProcessor::OnConsentCheckCompleted,
+                     this, std::move(callback_runner),
                      std::move(loader_factory), browser_process_uptime));
 }
 
-#endif  // !defined(OS_WIN)
-
-void SetCrashEndpointForTesting(const std::string& endpoint) {
-  GetCrashEndpoint() = endpoint;
+std::string ChromeJsErrorReportProcessor::GetCrashEndpoint() {
+  return kCrashEndpointUrl;
 }
 
-// The weird "{" comment is to get the
-// CheckNoProductionCodeUsingTestOnlyFunctions PRESUBMIT to be quiet.
-void SetOsVersionForTesting(int32_t os_major_version,  // {
-                            int32_t os_minor_version,
-                            int32_t os_bugfix_version) {
-  GetOsVersionOverrides().emplace(os_major_version, os_minor_version,
-                                  os_bugfix_version);
-}
-
-void ClearOsVersionTestingOverride() {
-  GetOsVersionOverrides().reset();
+void ChromeJsErrorReportProcessor::GetOsVersion(int32_t& os_major_version,
+                                                int32_t& os_minor_version,
+                                                int32_t& os_bugfix_version) {
+  base::SysInfo::OperatingSystemVersionNumbers(
+      &os_major_version, &os_minor_version, &os_bugfix_version);
 }
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor.h b/chrome/browser/error_reporting/chrome_js_error_report_processor.h
new file mode 100644
index 0000000..c28cdf5
--- /dev/null
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor.h
@@ -0,0 +1,80 @@
+// Copyright 2020 The Chromium 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_ERROR_REPORTING_CHROME_JS_ERROR_REPORT_PROCESSOR_H_
+#define CHROME_BROWSER_ERROR_REPORTING_CHROME_JS_ERROR_REPORT_PROCESSOR_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/callback_helpers.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/crash/content/browser/error_reporting/js_error_report_processor.h"
+
+namespace content {
+class BrowserContext;
+}
+namespace network {
+class SimpleURLLoader;
+class SharedURLLoaderFactory;
+}  // namespace network
+class GURL;
+struct JavaScriptErrorReport;
+
+// Chrome's implementation of the JavaScript error reporter.
+class ChromeJsErrorReportProcessor : public JsErrorReportProcessor {
+ public:
+  // Creates a ChromeJsErrorReportProcessor and sets it as the processor that
+  // will be returned from JsErrorReportProcessor::Get(). This will only create
+  // the processor if appropriate.
+  static void Create();
+
+  void SendErrorReport(JavaScriptErrorReport error_report,
+                       base::OnceClosure completion_callback,
+                       content::BrowserContext* browser_context) override;
+
+ protected:
+  // Non-tests should call ChromeJsErrorReportProcessor::Create() instead.
+  ChromeJsErrorReportProcessor();
+  ~ChromeJsErrorReportProcessor() override;
+
+  // Testing hook -- returns the URL we will send the error reports to. By
+  // default, returns the real endpoint.
+  virtual std::string GetCrashEndpoint();
+
+  // Determines the version of the OS we are on. Virtual so that tests can
+  // override.
+  virtual void GetOsVersion(int32_t& os_major_version,
+                            int32_t& os_minor_version,
+                            int32_t& os_bugfix_version);
+
+ private:
+  struct PlatformInfo;
+
+  void OnRequestComplete(std::unique_ptr<network::SimpleURLLoader> url_loader,
+                         base::ScopedClosureRunner callback_runner,
+                         std::unique_ptr<std::string> response_body);
+
+  base::Optional<JavaScriptErrorReport> CheckConsentAndRedact(
+      JavaScriptErrorReport error_report);
+
+  PlatformInfo GetPlatformInfo();
+
+  void SendReport(const GURL& url,
+                  const std::string& body,
+                  base::ScopedClosureRunner callback_runner,
+                  network::SharedURLLoaderFactory* loader_factory);
+
+  void OnConsentCheckCompleted(
+      base::ScopedClosureRunner callback_runner,
+      scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
+      base::TimeDelta browser_process_uptime,
+      base::Optional<JavaScriptErrorReport> error_report);
+};
+
+#endif  // CHROME_BROWSER_ERROR_REPORTING_CHROME_JS_ERROR_REPORT_PROCESSOR_H_
diff --git a/components/crash/content/browser/error_reporting/send_javascript_error_report_unittest.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc
similarity index 75%
rename from components/crash/content/browser/error_reporting/send_javascript_error_report_unittest.cc
rename to chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc
index 860549e..b935157 100644
--- a/components/crash/content/browser/error_reporting/send_javascript_error_report_unittest.cc
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/crash/content/browser/error_reporting/send_javascript_error_report.h"
+#include "chrome/browser/error_reporting/chrome_js_error_report_processor.h"
 
 #include <memory>
 #include <utility>
@@ -10,35 +10,31 @@
 #include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "build/build_config.h"
+#include "chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h"
+#include "chrome/test/base/testing_profile.h"
 #include "components/crash/content/browser/error_reporting/javascript_error_report.h"
 #include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h"
 #include "content/public/test/browser_task_environment.h"
-#include "content/public/test/test_browser_context.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-// TODO(crbug.com/1129544) The SendJavaScriptErrorReport function is currently
-// disabled due to Windows DLL thunking issues. Fix & re-enable.
-#if !defined(OS_WIN)
-
 using ::testing::AllOf;
 using ::testing::HasSubstr;
 
-class SendJavaScriptErrorReportTest : public ::testing::Test {
+class ChromeJsErrorReportProcessorTest : public ::testing::Test {
  public:
-  SendJavaScriptErrorReportTest()
+  ChromeJsErrorReportProcessorTest()
       : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
-        run_loop_quit_(run_loop_.QuitClosure()) {}
+        run_loop_quit_(run_loop_.QuitClosure()),
+        processor_(base::MakeRefCounted<MockChromeJsErrorReportProcessor>()) {}
 
   void SetUp() override {
     test_server_ = std::make_unique<net::test_server::EmbeddedTestServer>();
     endpoint_ = std::make_unique<MockCrashEndpoint>(test_server_.get());
-    SetOsVersionForTesting(7, 20, 1);
+    processor_->SetCrashEndpoint(endpoint_->GetCrashEndpointURL());
   }
 
-  void TearDown() override { ClearOsVersionTestingOverride(); }
-
   void FinishCallback() {
     finish_callback_was_called_ = true;
     run_loop_quit_.Run();
@@ -48,20 +44,21 @@
   content::BrowserTaskEnvironment task_environment_;
   base::RunLoop run_loop_;
   base::RepeatingClosure run_loop_quit_;
-  content::TestBrowserContext browser_context_;
+  TestingProfile browser_context_;
   std::unique_ptr<net::test_server::EmbeddedTestServer> test_server_;
   std::unique_ptr<MockCrashEndpoint> endpoint_;
   bool finish_callback_was_called_ = false;
+  scoped_refptr<MockChromeJsErrorReportProcessor> processor_;
 };
 
-TEST_F(SendJavaScriptErrorReportTest, Basic) {
+TEST_F(ChromeJsErrorReportProcessorTest, Basic) {
   JavaScriptErrorReport report;
   report.message = "Hello World";
   report.url = "https://www.chromium.org/Home";
 
-  SendJavaScriptErrorReport(
+  processor_->SendErrorReport(
       std::move(report),
-      base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
+      base::BindOnce(&ChromeJsErrorReportProcessorTest::FinishCallback,
                      base::Unretained(this)),
       &browser_context_);
   run_loop_.Run();
@@ -79,7 +76,7 @@
   EXPECT_THAT(actual_report->query,
               HasSubstr("full_url=https%3A%2F%2Fwww.chromium.org%2FHome"));
   EXPECT_THAT(actual_report->query, HasSubstr("url=%2FHome"));
-  // This is from SetOsVersionForTesting(7, 20, 1) in SetUp().
+  // This is from MockChromeJsErrorReportProcessor::GetOsVersion()
   EXPECT_THAT(actual_report->query, HasSubstr("os_version=7.20.1"));
   EXPECT_THAT(actual_report->query, HasSubstr("browser=Chrome"));
   // These are from MockCrashEndpoint::Client::GetProductNameAndVersion, which
@@ -94,7 +91,7 @@
   EXPECT_EQ(actual_report->content, "");
 }
 
-TEST_F(SendJavaScriptErrorReportTest, AllFields) {
+TEST_F(ChromeJsErrorReportProcessorTest, AllFields) {
   JavaScriptErrorReport report;
   report.message = "Hello World";
   report.url = "https://www.chromium.org/Home";
@@ -104,9 +101,9 @@
   report.column_number = 14;
   report.stack_trace = "bad_func(1, 2)\nonclick()\n";
 
-  SendJavaScriptErrorReport(
+  processor_->SendErrorReport(
       std::move(report),
-      base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
+      base::BindOnce(&ChromeJsErrorReportProcessorTest::FinishCallback,
                      base::Unretained(this)),
       &browser_context_);
   run_loop_.Run();
@@ -124,7 +121,7 @@
   EXPECT_THAT(actual_report->query,
               HasSubstr("full_url=https%3A%2F%2Fwww.chromium.org%2FHome"));
   EXPECT_THAT(actual_report->query, HasSubstr("url=%2FHome"));
-  // This is from SetOsVersionForTesting(7, 20, 1) in SetUp().
+  // This is from MockChromeJsErrorReportProcessor::GetOsVersion()
   EXPECT_THAT(actual_report->query, HasSubstr("os_version=7.20.1"));
   EXPECT_THAT(actual_report->query, HasSubstr("browser=Chrome"));
   // product is double-escaped. The first time, it transforms to Unit%20test,
@@ -143,15 +140,15 @@
   EXPECT_EQ(actual_report->content, "bad_func(1, 2)\nonclick()\n");
 }
 
-TEST_F(SendJavaScriptErrorReportTest, NoConsent) {
+TEST_F(ChromeJsErrorReportProcessorTest, NoConsent) {
   endpoint_->set_consented(false);
   JavaScriptErrorReport report;
   report.message = "Hello World";
   report.url = "https://www.chromium.org/Home";
 
-  SendJavaScriptErrorReport(
+  processor_->SendErrorReport(
       std::move(report),
-      base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
+      base::BindOnce(&ChromeJsErrorReportProcessorTest::FinishCallback,
                      base::Unretained(this)),
       &browser_context_);
   run_loop_.Run();
@@ -160,15 +157,15 @@
   EXPECT_FALSE(endpoint_->last_report());
 }
 
-TEST_F(SendJavaScriptErrorReportTest, StackTraceWithErrorMessage) {
+TEST_F(ChromeJsErrorReportProcessorTest, StackTraceWithErrorMessage) {
   JavaScriptErrorReport report;
   report.message = "Hello World";
   report.url = "https://www.chromium.org/Home";
   report.stack_trace = "Hello World\nbad_func(1, 2)\nonclick()\n";
 
-  SendJavaScriptErrorReport(
+  processor_->SendErrorReport(
       std::move(report),
-      base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
+      base::BindOnce(&ChromeJsErrorReportProcessorTest::FinishCallback,
                      base::Unretained(this)),
       &browser_context_);
   run_loop_.Run();
@@ -181,7 +178,7 @@
   EXPECT_EQ(actual_report->content, "bad_func(1, 2)\nonclick()\n");
 }
 
-TEST_F(SendJavaScriptErrorReportTest, RedactMessage) {
+TEST_F(ChromeJsErrorReportProcessorTest, RedactMessage) {
   JavaScriptErrorReport report;
   report.message = "alpha@beta.org says hi to gamma@omega.co.uk";
   report.url = "https://www.chromium.org/Home";
@@ -189,9 +186,9 @@
       "alpha@beta.org says hi to gamma@omega.co.uk\n"
       "bad_func(1, 2)\nonclick()\n";
 
-  SendJavaScriptErrorReport(
+  processor_->SendErrorReport(
       std::move(report),
-      base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
+      base::BindOnce(&ChromeJsErrorReportProcessorTest::FinishCallback,
                      base::Unretained(this)),
       &browser_context_);
   run_loop_.Run();
@@ -207,26 +204,3 @@
   // Redacted messages still need to be removed from stack trace.
   EXPECT_EQ(actual_report->content, "bad_func(1, 2)\nonclick()\n");
 }
-
-TEST_F(SendJavaScriptErrorReportTest, NonGoogleChrome) {
-  JavaScriptErrorReport report;
-  report.message = "Hello World";
-  report.url = "https://www.chromium.org/Home";
-  // We use a blank URL in non-GOOGLE_CHROME_BUILDs to avoid uploading reports
-  // from those browsers.
-  SetCrashEndpointForTesting("");
-
-  SendJavaScriptErrorReport(
-      std::move(report),
-      base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
-                     base::Unretained(this)),
-      &browser_context_);
-  run_loop_.Run();
-  EXPECT_TRUE(finish_callback_was_called_);
-
-  const base::Optional<MockCrashEndpoint::Report>& actual_report =
-      endpoint_->last_report();
-  EXPECT_FALSE(actual_report);
-}
-
-#endif  // !defined(OS_WIN)
diff --git a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc
new file mode 100644
index 0000000..051ffb3f
--- /dev/null
+++ b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc
@@ -0,0 +1,55 @@
+// Copyright 2020 The Chromium 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/error_reporting/mock_chrome_js_error_report_processor.h"
+
+#include "base/check.h"
+#include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h"
+
+MockChromeJsErrorReportProcessor::MockChromeJsErrorReportProcessor() = default;
+MockChromeJsErrorReportProcessor::~MockChromeJsErrorReportProcessor() = default;
+
+void MockChromeJsErrorReportProcessor::SetAsDefault() {
+  JsErrorReportProcessor::SetDefault(this);
+}
+
+// static
+void MockChromeJsErrorReportProcessor::SetDefaultTo(
+    scoped_refptr<JsErrorReportProcessor> new_default) {
+  JsErrorReportProcessor::SetDefault(new_default);
+}
+
+void MockChromeJsErrorReportProcessor::SetCrashEndpoint(
+    std::string crash_endpoint) {
+  crash_endpoint_ = crash_endpoint;
+}
+
+std::string MockChromeJsErrorReportProcessor::GetCrashEndpoint() {
+  return crash_endpoint_;
+}
+
+void MockChromeJsErrorReportProcessor::GetOsVersion(
+    int32_t& os_major_version,
+    int32_t& os_minor_version,
+    int32_t& os_bugfix_version) {
+  os_major_version = 7;
+  os_minor_version = 20;
+  os_bugfix_version = 1;
+}
+
+ScopedMockChromeJsErrorReportProcessor::ScopedMockChromeJsErrorReportProcessor(
+    const MockCrashEndpoint& endpoint)
+    : processor_(base::MakeRefCounted<MockChromeJsErrorReportProcessor>()),
+      previous_(JsErrorReportProcessor::Get()) {
+  processor_->SetCrashEndpoint(endpoint.GetCrashEndpointURL());
+  processor_->SetAsDefault();
+}
+
+ScopedMockChromeJsErrorReportProcessor::
+    ~ScopedMockChromeJsErrorReportProcessor() {
+  DCHECK(processor_ == JsErrorReportProcessor::Get())
+      << "processor_ is no longer the default processor.";
+
+  MockChromeJsErrorReportProcessor::SetDefaultTo(previous_);
+}
diff --git a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h
new file mode 100644
index 0000000..230f91d0
--- /dev/null
+++ b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h
@@ -0,0 +1,67 @@
+// Copyright 2020 The Chromium 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_ERROR_REPORTING_MOCK_CHROME_JS_ERROR_REPORT_PROCESSOR_H_
+#define CHROME_BROWSER_ERROR_REPORTING_MOCK_CHROME_JS_ERROR_REPORT_PROCESSOR_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/memory/scoped_refptr.h"
+#include "chrome/browser/error_reporting/chrome_js_error_report_processor.h"
+
+class MockCrashEndpoint;
+
+class MockChromeJsErrorReportProcessor : public ChromeJsErrorReportProcessor {
+ public:
+  MockChromeJsErrorReportProcessor();
+
+  // Controls what is returned from GetCrashEndpoint() override.
+  void SetCrashEndpoint(std::string crash_endpoint);
+
+  // Allow tests to manipulate the result of JsErrorReportProcessor::Get().
+  // Calling this will cause JsErrorReportProcessor::Get() to return this
+  // object....
+  void SetAsDefault();
+  // ...and calling SetDefaultTo() will cause JsErrorReportProcessor::Get() to
+  // return the given (other) JsErrorReportProcessor.
+  static void SetDefaultTo(scoped_refptr<JsErrorReportProcessor> new_default);
+
+ protected:
+  std::string GetCrashEndpoint() override;
+
+  // Always returns 7.20.1 (arbitrary).
+  void GetOsVersion(int32_t& os_major_version,
+                    int32_t& os_minor_version,
+                    int32_t& os_bugfix_version) override;
+
+ private:
+  ~MockChromeJsErrorReportProcessor() override;
+  std::string crash_endpoint_;
+};
+
+// Wrapper for MockChromeJsErrorReportProcessor. Will automatically create, set
+// up, and register a MockChromeJsErrorReportProcessor in the constructor and
+// then unregister it in the destructor.
+class ScopedMockChromeJsErrorReportProcessor {
+ public:
+  // Creates a MockChromeJsErrorReportProcessor, sets its crash endpoint to
+  // the provided MockCrashEndpoint, and then registers the
+  // MockChromeJsErrorReportProcessor as the processor returned from
+  // JsErrorReportProcessor::Get().
+  explicit ScopedMockChromeJsErrorReportProcessor(
+      const MockCrashEndpoint& endpoint);
+
+  // Removes the MockChromeJsErrorReportProcessor created in the constructor
+  // from JsErrorReportProcessor::Get(). After this,
+  // JsErrorReportProcessor::Get() will return nullptr.
+  ~ScopedMockChromeJsErrorReportProcessor();
+
+ private:
+  scoped_refptr<MockChromeJsErrorReportProcessor> processor_;
+  scoped_refptr<JsErrorReportProcessor> previous_;
+};
+
+#endif  // CHROME_BROWSER_ERROR_REPORTING_MOCK_CHROME_JS_ERROR_REPORT_PROCESSOR_H_
diff --git a/chrome/browser/extensions/api/context_menus/context_menus_api.cc b/chrome/browser/extensions/api/context_menus/context_menus_api.cc
index 44c82334e..42ced3e 100644
--- a/chrome/browser/extensions/api/context_menus/context_menus_api.cc
+++ b/chrome/browser/extensions/api/context_menus/context_menus_api.cc
@@ -39,7 +39,7 @@
   if (params->create_properties.id.get()) {
     id.string_uid = *params->create_properties.id;
   } else {
-    if (context_menus_api_helpers::HasLazyContext(extension()))
+    if (BackgroundInfo::HasLazyContext(extension()))
       return RespondNow(Error(kIdRequiredError));
 
     // The Generated Id is added by context_menus_custom_bindings.js.
diff --git a/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.cc b/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.cc
index 8710a97c..f7bcc22 100644
--- a/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.cc
+++ b/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.cc
@@ -127,10 +127,5 @@
   return extensions::MenuItem::NORMAL;
 }
 
-bool HasLazyContext(const Extension* extension) {
-  return BackgroundInfo::HasLazyBackgroundPage(extension) ||
-         BackgroundInfo::IsServiceWorkerBased(extension);
-}
-
 }  // namespace context_menus_api_helpers
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h b/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h
index b45a66a..ccc352794 100644
--- a/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h
+++ b/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h
@@ -61,8 +61,6 @@
 MenuItem::Type GetType(extensions::api::context_menus::ItemType type,
                        MenuItem::Type default_type);
 
-bool HasLazyContext(const Extension* extension);
-
 // Creates and adds a menu item from |create_properties|.
 template <typename PropertyWithEnumT>
 bool CreateMenuItem(const PropertyWithEnumT& create_properties,
@@ -79,7 +77,7 @@
     return false;
   }
 
-  if (!is_webview && HasLazyContext(extension) &&
+  if (!is_webview && BackgroundInfo::HasLazyContext(extension) &&
       create_properties.onclick.get()) {
     *error = kOnclickDisallowedError;
     return false;
diff --git a/chrome/browser/extensions/api/crash_report_private/crash_report_private_api.cc b/chrome/browser/extensions/api/crash_report_private/crash_report_private_api.cc
index 4f5386d..0ce30cf 100644
--- a/chrome/browser/extensions/api/crash_report_private/crash_report_private_api.cc
+++ b/chrome/browser/extensions/api/crash_report_private/crash_report_private_api.cc
@@ -7,7 +7,7 @@
 #include "base/time/default_clock.h"
 #include "chrome/browser/browser_process.h"
 #include "components/crash/content/browser/error_reporting/javascript_error_report.h"
-#include "components/crash/content/browser/error_reporting/send_javascript_error_report.h"
+#include "components/crash/content/browser/error_reporting/js_error_report_processor.h"
 #include "content/public/browser/devtools_agent_host.h"
 
 namespace extensions {
@@ -50,6 +50,12 @@
   const auto params = crash_report_private::ReportError::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
+  auto processor = JsErrorReportProcessor::Get();
+  if (!processor) {
+    VLOG(3) << "No processor for error report";
+    return RespondNow(Error("No processor for error report"));
+  }
+
   JavaScriptErrorReport error_report;
   error_report.message = std::move(params->info.message);
   error_report.url = std::move(params->info.url);
@@ -75,7 +81,7 @@
 
   error_report.app_locale = g_browser_process->GetApplicationLocale();
 
-  SendJavaScriptErrorReport(
+  processor->SendErrorReport(
       std::move(error_report),
       base::BindOnce(&CrashReportPrivateReportErrorFunction::OnReportComplete,
                      this),
diff --git a/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc b/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
index 6d1c30f..d55ee84f 100644
--- a/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
+++ b/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
@@ -5,6 +5,7 @@
 #include "base/system/sys_info.h"
 #include "base/test/simple_test_clock.h"
 #include "chrome/browser/devtools/devtools_window_testing.h"
+#include "chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h"
 #include "chrome/browser/extensions/api/crash_report_private/crash_report_private_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h"
@@ -25,16 +26,6 @@
 
 constexpr const char* kTestExtensionId = "jjeoclcdfjddkdjokiejckgcildcflpp";
 
-std::string GetOsVersion() {
-  int32_t os_major_version = 0;
-  int32_t os_minor_version = 0;
-  int32_t os_bugfix_version = 0;
-  base::SysInfo::OperatingSystemVersionNumbers(
-      &os_major_version, &os_minor_version, &os_bugfix_version);
-  return base::StringPrintf("%d.%d.%d", os_major_version, os_minor_version,
-                            os_bugfix_version);
-}
-
 }  // namespace
 
 class CrashReportPrivateApiTest : public ExtensionApiTest {
@@ -71,6 +62,8 @@
 
     crash_endpoint_ =
         std::make_unique<MockCrashEndpoint>(embedded_test_server());
+    processor_ = std::make_unique<ScopedMockChromeJsErrorReportProcessor>(
+        *crash_endpoint_);
   }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -85,6 +78,7 @@
   }
   const Extension* extension_;
   std::unique_ptr<MockCrashEndpoint> crash_endpoint_;
+  std::unique_ptr<ScopedMockChromeJsErrorReportProcessor> processor_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(CrashReportPrivateApiTest);
@@ -108,8 +102,7 @@
                    "\\d+&browser_"
                    "version=1.2.3.4&channel=Stable&"
                    "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2F&"
-                   "os=ChromeOS&os_version=" +
-                   GetOsVersion() +
+                   "os=ChromeOS&os_version=7.20.1"
                    "&prod=Chrome_ChromeOS&src=http%3A%2F%2Fwww.test."
                    "com%2F&type=JavascriptError&url=%2F&ver=1.2.3.4"));
   EXPECT_EQ(report->content, "");
@@ -140,8 +133,7 @@
                    "\\d+&browser_"
                    "version=1.2.3.4&channel=Stable&column=456&"
                    "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2Ffoo"
-                   "&line=123&os=ChromeOS&os_version=" +
-                   GetOsVersion() +
+                   "&line=123&os=ChromeOS&os_version=7.20.1"
                    "&prod=Chrome%2520\\(Chrome%2520OS\\)&"
                    "src=http%3A%2F%2Fwww.test.com%2Ffoo&"
                    "type=JavascriptError&url=%2Ffoo&ver=1.0.0.0"));
@@ -171,8 +163,7 @@
                    "\\d+&browser_version=1.2."
                    "3.4&channel=Stable&column=456&"
                    "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2Ffoo&"
-                   "line=123&os=ChromeOS&os_version=" +
-                   GetOsVersion() +
+                   "line=123&os=ChromeOS&os_version=7.20.1"
                    "&prod=TestApp&src=http%3A%2F%2Fwww.test.com%2Ffoo&type="
                    "JavascriptError&url=%2Ffoo&ver=1.0.0.0"));
   EXPECT_EQ(report->content, "");
@@ -204,8 +195,7 @@
           "3.4&channel=Stable&column=456&"
           "error_message=%5BMAC%20OUI%3D06%3A00%3A00%20IFACE%3D1%5D&"
           "full_url=http%3A%2F%2Fwww.test.com%2Ffoo&line=123&os=ChromeOS&"
-          "os_version=" +
-          GetOsVersion() +
+          "os_version=7.20.1"
           "&prod=TestApp&src=http%3A%2F%2Fwww.test.com%2Ffoo&type="
           "JavascriptError&url=%2Ffoo&ver=1.0.0.0"));
   EXPECT_EQ(report->content, "");
diff --git a/chrome/browser/extensions/extension_context_menu_browsertest.cc b/chrome/browser/extensions/extension_context_menu_browsertest.cc
index ea1605f..e863cc1 100644
--- a/chrome/browser/extensions/extension_context_menu_browsertest.cc
+++ b/chrome/browser/extensions/extension_context_menu_browsertest.cc
@@ -5,12 +5,15 @@
 #include <stddef.h>
 
 #include <memory>
+#include <set>
 
 #include "base/bind.h"
+#include "base/run_loop.h"
 #include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "chrome/browser/extensions/browsertest_util.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/lazy_background_page_test_util.h"
 #include "chrome/browser/profiles/profile.h"
@@ -28,11 +31,13 @@
 #include "extensions/browser/extension_api_frame_id_map.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/process_manager.h"
+#include "extensions/browser/state_store.h"
 #include "extensions/browser/test_management_policy.h"
 #include "extensions/common/extension_set.h"
 #include "extensions/common/features/feature_channel.h"
 #include "extensions/common/scoped_worker_based_extensions_channel.h"
 #include "extensions/test/extension_test_message_listener.h"
+#include "extensions/test/result_catcher.h"
 #include "net/dns/mock_host_resolver.h"
 #include "ui/base/models/menu_model.h"
 
@@ -40,8 +45,107 @@
 using extensions::ContextMenuMatcher;
 using ContextType = extensions::ExtensionBrowserTest::ContextType;
 using extensions::MenuItem;
+using extensions::ResultCatcher;
 using ui::MenuModel;
 
+namespace {
+
+using extensions::MenuManager;
+using extensions::StateStore;
+
+// Observe when an extension's context menu data is written to the state store.
+class StateStoreObserver : public StateStore::TestObserver {
+ public:
+  explicit StateStoreObserver(content::BrowserContext* context)
+      : state_store_(extensions::ExtensionSystem::Get(context)->state_store()) {
+    observed_.Add(state_store_);
+  }
+
+  ~StateStoreObserver() final = default;
+
+  void WaitForExtension(const std::string& extension_id) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    if (ids_with_writes_.count(extension_id) == 0) {
+      waiting_for_id_ = extension_id;
+    } else {
+      state_store_->FlushForTesting(run_loop_.QuitWhenIdleClosure());
+    }
+    run_loop_.Run();
+  }
+
+  void WillSetExtensionValue(const std::string& extension_id,
+                             const std::string& key) override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    if (key != "context_menus")
+      return;
+
+    if (extension_id == waiting_for_id_) {
+      state_store_->FlushForTesting(run_loop_.QuitWhenIdleClosure());
+    } else {
+      ids_with_writes_.insert(extension_id);
+    }
+  }
+
+ private:
+  StateStore* const state_store_;
+  std::set<std::string> ids_with_writes_;
+  std::string waiting_for_id_;
+  base::RunLoop run_loop_;
+  ScopedObserver<StateStore, StateStore::TestObserver> observed_{this};
+};
+
+// Observe when a extension's context menu data is read from storage.
+class MenuManagerObserver : public MenuManager::TestObserver {
+ public:
+  explicit MenuManagerObserver(MenuManager* menu_manager)
+      : menu_manager_(menu_manager) {
+    observed_.Add(menu_manager_);
+  }
+
+  ~MenuManagerObserver() final = default;
+
+  void WaitForExtension(const std::string& extension_id) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    // The extension's menus may have already been loaded before we were
+    // able to observe it.
+    if (MenusItemsFound(extension_id))
+      return;
+
+    if (ids_with_reads_.count(extension_id) == 0) {
+      waiting_for_id_ = extension_id;
+      run_loop_.Run();
+      DCHECK(MenusItemsFound(extension_id));
+    }
+  }
+
+  void DidReadFromStorage(const std::string& extension_id) override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    if (extension_id == waiting_for_id_) {
+      run_loop_.Quit();
+    } else {
+      ids_with_reads_.insert(extension_id);
+    }
+  }
+
+ private:
+  bool MenusItemsFound(const std::string& extension_id) {
+    const extensions::MenuItem::ExtensionKey key(extension_id);
+    return menu_manager_->MenuItems(key) &&
+           !menu_manager_->MenuItems(key)->empty();
+  }
+
+  MenuManager* const menu_manager_;
+  std::set<std::string> ids_with_reads_;
+  std::string waiting_for_id_;
+  base::RunLoop run_loop_;
+  ScopedObserver<MenuManager, MenuManager::TestObserver> observed_{this};
+};
+
+constexpr char kPersistentExtensionId[] = "cmgkkmeeoiceijkpmaabbmpgnkpaaela";
+
+}  // namespace
+
 class ExtensionContextMenuBrowserTest
     : public extensions::ExtensionBrowserTest {
  public:
@@ -192,6 +296,10 @@
     ASSERT_TRUE(FindCommandId(menu, id, &command_id));
     EXPECT_EQ(should_be_checked, menu->IsCommandIdChecked(command_id));
   }
+
+  base::FilePath GetRootDir() const {
+    return test_data_dir_.AppendASCII("context_menus");
+  }
 };
 
 class ExtensionContextMenuLazyTest
@@ -220,13 +328,13 @@
       int flags) {
     if (GetParam() == ContextType::kServiceWorker)
       flags |= kFlagRunAsServiceWorkerBasedExtension;
+
     return LoadExtensionWithFlags(path, flags);
   }
 
   const extensions::Extension* LoadContextMenuExtension(
       base::StringPiece subdirectory) {
-    base::FilePath extension_dir =
-        test_data_dir_.AppendASCII("context_menus").AppendASCII(subdirectory);
+    base::FilePath extension_dir = GetRootDir().AppendASCII(subdirectory);
     return LoadExtensionWithParamFlags(extension_dir, kFlagEnableFileAccess);
   }
 
@@ -234,20 +342,25 @@
   // the extensions test data dir.
   const extensions::Extension* LoadTopLevelContextMenuExtension(
       base::StringPiece subdirectory) {
-    base::FilePath extension_dir = test_data_dir_.AppendASCII("context_menus")
-                                       .AppendASCII("top_level")
-                                       .AppendASCII(subdirectory);
+    base::FilePath extension_dir =
+        GetRootDir().AppendASCII("top_level").AppendASCII(subdirectory);
     return LoadExtensionWithParamFlags(extension_dir, kFlagEnableFileAccess);
   }
 
   const extensions::Extension* LoadContextMenuExtensionWithIncognitoFlags(
       base::StringPiece subdirectory) {
-    base::FilePath extension_dir =
-        test_data_dir_.AppendASCII("context_menus").AppendASCII(subdirectory);
+    base::FilePath extension_dir = GetRootDir().AppendASCII(subdirectory);
     return LoadExtensionWithParamFlags(
         extension_dir, kFlagEnableFileAccess | kFlagEnableIncognito);
   }
 
+  base::FilePath GetDirForContext(base::StringPiece subdirectory) {
+    const char* context_dir = GetParam() == ContextType::kServiceWorker
+                                  ? "service_worker"
+                                  : "event_page";
+    return GetRootDir().AppendASCII(subdirectory).AppendASCII(context_dir);
+  }
+
   // This creates an extension that starts |enabled| and then switches to
   // |!enabled|.
   void TestEnabledContextMenu(bool enabled) {
@@ -295,8 +408,7 @@
   // extensions test data dir.
   const extensions::Extension* LoadContextMenuExtension(
       base::StringPiece subdirectory) {
-    base::FilePath extension_dir =
-        test_data_dir_.AppendASCII("context_menus").AppendASCII(subdirectory);
+    base::FilePath extension_dir = GetRootDir().AppendASCII(subdirectory);
     return LoadExtension(extension_dir);
   }
 };
@@ -326,6 +438,38 @@
   ASSERT_TRUE(listener2.WaitUntilSatisfied());
 }
 
+// Tests that context menus for event page and Service Worker-based
+// extensions are stored properly.
+IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, PRE_Persistent) {
+  StateStoreObserver observer(profile());
+  ResultCatcher catcher;
+  base::FilePath path =
+      GetDirForContext("persistent").AddExtensionASCII(".crx");
+  const extensions::Extension* extension =
+      LoadExtensionWithFlags(path, kFlagNone);
+  ASSERT_TRUE(extension);
+
+  // Wait for the extension to tell us it's been installed and the
+  // context menu has been created.
+  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
+
+  // Wait for the context menu to be stored.
+  observer.WaitForExtension(extension->id());
+}
+
+IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, Persistent) {
+  MenuManagerObserver observer(menu_manager());
+  ResultCatcher catcher;
+
+  // Wait for the context menu to finish loading.
+  observer.WaitForExtension(kPersistentExtensionId);
+
+  // Open a tab to trigger the update.
+  ASSERT_TRUE(
+      extensions::browsertest_util::AddTab(browser(), GURL("chrome:version")));
+  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
 // Tests that previous onclick is not fired after updating the menu's onclick,
 // and whether setting onclick to null removes the handler.
 IN_PROC_BROWSER_TEST_F(ExtensionContextMenuPersistentTest, UpdateOnclick) {
diff --git a/chrome/browser/extensions/menu_manager.cc b/chrome/browser/extensions/menu_manager.cc
index 497b0dc..b1619d61 100644
--- a/chrome/browser/extensions/menu_manager.cc
+++ b/chrome/browser/extensions/menu_manager.cc
@@ -807,7 +807,7 @@
 
 void MenuManager::WriteToStorage(const Extension* extension,
                                  const MenuItem::ExtensionKey& extension_key) {
-  if (!BackgroundInfo::HasLazyBackgroundPage(extension))
+  if (!BackgroundInfo::HasLazyContext(extension))
     return;
   // <webview> menu items are transient and not stored in storage.
   if (extension_key.webview_instance_id)
@@ -849,11 +849,14 @@
       AddContextItem(extension, std::move(items[i]));
     }
   }
+
+  for (TestObserver& observer : observers_)
+    observer.DidReadFromStorage(extension_id);
 }
 
 void MenuManager::OnExtensionLoaded(content::BrowserContext* browser_context,
                                     const Extension* extension) {
-  if (store_ && BackgroundInfo::HasLazyBackgroundPage(extension)) {
+  if (store_ && BackgroundInfo::HasLazyContext(extension)) {
     store_->GetExtensionValue(extension->id(), kContextMenusKey,
                               base::BindOnce(&MenuManager::ReadFromStorage,
                                              AsWeakPtr(), extension->id()));
@@ -900,6 +903,14 @@
     RemoveContextMenuItem(*remove_iter);
 }
 
+void MenuManager::AddObserver(TestObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void MenuManager::RemoveObserver(TestObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 MenuItem::ExtensionKey::ExtensionKey()
     : webview_embedder_process_id(ChildProcessHost::kInvalidUniqueID),
       webview_instance_id(kInstanceIDNone) {}
diff --git a/chrome/browser/extensions/menu_manager.h b/chrome/browser/extensions/menu_manager.h
index 12827e2c..bdb0c06d 100644
--- a/chrome/browser/extensions/menu_manager.h
+++ b/chrome/browser/extensions/menu_manager.h
@@ -18,6 +18,8 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "base/scoped_observer.h"
 #include "base/strings/string16.h"
 #include "base/values.h"
@@ -291,6 +293,12 @@
   static const char kOnContextMenus[];
   static const char kOnWebviewContextMenus[];
 
+  class TestObserver : public base::CheckedObserver {
+   public:
+    ~TestObserver() override = default;
+    virtual void DidReadFromStorage(const std::string& extension_id) = 0;
+  };
+
   MenuManager(content::BrowserContext* context, StateStore* store_);
   ~MenuManager() override;
 
@@ -379,6 +387,9 @@
   // Removes all "incognito" "split" mode context items.
   void RemoveAllIncognitoContextItems();
 
+  void AddObserver(TestObserver* observer);
+  void RemoveObserver(TestObserver* observer);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(MenuManagerTest, DeleteParent);
   FRIEND_TEST_ALL_PREFIXES(MenuManagerTest, RemoveOneByOne);
@@ -417,6 +428,8 @@
   // Owned by ExtensionSystem.
   StateStore* store_;
 
+  base::ObserverList<TestObserver> observers_;
+
   DISALLOW_COPY_AND_ASSIGN(MenuManager);
 };
 
diff --git a/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc b/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc
index b67814f..6705cf7 100644
--- a/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc
@@ -52,8 +52,14 @@
   base::RunLoop loop_;
 };
 
+// Flaky on Mac: https://crbug.com/1143762:
+#if defined(OS_MAC)
+#define MAYBE_AutoCloseTabOnNonWebProtocolNavigation DISABLED_AutoCloseTabOnNonWebProtocolNavigation
+#else
+#define MAYBE_AutoCloseTabOnNonWebProtocolNavigation AutoCloseTabOnNonWebProtocolNavigation
+#endif
 IN_PROC_BROWSER_TEST_F(ExternalProtocolHandlerBrowserTest,
-                       AutoCloseTabOnNonWebProtocolNavigation) {
+                       MAYBE_AutoCloseTabOnNonWebProtocolNavigation) {
 #if defined(OS_WIN)
   // On Win 7 the protocol is registered to be handled by Chrome and thus never
   // reaches the ExternalProtocolHandler so we skip the test. For
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 7a86afd..efda45a 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2365,7 +2365,7 @@
   {
     "name": "enable-webrtc-hide-local-ips-with-mdns",
     "owners": [ "qingsi" ],
-    "expiry_milestone": 85
+    "expiry_milestone": 90 
   },
   {
     "name": "enable-webrtc-hybrid-agc",
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index fb73178f..0d5d345 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -27,6 +27,7 @@
 #include "components/download/public/common/download_features.h"
 #include "components/feature_engagement/public/feature_list.h"
 #include "components/feed/feed_feature_list.h"
+#include "components/history/core/browser/features.h"
 #include "components/invalidation/impl/invalidation_switches.h"
 #include "components/language/core/common/language_experiments.h"
 #include "components/messages/android/messages_feature.h"
@@ -105,6 +106,7 @@
     &feed::kInterestFeedContentSuggestions,
     &feed::kInterestFeedV2,
     &feed::kReportFeedUserActions,
+    &history::kHideFromApi3Transitions,
     &kAdjustWebApkInstallationSpace,
     &kAllowNewIncognitoTabIntents,
     &kAllowRemoteContextForNotifications,
@@ -653,9 +655,6 @@
 const base::Feature kUsageStatsFeature{"UsageStats",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kUserMediaScreenCapturing{
-    "UserMediaScreenCapturing", base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kVrBrowsingFeedback{"VrBrowsingFeedback",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 7bd5bf4..b4daf76 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -30,6 +30,7 @@
 extern const base::Feature kCCTBackgroundTab;
 extern const base::Feature kCCTClientDataHeader;
 extern const base::Feature kCCTExternalLinkHandling;
+extern const base::Feature kCCTHideVisits;
 extern const base::Feature kCCTIncognito;
 extern const base::Feature kCCTPostMessageAPI;
 extern const base::Feature kCCTRedirectPreconnect;
@@ -132,7 +133,6 @@
 extern const base::Feature
     kUpdateNotificationScheduleServiceImmediateShowOption;
 extern const base::Feature kUsageStatsFeature;
-extern const base::Feature kUserMediaScreenCapturing;
 extern const base::Feature kVrBrowsingFeedback;
 extern const base::Feature kWebApkAdaptiveIcon;
 extern const base::Feature kPrefetchNotificationSchedulingIntegration;
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 5c3ae14..f985dd3f 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -297,6 +297,8 @@
             "FocusOmniboxInIncognitoTabIntents";
     public static final String GRANT_NOTIFICATIONS_TO_DSE = "GrantNotificationsToDSE";
     public static final String HANDLE_MEDIA_INTENTS = "HandleMediaIntents";
+    public static final String HIDE_FROM_API_3_TRANSITIONS_FROM_HISTORY =
+            "HideFromApi3TransitionsFromHistory";
     public static final String HOMEPAGE_PROMO_CARD = "HomepagePromoCard";
     public static final String HOMEPAGE_PROMO_SYNTHETIC_PROMO_SEEN_ENABLED =
             "HomepagePromoSyntheticPromoSeenEnabled";
diff --git a/chrome/browser/history/history_browsertest.cc b/chrome/browser/history/history_browsertest.cc
index 34649c7..c7faf85 100644
--- a/chrome/browser/history/history_browsertest.cc
+++ b/chrome/browser/history/history_browsertest.cc
@@ -15,6 +15,7 @@
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/history/history_tab_helper.h"
 #include "chrome/browser/history/history_test_utils.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
@@ -117,6 +118,12 @@
     return query_url_result;
   }
 
+  void NavigateToUrlAsTypeLink(const GURL& url) {
+    NavigateParams params(browser(), url,
+                          ui::PageTransition::PAGE_TRANSITION_LINK);
+    ui_test_utils::NavigateToURL(&params);
+  }
+
  private:
   // Callback for HistoryService::QueryURL.
   void SaveResultAndQuit(bool* success_out,
@@ -206,6 +213,87 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SetHideAllNavigations) {
+  ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
+      browser()->profile(), ServiceAccessType::EXPLICIT_ACCESS));
+  ExpectEmptyHistory();
+
+  HistoryTabHelper::FromWebContents(
+      browser()->tab_strip_model()->GetActiveWebContents())
+      ->set_hide_all_navigations(true);
+  NavigateToUrlAsTypeLink(GetTestUrl());
+  WaitForHistoryBackendToRun(GetProfile());
+
+  {
+    auto result = QueryURL(GetTestUrl());
+    ASSERT_TRUE(result.success);
+    EXPECT_TRUE(result.row.hidden());
+    EXPECT_EQ(0, result.row.typed_count());
+    EXPECT_EQ(1, result.row.visit_count());
+    ASSERT_EQ(1u, result.visits.size());
+    EXPECT_FALSE(result.visits[0].incremented_omnibox_typed_score);
+  }
+
+  GURL url2 = ui_test_utils::GetTestUrl(
+      base::FilePath(), base::FilePath(FILE_PATH_LITERAL("simple.html")));
+  NavigateToUrlAsTypeLink(url2);
+  WaitForHistoryBackendToRun(GetProfile());
+
+  {
+    auto result = QueryURL(url2);
+    ASSERT_TRUE(result.success);
+    EXPECT_TRUE(result.row.hidden());
+    EXPECT_EQ(0, result.row.typed_count());
+    EXPECT_EQ(1, result.row.visit_count());
+    ASSERT_EQ(1u, result.visits.size());
+    EXPECT_FALSE(result.visits[0].incremented_omnibox_typed_score);
+  }
+
+  HistoryTabHelper::FromWebContents(
+      browser()->tab_strip_model()->GetActiveWebContents())
+      ->set_hide_all_navigations(false);
+  NavigateToUrlAsTypeLink(GetTestUrl());
+  WaitForHistoryBackendToRun(GetProfile());
+
+  {
+    auto result = QueryURL(GetTestUrl());
+    ASSERT_TRUE(result.success);
+    EXPECT_FALSE(result.row.hidden());
+    EXPECT_EQ(2, result.row.visit_count());
+    ASSERT_EQ(2u, result.visits.size());
+    EXPECT_FALSE(result.visits[0].incremented_omnibox_typed_score);
+    EXPECT_FALSE(result.visits[1].incremented_omnibox_typed_score);
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(HistoryBrowserTest,
+                       SetHideAllNavigationsDoesntAddApi3ForTypedNavigation) {
+  ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
+      browser()->profile(), ServiceAccessType::EXPLICIT_ACCESS));
+  ExpectEmptyHistory();
+
+  HistoryTabHelper::FromWebContents(
+      browser()->tab_strip_model()->GetActiveWebContents())
+      ->set_hide_all_navigations(true);
+  // This navigates with a TYPED navigation.
+  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
+  WaitForHistoryBackendToRun(GetProfile());
+
+  {
+    auto result = QueryURL(GetTestUrl());
+    ASSERT_TRUE(result.success);
+    EXPECT_FALSE(result.row.hidden());
+    EXPECT_EQ(1, result.row.typed_count());
+    EXPECT_EQ(1, result.row.visit_count());
+    ASSERT_EQ(1u, result.visits.size());
+    EXPECT_TRUE(result.visits[0].incremented_omnibox_typed_score);
+    // As the transition was TYPED, set_hide_all_navigations() was ignored and
+    // PAGE_TRANSITION_FROM_API_3 should not be added.
+    EXPECT_TRUE((ui::PageTransitionGetQualifier(result.visits[0].transition) &
+                 ui::PAGE_TRANSITION_FROM_API_3) == 0);
+  }
+}
+
 // Test that changing the pref takes effect immediately
 // when the browser is running.
 IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryDisabledThenEnabled) {
diff --git a/chrome/browser/history/history_tab_helper.cc b/chrome/browser/history/history_tab_helper.cc
index 3ec3f17..f965817 100644
--- a/chrome/browser/history/history_tab_helper.cc
+++ b/chrome/browser/history/history_tab_helper.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/prerender/prerender_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/history/content/browser/history_context_helper.h"
+#include "components/history/core/browser/history_backend.h"
 #include "components/history/core/browser/history_constants.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/prerender/browser/prerender_manager.h"
@@ -57,13 +58,14 @@
     base::Time timestamp,
     int nav_entry_id,
     content::NavigationHandle* navigation_handle) {
+  ui::PageTransition page_transition = navigation_handle->GetPageTransition();
 #if defined(OS_ANDROID)
   // Clicks on content suggestions on the NTP should not contribute to the
   // Most Visited tiles in the NTP.
   const GURL& referrer_url = navigation_handle->GetReferrer().url;
   const bool content_suggestions_navigation =
       referrer_url == feed::GetFeedReferrerUrl() &&
-      ui::PageTransitionCoreTypeIs(navigation_handle->GetPageTransition(),
+      ui::PageTransitionCoreTypeIs(page_transition,
                                    ui::PAGE_TRANSITION_AUTO_BOOKMARK);
 #else
   const bool content_suggestions_navigation = false;
@@ -73,29 +75,41 @@
       navigation_handle->GetResponseHeaders() &&
       (navigation_handle->GetResponseHeaders()->response_code() >= 400) &&
       (navigation_handle->GetResponseHeaders()->response_code() < 600);
-  // Top-level frame navigations are visible; everything else is hidden.
-  // Also hide top-level navigations that result in an error in order to
-  // prevent the omnibox from suggesting URLs that have never been navigated
-  // to successfully.  (If a top-level navigation to the URL succeeds at some
-  // point, the URL will be unhidden and thus eligible to be suggested by the
-  // omnibox.)
-  const bool hidden =
-      !ui::PageTransitionIsMainFrame(navigation_handle->GetPageTransition()) ||
-      status_code_is_error;
+  // Top-level frame navigations are visible, unless hiding all visits;
+  // everything else is hidden. Also hide top-level navigations that result in
+  // an error in order to prevent the omnibox from suggesting URLs that have
+  // never been navigated to successfully.  (If a top-level navigation to the
+  // URL succeeds at some point, the URL will be unhidden and thus eligible to
+  // be suggested by the omnibox.)
+  // Don't attempt hide navigations that increment the typed count. Doing that
+  // would lead to a state where the omnibox would suggest urls that don't
+  // show up in history.
+  const bool hide_normally_visible_navigation =
+      hide_all_navigations_ && ui::PageTransitionIsMainFrame(page_transition) &&
+      !history::HistoryBackend::IsTypedIncrement(page_transition);
+  const bool hidden = hide_normally_visible_navigation ||
+                      !ui::PageTransitionIsMainFrame(page_transition) ||
+                      status_code_is_error;
+  if (hide_normally_visible_navigation) {
+    // Add PAGE_TRANSITION_FROM_API_3 so that VisitsDatabase won't return this
+    // visit in queries for visible visits.
+    page_transition = ui::PageTransitionFromInt(ui::PAGE_TRANSITION_FROM_API_3 |
+                                                page_transition);
+  }
   history::HistoryAddPageArgs add_page_args(
       navigation_handle->GetURL(), timestamp,
       history::ContextIDForWebContents(web_contents()), nav_entry_id,
       navigation_handle->GetReferrer().url,
-      navigation_handle->GetRedirectChain(),
-      navigation_handle->GetPageTransition(), hidden, history::SOURCE_BROWSED,
-      navigation_handle->DidReplaceEntry(), !content_suggestions_navigation,
+      navigation_handle->GetRedirectChain(), page_transition, hidden,
+      history::SOURCE_BROWSED, navigation_handle->DidReplaceEntry(),
+      !content_suggestions_navigation,
       navigation_handle->GetSocketAddress().address().IsPubliclyRoutable(),
       navigation_handle->IsSameDocument()
           ? base::Optional<base::string16>(
                 navigation_handle->GetWebContents()->GetTitle())
           : base::nullopt);
 
-  if (ui::PageTransitionIsMainFrame(navigation_handle->GetPageTransition()) &&
+  if (ui::PageTransitionIsMainFrame(page_transition) &&
       virtual_url != navigation_handle->GetURL()) {
     // Hack on the "virtual" URL so that it will appear in history. For some
     // types of URLs, we will display a magic URL that is different from where
diff --git a/chrome/browser/history/history_tab_helper.h b/chrome/browser/history/history_tab_helper.h
index 2c1a461..272cd24 100644
--- a/chrome/browser/history/history_tab_helper.h
+++ b/chrome/browser/history/history_tab_helper.h
@@ -21,6 +21,18 @@
  public:
   ~HistoryTabHelper() override;
 
+  // If true, visits that do not increment the typed count (see
+  // HistoryBackend::IsTypedIncrement()) are marked as hidden. More
+  // specifically, this does two things:
+  //
+  // . |HistoryAddPageArgs::hidden| supplied to HistoryService::AddPage() is set
+  //   to true.
+  // . The transition type PAGE_TRANSITION_FROM_API_3 is added.
+  //
+  // This results in the visit not directly influencing the omnibox and not
+  // being shown in history ui.
+  void set_hide_all_navigations(bool value) { hide_all_navigations_ = value; }
+
   // Updates history with the specified navigation. This is called by
   // DidFinishNavigation to update history state.
   void UpdateHistoryForNavigation(
@@ -63,6 +75,9 @@
   // history system. Only applies to the main frame of the page.
   base::TimeTicks last_load_completion_;
 
+  // See comment above setter for details.
+  bool hide_all_navigations_ = false;
+
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 
   DISALLOW_COPY_AND_ASSIGN(HistoryTabHelper);
diff --git a/chrome/browser/history/top_sites_factory.cc b/chrome/browser/history/top_sites_factory.cc
index 1cae360..95eab51d 100644
--- a/chrome/browser/history/top_sites_factory.cc
+++ b/chrome/browser/history/top_sites_factory.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/history_utils.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -32,6 +31,7 @@
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc b/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc
index da0b56d..bdfe4f4 100644
--- a/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc
+++ b/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc
@@ -34,10 +34,11 @@
 #include "extensions/buildflags/buildflags.h"
 #include "extensions/common/constants.h"
 #include "media/base/media_switches.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
 
-#if !defined(OS_ANDROID)
+#if defined(OS_ANDROID)
+#include "content/public/common/content_features.h"
+#else  // !OS_ANDROID
 #include "chrome/browser/media/webrtc/display_media_access_handler.h"
 #endif  //  defined(OS_ANDROID)
 
@@ -149,16 +150,18 @@
     const extensions::Extension* extension) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+#if defined(OS_ANDROID)
   // Kill switch for getDisplayMedia() on browser side to prevent renderer from
   // bypassing blink side checks.
   if (request.video_type ==
           blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE &&
-      !base::FeatureList::IsEnabled(blink::features::kRTCGetDisplayMedia)) {
+      !base::FeatureList::IsEnabled(features::kUserMediaScreenCapturing)) {
     std::move(callback).Run(
         blink::MediaStreamDevices(),
         blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED, nullptr);
     return;
   }
+#endif
 
   for (const auto& handler : media_access_handlers_) {
     if (handler->SupportsStreamType(web_contents, request.video_type,
diff --git a/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc b/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
index fe81c159..ac3b3f2 100644
--- a/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
+++ b/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
@@ -33,10 +33,10 @@
 #if defined(OS_ANDROID)
 #include <vector>
 
-#include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "chrome/browser/media/webrtc/screen_capture_infobar_delegate_android.h"
 #include "components/permissions/permission_uma_util.h"
 #include "components/permissions/permission_util.h"
+#include "content/public/common/content_features.h"
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_MAC)
@@ -194,8 +194,7 @@
 
 #if defined(OS_ANDROID)
   if (blink::IsScreenCaptureMediaType(request.video_type) &&
-      !base::FeatureList::IsEnabled(
-          chrome::android::kUserMediaScreenCapturing)) {
+      !base::FeatureList::IsEnabled(features::kUserMediaScreenCapturing)) {
     // If screen capturing isn't enabled on Android, we'll use "invalid state"
     // as result, same as on desktop.
     std::move(callback).Run(
diff --git a/chrome/browser/net/storage_test_utils.cc b/chrome/browser/net/storage_test_utils.cc
index d2a2681..26b585e 100644
--- a/chrome/browser/net/storage_test_utils.cc
+++ b/chrome/browser/net/storage_test_utils.cc
@@ -10,8 +10,9 @@
 namespace test {
 
 const std::vector<std::string> kStorageTypes{
-    "Cookie", "LocalStorage", "FileSystem",    "SessionStorage", "IndexedDb",
-    "WebSql", "CacheStorage", "ServiceWorker", "CookieStore"};
+    "Cookie",         "LocalStorage", "FileSystem", "FileSystemAccess",
+    "SessionStorage", "IndexedDb",    "WebSql",     "CacheStorage",
+    "ServiceWorker",  "CookieStore"};
 
 const std::vector<std::string> kCrossTabCommunicationTypes{
     "SharedWorker",
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ad_density_intervention_android_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ad_density_intervention_android_browsertest.cc
new file mode 100644
index 0000000..96f47f6f
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ad_density_intervention_android_browsertest.cc
@@ -0,0 +1,264 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h"
+#include "chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/test/base/chrome_test_utils.h"
+#include "components/infobars/core/infobar.h"
+#include "components/infobars/core/infobar_delegate.h"
+#include "components/infobars/core/infobar_manager.h"
+#include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
+#include "components/subresource_filter/core/common/common_features.h"
+#include "components/subresource_filter/core/common/test_ruleset_utils.h"
+#include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/widget/screen_info.h"
+#include "ui/gfx/geometry/rect.h"
+#include "url/gurl.h"
+
+namespace {
+
+const char kAdsInterventionRecordedHistogram[] =
+    "SubresourceFilter.PageLoad.AdsInterventionTriggered";
+
+// Gets the body height of the document embedded in |web_contents|.
+int GetDocumentHeight(content::WebContents* web_contents) {
+  return EvalJs(web_contents, "document.body.scrollHeight").ExtractInt();
+}
+
+// Scales the rect by the web content's render widget host's device scale
+// factor.
+gfx::Rect ScaleRectByDeviceScaleFactor(const gfx::Rect& rect,
+                                       content::WebContents* web_contents) {
+  blink::ScreenInfo screen_info;
+  web_contents->GetRenderWidgetHostView()->GetScreenInfo(&screen_info);
+  return gfx::ScaleToRoundedRect(rect, screen_info.device_scale_factor);
+}
+
+void CreateAndWaitForIframeAtRect(
+    content::WebContents* web_contents,
+    page_load_metrics::PageLoadMetricsTestWaiter* waiter,
+    net::EmbeddedTestServer* embedded_test_server,
+    const gfx::Rect& rect) {
+  // The intersections returned by the renderer are scaled to the device's
+  // scale factor.
+  gfx::Rect scaled_rect = ScaleRectByDeviceScaleFactor(rect, web_contents);
+
+  // The renderer propagates values scaled by the device scale factor.
+  // Wait on these values.
+  waiter->AddMainFrameIntersectionExpectation(scaled_rect);
+
+  // Create the frame with b.com as origin to not get caught by
+  // restricted ad tagging.
+  EXPECT_TRUE(ExecJs(
+      web_contents,
+      content::JsReplace(
+          "let frame = createAdIframeAtRect($1, $2, $3, $4); "
+          "frame.src = $5",
+          rect.x(), rect.y(), rect.width(), rect.height(),
+          embedded_test_server->GetURL("b.com", "/ads_observer/pixel.png")
+              .spec())));
+
+  waiter->Wait();
+}
+
+}  // namespace
+
+class AdDensityViolationBrowserTest
+    : public subresource_filter::SubresourceFilterBrowserTest {
+ public:
+  AdDensityViolationBrowserTest() = default;
+
+  void SetUp() override {
+    std::vector<base::Feature> enabled = {
+        subresource_filter::kAdTagging,
+        subresource_filter::kAdsInterventionsEnforced};
+    std::vector<base::Feature> disabled = {};
+
+    feature_list_.InitWithFeatures(enabled, disabled);
+    subresource_filter::SubresourceFilterBrowserTest::SetUp();
+  }
+
+  void SetUpOnMainThread() override {
+    SubresourceFilterBrowserTest::SetUpOnMainThread();
+    SetRulesetWithRules(
+        {subresource_filter::testing::CreateSuffixRule("ad_iframe_writer.js")});
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(
+    AdDensityViolationBrowserTest,
+    MobilePageAdDensityByHeightAbove30_AdInterventionTriggered) {
+  base::HistogramTester histogram_tester;
+  ukm::TestAutoSetUkmRecorder ukm_recorder;
+
+  content::WebContents* web_contents =
+      chrome_test_utils::GetActiveWebContents(this);
+  auto waiter = std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
+      web_contents);
+  const GURL url(embedded_test_server()->GetURL(
+      "a.com", "/ads_observer/blank_with_adiframe_writer.html"));
+
+  waiter->AddMainFrameIntersectionExpectation();
+  EXPECT_TRUE(content::NavigateToURL(web_contents, url));
+  waiter->Wait();
+
+  int document_height = GetDocumentHeight(web_contents);
+
+  int frame_width = 100;  // Ad density by height is independent of frame width.
+  int frame_height = document_height * 0.45;
+
+  CreateAndWaitForIframeAtRect(web_contents, waiter.get(),
+                               embedded_test_server(),
+                               gfx::Rect(0, 0, frame_width, frame_height));
+
+  // Delete the page load metrics test waiter instead of reinitializing it
+  // for the next page load.
+  waiter.reset();
+
+  EXPECT_TRUE(content::NavigateToURL(web_contents, url));
+
+  // blank_with_adiframe_writer loads a script tagged as an ad, verify it is not
+  // loaded and the subresource filter UI for ad blocking is shown.
+  EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
+  EXPECT_EQ(InfoBarService::FromWebContents(web_contents)->infobar_count(), 1u);
+  EXPECT_EQ(InfoBarService::FromWebContents(web_contents)
+                ->infobar_at(0)
+                ->delegate()
+                ->GetIdentifier(),
+            infobars::InfoBarDelegate::ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID);
+  histogram_tester.ExpectBucketCount(
+      kAdsInterventionRecordedHistogram,
+      static_cast<int>(subresource_filter::mojom::AdsViolation::
+                           kMobileAdDensityByHeightAbove30),
+      1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    AdDensityViolationBrowserTest,
+    MobilePageAdDensityByHeightBelow30_AdInterventionNotTriggered) {
+  base::HistogramTester histogram_tester;
+  ukm::TestAutoSetUkmRecorder ukm_recorder;
+
+  content::WebContents* web_contents =
+      chrome_test_utils::GetActiveWebContents(this);
+  auto waiter = std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
+      web_contents);
+  const GURL url(embedded_test_server()->GetURL(
+      "a.com", "/ads_observer/blank_with_adiframe_writer.html"));
+
+  waiter->AddMainFrameIntersectionExpectation();
+  EXPECT_TRUE(content::NavigateToURL(web_contents, url));
+  waiter->Wait();
+
+  int document_height = GetDocumentHeight(web_contents);
+
+  int frame_width = 100;  // Ad density by height is independent of frame width.
+  int frame_height = document_height * 0.25;
+
+  CreateAndWaitForIframeAtRect(web_contents, waiter.get(),
+                               embedded_test_server(),
+                               gfx::Rect(0, 0, frame_width, frame_height));
+
+  // Delete the page load metrics test waiter instead of reinitializing it
+  // for the next page load.
+  waiter.reset();
+
+  EXPECT_TRUE(content::NavigateToURL(web_contents, url));
+
+  // blank_with_adiframe_writer loads a script tagged as an ad, verify it is
+  // loaded as ads are not blocked and the subresource filter UI is not
+  // shown.
+  EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
+
+  // No ads blocked infobar should be shown as we have not triggered the
+  // intervention.
+  EXPECT_EQ(InfoBarService::FromWebContents(web_contents)->infobar_count(), 0u);
+  histogram_tester.ExpectTotalCount(kAdsInterventionRecordedHistogram, 0);
+}
+
+class AdDensityViolationBrowserTestWithoutEnforcement
+    : public subresource_filter::SubresourceFilterBrowserTest {
+ public:
+  AdDensityViolationBrowserTestWithoutEnforcement() = default;
+
+  void SetUp() override {
+    std::vector<base::Feature> enabled = {subresource_filter::kAdTagging};
+    std::vector<base::Feature> disabled = {
+        subresource_filter::kAdsInterventionsEnforced};
+
+    feature_list_.InitWithFeatures(enabled, disabled);
+    subresource_filter::SubresourceFilterBrowserTest::SetUp();
+  }
+
+  void SetUpOnMainThread() override {
+    SubresourceFilterBrowserTest::SetUpOnMainThread();
+    SetRulesetWithRules(
+        {subresource_filter::testing::CreateSuffixRule("ad_iframe_writer.js")});
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(
+    AdDensityViolationBrowserTestWithoutEnforcement,
+    MobilePageAdDensityByHeightAbove30_NoAdInterventionTriggered) {
+  base::HistogramTester histogram_tester;
+  ukm::TestAutoSetUkmRecorder ukm_recorder;
+
+  content::WebContents* web_contents =
+      chrome_test_utils::GetActiveWebContents(this);
+  auto waiter = std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
+      web_contents);
+  const GURL url(embedded_test_server()->GetURL(
+      "a.com", "/ads_observer/blank_with_adiframe_writer.html"));
+
+  waiter->AddMainFrameIntersectionExpectation();
+  EXPECT_TRUE(content::NavigateToURL(web_contents, url));
+  waiter->Wait();
+
+  int document_height = GetDocumentHeight(web_contents);
+
+  int frame_width = 100;  // Ad density by height is independent of frame width.
+  int frame_height = document_height * 0.45;
+
+  CreateAndWaitForIframeAtRect(web_contents, waiter.get(),
+                               embedded_test_server(),
+                               gfx::Rect(0, 0, frame_width, frame_height));
+
+  // Delete the page load metrics test waiter instead of reinitializing it
+  // for the next page load.
+  waiter.reset();
+
+  EXPECT_TRUE(content::NavigateToURL(web_contents, url));
+
+  // We are not enforcing ad blocking on ads violations, site should load
+  // as expected without subresource filter UI.
+  EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
+
+  // No ads blocked infobar should be shown as we have not triggered the
+  // intervention.
+  EXPECT_EQ(InfoBarService::FromWebContents(web_contents)->infobar_count(), 0u);
+  histogram_tester.ExpectBucketCount(
+      kAdsInterventionRecordedHistogram,
+      static_cast<int>(subresource_filter::mojom::AdsViolation::
+                           kMobileAdDensityByHeightAbove30),
+      1);
+}
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ad_density_intervention_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ad_density_intervention_browsertest.cc
new file mode 100644
index 0000000..f8fdf542
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ad_density_intervention_browsertest.cc
@@ -0,0 +1,136 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h"
+#include "chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/test/base/chrome_test_utils.h"
+#include "components/infobars/core/infobar.h"
+#include "components/infobars/core/infobar_delegate.h"
+#include "components/infobars/core/infobar_manager.h"
+#include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
+#include "components/subresource_filter/core/common/common_features.h"
+#include "components/subresource_filter/core/common/test_ruleset_utils.h"
+#include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+
+const char kAdsInterventionRecordedHistogram[] =
+    "SubresourceFilter.PageLoad.AdsInterventionTriggered";
+
+// Gets the body height of the document embedded in |web_contents|.
+int GetDocumentHeight(content::WebContents* web_contents) {
+  return EvalJs(web_contents, "document.body.scrollHeight").ExtractInt();
+}
+
+}  // namespace
+
+class AdDensityViolationBrowserTest
+    : public subresource_filter::SubresourceFilterBrowserTest {
+ public:
+  AdDensityViolationBrowserTest() = default;
+
+  void SetUp() override {
+    std::vector<base::Feature> enabled = {
+        subresource_filter::kAdTagging,
+        subresource_filter::kAdsInterventionsEnforced,
+        features::kSitePerProcess};
+    std::vector<base::Feature> disabled = {};
+
+    feature_list_.InitWithFeatures(enabled, disabled);
+    subresource_filter::SubresourceFilterBrowserTest::SetUp();
+  }
+
+  void SetUpOnMainThread() override {
+    SubresourceFilterBrowserTest::SetUpOnMainThread();
+    SetRulesetWithRules(
+        {subresource_filter::testing::CreateSuffixRule("ad_iframe_writer.js")});
+  }
+
+  void CreateAndWaitForIframeAtRect(
+      content::WebContents* web_contents,
+      page_load_metrics::PageLoadMetricsTestWaiter* waiter,
+      int x,
+      int y,
+      int width,
+      int height) {
+    waiter->AddMainFrameIntersectionExpectation(gfx::Rect(x, y, width, height));
+
+    // Create the frame with b.com as origin to not get caught by
+    // restricted ad tagging.
+    EXPECT_TRUE(ExecJs(
+        web_contents,
+        content::JsReplace("let frame = createAdIframeAtRect($1, $2, $3, $4); "
+                           "frame.src = $5",
+                           x, y, width, height,
+                           embedded_test_server()
+                               ->GetURL("b.com", "/ads_observer/pixel.png")
+                               .spec())));
+
+    waiter->Wait();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+// TODO(https://crbug.com/1142592): Replace this heavy-weight browsertest with
+// a unit test.
+IN_PROC_BROWSER_TEST_F(
+    AdDensityViolationBrowserTest,
+    DesktopPageAdDensityByHeightAbove30_AdInterventionNotTriggered) {
+  base::HistogramTester histogram_tester;
+  ukm::TestAutoSetUkmRecorder ukm_recorder;
+
+  content::WebContents* web_contents =
+      chrome_test_utils::GetActiveWebContents(this);
+  auto waiter = std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
+      web_contents);
+  const GURL url(embedded_test_server()->GetURL(
+      "a.com", "/ads_observer/blank_with_adiframe_writer.html"));
+
+  waiter->AddMainFrameIntersectionExpectation();
+  EXPECT_TRUE(content::NavigateToURL(web_contents, url));
+  waiter->Wait();
+
+  int document_width =
+      EvalJs(web_contents, "document.body.scrollWidth").ExtractInt();
+  int document_height = GetDocumentHeight(web_contents);
+
+  // Set to document width so ad density is 100%.
+  int frame_width = document_width;
+  int frame_height = document_height;
+
+  CreateAndWaitForIframeAtRect(web_contents, waiter.get(), 400, 400,
+                               frame_width, frame_height);
+
+  // Delete the page load metrics test waiter instead of reinitializing it
+  // for the next page load.
+  waiter.reset();
+
+  EXPECT_TRUE(content::NavigateToURL(web_contents, url));
+
+  // We are not enforcing ad blocking on ads violations, site should load
+  // as expected without subresource filter UI.
+  EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
+  // No ads blocked infobar should be shown as we have not triggered the
+  // intervention.
+  histogram_tester.ExpectBucketCount(
+      "SubresourceFilter.Actions2",
+      subresource_filter::SubresourceFilterAction::kUIShown, 0);
+  histogram_tester.ExpectTotalCount(kAdsInterventionRecordedHistogram, 0);
+}
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
index 3dd1dcd..c9d02297 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/heavy_ad_intervention/heavy_ad_helper.h"
 #include "chrome/browser/heavy_ad_intervention/heavy_ad_service.h"
 #include "chrome/browser/heavy_ad_intervention/heavy_ad_service_factory.h"
+#include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h"
 #include "chrome/common/chrome_features.h"
 #include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
 #include "components/page_load_metrics/browser/page_load_metrics_util.h"
@@ -31,6 +32,7 @@
 #include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
 #include "components/subresource_filter/core/common/common_features.h"
 #include "components/subresource_filter/core/common/load_policy.h"
+#include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
 #include "components/ukm/content/source_url_recorder.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/navigation_handle.h"
@@ -663,6 +665,32 @@
           *intersection_update.main_frame_intersection_rect);
     }
   }
+
+  CheckForAdDensityViolation();
+}
+
+// TODO(https://crbug.com/1142669): Evaluate imposing width requirements
+// for ad density violations.
+void AdsPageLoadMetricsObserver::CheckForAdDensityViolation() {
+#if defined(OS_ANDROID)
+  const int kMaxMobileAdDensityByHeight = 30;
+  if (page_ad_density_tracker_.MaxPageAdDensityByHeight() >
+      kMaxMobileAdDensityByHeight) {
+    auto* client = ChromeSubresourceFilterClient::FromWebContents(
+        GetDelegate().GetWebContents());
+    // AdsPageLoadMetricsObserver is not created unless there is a
+    // ChromeSubresourceFilterClient
+    DCHECK(client);
+
+    // Violations can be triggered multiple times for the same page as
+    // violations after the first are ignored. Ad frame violations are
+    // attributed to the main frame url.
+    client->OnAdsViolationTriggered(
+        GetDelegate().GetWebContents()->GetMainFrame(),
+        subresource_filter::mojom::AdsViolation::
+            kMobileAdDensityByHeightAbove30);
+  }
+#endif
 }
 
 void AdsPageLoadMetricsObserver::OnFrameDeleted(
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h
index 73df035..84cf0f2 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h
@@ -15,6 +15,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/scoped_observer.h"
 #include "base/time/tick_clock.h"
+#include "build/build_config.h"
 #include "chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h"
 #include "chrome/browser/page_load_metrics/observers/ad_metrics/page_ad_density_tracker.h"
 #include "components/page_load_metrics/browser/page_load_metrics_observer.h"
@@ -178,6 +179,11 @@
     base::WeakPtr<FrameTreeData> unowned_frame_data_;
   };
 
+  // Checks the current page ad density by height for an better ads standard
+  // violation. The better ads standard defines ad density violations as any
+  // site with more than 30 percent ad density by height.
+  void CheckForAdDensityViolation();
+
   // subresource_filter::SubresourceFilterObserver:
   void OnAdSubframeDetected(
       content::RenderFrameHost* render_frame_host) override;
diff --git a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc
index 9e816dcf..a084fb7c 100644
--- a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc
@@ -38,8 +38,6 @@
     case blink::mojom::WebFeature::kThirdPartySessionStorage:
       EXPECT_TRUE(content::ExecJs(frame, "window.sessionStorage"));
       break;
-    // TODO(crbug/1061448): Add browsertest for FileSystem access through
-    // FileSystemDirectoryHandle.
     case blink::mojom::WebFeature::kThirdPartyFileSystem:
       EXPECT_EQ(true, content::EvalJs(
                           frame,
@@ -49,6 +47,12 @@
                           " () => resolve(false));"
                           "});"));
       break;
+    case blink::mojom::WebFeature::kV8StorageManager_GetDirectory_Method:
+      EXPECT_EQ(
+          true,
+          content::EvalJs(
+              frame, "navigator.storage.getDirectory().then(() => true);"));
+      break;
     case blink::mojom::WebFeature::kThirdPartyIndexedDb:
       EXPECT_EQ(true,
                 content::EvalJs(
@@ -74,6 +78,14 @@
   }
 }
 
+blink::mojom::WebFeature MetricForTestCase(blink::mojom::WebFeature test_case) {
+  if (test_case ==
+      blink::mojom::WebFeature::kV8StorageManager_GetDirectory_Method) {
+    return blink::mojom::WebFeature::kThirdPartyFileSystem;
+  }
+  return test_case;
+}
+
 class ThirdPartyMetricsObserverBrowserTest : public InProcessBrowserTest {
  protected:
   ThirdPartyMetricsObserverBrowserTest()
@@ -535,7 +547,8 @@
       blink::mojom::WebFeature::kThirdPartySessionStorage,
       blink::mojom::WebFeature::kThirdPartyFileSystem,
       blink::mojom::WebFeature::kThirdPartyIndexedDb,
-      blink::mojom::WebFeature::kThirdPartyCacheStorage};
+      blink::mojom::WebFeature::kThirdPartyCacheStorage,
+      blink::mojom::WebFeature::kV8StorageManager_GetDirectory_Method};
 
   for (const auto& test_case : test_cases) {
     base::HistogramTester histogram_tester;
@@ -545,8 +558,8 @@
                                test_case);
     NavigateToUntrackedUrl();
 
-    histogram_tester.ExpectBucketCount("Blink.UseCounter.Features", test_case,
-                                       0);
+    histogram_tester.ExpectBucketCount("Blink.UseCounter.Features",
+                                       MetricForTestCase(test_case), 0);
     histogram_tester.ExpectBucketCount(
         "Blink.UseCounter.Features",
         blink::mojom::WebFeature::kThirdPartyAccess, 0);
@@ -560,7 +573,8 @@
       blink::mojom::WebFeature::kThirdPartySessionStorage,
       blink::mojom::WebFeature::kThirdPartyFileSystem,
       blink::mojom::WebFeature::kThirdPartyIndexedDb,
-      blink::mojom::WebFeature::kThirdPartyCacheStorage};
+      blink::mojom::WebFeature::kThirdPartyCacheStorage,
+      blink::mojom::WebFeature::kV8StorageManager_GetDirectory_Method};
 
   for (const auto& test_case : test_cases) {
     base::HistogramTester histogram_tester;
@@ -570,8 +584,8 @@
                                test_case);
     NavigateToUntrackedUrl();
 
-    histogram_tester.ExpectBucketCount("Blink.UseCounter.Features", test_case,
-                                       1);
+    histogram_tester.ExpectBucketCount("Blink.UseCounter.Features",
+                                       MetricForTestCase(test_case), 1);
     histogram_tester.ExpectBucketCount(
         "Blink.UseCounter.Features",
         blink::mojom::WebFeature::kThirdPartyAccess, 1);
diff --git a/chrome/browser/paint_preview/android/BUILD.gn b/chrome/browser/paint_preview/android/BUILD.gn
index b3eb9829..d7320f15 100644
--- a/chrome/browser/paint_preview/android/BUILD.gn
+++ b/chrome/browser/paint_preview/android/BUILD.gn
@@ -49,3 +49,42 @@
 android_resources("java_resources") {
   deps = [ "//chrome/browser/ui/android/strings:ui_strings_grd" ]
 }
+
+android_library("javatests") {
+  testonly = true
+
+  sources = [
+    "javatests/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreviewTest.java",
+    "javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewTest.java",
+    "javatests/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewTest.java",
+    "javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java",
+  ]
+
+  deps = [
+    ":java",
+    "//base:base_java",
+    "//base:base_java_test_support",
+    "//chrome/android:chrome_java",
+    "//chrome/browser/browser_controls/android:java",
+    "//chrome/browser/flags:java",
+    "//chrome/browser/tab:java",
+    "//chrome/browser/tabmodel:java",
+    "//chrome/browser/ui/messages/android:java",
+    "//chrome/test/android:chrome_java_test_support",
+    "//components/paint_preview/browser/android:java",
+    "//components/paint_preview/player/android:java",
+    "//content/public/android:content_java",
+    "//content/public/test/android:content_java_test_support",
+    "//net/android:net_java_test_support",
+    "//third_party/android_deps:androidx_annotation_annotation_java",
+    "//third_party/android_deps:androidx_test_runner_java",
+    "//third_party/android_support_test_runner:rules_java",
+    "//third_party/android_support_test_runner:runner_java",
+    "//third_party/junit",
+    "//third_party/mockito:mockito_java",
+    "//third_party/ub-uiautomator:ub_uiautomator_java",
+    "//ui/android:ui_java_test_support",
+    "//ui/android:ui_no_recycler_view_java",
+    "//url:gurl_java",
+  ]
+}
diff --git a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreview.java b/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreview.java
index 6e2413fc..f0cbae1 100644
--- a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreview.java
+++ b/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreview.java
@@ -37,8 +37,6 @@
     }
 
     private void show() {
-        if (mTabbedPaintPreview.maybeShow(this)) return;
-
         PaintPreviewCompositorUtils.warmupCompositor();
         mTabbedPaintPreview.capture(success
                 -> PostTask.runOrPostTask(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreviewTest.java b/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreviewTest.java
similarity index 84%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreviewTest.java
rename to chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreviewTest.java
index 7b882803..f3e9105 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreviewTest.java
+++ b/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/DemoPaintPreviewTest.java
@@ -76,25 +76,6 @@
     }
 
     /**
-     * Tests the demo mode is accessible from app menu and works successfully when the page has been
-     * captured before.
-     */
-    @Test
-    @MediumTest
-    public void testWithExistingCapture() throws UiObjectNotFoundException, ExecutionException {
-        Mockito.doReturn(true).when(sMockService).hasCaptureForTab(Mockito.anyInt());
-
-        UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        uiDevice.pressMenu();
-        uiDevice.findObject(new UiSelector().text("Show Paint Preview")).click();
-
-        Tab tab = sActivityTestRule.getActivity().getActivityTab();
-        TabbedPaintPreview tabbedPaintPreview =
-                TestThreadUtils.runOnUiThreadBlocking(() -> TabbedPaintPreview.get(tab));
-        assertAttachedAndShown(tabbedPaintPreview, true, true);
-    }
-
-    /**
      * Tests the demo mode is accessible from app menu and works successfully when the page has not
      * been captured before.
      */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewTest.java b/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewTest.java
similarity index 100%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewTest.java
rename to chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewTest.java
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewTest.java b/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewTest.java
similarity index 100%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewTest.java
rename to chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewTest.java
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java b/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java
similarity index 100%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java
rename to chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java
diff --git a/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc b/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc
index 5ab4a6b..38522ff 100644
--- a/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc
+++ b/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc
@@ -23,6 +23,7 @@
 #include "components/password_manager/core/browser/password_bubble_experiment.h"
 #include "components/password_manager/core/browser/password_form_metrics_recorder.h"
 #include "components/signin/public/identity_manager/account_info.h"
+#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/sync/driver/sync_service.h"
 #include "content/public/browser/web_contents.h"
@@ -45,20 +46,23 @@
       identity_manager
           ->FindExtendedAccountInfoForAccountWithRefreshTokenByAccountId(
               account_id);
+  bool is_single_account_user =
+      identity_manager->GetAccountsWithRefreshTokens().size() == 1;
 
   // is_smartlock_branding_enabled indicates whether the user is syncing
   // passwords to their Google Account.
   bool is_smartlock_branding_enabled =
       password_bubble_experiment::IsSmartLockUser(sync_service);
+  bool should_show_account_footer = is_smartlock_branding_enabled &&
+                                    !is_single_account_user &&
+                                    account_info.has_value();
   InfoBarService* infobar_service =
       InfoBarService::FromWebContents(web_contents);
   infobar_service->AddInfoBar(std::make_unique<SavePasswordInfoBar>(
       base::WrapUnique(
           new SavePasswordInfoBarDelegate(web_contents, std::move(form_to_save),
                                           is_smartlock_branding_enabled)),
-      is_smartlock_branding_enabled && account_info.has_value()
-          ? account_info.value()
-          : AccountInfo()));
+      should_show_account_footer ? account_info.value() : AccountInfo()));
 }
 
 SavePasswordInfoBarDelegate::~SavePasswordInfoBarDelegate() {
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
index bbdc6b9..e172a58 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
@@ -201,13 +201,14 @@
     const AccountId& account_id,
     scoped_refptr<network::SharedURLLoaderFactory> profile_url_loader_factory) {
   DCHECK(account_id.is_valid());
+  UserCloudPolicyManager* manager = policy_manager();
   if (!ShouldLoadPolicyForUser(account_id.GetUserEmail())) {
+    manager->SetPoliciesRequired(false);
     DVLOG(1) << "Policy load not enabled for user: "
              << account_id.GetUserEmail();
     return;
   }
 
-  UserCloudPolicyManager* manager = policy_manager();
   // Initialize the UCPM if it is not already initialized.
   if (!manager->core()->service()) {
     // If there is no cached DMToken then we can detect this when the
diff --git a/chrome/browser/policy/policy_prefs_browsertest.cc b/chrome/browser/policy/policy_prefs_browsertest.cc
index 35abd129..09944f9 100644
--- a/chrome/browser/policy/policy_prefs_browsertest.cc
+++ b/chrome/browser/policy/policy_prefs_browsertest.cc
@@ -80,6 +80,8 @@
   void SetUpInProcessBrowserTestFixture() override {
     EXPECT_CALL(provider_, IsInitializationComplete(_))
         .WillRepeatedly(Return(true));
+    EXPECT_CALL(provider_, IsFirstPolicyLoadComplete(testing::_))
+        .WillRepeatedly(testing::Return(true));
     BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
   }
 
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index 8d2163b..398c465 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -350,39 +350,6 @@
     output_dir = "$root_gen_dir/chrome"
   }
 
-  grit("os_settings_resources") {
-    grit_flags = [
-      "-E",
-      "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
-    ]
-    deps = [ "//chrome/browser/ui/webui/settings/chromeos:mojom_js" ]
-    if (optimize_webui) {
-      # Required due to flattenhtml="true" on a generated file.
-      enable_input_discovery_for_gn_analyze = false
-      source = "settings/os_settings_resources_vulcanized.grd"
-
-      deps += [
-        "//chrome/browser/resources/settings/chromeos:build",
-        "//chrome/browser/resources/settings/chromeos:build_polymer3",
-      ]
-    } else {
-      source = "settings/os_settings_resources.grd"
-      deps += [
-        "//chrome/browser/resources/settings/chromeos:polymer3_elements",
-        "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js",
-      ]
-    }
-
-    defines = chrome_grit_defines
-    outputs = [
-      "grit/os_settings_resources.h",
-      "grit/os_settings_resources_map.cc",
-      "grit/os_settings_resources_map.h",
-      "os_settings_resources.pak",
-    ]
-    output_dir = "$root_gen_dir/chrome"
-  }
-
   grit("bluetooth_pairing_dialog_resources") {
     grit_flags = [
       "-E",
diff --git a/chrome/browser/resources/chromeos/login/components/oobe_dialog.css b/chrome/browser/resources/chromeos/login/components/oobe_dialog.css
index 78a6776a..e0297e4 100644
--- a/chrome/browser/resources/chromeos/login/components/oobe_dialog.css
+++ b/chrome/browser/resources/chromeos/login/components/oobe_dialog.css
@@ -27,10 +27,6 @@
   padding-top: var(--oobe-dialog-content-padding);
 }
 
-#header-container[android] {
-  padding: 48px 48px 0 48px;
-}
-
 #oobe-title {
   padding-top: 20px;
 }
diff --git a/chrome/browser/resources/chromeos/login/components/oobe_dialog.html b/chrome/browser/resources/chromeos/login/components/oobe_dialog.html
index 2a07681..19af8381 100644
--- a/chrome/browser/resources/chromeos/login/components/oobe_dialog.html
+++ b/chrome/browser/resources/chromeos/login/components/oobe_dialog.html
@@ -109,7 +109,7 @@
           </div>
         </template>
       </template>
-    </template>
-  </cr-lazy-render>
+    </cr-lazy-render>
+  </template>
 </dom-module>
 
diff --git a/chrome/browser/resources/optimize_webui.py b/chrome/browser/resources/optimize_webui.py
index cd78d54..d7bade1 100755
--- a/chrome/browser/resources/optimize_webui.py
+++ b/chrome/browser/resources/optimize_webui.py
@@ -413,7 +413,10 @@
   if args.out_manifest:
     manifest_data = {}
     manifest_data['base_dir'] = '%s' % args.out_folder
-    manifest_data['files'] = manifest.keys()
+    if (is_polymer3):
+      manifest_data['files'] = manifest.keys()
+    else:
+      manifest_data['files'] = args.html_out_files + args.js_out_files
     manifest_file = open(
         os.path.normpath(os.path.join(_CWD, args.out_manifest)), 'wb')
     json.dump(manifest_data, manifest_file)
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index 24d0bd6..ffc6c37 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -4,15 +4,28 @@
 
 import("//chrome/common/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/grit/grit_rule.gni")
 import("//tools/grit/preprocess_grit.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
 import("//ui/webui/resources/tools/js_modulizer.gni")
 import("//ui/webui/webui_features.gni")
 import("../../optimize_webui.gni")
 import("./os_settings.gni")
 
+preprocess_folder_v2 = "preprocess_v2"
+preprocess_folder_v3 = "preprocess_v3"
+
+preprocess_v2_manifest = "preprocessed_v2_manifest.json"
+preprocess_nearby_v2_manifest = "preprocessed_nearby_v2_manifest.json"
+preprocess_v3_manifest = "preprocessed_manifest.json"
+preprocess_gen_v3_manifest = "preprocessed_gen_manifest.json"
+preprocess_nearby_v3_manifest = "preprocessed_nearby_v3_manifest.json"
+preprocess_external_mojo_manifest = "preprocessed_external_mojo_manifest.json"
+preprocess_mojo_manifest = "preprocessed_mojo_manifest.json"
+
 if (optimize_webui) {
-  preprocess_folder_v2 = "preprocess_v2"
-  preprocess_folder_v3 = "preprocess_v3"
+  build_manifest_v2 = "build_v2_manifest.json"
+  build_manifest_v3 = "build_v3_manifest.json"
 
   optimize_webui("build") {
     host = "os-settings"
@@ -30,6 +43,7 @@
       "crisper.js",
       "lazy_load.crisper.js",
     ]
+    out_manifest = "$target_gen_dir/$build_manifest_v2"
     excludes = [
       # TODO(calamity): Update optimize_webui to handle generated files.
       "chrome://resources/chromeos/colors/cros_colors.generated.css",
@@ -40,11 +54,6 @@
       "chrome://os-settings/app-management/file_path.mojom-lite.js",
       "chrome://os-settings/app-management/image.mojom-lite.js",
       "chrome://os-settings/app-management/types.mojom-lite.js",
-      "chrome://os-settings/constants/routes.mojom-lite.js",
-      "chrome://os-settings/constants/setting.mojom-lite.js",
-      "chrome://os-settings/search/search.mojom-lite.js",
-      "chrome://os-settings/search/search_result_icon.mojom-lite.js",
-      "chrome://os-settings/search/user_action_recorder.mojom-lite.js",
       "chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom.html",
       "chrome://resources/mojo/mojo/public/mojom/base/string16.mojom.html",
       "chrome://resources/mojo/mojo/public/mojom/base/time.mojom.html",
@@ -57,6 +66,7 @@
     ]
 
     deps = [
+      ":preprocess_mojo_v2",
       ":preprocess_nearby_v2",
       ":preprocess_v2",
     ]
@@ -74,9 +84,11 @@
       "lazy_load.rollup.js",
       "shared.rollup.js",
     ]
+    out_manifest = "$target_gen_dir/$build_manifest_v3"
 
     deps = [
       ":preprocess_gen_v3",
+      ":preprocess_mojo_v3",
       ":preprocess_nearby_v3",
       ":preprocess_v3",
       "../../../../../ui/webui/resources:preprocess",
@@ -98,772 +110,915 @@
       "app-management/image_info.mojom-lite.js",
       "app-management/image.mojom-lite.js",
       "app-management/types.mojom-lite.js",
-      "constants/routes.mojom-lite.js",
-      "constants/setting.mojom-lite.js",
-      "search/search.mojom-lite.js",
-      "search/search_result_icon.mojom-lite.js",
-      "search/user_action_recorder.mojom-lite.js",
       "mojo/nearby_share.mojom-lite.js",
       "mojo/nearby_share_target_types.mojom-lite.js",
       "mojo/nearby_share_settings.mojom-lite.js",
     ]
   }
+}
 
-  preprocess_grit("preprocess_v3") {
-    defines = chrome_grit_defines
-    in_folder = "../"
-    out_folder = "$target_gen_dir/$preprocess_folder_v3"
-    in_files = [
-      "chromeos/ensure_lazy_loaded.m.js",
-      "chromeos/lazy_load.js",
-      "chromeos/os_settings.js",
-      "i18n_setup.js",
-      "page_visibility.js",
-    ]
-  }
+# OS Settings specific mojo files, bundled in optimized builds. No need for a
+# manifest as the preprocess_mojo_v3 target generates the manifest file for the
+# grd.
+preprocess_grit("preprocess_mojo_v2") {
+  deps = [
+    "//chrome/browser/ui/webui/settings/chromeos/constants:mojom_js",
+    "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js",
+  ]
+  in_folder = get_path_info("../../../ui/webui/settings/chromeos/", "gen_dir")
+  out_folder = "$target_gen_dir/$preprocess_folder_v2"
+  in_files = [
+    "constants/routes.mojom-lite.js",
+    "constants/setting.mojom-lite.js",
+    "search/search.mojom-lite.js",
+    "search/search_result_icon.mojom-lite.js",
+    "search/user_action_recorder.mojom-lite.js",
+  ]
+}
 
-  preprocess_grit("preprocess_gen_v3") {
-    defines = chrome_grit_defines
-    deps = [ ":polymer3_elements" ]
-    in_folder = get_path_info("../", "gen_dir")
-    out_folder = "$target_gen_dir/$preprocess_folder_v3"
-    in_files = [
-      "about_page/about_page_browser_proxy.m.js",
-      "chromeos/ambient_mode_page/album_item.m.js",
-      "chromeos/ambient_mode_page/album_list.m.js",
-      "chromeos/ambient_mode_page/ambient_mode_browser_proxy.m.js",
-      "chromeos/ambient_mode_page/ambient_mode_page.m.js",
-      "chromeos/ambient_mode_page/ambient_mode_photos_page.m.js",
-      "chromeos/ambient_mode_page/constants.m.js",
-      "chromeos/ambient_mode_page/topic_source_item.m.js",
-      "chromeos/ambient_mode_page/topic_source_list.m.js",
-      "chromeos/bluetooth_page/bluetooth_device_list_item.m.js",
-      "chromeos/bluetooth_page/bluetooth_page.m.js",
-      "chromeos/bluetooth_page/bluetooth_subpage.m.js",
-      "chromeos/date_time_page/date_time_page.m.js",
-      "chromeos/date_time_page/date_time_types.m.js",
-      "chromeos/date_time_page/timezone_browser_proxy.m.js",
-      "chromeos/date_time_page/timezone_selector.m.js",
-      "chromeos/date_time_page/timezone_subpage.m.js",
-      "chromeos/deep_linking_behavior.m.js",
-      "chromeos/google_assistant_page/google_assistant_browser_proxy.m.js",
-      "chromeos/google_assistant_page/google_assistant_page.m.js",
-      "chromeos/internet_page/cellular_setup_dialog.m.js",
-      "chromeos/internet_page/cellular_setup_settings_delegate.m.js",
-      "chromeos/internet_page/internet_config.m.js",
-      "chromeos/internet_page/internet_detail_menu.m.js",
-      "chromeos/internet_page/internet_detail_page.m.js",
-      "chromeos/internet_page/internet_known_networks_page.m.js",
-      "chromeos/internet_page/internet_page.m.js",
-      "chromeos/internet_page/internet_page_browser_proxy.m.js",
-      "chromeos/internet_page/internet_shared_css.m.js",
-      "chromeos/internet_page/internet_subpage.m.js",
-      "chromeos/internet_page/network_proxy_section.m.js",
-      "chromeos/internet_page/network_summary.m.js",
-      "chromeos/internet_page/network_summary_item.m.js",
-      "chromeos/internet_page/tether_connection_dialog.m.js",
-      "chromeos/localized_link/localized_link.m.js",
-      "chromeos/metrics_recorder.m.js",
-      "chromeos/multidevice_page/multidevice_browser_proxy.m.js",
-      "chromeos/multidevice_page/multidevice_constants.m.js",
-      "chromeos/multidevice_page/multidevice_feature_behavior.m.js",
-      "chromeos/multidevice_page/multidevice_feature_item.m.js",
-      "chromeos/multidevice_page/multidevice_feature_toggle.m.js",
-      "chromeos/multidevice_page/multidevice_notification_access_setup_dialog.m.js",
-      "chromeos/multidevice_page/multidevice_page.m.js",
-      "chromeos/multidevice_page/multidevice_radio_button.m.js",
-      "chromeos/multidevice_page/multidevice_smartlock_subpage.m.js",
-      "chromeos/multidevice_page/multidevice_subpage.m.js",
-      "chromeos/multidevice_page/multidevice_tether_item.m.js",
-      "chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.m.js",
-      "chromeos/multidevice_page/multidevice_wifi_sync_item.m.js",
-      "chromeos/nearby_share_page/nearby_account_manager_browser_proxy.m.js",
-      "chromeos/nearby_share_page/nearby_share_confirm_page.m.js",
-      "chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.m.js",
-      "chromeos/nearby_share_page/nearby_share_data_usage_dialog.m.js",
-      "chromeos/nearby_share_page/nearby_share_device_name_dialog.m.js",
-      "chromeos/nearby_share_page/nearby_share_high_visibility_page.m.js",
-      "chromeos/nearby_share_page/nearby_share_receive_dialog.m.js",
-      "chromeos/nearby_share_page/nearby_share_receive_manager.m.js",
-      "chromeos/nearby_share_page/nearby_share_subpage.m.js",
-      "chromeos/nearby_share_page/types.m.js",
-      "chromeos/os_about_page/channel_switcher_dialog.m.js",
-      "chromeos/os_about_page/detailed_build_info.m.js",
-      "chromeos/os_about_page/edit_hostname_dialog.m.js",
-      "chromeos/os_about_page/os_about_page.m.js",
-      "chromeos/os_about_page/update_warning_dialog.m.js",
-      "chromeos/os_files_page/os_files_page.m.js",
-      "chromeos/os_files_page/smb_shares_page.m.js",
-      "chromeos/os_icons.m.js",
-      "chromeos/os_languages_page/add_input_methods_dialog.m.js",
-      "chromeos/os_languages_page/change_device_language_dialog.m.js",
-      "chromeos/os_languages_page/input_method_options_page.m.js",
-      "chromeos/os_languages_page/input_method_util.m.js",
-      "chromeos/os_languages_page/input_page.m.js",
-      "chromeos/os_languages_page/languages_metrics_proxy.m.js",
-      "chromeos/os_languages_page/manage_input_methods_page.m.js",
-      "chromeos/os_languages_page/os_add_languages_dialog.m.js",
-      "chromeos/os_languages_page/os_edit_dictionary_page.m.js",
-      "chromeos/os_languages_page/os_languages_page.m.js",
-      "chromeos/os_languages_page/os_languages_page_v2.m.js",
-      "chromeos/os_languages_page/os_languages_section.m.js",
-      "chromeos/os_languages_page/shared_style.m.js",
-      "chromeos/os_languages_page/shared_vars.m.js",
-      "chromeos/os_languages_page/smart_inputs_page.m.js",
-      "chromeos/os_page_visibility.m.js",
-      "chromeos/os_people_page/account_manager.m.js",
-      "chromeos/os_people_page/fingerprint_browser_proxy.m.js",
-      "chromeos/os_people_page/fingerprint_list.m.js",
-      "chromeos/os_people_page/kerberos_accounts.m.js",
-      "chromeos/os_people_page/kerberos_accounts_browser_proxy.m.js",
-      "chromeos/os_people_page/kerberos_add_account_dialog.m.js",
-      "chromeos/os_people_page/lock_screen.m.js",
-      "chromeos/os_people_page/lock_screen_password_prompt_dialog.m.js",
-      "chromeos/os_people_page/lock_state_behavior.m.js",
-      "chromeos/os_people_page/os_people_page.m.js",
-      "chromeos/os_people_page/os_sync_browser_proxy.m.js",
-      "chromeos/os_people_page/os_sync_controls.m.js",
-      "chromeos/os_people_page/pin_autosubmit_dialog.m.js",
-      "chromeos/os_people_page/setup_fingerprint_dialog.m.js",
-      "chromeos/os_people_page/setup_pin_dialog.m.js",
-      "chromeos/os_people_page/user_list.m.js",
-      "chromeos/os_people_page/users_add_user_dialog.m.js",
-      "chromeos/os_people_page/users_page.m.js",
-      "chromeos/os_printing_page/cups_add_print_server_dialog.m.js",
-      "chromeos/os_printing_page/cups_add_printer_dialog.m.js",
-      "chromeos/os_printing_page/cups_add_printer_manually_dialog.m.js",
-      "chromeos/os_printing_page/cups_add_printer_manufacturer_model_dialog.m.js",
-      "chromeos/os_printing_page/cups_edit_printer_dialog.m.js",
-      "chromeos/os_printing_page/cups_nearby_printers.m.js",
-      "chromeos/os_printing_page/cups_printer_dialog_error.m.js",
-      "chromeos/os_printing_page/cups_printer_dialog_util.m.js",
-      "chromeos/os_printing_page/cups_printer_shared_css.m.js",
-      "chromeos/os_printing_page/cups_printer_types.m.js",
-      "chromeos/os_printing_page/cups_printers.m.js",
-      "chromeos/os_printing_page/cups_printers_browser_proxy.m.js",
-      "chromeos/os_printing_page/cups_printers_entry.m.js",
-      "chromeos/os_printing_page/cups_printers_entry_list_behavior.m.js",
-      "chromeos/os_printing_page/cups_printers_entry_manager.m.js",
-      "chromeos/os_printing_page/cups_saved_printers.m.js",
-      "chromeos/os_printing_page/cups_settings_add_printer_dialog.m.js",
-      "chromeos/os_printing_page/os_printing_page.m.js",
-      "chromeos/os_privacy_page/os_privacy_page.m.js",
-      "chromeos/os_reset_page/os_powerwash_dialog.m.js",
-      "chromeos/os_reset_page/os_reset_browser_proxy.m.js",
-      "chromeos/os_reset_page/os_reset_page.m.js",
-      "chromeos/os_route.m.js",
-      "chromeos/os_search_page/os_search_page.m.js",
-      "chromeos/os_search_page/os_search_selection_dialog.m.js",
-      "chromeos/os_settings_icons_css.m.js",
-      "chromeos/os_settings_page/main_page_behavior.m.js",
-      "chromeos/os_settings_routes.m.js",
-      "chromeos/parental_controls_page/parental_controls_browser_proxy.m.js",
-      "chromeos/parental_controls_page/parental_controls_page.m.js",
-      "chromeos/personalization_page/change_picture.m.js",
-      "chromeos/personalization_page/change_picture_browser_proxy.m.js",
-      "chromeos/personalization_page/personalization_page.m.js",
-      "chromeos/personalization_page/wallpaper_browser_proxy.m.js",
-      "chromeos/pref_to_setting_metric_converter.m.js",
-      "chromeos/route_origin_behavior.m.js",
-      "controls/controlled_button.m.js",
-      "controls/controlled_radio_button.m.js",
-      "controls/extension_controlled_indicator.m.js",
-      "controls/password_prompt_dialog.m.js",
-      "controls/pref_control_behavior.m.js",
-      "controls/settings_boolean_control_behavior.m.js",
-      "controls/settings_dropdown_menu.m.js",
-      "controls/settings_radio_group.m.js",
-      "controls/settings_textarea.m.js",
-      "controls/settings_toggle_button.m.js",
-      "extension_control_browser_proxy.m.js",
-      "global_scroll_target_behavior.m.js",
-      "icons.m.js",
-      "languages_page/languages.m.js",
-      "languages_page/languages_browser_proxy.m.js",
-      "lifetime_browser_proxy.m.js",
-      "people_page/account_manager_browser_proxy.m.js",
-      "people_page/profile_info_browser_proxy.m.js",
-      "people_page/signout_dialog.m.js",
-      "people_page/sync_account_control.m.js",
-      "people_page/sync_browser_proxy.m.js",
-      "people_page/sync_controls.m.js",
-      "people_page/sync_encryption_options.m.js",
-      "people_page/sync_page.m.js",
-      "prefs/pref_util.m.js",
-      "prefs/prefs.m.js",
-      "prefs/prefs_behavior.m.js",
-      "prefs/prefs_types.m.js",
-      "privacy_page/personalization_options.m.js",
-      "privacy_page/privacy_page_browser_proxy.m.js",
-      "router.m.js",
-      "search_engines_page/search_engines_browser_proxy.m.js",
-      "setting_id_param_util.m.js",
-      "settings_page/settings_animated_pages.m.js",
-      "settings_page/settings_section.m.js",
-      "settings_page/settings_subpage.m.js",
-      "settings_page_css.m.js",
-      "settings_shared_css.m.js",
-      "settings_vars_css.m.js",
-    ]
-  }
+# OS Settings specific mojo files, bundled in optimized builds.
+preprocess_grit("preprocess_mojo_v3") {
+  deps = [
+    "//chrome/browser/ui/webui/settings/chromeos/constants:mojom_js",
+    "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js",
+  ]
+  in_folder = get_path_info("../../../ui/webui/settings/chromeos/", "gen_dir")
+  out_folder = "$target_gen_dir/$preprocess_folder_v3"
+  out_manifest = "$target_gen_dir/$preprocess_mojo_manifest"
+  in_files = [
+    "constants/routes.mojom-lite.js",
+    "constants/setting.mojom-lite.js",
+    "search/search.mojom-lite.js",
+    "search/search_result_icon.mojom-lite.js",
+    "search/user_action_recorder.mojom-lite.js",
+  ]
+}
 
-  preprocess_grit("preprocess_v2") {
-    defines = chrome_grit_defines
-    in_folder = "../"
-    out_folder = "$target_gen_dir/$preprocess_folder_v2"
-    in_files = [
-      "a11y_page/captions_subpage.html",
-      "a11y_page/captions_subpage.js",
-      "about_page/about_page_browser_proxy.html",
-      "about_page/about_page_browser_proxy.js",
-      "appearance_page/fonts_browser_proxy.html",
-      "appearance_page/fonts_browser_proxy.js",
-      "chromeos/ambient_mode_page/album_item.html",
-      "chromeos/ambient_mode_page/album_item.js",
-      "chromeos/ambient_mode_page/album_list.html",
-      "chromeos/ambient_mode_page/album_list.js",
-      "chromeos/ambient_mode_page/ambient_mode_browser_proxy.html",
-      "chromeos/ambient_mode_page/ambient_mode_browser_proxy.js",
-      "chromeos/ambient_mode_page/ambient_mode_page.html",
-      "chromeos/ambient_mode_page/ambient_mode_page.js",
-      "chromeos/ambient_mode_page/ambient_mode_photos_page.html",
-      "chromeos/ambient_mode_page/ambient_mode_photos_page.js",
-      "chromeos/ambient_mode_page/constants.html",
-      "chromeos/ambient_mode_page/constants.js",
-      "chromeos/ambient_mode_page/topic_source_item.html",
-      "chromeos/ambient_mode_page/topic_source_item.js",
-      "chromeos/ambient_mode_page/topic_source_list.html",
-      "chromeos/ambient_mode_page/topic_source_list.js",
-      "chromeos/bluetooth_page/bluetooth_device_list_item.html",
-      "chromeos/bluetooth_page/bluetooth_device_list_item.js",
-      "chromeos/bluetooth_page/bluetooth_page.html",
-      "chromeos/bluetooth_page/bluetooth_page.js",
-      "chromeos/bluetooth_page/bluetooth_subpage.html",
-      "chromeos/bluetooth_page/bluetooth_subpage.js",
-      "chromeos/crostini_page/crostini_arc_adb.html",
-      "chromeos/crostini_page/crostini_arc_adb.js",
-      "chromeos/crostini_page/crostini_arc_adb_confirmation_dialog.html",
-      "chromeos/crostini_page/crostini_arc_adb_confirmation_dialog.js",
-      "chromeos/crostini_page/crostini_browser_proxy.html",
-      "chromeos/crostini_page/crostini_browser_proxy.js",
-      "chromeos/crostini_page/crostini_disk_resize_confirmation_dialog.html",
-      "chromeos/crostini_page/crostini_disk_resize_confirmation_dialog.js",
-      "chromeos/crostini_page/crostini_disk_resize_dialog.html",
-      "chromeos/crostini_page/crostini_disk_resize_dialog.js",
-      "chromeos/crostini_page/crostini_export_import.html",
-      "chromeos/crostini_page/crostini_export_import.js",
-      "chromeos/crostini_page/crostini_import_confirmation_dialog.html",
-      "chromeos/crostini_page/crostini_import_confirmation_dialog.js",
-      "chromeos/crostini_page/crostini_mic_sharing_dialog.html",
-      "chromeos/crostini_page/crostini_mic_sharing_dialog.js",
-      "chromeos/crostini_page/crostini_page.html",
-      "chromeos/crostini_page/crostini_page.js",
-      "chromeos/crostini_page/crostini_port_forwarding.html",
-      "chromeos/crostini_page/crostini_port_forwarding.js",
-      "chromeos/crostini_page/crostini_port_forwarding_add_port_dialog.html",
-      "chromeos/crostini_page/crostini_port_forwarding_add_port_dialog.js",
-      "chromeos/crostini_page/crostini_shared_paths.html",
-      "chromeos/crostini_page/crostini_shared_paths.js",
-      "chromeos/crostini_page/crostini_shared_usb_devices.html",
-      "chromeos/crostini_page/crostini_shared_usb_devices.js",
-      "chromeos/crostini_page/crostini_subpage.html",
-      "chromeos/crostini_page/crostini_subpage.js",
-      "chromeos/date_time_page/date_time_page.html",
-      "chromeos/date_time_page/date_time_page.js",
-      "chromeos/date_time_page/date_time_types.html",
-      "chromeos/date_time_page/date_time_types.js",
-      "chromeos/date_time_page/timezone_browser_proxy.html",
-      "chromeos/date_time_page/timezone_browser_proxy.js",
-      "chromeos/date_time_page/timezone_selector.html",
-      "chromeos/date_time_page/timezone_selector.js",
-      "chromeos/date_time_page/timezone_subpage.html",
-      "chromeos/date_time_page/timezone_subpage.js",
-      "chromeos/deep_linking_behavior.html",
-      "chromeos/deep_linking_behavior.js",
-      "chromeos/device_page/device_page.html",
-      "chromeos/device_page/device_page.js",
-      "chromeos/device_page/device_page_browser_proxy.html",
-      "chromeos/device_page/device_page_browser_proxy.js",
-      "chromeos/device_page/display.html",
-      "chromeos/device_page/display.js",
-      "chromeos/device_page/display_layout.html",
-      "chromeos/device_page/display_layout.js",
-      "chromeos/device_page/display_overscan_dialog.html",
-      "chromeos/device_page/display_overscan_dialog.js",
-      "chromeos/device_page/drag_behavior.html",
-      "chromeos/device_page/drag_behavior.js",
-      "chromeos/device_page/keyboard.html",
-      "chromeos/device_page/keyboard.js",
-      "chromeos/device_page/layout_behavior.html",
-      "chromeos/device_page/layout_behavior.js",
-      "chromeos/device_page/night_light_slider.html",
-      "chromeos/device_page/night_light_slider.js",
-      "chromeos/device_page/pointers.html",
-      "chromeos/device_page/pointers.js",
-      "chromeos/device_page/power.html",
-      "chromeos/device_page/power.js",
-      "chromeos/device_page/storage.html",
-      "chromeos/device_page/storage.js",
-      "chromeos/device_page/storage_external.html",
-      "chromeos/device_page/storage_external.js",
-      "chromeos/device_page/storage_external_entry.html",
-      "chromeos/device_page/storage_external_entry.js",
-      "chromeos/device_page/stylus.html",
-      "chromeos/device_page/stylus.js",
-      "chromeos/ensure_lazy_loaded.html",
-      "chromeos/google_assistant_page/google_assistant_browser_proxy.html",
-      "chromeos/google_assistant_page/google_assistant_browser_proxy.js",
-      "chromeos/google_assistant_page/google_assistant_page.html",
-      "chromeos/google_assistant_page/google_assistant_page.js",
-      "chromeos/internet_page/cellular_setup_dialog.html",
-      "chromeos/internet_page/cellular_setup_dialog.js",
-      "chromeos/internet_page/cellular_setup_settings_delegate.html",
-      "chromeos/internet_page/cellular_setup_settings_delegate.js",
-      "chromeos/internet_page/internet_config.html",
-      "chromeos/internet_page/internet_config.js",
-      "chromeos/internet_page/internet_detail_menu.html",
-      "chromeos/internet_page/internet_detail_menu.js",
-      "chromeos/internet_page/internet_detail_page.html",
-      "chromeos/internet_page/internet_detail_page.js",
-      "chromeos/internet_page/internet_known_networks_page.html",
-      "chromeos/internet_page/internet_known_networks_page.js",
-      "chromeos/internet_page/internet_page.html",
-      "chromeos/internet_page/internet_page.js",
-      "chromeos/internet_page/internet_page_browser_proxy.html",
-      "chromeos/internet_page/internet_page_browser_proxy.js",
-      "chromeos/internet_page/internet_shared_css.html",
-      "chromeos/internet_page/internet_subpage.html",
-      "chromeos/internet_page/internet_subpage.js",
-      "chromeos/internet_page/network_proxy_section.html",
-      "chromeos/internet_page/network_proxy_section.js",
-      "chromeos/internet_page/network_summary.html",
-      "chromeos/internet_page/network_summary.js",
-      "chromeos/internet_page/network_summary_item.html",
-      "chromeos/internet_page/network_summary_item.js",
-      "chromeos/internet_page/tether_connection_dialog.html",
-      "chromeos/internet_page/tether_connection_dialog.js",
-      "chromeos/lazy_load.html",
-      "chromeos/localized_link/localized_link.html",
-      "chromeos/localized_link/localized_link.js",
-      "chromeos/metrics_recorder.html",
-      "chromeos/metrics_recorder.js",
-      "chromeos/multidevice_page/multidevice_browser_proxy.html",
-      "chromeos/multidevice_page/multidevice_browser_proxy.js",
-      "chromeos/multidevice_page/multidevice_constants.html",
-      "chromeos/multidevice_page/multidevice_constants.js",
-      "chromeos/multidevice_page/multidevice_feature_behavior.html",
-      "chromeos/multidevice_page/multidevice_feature_behavior.js",
-      "chromeos/multidevice_page/multidevice_feature_item.html",
-      "chromeos/multidevice_page/multidevice_feature_item.js",
-      "chromeos/multidevice_page/multidevice_feature_toggle.html",
-      "chromeos/multidevice_page/multidevice_feature_toggle.js",
-      "chromeos/multidevice_page/multidevice_notification_access_setup_dialog.html",
-      "chromeos/multidevice_page/multidevice_notification_access_setup_dialog.js",
-      "chromeos/multidevice_page/multidevice_page.html",
-      "chromeos/multidevice_page/multidevice_page.js",
-      "chromeos/multidevice_page/multidevice_radio_button.html",
-      "chromeos/multidevice_page/multidevice_radio_button.js",
-      "chromeos/multidevice_page/multidevice_smartlock_subpage.html",
-      "chromeos/multidevice_page/multidevice_smartlock_subpage.js",
-      "chromeos/multidevice_page/multidevice_subpage.html",
-      "chromeos/multidevice_page/multidevice_subpage.js",
-      "chromeos/multidevice_page/multidevice_tether_item.html",
-      "chromeos/multidevice_page/multidevice_tether_item.js",
-      "chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.html",
-      "chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.js",
-      "chromeos/multidevice_page/multidevice_wifi_sync_item.html",
-      "chromeos/multidevice_page/multidevice_wifi_sync_item.js",
-      "chromeos/nearby_share_page/nearby_account_manager_browser_proxy.html",
-      "chromeos/nearby_share_page/nearby_account_manager_browser_proxy.js",
-      "chromeos/nearby_share_page/nearby_share_confirm_page.html",
-      "chromeos/nearby_share_page/nearby_share_confirm_page.js",
-      "chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.html",
-      "chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.js",
-      "chromeos/nearby_share_page/nearby_share_data_usage_dialog.html",
-      "chromeos/nearby_share_page/nearby_share_data_usage_dialog.js",
-      "chromeos/nearby_share_page/nearby_share_device_name_dialog.html",
-      "chromeos/nearby_share_page/nearby_share_device_name_dialog.js",
-      "chromeos/nearby_share_page/nearby_share_high_visibility_page.html",
-      "chromeos/nearby_share_page/nearby_share_high_visibility_page.js",
-      "chromeos/nearby_share_page/nearby_share_receive_dialog.html",
-      "chromeos/nearby_share_page/nearby_share_receive_dialog.js",
-      "chromeos/nearby_share_page/nearby_share_receive_manager.html",
-      "chromeos/nearby_share_page/nearby_share_receive_manager.js",
-      "chromeos/nearby_share_page/nearby_share_subpage.html",
-      "chromeos/nearby_share_page/nearby_share_subpage.js",
-      "chromeos/nearby_share_page/types.html",
-      "chromeos/nearby_share_page/types.js",
-      "chromeos/os_a11y_page/manage_a11y_page.html",
-      "chromeos/os_a11y_page/manage_a11y_page.js",
-      "chromeos/os_a11y_page/manage_a11y_page_browser_proxy.html",
-      "chromeos/os_a11y_page/manage_a11y_page_browser_proxy.js",
-      "chromeos/os_a11y_page/os_a11y_page.html",
-      "chromeos/os_a11y_page/os_a11y_page.js",
-      "chromeos/os_a11y_page/os_a11y_page_browser_proxy.html",
-      "chromeos/os_a11y_page/os_a11y_page_browser_proxy.js",
-      "chromeos/os_a11y_page/switch_access_action_assignment_dialog.html",
-      "chromeos/os_a11y_page/switch_access_action_assignment_dialog.js",
-      "chromeos/os_a11y_page/switch_access_constants.html",
-      "chromeos/os_a11y_page/switch_access_constants.js",
-      "chromeos/os_a11y_page/switch_access_subpage.html",
-      "chromeos/os_a11y_page/switch_access_subpage.js",
-      "chromeos/os_a11y_page/switch_access_subpage_browser_proxy.html",
-      "chromeos/os_a11y_page/switch_access_subpage_browser_proxy.js",
-      "chromeos/os_a11y_page/tts_subpage.html",
-      "chromeos/os_a11y_page/tts_subpage.js",
-      "chromeos/os_a11y_page/tts_subpage_browser_proxy.html",
-      "chromeos/os_a11y_page/tts_subpage_browser_proxy.js",
-      "chromeos/os_about_page/channel_switcher_dialog.html",
-      "chromeos/os_about_page/channel_switcher_dialog.js",
-      "chromeos/os_about_page/detailed_build_info.html",
-      "chromeos/os_about_page/detailed_build_info.js",
-      "chromeos/os_about_page/edit_hostname_dialog.html",
-      "chromeos/os_about_page/edit_hostname_dialog.js",
-      "chromeos/os_about_page/os_about_page.html",
-      "chromeos/os_about_page/os_about_page.js",
-      "chromeos/os_about_page/update_warning_dialog.html",
-      "chromeos/os_about_page/update_warning_dialog.js",
-      "chromeos/os_apps_page/android_apps_browser_proxy.html",
-      "chromeos/os_apps_page/android_apps_browser_proxy.js",
-      "chromeos/os_apps_page/android_apps_subpage.html",
-      "chromeos/os_apps_page/android_apps_subpage.js",
-      "chromeos/os_apps_page/app_management_page/actions.html",
-      "chromeos/os_apps_page/app_management_page/actions.js",
-      "chromeos/os_apps_page/app_management_page/api_listener.html",
-      "chromeos/os_apps_page/app_management_page/api_listener.js",
-      "chromeos/os_apps_page/app_management_page/app_detail_view.html",
-      "chromeos/os_apps_page/app_management_page/app_detail_view.js",
-      "chromeos/os_apps_page/app_management_page/app_item.html",
-      "chromeos/os_apps_page/app_management_page/app_item.js",
-      "chromeos/os_apps_page/app_management_page/app_management_page.html",
-      "chromeos/os_apps_page/app_management_page/app_management_page.js",
-      "chromeos/os_apps_page/app_management_page/arc_detail_view.html",
-      "chromeos/os_apps_page/app_management_page/arc_detail_view.js",
-      "chromeos/os_apps_page/app_management_page/browser_proxy.html",
-      "chromeos/os_apps_page/app_management_page/browser_proxy.js",
-      "chromeos/os_apps_page/app_management_page/chrome_app_detail_view.html",
-      "chromeos/os_apps_page/app_management_page/chrome_app_detail_view.js",
-      "chromeos/os_apps_page/app_management_page/constants.html",
-      "chromeos/os_apps_page/app_management_page/constants.js",
-      "chromeos/os_apps_page/app_management_page/dom_switch.html",
-      "chromeos/os_apps_page/app_management_page/dom_switch.js",
-      "chromeos/os_apps_page/app_management_page/fake_page_handler.js",
-      "chromeos/os_apps_page/app_management_page/icons.html",
-      "chromeos/os_apps_page/app_management_page/main_view.html",
-      "chromeos/os_apps_page/app_management_page/main_view.js",
-      "chromeos/os_apps_page/app_management_page/permission_item.html",
-      "chromeos/os_apps_page/app_management_page/permission_item.js",
-      "chromeos/os_apps_page/app_management_page/pin_to_shelf_item.html",
-      "chromeos/os_apps_page/app_management_page/pin_to_shelf_item.js",
-      "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_browser_proxy.html",
-      "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_browser_proxy.js",
-      "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_detail_view.html",
-      "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_detail_view.js",
-      "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_paths.html",
-      "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_paths.js",
-      "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_usb_devices.html",
-      "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_usb_devices.js",
-      "chromeos/os_apps_page/app_management_page/pwa_detail_view.html",
-      "chromeos/os_apps_page/app_management_page/pwa_detail_view.js",
-      "chromeos/os_apps_page/app_management_page/reducers.html",
-      "chromeos/os_apps_page/app_management_page/reducers.js",
-      "chromeos/os_apps_page/app_management_page/shared_style.html",
-      "chromeos/os_apps_page/app_management_page/shared_vars.html",
-      "chromeos/os_apps_page/app_management_page/store.html",
-      "chromeos/os_apps_page/app_management_page/store.js",
-      "chromeos/os_apps_page/app_management_page/store_client.html",
-      "chromeos/os_apps_page/app_management_page/store_client.js",
-      "chromeos/os_apps_page/app_management_page/toggle_row.html",
-      "chromeos/os_apps_page/app_management_page/toggle_row.js",
-      "chromeos/os_apps_page/app_management_page/types.js",
-      "chromeos/os_apps_page/app_management_page/uninstall_button.html",
-      "chromeos/os_apps_page/app_management_page/uninstall_button.js",
-      "chromeos/os_apps_page/app_management_page/util.html",
-      "chromeos/os_apps_page/app_management_page/util.js",
-      "chromeos/os_apps_page/os_apps_page.html",
-      "chromeos/os_apps_page/os_apps_page.js",
-      "chromeos/os_files_page/os_files_page.html",
-      "chromeos/os_files_page/os_files_page.js",
-      "chromeos/os_files_page/smb_shares_page.html",
-      "chromeos/os_files_page/smb_shares_page.js",
-      "chromeos/os_icons.html",
-      "chromeos/os_languages_page/add_input_methods_dialog.html",
-      "chromeos/os_languages_page/add_input_methods_dialog.js",
-      "chromeos/os_languages_page/change_device_language_dialog.html",
-      "chromeos/os_languages_page/change_device_language_dialog.js",
-      "chromeos/os_languages_page/input_method_options_page.html",
-      "chromeos/os_languages_page/input_method_options_page.js",
-      "chromeos/os_languages_page/input_method_util.html",
-      "chromeos/os_languages_page/input_method_util.js",
-      "chromeos/os_languages_page/input_page.html",
-      "chromeos/os_languages_page/input_page.js",
-      "chromeos/os_languages_page/languages_metrics_proxy.html",
-      "chromeos/os_languages_page/languages_metrics_proxy.js",
-      "chromeos/os_languages_page/manage_input_methods_page.html",
-      "chromeos/os_languages_page/manage_input_methods_page.js",
-      "chromeos/os_languages_page/os_add_languages_dialog.html",
-      "chromeos/os_languages_page/os_add_languages_dialog.js",
-      "chromeos/os_languages_page/os_edit_dictionary_page.html",
-      "chromeos/os_languages_page/os_edit_dictionary_page.js",
-      "chromeos/os_languages_page/os_languages_page.html",
-      "chromeos/os_languages_page/os_languages_page.js",
-      "chromeos/os_languages_page/os_languages_page_v2.html",
-      "chromeos/os_languages_page/os_languages_page_v2.js",
-      "chromeos/os_languages_page/os_languages_section.html",
-      "chromeos/os_languages_page/os_languages_section.js",
-      "chromeos/os_languages_page/shared_style.html",
-      "chromeos/os_languages_page/shared_vars.html",
-      "chromeos/os_languages_page/smart_inputs_page.html",
-      "chromeos/os_languages_page/smart_inputs_page.js",
-      "chromeos/os_page_visibility.html",
-      "chromeos/os_page_visibility.js",
-      "chromeos/os_people_page/account_manager.html",
-      "chromeos/os_people_page/account_manager.js",
-      "chromeos/os_people_page/fingerprint_browser_proxy.html",
-      "chromeos/os_people_page/fingerprint_browser_proxy.js",
-      "chromeos/os_people_page/fingerprint_list.html",
-      "chromeos/os_people_page/fingerprint_list.js",
-      "chromeos/os_people_page/kerberos_accounts.html",
-      "chromeos/os_people_page/kerberos_accounts.js",
-      "chromeos/os_people_page/kerberos_accounts_browser_proxy.html",
-      "chromeos/os_people_page/kerberos_accounts_browser_proxy.js",
-      "chromeos/os_people_page/kerberos_add_account_dialog.html",
-      "chromeos/os_people_page/kerberos_add_account_dialog.js",
-      "chromeos/os_people_page/lock_screen.html",
-      "chromeos/os_people_page/lock_screen.js",
-      "chromeos/os_people_page/lock_screen_password_prompt_dialog.html",
-      "chromeos/os_people_page/lock_screen_password_prompt_dialog.js",
-      "chromeos/os_people_page/lock_state_behavior.html",
-      "chromeos/os_people_page/lock_state_behavior.js",
-      "chromeos/os_people_page/os_people_page.html",
-      "chromeos/os_people_page/os_people_page.js",
-      "chromeos/os_people_page/os_sync_browser_proxy.html",
-      "chromeos/os_people_page/os_sync_browser_proxy.js",
-      "chromeos/os_people_page/os_sync_controls.html",
-      "chromeos/os_people_page/os_sync_controls.js",
-      "chromeos/os_people_page/pin_autosubmit_dialog.html",
-      "chromeos/os_people_page/pin_autosubmit_dialog.js",
-      "chromeos/os_people_page/setup_fingerprint_dialog.html",
-      "chromeos/os_people_page/setup_fingerprint_dialog.js",
-      "chromeos/os_people_page/setup_pin_dialog.html",
-      "chromeos/os_people_page/setup_pin_dialog.js",
-      "chromeos/os_people_page/user_list.html",
-      "chromeos/os_people_page/user_list.js",
-      "chromeos/os_people_page/users_add_user_dialog.html",
-      "chromeos/os_people_page/users_add_user_dialog.js",
-      "chromeos/os_people_page/users_page.html",
-      "chromeos/os_people_page/users_page.js",
-      "chromeos/os_printing_page/cups_add_print_server_dialog.html",
-      "chromeos/os_printing_page/cups_add_print_server_dialog.js",
-      "chromeos/os_printing_page/cups_add_printer_dialog.html",
-      "chromeos/os_printing_page/cups_add_printer_dialog.js",
-      "chromeos/os_printing_page/cups_add_printer_manually_dialog.html",
-      "chromeos/os_printing_page/cups_add_printer_manually_dialog.js",
-      "chromeos/os_printing_page/cups_add_printer_manufacturer_model_dialog.html",
-      "chromeos/os_printing_page/cups_add_printer_manufacturer_model_dialog.js",
-      "chromeos/os_printing_page/cups_edit_printer_dialog.html",
-      "chromeos/os_printing_page/cups_edit_printer_dialog.js",
-      "chromeos/os_printing_page/cups_nearby_printers.html",
-      "chromeos/os_printing_page/cups_nearby_printers.js",
-      "chromeos/os_printing_page/cups_printer_dialog_error.html",
-      "chromeos/os_printing_page/cups_printer_dialog_error.js",
-      "chromeos/os_printing_page/cups_printer_dialog_util.html",
-      "chromeos/os_printing_page/cups_printer_dialog_util.js",
-      "chromeos/os_printing_page/cups_printer_shared_css.html",
-      "chromeos/os_printing_page/cups_printer_types.html",
-      "chromeos/os_printing_page/cups_printer_types.js",
-      "chromeos/os_printing_page/cups_printers.html",
-      "chromeos/os_printing_page/cups_printers.js",
-      "chromeos/os_printing_page/cups_printers_browser_proxy.html",
-      "chromeos/os_printing_page/cups_printers_browser_proxy.js",
-      "chromeos/os_printing_page/cups_printers_entry.html",
-      "chromeos/os_printing_page/cups_printers_entry.js",
-      "chromeos/os_printing_page/cups_printers_entry_list_behavior.html",
-      "chromeos/os_printing_page/cups_printers_entry_list_behavior.js",
-      "chromeos/os_printing_page/cups_printers_entry_manager.html",
-      "chromeos/os_printing_page/cups_printers_entry_manager.js",
-      "chromeos/os_printing_page/cups_saved_printers.html",
-      "chromeos/os_printing_page/cups_saved_printers.js",
-      "chromeos/os_printing_page/cups_settings_add_printer_dialog.html",
-      "chromeos/os_printing_page/cups_settings_add_printer_dialog.js",
-      "chromeos/os_printing_page/os_printing_page.html",
-      "chromeos/os_printing_page/os_printing_page.js",
-      "chromeos/os_privacy_page/os_privacy_page.html",
-      "chromeos/os_privacy_page/os_privacy_page.js",
-      "chromeos/os_reset_page/os_powerwash_dialog.html",
-      "chromeos/os_reset_page/os_powerwash_dialog.js",
-      "chromeos/os_reset_page/os_reset_browser_proxy.html",
-      "chromeos/os_reset_page/os_reset_browser_proxy.js",
-      "chromeos/os_reset_page/os_reset_page.html",
-      "chromeos/os_reset_page/os_reset_page.js",
-      "chromeos/os_route.html",
-      "chromeos/os_route.js",
-      "chromeos/os_search_page/os_search_page.html",
-      "chromeos/os_search_page/os_search_page.js",
-      "chromeos/os_search_page/os_search_selection_dialog.html",
-      "chromeos/os_search_page/os_search_selection_dialog.js",
-      "chromeos/os_settings.html",
-      "chromeos/os_settings_icons_css.html",
-      "chromeos/os_settings_main/os_settings_main.html",
-      "chromeos/os_settings_main/os_settings_main.js",
-      "chromeos/os_settings_menu/os_settings_menu.html",
-      "chromeos/os_settings_menu/os_settings_menu.js",
-      "chromeos/os_settings_page/main_page_behavior.html",
-      "chromeos/os_settings_page/main_page_behavior.js",
-      "chromeos/os_settings_page/os_settings_page.html",
-      "chromeos/os_settings_page/os_settings_page.js",
-      "chromeos/os_settings_page/settings_idle_load.html",
-      "chromeos/os_settings_page/settings_idle_load.js",
-      "chromeos/os_settings_routes.html",
-      "chromeos/os_settings_routes.js",
-      "chromeos/os_settings_search_box/os_search_result_row.html",
-      "chromeos/os_settings_search_box/os_search_result_row.js",
-      "chromeos/os_settings_search_box/os_settings_search_box.html",
-      "chromeos/os_settings_search_box/os_settings_search_box.js",
-      "chromeos/os_settings_ui/os_settings_ui.html",
-      "chromeos/os_settings_ui/os_settings_ui.js",
-      "chromeos/os_toolbar/os_toolbar.html",
-      "chromeos/os_toolbar/os_toolbar.js",
-      "chromeos/parental_controls_page/parental_controls_browser_proxy.html",
-      "chromeos/parental_controls_page/parental_controls_browser_proxy.js",
-      "chromeos/parental_controls_page/parental_controls_page.html",
-      "chromeos/parental_controls_page/parental_controls_page.js",
-      "chromeos/personalization_page/change_picture.html",
-      "chromeos/personalization_page/change_picture.js",
-      "chromeos/personalization_page/change_picture_browser_proxy.html",
-      "chromeos/personalization_page/change_picture_browser_proxy.js",
-      "chromeos/personalization_page/personalization_page.html",
-      "chromeos/personalization_page/personalization_page.js",
-      "chromeos/personalization_page/wallpaper_browser_proxy.html",
-      "chromeos/personalization_page/wallpaper_browser_proxy.js",
-      "chromeos/pref_to_setting_metric_converter.html",
-      "chromeos/pref_to_setting_metric_converter.js",
-      "chromeos/route_origin_behavior.html",
-      "chromeos/route_origin_behavior.js",
-      "chromeos/search_handler.html",
-      "chromeos/search_handler.js",
-      "controls/controlled_button.html",
-      "controls/controlled_button.js",
-      "controls/controlled_radio_button.html",
-      "controls/controlled_radio_button.js",
-      "controls/extension_controlled_indicator.html",
-      "controls/extension_controlled_indicator.js",
-      "controls/password_prompt_dialog.html",
-      "controls/password_prompt_dialog.js",
-      "controls/pref_control_behavior.html",
-      "controls/pref_control_behavior.js",
-      "controls/settings_boolean_control_behavior.html",
-      "controls/settings_boolean_control_behavior.js",
-      "controls/settings_dropdown_menu.html",
-      "controls/settings_dropdown_menu.js",
-      "controls/settings_radio_group.html",
-      "controls/settings_radio_group.js",
-      "controls/settings_slider.html",
-      "controls/settings_slider.js",
-      "controls/settings_textarea.html",
-      "controls/settings_textarea.js",
-      "controls/settings_toggle_button.html",
-      "controls/settings_toggle_button.js",
-      "extension_control_browser_proxy.html",
-      "extension_control_browser_proxy.js",
-      "global_scroll_target_behavior.html",
-      "global_scroll_target_behavior.js",
-      "i18n_setup.html",
-      "icons.html",
-      "languages_page/languages.html",
-      "languages_page/languages.js",
-      "languages_page/languages_browser_proxy.html",
-      "languages_page/languages_browser_proxy.js",
-      "lifetime_browser_proxy.html",
-      "lifetime_browser_proxy.js",
-      "people_page/account_manager_browser_proxy.html",
-      "people_page/account_manager_browser_proxy.js",
-      "people_page/profile_info_browser_proxy.html",
-      "people_page/profile_info_browser_proxy.js",
-      "people_page/signout_dialog.html",
-      "people_page/signout_dialog.js",
-      "people_page/sync_account_control.html",
-      "people_page/sync_account_control.js",
-      "people_page/sync_browser_proxy.html",
-      "people_page/sync_browser_proxy.js",
-      "people_page/sync_controls.html",
-      "people_page/sync_controls.js",
-      "people_page/sync_encryption_options.html",
-      "people_page/sync_encryption_options.js",
-      "people_page/sync_page.html",
-      "people_page/sync_page.js",
-      "prefs/pref_util.html",
-      "prefs/pref_util.js",
-      "prefs/prefs.html",
-      "prefs/prefs.js",
-      "prefs/prefs_behavior.html",
-      "prefs/prefs_behavior.js",
-      "prefs/prefs_types.html",
-      "prefs/prefs_types.js",
-      "privacy_page/personalization_options.html",
-      "privacy_page/personalization_options.js",
-      "privacy_page/privacy_page_browser_proxy.html",
-      "privacy_page/privacy_page_browser_proxy.js",
-      "router.html",
-      "router.js",
-      "search_engines_page/search_engines_browser_proxy.html",
-      "search_engines_page/search_engines_browser_proxy.js",
-      "search_settings.html",
-      "search_settings.js",
-      "setting_id_param_util.html",
-      "setting_id_param_util.js",
-      "settings_page/settings_animated_pages.html",
-      "settings_page/settings_animated_pages.js",
-      "settings_page/settings_section.html",
-      "settings_page/settings_section.js",
-      "settings_page/settings_subpage.html",
-      "settings_page/settings_subpage.js",
-      "settings_page_css.html",
-      "settings_shared_css.html",
-      "settings_vars_css.html",
-    ]
-  }
+# Mojo files generated by non-OS-settings targets, not bundled.
+preprocess_grit("preprocess_external_mojo") {
+  deps = [
+    "//chrome/browser/ui/webui/app_management:mojo_bindings_js",
+    "//components/services/app_service/public/mojom:mojom_js",
+    "//mojo/public/mojom/base",
+    "//ui/gfx/image/mojom:mojom_js",
+  ]
+  in_folder = "$root_gen_dir"
 
-  preprocess_grit("preprocess_nearby_v2") {
-    in_folder = "../../nearby_share/shared/"
-    out_folder = "$target_gen_dir/$preprocess_folder_v2/shared"
-    in_files = [
-      "nearby_contact_manager.html",
-      "nearby_contact_manager.js",
-      "nearby_contact_visibility.html",
-      "nearby_contact_visibility.js",
-      "nearby_onboarding_page.html",
-      "nearby_onboarding_page.js",
-      "nearby_page_template.html",
-      "nearby_page_template.js",
-      "nearby_share_settings.html",
-      "nearby_share_settings.js",
-      "nearby_share_settings_behavior.html",
-      "nearby_share_settings_behavior.js",
-      "nearby_shared_icons.html",
-      "nearby_visibility_page.html",
-      "nearby_visibility_page.js",
-    ]
-  }
+  # It does not matter which preprocess folder these files are pasted into, as
+  # they are not used for bundling; the purpose of this build rule is to
+  # include them in the generated grd file.
+  out_folder = "$target_gen_dir/$preprocess_folder_v3"
+  out_manifest = "$target_gen_dir/$preprocess_external_mojo_manifest"
+  in_files = [
+    "mojo/public/mojom/base/file_path.mojom-lite.js",
+    "ui/gfx/image/mojom/image.mojom-lite.js",
+    "chrome/browser/ui/webui/app_management/app_management.mojom-lite.js",
+    "components/services/app_service/public/mojom/types.mojom-lite.js",
+  ]
+}
 
-  preprocess_grit("preprocess_nearby_v3") {
-    deps =
-        [ "//chrome/browser/resources/nearby_share/shared:polymer3_elements" ]
-    in_folder = get_path_info("../../nearby_share/shared/", "gen_dir")
-    out_folder = "$target_gen_dir/$preprocess_folder_v3/shared"
-    in_files = [
-      "nearby_contact_manager.m.js",
-      "nearby_contact_visibility.m.js",
-      "nearby_onboarding_page.m.js",
-      "nearby_page_template.m.js",
-      "nearby_share_settings.m.js",
-      "nearby_share_settings_behavior.m.js",
-      "nearby_shared_icons.m.js",
-      "nearby_visibility_page.m.js",
+grit("os_settings_resources") {
+  grit_flags = [
+    "-E",
+    "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
+    "-E",
+    "root_src_dir=" + rebase_path("//", root_build_dir),
+  ]
+
+  defines = chrome_grit_defines
+
+  # These arguments are needed since the grd is generated at build time.
+  enable_input_discovery_for_gn_analyze = false
+  defines +=
+      [ "SHARED_INTERMEDIATE_DIR=" + rebase_path(root_gen_dir, root_build_dir) ]
+  source = "$target_gen_dir/os_settings_resources.grd"
+  deps = [ ":build_grd" ]
+
+  outputs = [
+    "grit/os_settings_resources.h",
+    "grit/os_settings_resources_map.cc",
+    "grit/os_settings_resources_map.h",
+    "os_settings_resources.pak",
+  ]
+  output_dir = "$root_gen_dir/chrome"
+}
+
+generate_grd("build_grd") {
+  grd_prefix = "os_settings"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+  input_files = [
+    "os_settings_v3.html",
+    "images/icon_add_circle.svg",
+    "images/icon_add_wifi.svg",
+    "images/icon_add_cellular.svg",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+  deps = [ ":preprocess_external_mojo" ]
+  manifest_files = [ "$target_gen_dir/$preprocess_external_mojo_manifest" ]
+  resource_path_rewrites = [
+    "os_settings_v3.html|chromeos/os_settings_v3.html",
+    "mojo/public/mojom/base/file_path.mojom-lite.js|app-management/file_path.mojom-lite.js",
+    "ui/gfx/image/mojom/image.mojom-lite.js|app-management/image.mojom-lite.js",
+    "chrome/browser/ui/webui/app_management/app_management.mojom-lite.js|app-management/app_management.mojom-lite.js",
+    "components/services/app_service/public/mojom/types.mojom-lite.js|app-management/types.mojom-lite.js",
+  ]
+
+  if (optimize_webui) {
+    deps += [
+      ":build",
+      ":build_polymer3",
     ]
+    manifest_files += [
+      "$target_gen_dir/$build_manifest_v2",
+      "$target_gen_dir/$build_manifest_v3",
+    ]
+    input_files += [ "../../nearby_share/shared/nearby_shared_icons.html" ]
+    resource_path_rewrites += [
+      "../../nearby_share/shared/nearby_shared_icons.html|shared/nearby_shared_icons.html",
+      "lazy_load.vulcanized.html|chromeos/lazy_load.html",
+      "os_settings.rollup.js|chromeos/os_settings.js",
+      "shared.rollup.js|chromeos/shared.rollup.js",
+      "lazy_load.rollup.js|chromeos/lazy_load.js",
+    ]
+  } else {
+    deps += [
+      ":preprocess_gen_v3",
+      ":preprocess_mojo_v3",
+      ":preprocess_nearby_v2",
+      ":preprocess_nearby_v3",
+      ":preprocess_v2",
+      ":preprocess_v3",
+    ]
+    manifest_files += [
+      "$target_gen_dir/$preprocess_gen_v3_manifest",
+      "$target_gen_dir/$preprocess_nearby_v2_manifest",
+      "$target_gen_dir/$preprocess_nearby_v3_manifest",
+      "$target_gen_dir/$preprocess_v2_manifest",
+      "$target_gen_dir/$preprocess_v3_manifest",
+      "$target_gen_dir/$preprocess_mojo_manifest",
+    ]
+    resource_path_rewrites += [ "chromeos/os_settings.html|os_settings.html" ]
   }
 }
 
+preprocess_grit("preprocess_v3") {
+  defines = chrome_grit_defines
+  in_folder = "../"
+  out_folder = "$target_gen_dir/$preprocess_folder_v3"
+  out_manifest = "$target_gen_dir/$preprocess_v3_manifest"
+  in_files = [
+    "chromeos/ensure_lazy_loaded.m.js",
+    "chromeos/lazy_load.js",
+    "chromeos/os_settings.js",
+    "i18n_setup.js",
+    "page_visibility.js",
+  ]
+}
+
+preprocess_grit("preprocess_gen_v3") {
+  defines = chrome_grit_defines
+  deps = [ ":polymer3_elements" ]
+  in_folder = get_path_info("../", "gen_dir")
+  out_folder = "$target_gen_dir/$preprocess_folder_v3"
+  out_manifest = "$target_gen_dir/$preprocess_gen_v3_manifest"
+  in_files = [
+    "about_page/about_page_browser_proxy.m.js",
+    "chromeos/ambient_mode_page/album_item.m.js",
+    "chromeos/ambient_mode_page/album_list.m.js",
+    "chromeos/ambient_mode_page/ambient_mode_browser_proxy.m.js",
+    "chromeos/ambient_mode_page/ambient_mode_page.m.js",
+    "chromeos/ambient_mode_page/ambient_mode_photos_page.m.js",
+    "chromeos/ambient_mode_page/constants.m.js",
+    "chromeos/ambient_mode_page/topic_source_item.m.js",
+    "chromeos/ambient_mode_page/topic_source_list.m.js",
+    "chromeos/bluetooth_page/bluetooth_device_list_item.m.js",
+    "chromeos/bluetooth_page/bluetooth_page.m.js",
+    "chromeos/bluetooth_page/bluetooth_subpage.m.js",
+    "chromeos/date_time_page/date_time_page.m.js",
+    "chromeos/date_time_page/date_time_types.m.js",
+    "chromeos/date_time_page/timezone_browser_proxy.m.js",
+    "chromeos/date_time_page/timezone_selector.m.js",
+    "chromeos/date_time_page/timezone_subpage.m.js",
+    "chromeos/deep_linking_behavior.m.js",
+    "chromeos/google_assistant_page/google_assistant_browser_proxy.m.js",
+    "chromeos/google_assistant_page/google_assistant_page.m.js",
+    "chromeos/internet_page/cellular_setup_dialog.m.js",
+    "chromeos/internet_page/cellular_setup_settings_delegate.m.js",
+    "chromeos/internet_page/internet_config.m.js",
+    "chromeos/internet_page/internet_detail_menu.m.js",
+    "chromeos/internet_page/internet_detail_page.m.js",
+    "chromeos/internet_page/internet_known_networks_page.m.js",
+    "chromeos/internet_page/internet_page.m.js",
+    "chromeos/internet_page/internet_page_browser_proxy.m.js",
+    "chromeos/internet_page/internet_shared_css.m.js",
+    "chromeos/internet_page/internet_subpage.m.js",
+    "chromeos/internet_page/network_proxy_section.m.js",
+    "chromeos/internet_page/network_summary.m.js",
+    "chromeos/internet_page/network_summary_item.m.js",
+    "chromeos/internet_page/tether_connection_dialog.m.js",
+    "chromeos/localized_link/localized_link.m.js",
+    "chromeos/metrics_recorder.m.js",
+    "chromeos/multidevice_page/multidevice_browser_proxy.m.js",
+    "chromeos/multidevice_page/multidevice_constants.m.js",
+    "chromeos/multidevice_page/multidevice_feature_behavior.m.js",
+    "chromeos/multidevice_page/multidevice_feature_item.m.js",
+    "chromeos/multidevice_page/multidevice_feature_toggle.m.js",
+    "chromeos/multidevice_page/multidevice_notification_access_setup_dialog.m.js",
+    "chromeos/multidevice_page/multidevice_page.m.js",
+    "chromeos/multidevice_page/multidevice_radio_button.m.js",
+    "chromeos/multidevice_page/multidevice_smartlock_subpage.m.js",
+    "chromeos/multidevice_page/multidevice_subpage.m.js",
+    "chromeos/multidevice_page/multidevice_tether_item.m.js",
+    "chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.m.js",
+    "chromeos/multidevice_page/multidevice_wifi_sync_item.m.js",
+    "chromeos/nearby_share_page/nearby_account_manager_browser_proxy.m.js",
+    "chromeos/nearby_share_page/nearby_share_confirm_page.m.js",
+    "chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.m.js",
+    "chromeos/nearby_share_page/nearby_share_data_usage_dialog.m.js",
+    "chromeos/nearby_share_page/nearby_share_device_name_dialog.m.js",
+    "chromeos/nearby_share_page/nearby_share_high_visibility_page.m.js",
+    "chromeos/nearby_share_page/nearby_share_receive_dialog.m.js",
+    "chromeos/nearby_share_page/nearby_share_receive_manager.m.js",
+    "chromeos/nearby_share_page/nearby_share_subpage.m.js",
+    "chromeos/nearby_share_page/types.m.js",
+    "chromeos/os_about_page/channel_switcher_dialog.m.js",
+    "chromeos/os_about_page/detailed_build_info.m.js",
+    "chromeos/os_about_page/edit_hostname_dialog.m.js",
+    "chromeos/os_about_page/os_about_page.m.js",
+    "chromeos/os_about_page/update_warning_dialog.m.js",
+    "chromeos/os_files_page/os_files_page.m.js",
+    "chromeos/os_files_page/smb_shares_page.m.js",
+    "chromeos/os_icons.m.js",
+    "chromeos/os_languages_page/add_input_methods_dialog.m.js",
+    "chromeos/os_languages_page/change_device_language_dialog.m.js",
+    "chromeos/os_languages_page/input_method_options_page.m.js",
+    "chromeos/os_languages_page/input_method_util.m.js",
+    "chromeos/os_languages_page/input_page.m.js",
+    "chromeos/os_languages_page/languages_metrics_proxy.m.js",
+    "chromeos/os_languages_page/manage_input_methods_page.m.js",
+    "chromeos/os_languages_page/os_add_languages_dialog.m.js",
+    "chromeos/os_languages_page/os_edit_dictionary_page.m.js",
+    "chromeos/os_languages_page/os_languages_page.m.js",
+    "chromeos/os_languages_page/os_languages_page_v2.m.js",
+    "chromeos/os_languages_page/os_languages_section.m.js",
+    "chromeos/os_languages_page/shared_style.m.js",
+    "chromeos/os_languages_page/shared_vars.m.js",
+    "chromeos/os_languages_page/smart_inputs_page.m.js",
+    "chromeos/os_page_visibility.m.js",
+    "chromeos/os_people_page/account_manager.m.js",
+    "chromeos/os_people_page/fingerprint_browser_proxy.m.js",
+    "chromeos/os_people_page/fingerprint_list.m.js",
+    "chromeos/os_people_page/kerberos_accounts.m.js",
+    "chromeos/os_people_page/kerberos_accounts_browser_proxy.m.js",
+    "chromeos/os_people_page/kerberos_add_account_dialog.m.js",
+    "chromeos/os_people_page/lock_screen.m.js",
+    "chromeos/os_people_page/lock_screen_password_prompt_dialog.m.js",
+    "chromeos/os_people_page/lock_state_behavior.m.js",
+    "chromeos/os_people_page/os_people_page.m.js",
+    "chromeos/os_people_page/os_sync_browser_proxy.m.js",
+    "chromeos/os_people_page/os_sync_controls.m.js",
+    "chromeos/os_people_page/pin_autosubmit_dialog.m.js",
+    "chromeos/os_people_page/setup_fingerprint_dialog.m.js",
+    "chromeos/os_people_page/setup_pin_dialog.m.js",
+    "chromeos/os_people_page/user_list.m.js",
+    "chromeos/os_people_page/users_add_user_dialog.m.js",
+    "chromeos/os_people_page/users_page.m.js",
+    "chromeos/os_printing_page/cups_add_print_server_dialog.m.js",
+    "chromeos/os_printing_page/cups_add_printer_dialog.m.js",
+    "chromeos/os_printing_page/cups_add_printer_manually_dialog.m.js",
+    "chromeos/os_printing_page/cups_add_printer_manufacturer_model_dialog.m.js",
+    "chromeos/os_printing_page/cups_edit_printer_dialog.m.js",
+    "chromeos/os_printing_page/cups_nearby_printers.m.js",
+    "chromeos/os_printing_page/cups_printer_dialog_error.m.js",
+    "chromeos/os_printing_page/cups_printer_dialog_util.m.js",
+    "chromeos/os_printing_page/cups_printer_shared_css.m.js",
+    "chromeos/os_printing_page/cups_printer_types.m.js",
+    "chromeos/os_printing_page/cups_printers.m.js",
+    "chromeos/os_printing_page/cups_printers_browser_proxy.m.js",
+    "chromeos/os_printing_page/cups_printers_entry.m.js",
+    "chromeos/os_printing_page/cups_printers_entry_list_behavior.m.js",
+    "chromeos/os_printing_page/cups_printers_entry_manager.m.js",
+    "chromeos/os_printing_page/cups_saved_printers.m.js",
+    "chromeos/os_printing_page/cups_settings_add_printer_dialog.m.js",
+    "chromeos/os_printing_page/os_printing_page.m.js",
+    "chromeos/os_privacy_page/os_privacy_page.m.js",
+    "chromeos/os_reset_page/os_powerwash_dialog.m.js",
+    "chromeos/os_reset_page/os_reset_browser_proxy.m.js",
+    "chromeos/os_reset_page/os_reset_page.m.js",
+    "chromeos/os_route.m.js",
+    "chromeos/os_search_page/os_search_page.m.js",
+    "chromeos/os_search_page/os_search_selection_dialog.m.js",
+    "chromeos/os_settings_icons_css.m.js",
+    "chromeos/os_settings_page/main_page_behavior.m.js",
+    "chromeos/os_settings_routes.m.js",
+    "chromeos/parental_controls_page/parental_controls_browser_proxy.m.js",
+    "chromeos/parental_controls_page/parental_controls_page.m.js",
+    "chromeos/personalization_page/change_picture.m.js",
+    "chromeos/personalization_page/change_picture_browser_proxy.m.js",
+    "chromeos/personalization_page/personalization_page.m.js",
+    "chromeos/personalization_page/wallpaper_browser_proxy.m.js",
+    "chromeos/pref_to_setting_metric_converter.m.js",
+    "chromeos/route_origin_behavior.m.js",
+    "controls/controlled_button.m.js",
+    "controls/controlled_radio_button.m.js",
+    "controls/extension_controlled_indicator.m.js",
+    "controls/password_prompt_dialog.m.js",
+    "controls/pref_control_behavior.m.js",
+    "controls/settings_boolean_control_behavior.m.js",
+    "controls/settings_dropdown_menu.m.js",
+    "controls/settings_radio_group.m.js",
+    "controls/settings_textarea.m.js",
+    "controls/settings_toggle_button.m.js",
+    "extension_control_browser_proxy.m.js",
+    "global_scroll_target_behavior.m.js",
+    "icons.m.js",
+    "languages_page/languages.m.js",
+    "languages_page/languages_browser_proxy.m.js",
+    "lifetime_browser_proxy.m.js",
+    "people_page/account_manager_browser_proxy.m.js",
+    "people_page/profile_info_browser_proxy.m.js",
+    "people_page/signout_dialog.m.js",
+    "people_page/sync_account_control.m.js",
+    "people_page/sync_browser_proxy.m.js",
+    "people_page/sync_controls.m.js",
+    "people_page/sync_encryption_options.m.js",
+    "people_page/sync_page.m.js",
+    "prefs/pref_util.m.js",
+    "prefs/prefs.m.js",
+    "prefs/prefs_behavior.m.js",
+    "prefs/prefs_types.m.js",
+    "privacy_page/personalization_options.m.js",
+    "privacy_page/privacy_page_browser_proxy.m.js",
+    "router.m.js",
+    "search_engines_page/search_engines_browser_proxy.m.js",
+    "setting_id_param_util.m.js",
+    "settings_page/settings_animated_pages.m.js",
+    "settings_page/settings_section.m.js",
+    "settings_page/settings_subpage.m.js",
+    "settings_page_css.m.js",
+    "settings_shared_css.m.js",
+    "settings_vars_css.m.js",
+  ]
+}
+
+preprocess_grit("preprocess_v2") {
+  defines = chrome_grit_defines
+  in_folder = "../"
+  out_folder = "$target_gen_dir/$preprocess_folder_v2"
+  out_manifest = "$target_gen_dir/$preprocess_v2_manifest"
+  in_files = [
+    "a11y_page/captions_subpage.html",
+    "a11y_page/captions_subpage.js",
+    "about_page/about_page_browser_proxy.html",
+    "about_page/about_page_browser_proxy.js",
+    "appearance_page/fonts_browser_proxy.html",
+    "appearance_page/fonts_browser_proxy.js",
+    "chromeos/ambient_mode_page/album_item.html",
+    "chromeos/ambient_mode_page/album_item.js",
+    "chromeos/ambient_mode_page/album_list.html",
+    "chromeos/ambient_mode_page/album_list.js",
+    "chromeos/ambient_mode_page/ambient_mode_browser_proxy.html",
+    "chromeos/ambient_mode_page/ambient_mode_browser_proxy.js",
+    "chromeos/ambient_mode_page/ambient_mode_page.html",
+    "chromeos/ambient_mode_page/ambient_mode_page.js",
+    "chromeos/ambient_mode_page/ambient_mode_photos_page.html",
+    "chromeos/ambient_mode_page/ambient_mode_photos_page.js",
+    "chromeos/ambient_mode_page/constants.html",
+    "chromeos/ambient_mode_page/constants.js",
+    "chromeos/ambient_mode_page/topic_source_item.html",
+    "chromeos/ambient_mode_page/topic_source_item.js",
+    "chromeos/ambient_mode_page/topic_source_list.html",
+    "chromeos/ambient_mode_page/topic_source_list.js",
+    "chromeos/bluetooth_page/bluetooth_device_list_item.html",
+    "chromeos/bluetooth_page/bluetooth_device_list_item.js",
+    "chromeos/bluetooth_page/bluetooth_page.html",
+    "chromeos/bluetooth_page/bluetooth_page.js",
+    "chromeos/bluetooth_page/bluetooth_subpage.html",
+    "chromeos/bluetooth_page/bluetooth_subpage.js",
+    "chromeos/crostini_page/crostini_arc_adb.html",
+    "chromeos/crostini_page/crostini_arc_adb.js",
+    "chromeos/crostini_page/crostini_arc_adb_confirmation_dialog.html",
+    "chromeos/crostini_page/crostini_arc_adb_confirmation_dialog.js",
+    "chromeos/crostini_page/crostini_browser_proxy.html",
+    "chromeos/crostini_page/crostini_browser_proxy.js",
+    "chromeos/crostini_page/crostini_disk_resize_confirmation_dialog.html",
+    "chromeos/crostini_page/crostini_disk_resize_confirmation_dialog.js",
+    "chromeos/crostini_page/crostini_disk_resize_dialog.html",
+    "chromeos/crostini_page/crostini_disk_resize_dialog.js",
+    "chromeos/crostini_page/crostini_export_import.html",
+    "chromeos/crostini_page/crostini_export_import.js",
+    "chromeos/crostini_page/crostini_import_confirmation_dialog.html",
+    "chromeos/crostini_page/crostini_import_confirmation_dialog.js",
+    "chromeos/crostini_page/crostini_mic_sharing_dialog.html",
+    "chromeos/crostini_page/crostini_mic_sharing_dialog.js",
+    "chromeos/crostini_page/crostini_page.html",
+    "chromeos/crostini_page/crostini_page.js",
+    "chromeos/crostini_page/crostini_port_forwarding.html",
+    "chromeos/crostini_page/crostini_port_forwarding.js",
+    "chromeos/crostini_page/crostini_port_forwarding_add_port_dialog.html",
+    "chromeos/crostini_page/crostini_port_forwarding_add_port_dialog.js",
+    "chromeos/crostini_page/crostini_shared_paths.html",
+    "chromeos/crostini_page/crostini_shared_paths.js",
+    "chromeos/crostini_page/crostini_shared_usb_devices.html",
+    "chromeos/crostini_page/crostini_shared_usb_devices.js",
+    "chromeos/crostini_page/crostini_subpage.html",
+    "chromeos/crostini_page/crostini_subpage.js",
+    "chromeos/date_time_page/date_time_page.html",
+    "chromeos/date_time_page/date_time_page.js",
+    "chromeos/date_time_page/date_time_types.html",
+    "chromeos/date_time_page/date_time_types.js",
+    "chromeos/date_time_page/timezone_browser_proxy.html",
+    "chromeos/date_time_page/timezone_browser_proxy.js",
+    "chromeos/date_time_page/timezone_selector.html",
+    "chromeos/date_time_page/timezone_selector.js",
+    "chromeos/date_time_page/timezone_subpage.html",
+    "chromeos/date_time_page/timezone_subpage.js",
+    "chromeos/deep_linking_behavior.html",
+    "chromeos/deep_linking_behavior.js",
+    "chromeos/device_page/device_page.html",
+    "chromeos/device_page/device_page.js",
+    "chromeos/device_page/device_page_browser_proxy.html",
+    "chromeos/device_page/device_page_browser_proxy.js",
+    "chromeos/device_page/display.html",
+    "chromeos/device_page/display.js",
+    "chromeos/device_page/display_layout.html",
+    "chromeos/device_page/display_layout.js",
+    "chromeos/device_page/display_overscan_dialog.html",
+    "chromeos/device_page/display_overscan_dialog.js",
+    "chromeos/device_page/drag_behavior.html",
+    "chromeos/device_page/drag_behavior.js",
+    "chromeos/device_page/keyboard.html",
+    "chromeos/device_page/keyboard.js",
+    "chromeos/device_page/layout_behavior.html",
+    "chromeos/device_page/layout_behavior.js",
+    "chromeos/device_page/night_light_slider.html",
+    "chromeos/device_page/night_light_slider.js",
+    "chromeos/device_page/pointers.html",
+    "chromeos/device_page/pointers.js",
+    "chromeos/device_page/power.html",
+    "chromeos/device_page/power.js",
+    "chromeos/device_page/storage.html",
+    "chromeos/device_page/storage.js",
+    "chromeos/device_page/storage_external.html",
+    "chromeos/device_page/storage_external.js",
+    "chromeos/device_page/storage_external_entry.html",
+    "chromeos/device_page/storage_external_entry.js",
+    "chromeos/device_page/stylus.html",
+    "chromeos/device_page/stylus.js",
+    "chromeos/ensure_lazy_loaded.html",
+    "chromeos/google_assistant_page/google_assistant_browser_proxy.html",
+    "chromeos/google_assistant_page/google_assistant_browser_proxy.js",
+    "chromeos/google_assistant_page/google_assistant_page.html",
+    "chromeos/google_assistant_page/google_assistant_page.js",
+    "chromeos/internet_page/cellular_setup_dialog.html",
+    "chromeos/internet_page/cellular_setup_dialog.js",
+    "chromeos/internet_page/cellular_setup_settings_delegate.html",
+    "chromeos/internet_page/cellular_setup_settings_delegate.js",
+    "chromeos/internet_page/internet_config.html",
+    "chromeos/internet_page/internet_config.js",
+    "chromeos/internet_page/internet_detail_menu.html",
+    "chromeos/internet_page/internet_detail_menu.js",
+    "chromeos/internet_page/internet_detail_page.html",
+    "chromeos/internet_page/internet_detail_page.js",
+    "chromeos/internet_page/internet_known_networks_page.html",
+    "chromeos/internet_page/internet_known_networks_page.js",
+    "chromeos/internet_page/internet_page.html",
+    "chromeos/internet_page/internet_page.js",
+    "chromeos/internet_page/internet_page_browser_proxy.html",
+    "chromeos/internet_page/internet_page_browser_proxy.js",
+    "chromeos/internet_page/internet_shared_css.html",
+    "chromeos/internet_page/internet_subpage.html",
+    "chromeos/internet_page/internet_subpage.js",
+    "chromeos/internet_page/network_proxy_section.html",
+    "chromeos/internet_page/network_proxy_section.js",
+    "chromeos/internet_page/network_summary.html",
+    "chromeos/internet_page/network_summary.js",
+    "chromeos/internet_page/network_summary_item.html",
+    "chromeos/internet_page/network_summary_item.js",
+    "chromeos/internet_page/tether_connection_dialog.html",
+    "chromeos/internet_page/tether_connection_dialog.js",
+    "chromeos/lazy_load.html",
+    "chromeos/localized_link/localized_link.html",
+    "chromeos/localized_link/localized_link.js",
+    "chromeos/metrics_recorder.html",
+    "chromeos/metrics_recorder.js",
+    "chromeos/multidevice_page/multidevice_browser_proxy.html",
+    "chromeos/multidevice_page/multidevice_browser_proxy.js",
+    "chromeos/multidevice_page/multidevice_constants.html",
+    "chromeos/multidevice_page/multidevice_constants.js",
+    "chromeos/multidevice_page/multidevice_feature_behavior.html",
+    "chromeos/multidevice_page/multidevice_feature_behavior.js",
+    "chromeos/multidevice_page/multidevice_feature_item.html",
+    "chromeos/multidevice_page/multidevice_feature_item.js",
+    "chromeos/multidevice_page/multidevice_feature_toggle.html",
+    "chromeos/multidevice_page/multidevice_feature_toggle.js",
+    "chromeos/multidevice_page/multidevice_notification_access_setup_dialog.html",
+    "chromeos/multidevice_page/multidevice_notification_access_setup_dialog.js",
+    "chromeos/multidevice_page/multidevice_page.html",
+    "chromeos/multidevice_page/multidevice_page.js",
+    "chromeos/multidevice_page/multidevice_radio_button.html",
+    "chromeos/multidevice_page/multidevice_radio_button.js",
+    "chromeos/multidevice_page/multidevice_smartlock_subpage.html",
+    "chromeos/multidevice_page/multidevice_smartlock_subpage.js",
+    "chromeos/multidevice_page/multidevice_subpage.html",
+    "chromeos/multidevice_page/multidevice_subpage.js",
+    "chromeos/multidevice_page/multidevice_tether_item.html",
+    "chromeos/multidevice_page/multidevice_tether_item.js",
+    "chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.html",
+    "chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.js",
+    "chromeos/multidevice_page/multidevice_wifi_sync_item.html",
+    "chromeos/multidevice_page/multidevice_wifi_sync_item.js",
+    "chromeos/nearby_share_page/nearby_account_manager_browser_proxy.html",
+    "chromeos/nearby_share_page/nearby_account_manager_browser_proxy.js",
+    "chromeos/nearby_share_page/nearby_share_confirm_page.html",
+    "chromeos/nearby_share_page/nearby_share_confirm_page.js",
+    "chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.html",
+    "chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.js",
+    "chromeos/nearby_share_page/nearby_share_data_usage_dialog.html",
+    "chromeos/nearby_share_page/nearby_share_data_usage_dialog.js",
+    "chromeos/nearby_share_page/nearby_share_device_name_dialog.html",
+    "chromeos/nearby_share_page/nearby_share_device_name_dialog.js",
+    "chromeos/nearby_share_page/nearby_share_high_visibility_page.html",
+    "chromeos/nearby_share_page/nearby_share_high_visibility_page.js",
+    "chromeos/nearby_share_page/nearby_share_receive_dialog.html",
+    "chromeos/nearby_share_page/nearby_share_receive_dialog.js",
+    "chromeos/nearby_share_page/nearby_share_receive_manager.html",
+    "chromeos/nearby_share_page/nearby_share_receive_manager.js",
+    "chromeos/nearby_share_page/nearby_share_subpage.html",
+    "chromeos/nearby_share_page/nearby_share_subpage.js",
+    "chromeos/nearby_share_page/types.html",
+    "chromeos/nearby_share_page/types.js",
+    "chromeos/os_a11y_page/manage_a11y_page.html",
+    "chromeos/os_a11y_page/manage_a11y_page.js",
+    "chromeos/os_a11y_page/manage_a11y_page_browser_proxy.html",
+    "chromeos/os_a11y_page/manage_a11y_page_browser_proxy.js",
+    "chromeos/os_a11y_page/os_a11y_page.html",
+    "chromeos/os_a11y_page/os_a11y_page.js",
+    "chromeos/os_a11y_page/os_a11y_page_browser_proxy.html",
+    "chromeos/os_a11y_page/os_a11y_page_browser_proxy.js",
+    "chromeos/os_a11y_page/switch_access_action_assignment_dialog.html",
+    "chromeos/os_a11y_page/switch_access_action_assignment_dialog.js",
+    "chromeos/os_a11y_page/switch_access_constants.html",
+    "chromeos/os_a11y_page/switch_access_constants.js",
+    "chromeos/os_a11y_page/switch_access_subpage.html",
+    "chromeos/os_a11y_page/switch_access_subpage.js",
+    "chromeos/os_a11y_page/switch_access_subpage_browser_proxy.html",
+    "chromeos/os_a11y_page/switch_access_subpage_browser_proxy.js",
+    "chromeos/os_a11y_page/tts_subpage.html",
+    "chromeos/os_a11y_page/tts_subpage.js",
+    "chromeos/os_a11y_page/tts_subpage_browser_proxy.html",
+    "chromeos/os_a11y_page/tts_subpage_browser_proxy.js",
+    "chromeos/os_about_page/channel_switcher_dialog.html",
+    "chromeos/os_about_page/channel_switcher_dialog.js",
+    "chromeos/os_about_page/detailed_build_info.html",
+    "chromeos/os_about_page/detailed_build_info.js",
+    "chromeos/os_about_page/edit_hostname_dialog.html",
+    "chromeos/os_about_page/edit_hostname_dialog.js",
+    "chromeos/os_about_page/os_about_page.html",
+    "chromeos/os_about_page/os_about_page.js",
+    "chromeos/os_about_page/update_warning_dialog.html",
+    "chromeos/os_about_page/update_warning_dialog.js",
+    "chromeos/os_apps_page/android_apps_browser_proxy.html",
+    "chromeos/os_apps_page/android_apps_browser_proxy.js",
+    "chromeos/os_apps_page/android_apps_subpage.html",
+    "chromeos/os_apps_page/android_apps_subpage.js",
+    "chromeos/os_apps_page/app_management_page/actions.html",
+    "chromeos/os_apps_page/app_management_page/actions.js",
+    "chromeos/os_apps_page/app_management_page/api_listener.html",
+    "chromeos/os_apps_page/app_management_page/api_listener.js",
+    "chromeos/os_apps_page/app_management_page/app_detail_view.html",
+    "chromeos/os_apps_page/app_management_page/app_detail_view.js",
+    "chromeos/os_apps_page/app_management_page/app_item.html",
+    "chromeos/os_apps_page/app_management_page/app_item.js",
+    "chromeos/os_apps_page/app_management_page/app_management_page.html",
+    "chromeos/os_apps_page/app_management_page/app_management_page.js",
+    "chromeos/os_apps_page/app_management_page/arc_detail_view.html",
+    "chromeos/os_apps_page/app_management_page/arc_detail_view.js",
+    "chromeos/os_apps_page/app_management_page/browser_proxy.html",
+    "chromeos/os_apps_page/app_management_page/browser_proxy.js",
+    "chromeos/os_apps_page/app_management_page/chrome_app_detail_view.html",
+    "chromeos/os_apps_page/app_management_page/chrome_app_detail_view.js",
+    "chromeos/os_apps_page/app_management_page/constants.html",
+    "chromeos/os_apps_page/app_management_page/constants.js",
+    "chromeos/os_apps_page/app_management_page/dom_switch.html",
+    "chromeos/os_apps_page/app_management_page/dom_switch.js",
+    "chromeos/os_apps_page/app_management_page/fake_page_handler.js",
+    "chromeos/os_apps_page/app_management_page/icons.html",
+    "chromeos/os_apps_page/app_management_page/main_view.html",
+    "chromeos/os_apps_page/app_management_page/main_view.js",
+    "chromeos/os_apps_page/app_management_page/permission_item.html",
+    "chromeos/os_apps_page/app_management_page/permission_item.js",
+    "chromeos/os_apps_page/app_management_page/pin_to_shelf_item.html",
+    "chromeos/os_apps_page/app_management_page/pin_to_shelf_item.js",
+    "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_browser_proxy.html",
+    "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_browser_proxy.js",
+    "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_detail_view.html",
+    "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_detail_view.js",
+    "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_paths.html",
+    "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_paths.js",
+    "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_usb_devices.html",
+    "chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_usb_devices.js",
+    "chromeos/os_apps_page/app_management_page/pwa_detail_view.html",
+    "chromeos/os_apps_page/app_management_page/pwa_detail_view.js",
+    "chromeos/os_apps_page/app_management_page/reducers.html",
+    "chromeos/os_apps_page/app_management_page/reducers.js",
+    "chromeos/os_apps_page/app_management_page/shared_style.html",
+    "chromeos/os_apps_page/app_management_page/shared_vars.html",
+    "chromeos/os_apps_page/app_management_page/store.html",
+    "chromeos/os_apps_page/app_management_page/store.js",
+    "chromeos/os_apps_page/app_management_page/store_client.html",
+    "chromeos/os_apps_page/app_management_page/store_client.js",
+    "chromeos/os_apps_page/app_management_page/toggle_row.html",
+    "chromeos/os_apps_page/app_management_page/toggle_row.js",
+    "chromeos/os_apps_page/app_management_page/types.js",
+    "chromeos/os_apps_page/app_management_page/uninstall_button.html",
+    "chromeos/os_apps_page/app_management_page/uninstall_button.js",
+    "chromeos/os_apps_page/app_management_page/util.html",
+    "chromeos/os_apps_page/app_management_page/util.js",
+    "chromeos/os_apps_page/os_apps_page.html",
+    "chromeos/os_apps_page/os_apps_page.js",
+    "chromeos/os_files_page/os_files_page.html",
+    "chromeos/os_files_page/os_files_page.js",
+    "chromeos/os_files_page/smb_shares_page.html",
+    "chromeos/os_files_page/smb_shares_page.js",
+    "chromeos/os_icons.html",
+    "chromeos/os_languages_page/add_input_methods_dialog.html",
+    "chromeos/os_languages_page/add_input_methods_dialog.js",
+    "chromeos/os_languages_page/change_device_language_dialog.html",
+    "chromeos/os_languages_page/change_device_language_dialog.js",
+    "chromeos/os_languages_page/input_method_options_page.html",
+    "chromeos/os_languages_page/input_method_options_page.js",
+    "chromeos/os_languages_page/input_method_util.html",
+    "chromeos/os_languages_page/input_method_util.js",
+    "chromeos/os_languages_page/input_page.html",
+    "chromeos/os_languages_page/input_page.js",
+    "chromeos/os_languages_page/languages_metrics_proxy.html",
+    "chromeos/os_languages_page/languages_metrics_proxy.js",
+    "chromeos/os_languages_page/manage_input_methods_page.html",
+    "chromeos/os_languages_page/manage_input_methods_page.js",
+    "chromeos/os_languages_page/os_add_languages_dialog.html",
+    "chromeos/os_languages_page/os_add_languages_dialog.js",
+    "chromeos/os_languages_page/os_edit_dictionary_page.html",
+    "chromeos/os_languages_page/os_edit_dictionary_page.js",
+    "chromeos/os_languages_page/os_languages_page.html",
+    "chromeos/os_languages_page/os_languages_page.js",
+    "chromeos/os_languages_page/os_languages_page_v2.html",
+    "chromeos/os_languages_page/os_languages_page_v2.js",
+    "chromeos/os_languages_page/os_languages_section.html",
+    "chromeos/os_languages_page/os_languages_section.js",
+    "chromeos/os_languages_page/shared_style.html",
+    "chromeos/os_languages_page/shared_vars.html",
+    "chromeos/os_languages_page/smart_inputs_page.html",
+    "chromeos/os_languages_page/smart_inputs_page.js",
+    "chromeos/os_page_visibility.html",
+    "chromeos/os_page_visibility.js",
+    "chromeos/os_people_page/account_manager.html",
+    "chromeos/os_people_page/account_manager.js",
+    "chromeos/os_people_page/fingerprint_browser_proxy.html",
+    "chromeos/os_people_page/fingerprint_browser_proxy.js",
+    "chromeos/os_people_page/fingerprint_list.html",
+    "chromeos/os_people_page/fingerprint_list.js",
+    "chromeos/os_people_page/kerberos_accounts.html",
+    "chromeos/os_people_page/kerberos_accounts.js",
+    "chromeos/os_people_page/kerberos_accounts_browser_proxy.html",
+    "chromeos/os_people_page/kerberos_accounts_browser_proxy.js",
+    "chromeos/os_people_page/kerberos_add_account_dialog.html",
+    "chromeos/os_people_page/kerberos_add_account_dialog.js",
+    "chromeos/os_people_page/lock_screen.html",
+    "chromeos/os_people_page/lock_screen.js",
+    "chromeos/os_people_page/lock_screen_password_prompt_dialog.html",
+    "chromeos/os_people_page/lock_screen_password_prompt_dialog.js",
+    "chromeos/os_people_page/lock_state_behavior.html",
+    "chromeos/os_people_page/lock_state_behavior.js",
+    "chromeos/os_people_page/os_people_page.html",
+    "chromeos/os_people_page/os_people_page.js",
+    "chromeos/os_people_page/os_sync_browser_proxy.html",
+    "chromeos/os_people_page/os_sync_browser_proxy.js",
+    "chromeos/os_people_page/os_sync_controls.html",
+    "chromeos/os_people_page/os_sync_controls.js",
+    "chromeos/os_people_page/pin_autosubmit_dialog.html",
+    "chromeos/os_people_page/pin_autosubmit_dialog.js",
+    "chromeos/os_people_page/setup_fingerprint_dialog.html",
+    "chromeos/os_people_page/setup_fingerprint_dialog.js",
+    "chromeos/os_people_page/setup_pin_dialog.html",
+    "chromeos/os_people_page/setup_pin_dialog.js",
+    "chromeos/os_people_page/user_list.html",
+    "chromeos/os_people_page/user_list.js",
+    "chromeos/os_people_page/users_add_user_dialog.html",
+    "chromeos/os_people_page/users_add_user_dialog.js",
+    "chromeos/os_people_page/users_page.html",
+    "chromeos/os_people_page/users_page.js",
+    "chromeos/os_printing_page/cups_add_print_server_dialog.html",
+    "chromeos/os_printing_page/cups_add_print_server_dialog.js",
+    "chromeos/os_printing_page/cups_add_printer_dialog.html",
+    "chromeos/os_printing_page/cups_add_printer_dialog.js",
+    "chromeos/os_printing_page/cups_add_printer_manually_dialog.html",
+    "chromeos/os_printing_page/cups_add_printer_manually_dialog.js",
+    "chromeos/os_printing_page/cups_add_printer_manufacturer_model_dialog.html",
+    "chromeos/os_printing_page/cups_add_printer_manufacturer_model_dialog.js",
+    "chromeos/os_printing_page/cups_edit_printer_dialog.html",
+    "chromeos/os_printing_page/cups_edit_printer_dialog.js",
+    "chromeos/os_printing_page/cups_nearby_printers.html",
+    "chromeos/os_printing_page/cups_nearby_printers.js",
+    "chromeos/os_printing_page/cups_printer_dialog_error.html",
+    "chromeos/os_printing_page/cups_printer_dialog_error.js",
+    "chromeos/os_printing_page/cups_printer_dialog_util.html",
+    "chromeos/os_printing_page/cups_printer_dialog_util.js",
+    "chromeos/os_printing_page/cups_printer_shared_css.html",
+    "chromeos/os_printing_page/cups_printer_types.html",
+    "chromeos/os_printing_page/cups_printer_types.js",
+    "chromeos/os_printing_page/cups_printers.html",
+    "chromeos/os_printing_page/cups_printers.js",
+    "chromeos/os_printing_page/cups_printers_browser_proxy.html",
+    "chromeos/os_printing_page/cups_printers_browser_proxy.js",
+    "chromeos/os_printing_page/cups_printers_entry.html",
+    "chromeos/os_printing_page/cups_printers_entry.js",
+    "chromeos/os_printing_page/cups_printers_entry_list_behavior.html",
+    "chromeos/os_printing_page/cups_printers_entry_list_behavior.js",
+    "chromeos/os_printing_page/cups_printers_entry_manager.html",
+    "chromeos/os_printing_page/cups_printers_entry_manager.js",
+    "chromeos/os_printing_page/cups_saved_printers.html",
+    "chromeos/os_printing_page/cups_saved_printers.js",
+    "chromeos/os_printing_page/cups_settings_add_printer_dialog.html",
+    "chromeos/os_printing_page/cups_settings_add_printer_dialog.js",
+    "chromeos/os_printing_page/os_printing_page.html",
+    "chromeos/os_printing_page/os_printing_page.js",
+    "chromeos/os_privacy_page/os_privacy_page.html",
+    "chromeos/os_privacy_page/os_privacy_page.js",
+    "chromeos/os_reset_page/os_powerwash_dialog.html",
+    "chromeos/os_reset_page/os_powerwash_dialog.js",
+    "chromeos/os_reset_page/os_reset_browser_proxy.html",
+    "chromeos/os_reset_page/os_reset_browser_proxy.js",
+    "chromeos/os_reset_page/os_reset_page.html",
+    "chromeos/os_reset_page/os_reset_page.js",
+    "chromeos/os_route.html",
+    "chromeos/os_route.js",
+    "chromeos/os_search_page/os_search_page.html",
+    "chromeos/os_search_page/os_search_page.js",
+    "chromeos/os_search_page/os_search_selection_dialog.html",
+    "chromeos/os_search_page/os_search_selection_dialog.js",
+    "chromeos/os_settings.html",
+    "chromeos/os_settings_icons_css.html",
+    "chromeos/os_settings_main/os_settings_main.html",
+    "chromeos/os_settings_main/os_settings_main.js",
+    "chromeos/os_settings_menu/os_settings_menu.html",
+    "chromeos/os_settings_menu/os_settings_menu.js",
+    "chromeos/os_settings_page/main_page_behavior.html",
+    "chromeos/os_settings_page/main_page_behavior.js",
+    "chromeos/os_settings_page/os_settings_page.html",
+    "chromeos/os_settings_page/os_settings_page.js",
+    "chromeos/os_settings_page/settings_idle_load.html",
+    "chromeos/os_settings_page/settings_idle_load.js",
+    "chromeos/os_settings_routes.html",
+    "chromeos/os_settings_routes.js",
+    "chromeos/os_settings_search_box/os_search_result_row.html",
+    "chromeos/os_settings_search_box/os_search_result_row.js",
+    "chromeos/os_settings_search_box/os_settings_search_box.html",
+    "chromeos/os_settings_search_box/os_settings_search_box.js",
+    "chromeos/os_settings_ui/os_settings_ui.html",
+    "chromeos/os_settings_ui/os_settings_ui.js",
+    "chromeos/os_toolbar/os_toolbar.html",
+    "chromeos/os_toolbar/os_toolbar.js",
+    "chromeos/parental_controls_page/parental_controls_browser_proxy.html",
+    "chromeos/parental_controls_page/parental_controls_browser_proxy.js",
+    "chromeos/parental_controls_page/parental_controls_page.html",
+    "chromeos/parental_controls_page/parental_controls_page.js",
+    "chromeos/personalization_page/change_picture.html",
+    "chromeos/personalization_page/change_picture.js",
+    "chromeos/personalization_page/change_picture_browser_proxy.html",
+    "chromeos/personalization_page/change_picture_browser_proxy.js",
+    "chromeos/personalization_page/personalization_page.html",
+    "chromeos/personalization_page/personalization_page.js",
+    "chromeos/personalization_page/wallpaper_browser_proxy.html",
+    "chromeos/personalization_page/wallpaper_browser_proxy.js",
+    "chromeos/pref_to_setting_metric_converter.html",
+    "chromeos/pref_to_setting_metric_converter.js",
+    "chromeos/route_origin_behavior.html",
+    "chromeos/route_origin_behavior.js",
+    "chromeos/search_handler.html",
+    "chromeos/search_handler.js",
+    "controls/controlled_button.html",
+    "controls/controlled_button.js",
+    "controls/controlled_radio_button.html",
+    "controls/controlled_radio_button.js",
+    "controls/extension_controlled_indicator.html",
+    "controls/extension_controlled_indicator.js",
+    "controls/password_prompt_dialog.html",
+    "controls/password_prompt_dialog.js",
+    "controls/pref_control_behavior.html",
+    "controls/pref_control_behavior.js",
+    "controls/settings_boolean_control_behavior.html",
+    "controls/settings_boolean_control_behavior.js",
+    "controls/settings_dropdown_menu.html",
+    "controls/settings_dropdown_menu.js",
+    "controls/settings_radio_group.html",
+    "controls/settings_radio_group.js",
+    "controls/settings_slider.html",
+    "controls/settings_slider.js",
+    "controls/settings_textarea.html",
+    "controls/settings_textarea.js",
+    "controls/settings_toggle_button.html",
+    "controls/settings_toggle_button.js",
+    "extension_control_browser_proxy.html",
+    "extension_control_browser_proxy.js",
+    "global_scroll_target_behavior.html",
+    "global_scroll_target_behavior.js",
+    "i18n_setup.html",
+    "icons.html",
+    "languages_page/languages.html",
+    "languages_page/languages.js",
+    "languages_page/languages_browser_proxy.html",
+    "languages_page/languages_browser_proxy.js",
+    "lifetime_browser_proxy.html",
+    "lifetime_browser_proxy.js",
+    "people_page/account_manager_browser_proxy.html",
+    "people_page/account_manager_browser_proxy.js",
+    "people_page/profile_info_browser_proxy.html",
+    "people_page/profile_info_browser_proxy.js",
+    "people_page/signout_dialog.html",
+    "people_page/signout_dialog.js",
+    "people_page/sync_account_control.html",
+    "people_page/sync_account_control.js",
+    "people_page/sync_browser_proxy.html",
+    "people_page/sync_browser_proxy.js",
+    "people_page/sync_controls.html",
+    "people_page/sync_controls.js",
+    "people_page/sync_encryption_options.html",
+    "people_page/sync_encryption_options.js",
+    "people_page/sync_page.html",
+    "people_page/sync_page.js",
+    "prefs/pref_util.html",
+    "prefs/pref_util.js",
+    "prefs/prefs.html",
+    "prefs/prefs.js",
+    "prefs/prefs_behavior.html",
+    "prefs/prefs_behavior.js",
+    "prefs/prefs_types.html",
+    "prefs/prefs_types.js",
+    "privacy_page/personalization_options.html",
+    "privacy_page/personalization_options.js",
+    "privacy_page/privacy_page_browser_proxy.html",
+    "privacy_page/privacy_page_browser_proxy.js",
+    "router.html",
+    "router.js",
+    "search_engines_page/search_engines_browser_proxy.html",
+    "search_engines_page/search_engines_browser_proxy.js",
+    "search_settings.html",
+    "search_settings.js",
+    "setting_id_param_util.html",
+    "setting_id_param_util.js",
+    "settings_page/settings_animated_pages.html",
+    "settings_page/settings_animated_pages.js",
+    "settings_page/settings_section.html",
+    "settings_page/settings_section.js",
+    "settings_page/settings_subpage.html",
+    "settings_page/settings_subpage.js",
+    "settings_page_css.html",
+    "settings_shared_css.html",
+    "settings_vars_css.html",
+  ]
+}
+
+preprocess_grit("preprocess_nearby_v2") {
+  in_folder = "../../nearby_share/"
+  out_folder = "$target_gen_dir/$preprocess_folder_v2"
+  out_manifest = "$target_gen_dir/$preprocess_nearby_v2_manifest"
+  in_files = [
+    "shared/nearby_contact_manager.html",
+    "shared/nearby_contact_manager.js",
+    "shared/nearby_contact_visibility.html",
+    "shared/nearby_contact_visibility.js",
+    "shared/nearby_onboarding_page.html",
+    "shared/nearby_onboarding_page.js",
+    "shared/nearby_page_template.html",
+    "shared/nearby_page_template.js",
+    "shared/nearby_share_settings.html",
+    "shared/nearby_share_settings.js",
+    "shared/nearby_share_settings_behavior.html",
+    "shared/nearby_share_settings_behavior.js",
+    "shared/nearby_shared_icons.html",
+    "shared/nearby_visibility_page.html",
+    "shared/nearby_visibility_page.js",
+  ]
+}
+
+preprocess_grit("preprocess_nearby_v3") {
+  deps = [ "//chrome/browser/resources/nearby_share/shared:polymer3_elements" ]
+  in_folder = get_path_info("../../nearby_share/", "gen_dir")
+  out_folder = "$target_gen_dir/$preprocess_folder_v3"
+  out_manifest = "$target_gen_dir/$preprocess_nearby_v3_manifest"
+  in_files = [
+    "shared/nearby_contact_manager.m.js",
+    "shared/nearby_contact_visibility.m.js",
+    "shared/nearby_onboarding_page.m.js",
+    "shared/nearby_page_template.m.js",
+    "shared/nearby_share_settings.m.js",
+    "shared/nearby_share_settings_behavior.m.js",
+    "shared/nearby_shared_icons.m.js",
+    "shared/nearby_visibility_page.m.js",
+  ]
+}
+
 group("closure_compile") {
   deps = [
     ":deep_linking_behavior",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp b/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
deleted file mode 100644
index 027989a..0000000
--- a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
+++ /dev/null
@@ -1,924 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<grit-part>
-  <include name="IDR_OS_SETTINGS_ALBUM_ITEM_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/ambient_mode_page/album_item.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_ALBUM_LIST_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/ambient_mode_page/album_list.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_TOPIC_SOURCE_ITEM_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/ambient_mode_page/topic_source_item.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_TOPIC_SOURCE_LIST_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/ambient_mode_page/topic_source_list.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_AMBIENT_MODE_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_AMBIENT_MODE_PHOTOS_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_CELLULAR_SETUP_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/cellular_setup_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_INTERNET_CONFIG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/internet_config.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_INTERNET_DETAIL_MENU_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_menu.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_INTERNET_DETAIL_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_INTERNET_KNOWN_NETWORKS_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/internet_known_networks_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_INTERNET_PAGE_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/internet_page_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_CELLULAR_SETUP_SETTINGS_DELEGATE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/cellular_setup_settings_delegate.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_INTERNET_SHARED_CSS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/internet_shared_css.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_INTERNET_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/internet_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_INTERNET_SUBPAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NETWORK_PROXY_SECTION_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/network_proxy_section.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NETWORK_SUMMARY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/network_summary.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NETWORK_SUMMARY_ITEM_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_TETHER_CONNECTION_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/internet_page/tether_connection_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PERSONALIZATION_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_WALLPAPER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PERSONALIZATION_PAGE_CHANGE_PICTURE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PERSONALIZATION_PAGE_CHANGE_PICTURE_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/personalization_page/change_picture_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_AMBIENT_MODE_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_AMBIENT_MODE_CONSTANTS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/ambient_mode_page/constants.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_CONTROLLED_BUTTON_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/controls/controlled_button.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_EXTENSION_CONTROLLED_INDICATOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/controls/extension_controlled_indicator.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_GOOGLE_ASSISTANT_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/google_assistant_page/google_assistant_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_GOOGLE_ASSISTANT_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/google_assistant_page/google_assistant_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_RADIO_GROUP_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/controls/settings_radio_group.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_TEXTAREA_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/controls/settings_textarea.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_DROPDOWN_MENU_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/controls/settings_dropdown_menu.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_EXTENSION_CONTROL_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/extension_control_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_LANGUAGES_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/languages_page/languages_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_LANGUAGES_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/languages_page/languages.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_ADD_INPUT_METHODS_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/add_input_methods_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_CHANGE_DEVICE_LANGUAGE_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_ADD_LANGUAGES_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/os_add_languages_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_INPUT_METHOD_OPTIONS_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_INPUT_METHOD_UTIL_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_INPUT_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_MANAGE_INPUT_METHODS_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/manage_input_methods_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_LANGUAGES_METRICS_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/languages_metrics_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_EDIT_DICTIONARY_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_LANGUAGES_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_LANGUAGES_PAGE_V2_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_LANGUAGES_SECTION_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_SHARED_STYLE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/shared_style.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_SHARED_VARS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/shared_vars.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_SMART_INPUTS_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_ACCOUNT_MANAGER_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/people_page/account_manager_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-    <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_PROFILE_INFO_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/people_page/profile_info_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_SYNC_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/people_page/sync_browser_proxy.m.js"
-           use_base_dir="false"
-           preprocess="true"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_SYNC_ACCOUNT_CONTROL_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/people_page/sync_account_control.m.js"
-           use_base_dir="false"
-           preprocess="true"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_SYNC_ENCRYPTION_OPTIONS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/people_page/sync_encryption_options.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_SIGNOUT_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/people_page/signout_dialog.m.js"
-           use_base_dir="false"
-           preprocess="true"
-           compress="false" type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_SYNC_CONTROLS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/people_page/sync_controls.m.js"
-           use_base_dir="false"
-           preprocess="true"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_SYNC_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/people_page/sync_page.m.js"
-           use_base_dir="false"
-           preprocess="true"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_PRIVACY_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_privacy_page/os_privacy_page.m.js"
-           use_base_dir="false"
-           preprocess="true"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PRIVACY_PAGE_PERSONALIZATION_OPTIONS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/privacy_page/personalization_options.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PRIVACY_PAGE_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.m.js"
-           use_base_dir="false"
-           preprocess="true"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PARENTAL_CONTROLS_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PARENTAL_CONTROLS_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_KERBEROS_ACCOUNTS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/kerberos_accounts.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_KERBEROS_ACCOUNTS_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/kerberos_accounts_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_KERBEROS_ADD_ACCOUNT_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/kerberos_add_account_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_ACCOUNT_MANAGER_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_FINGERPRINT_LIST_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/fingerprint_list.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_LOCK_SCREEN_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_LOCK_SCREEN_PASSWORD_PROMPT_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen_password_prompt_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_LOCK_STATE_BEHAVIOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/lock_state_behavior.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_OS_SYNC_CONTROLS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_controls.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_USERS_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/users_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_USERS_ADD_USER_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/users_add_user_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_OS_SYNC_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_USERS_LIST_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/user_list.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_FINGERPRINT_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/fingerprint_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_SETUP_FINGERPRINT_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/setup_fingerprint_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_PIN_AUTOSUBMIT_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/pin_autosubmit_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_SETUP_PIN_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/setup_pin_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PEOPLE_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_RESET_POWERWASH_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_RESET_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_RESET_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_ADD_PRINT_SERVER_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_add_print_server_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_ADD_PRINTER_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_add_printer_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_ADD_PRINTER_MANUALLY_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_add_printer_manually_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_ADD_PRINTER_MANUFACTURER_MODEL_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_add_printer_manufacturer_model_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_EDIT_PRINTER_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_NEARBY_PRINTERS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_nearby_printers.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_PRINTER_DIALOG_ERROR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printer_dialog_error.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_PRINTER_DIALOG_UTIL_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printer_dialog_util.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_PRINTER_SHARED_CSS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printer_shared_css.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_PRINTER_TYPES_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printer_types.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_PRINTERS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_PRINTERS_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_PRINTERS_ENTRY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers_entry.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_PRINTERS_ENTRY_LIST_BEHAVIOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers_entry_list_behavior.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_PRINTERS_ENTRY_MANAGER_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers_entry_manager.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_SAVED_PRINTERS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_saved_printers.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_CUPS_SETTINGS_ADD_PRINTER_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/cups_settings_add_printer_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PRINTING_PAGE_OS_PRINTING_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_printing_page/os_printing_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_ABOUT_PAGE_OS_ABOUT_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_ABOUT_PAGE_CHANNEL_SWITCHER_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_about_page/channel_switcher_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_ABOUT_PAGE_DETAILED_BUILD_INFO_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_ABOUT_PAGE_EDIT_HOSTNAME_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_about_page/edit_hostname_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_ABOUT_PAGE_UPDATE_WARNING_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_about_page/update_warning_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SEARCH_ENGINES_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_SEARCH_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_SEARCH_SELECTION_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_search_page/os_search_selection_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_SETTINGS_PAGE_MAIN_PAGE_BEHAVIOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_settings_page/main_page_behavior.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_SETTINGS_ABOUT_PAGE_ABOUT_PAGE_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/about_page/about_page_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA" />
-  <include name="IDR_SETTINGS_SETTINGS_PAGE_SETTINGS_SECTION_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/settings_page/settings_section.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_SETTINGS_SETTINGS_PAGE_CSS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/settings_page_css.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_FILES_PAGE_OS_FILES_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_FILES_PAGE_SMB_SHARES_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_BLUETOOTH_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/bluetooth_page/bluetooth_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_BLUETOOTH_SUBPAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/bluetooth_page/bluetooth_subpage.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_BLUETOOTH_DEVICE_LIST_ITEM_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/bluetooth_page/bluetooth_device_list_item.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_DEEP_LINKING_BEHAVIOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/deep_linking_behavior.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LOCALIZED_LINK_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/localized_link/localized_link.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_METRIC_RECORDER_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/metrics_recorder.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_PAGE_VISIBILITY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_page_visibility.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PAGE_VISIBILITY_JS"
-           file="page_visibility.js"
-           preprocess="true"
-           compress="false" type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PREF_TO_SETTING_METRIC_CONVERTER_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/pref_to_setting_metric_converter.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_NOTIFICATIONS_ACCESS_SETUP_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_notification_access_setup_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_SUBPAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_CONSTANTS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_constants.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_FEATURE_BEHAVIOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_feature_behavior.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_FEATURE_ITEM_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_feature_item.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_TETHER_ITEM_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_tether_item.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_FEATURE_TOGGLE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_feature_toggle.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_multidevice_wifi_sync_item_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_wifi_sync_item.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_WIFI_SYNC_DISABLED_LINK_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_SMARTLOCK_SUBPAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_smartlock_subpage.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_MULTIDEVICE_RADIO_BUTTON_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_radio_button.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_ROUTE_ORIGIN_BEHAVIOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/route_origin_behavior.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_SETTINGS_CONTROLS_PASSWORD_PROMPT_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/controls/password_prompt_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_SETTINGS_CONTROLS_CONTROLLED_RADIO_BUTTON_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/controls/controlled_radio_button.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
- <include name="IDR_OS_SETTINGS_OS_ICONS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_icons.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_ICONS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/icons.m.js"
-           use_base_dir="false"
-           compress="false" type="BINDATA"
-           preprocess="true" />
-  <include name="IDR_OS_SETTINGS_OS_SETTINGS_ICONS_CSS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_settings_icons_css.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_OS_ROUTE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_route.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-   <include name="IDR_OS_SETTINGS_SETTINGS_OS_SETTINGS_ROUTE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_settings_routes.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_SUBPAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/settings_page/settings_subpage.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA"/>
-  <include name="IDR_OS_SETTINGS_SETTINGS_ANIMATED_PAGES_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/settings_page/settings_animated_pages.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA"/>
-  <include name="IDR_OS_SETTINGS_SETTINGS_TOGGLE_BUTTON_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/controls/settings_toggle_button.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_BOOLEAN_CONTROL_BEHAVIOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/controls/settings_boolean_control_behavior.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PREF_CONTROL_BEHAVIOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/controls/pref_control_behavior.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LIFETIME_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/lifetime_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA"/>
-  <include name="IDR_OS_SETTINGS_PREFS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/prefs/prefs.m.js"
-           use_base_dir="false"
-           compress="false"
-           preprocess="true"
-           type="BINDATA"/>
-  <include name="IDR_OS_SETTINGS_PREFS_PREF_UTIL_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/prefs/pref_util.m.js"
-           use_base_dir="false"
-           compress="false" type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_PREFS_BEHAVIOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/prefs/prefs_behavior.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA"/>
-  <include name="IDR_OS_SETTINGS_PREFS_TYPES_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/prefs/prefs_types.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA"/>
-  <include name="IDR_OS_SETTINGS_NEARBY_SHARE_CONFIRM_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_confirm_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NEARBY_ACCOUNT_MANAGER_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_account_manager_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NEARBY_SHARE_SUBPAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_subpage.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_device_name_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NEARBY_SHARE_HIGH_VISIBILITY_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_high_visibility_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NEARBY_SHARE_RECEIVE_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_receive_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NEARBY_SHARE_RECEIVE_MANAGER_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_receive_manager.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NEARBY_SHARE_DATA_USAGE_DIALOG_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_data_usage_dialog.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_NEARBY_SHARE_TYPES_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/nearby_share_page/types.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_ROUTER_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/router.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_SETTINGS_SETTING_ID_PARAM_UTIL_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/setting_id_param_util.m.js"
-           use_base_dir="false"
-           compress="false" type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_SHARED_CSS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/settings_shared_css.m.js"
-           use_base_dir="false"
-           preprocess="true"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_VARS_CSS_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/settings_vars_css.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_GLOBAL_SCROLL_TARGET_BEHAVIOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/global_scroll_target_behavior.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_I18N_SETUP_JS"
-           file="i18n_setup.js"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_ENSURE_LAZY_LOADED_JS"
-          file="chromeos/ensure_lazy_loaded.m.js"
-          preprocess="true"
-          compress="false" type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_LAZY_LOAD_V3_JS"
-           file="chromeos/lazy_load.js"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_SETTINGS_V3_HTML"
-           file="chromeos/os_settings_v3.html"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_OS_SETTINGS_V3_JS"
-           file="chromeos/os_settings.js"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_DATE_TIME_PAGE_DATE_TIME_PAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/date_time_page/date_time_page.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_DATE_TIME_PAGE_DATE_TIME_TYPES_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/date_time_page/date_time_types.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_DATE_TIME_PAGE_TIMEZONE_BROWSER_PROXY_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/date_time_page/timezone_browser_proxy.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_DATE_TIME_PAGE_TIMEZONE_SELECTOR_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/date_time_page/timezone_selector.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-  <include name="IDR_OS_SETTINGS_SETTINGS_DATE_TIME_PAGE_TIMEZONE_SUBPAGE_M_JS"
-           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/date_time_page/timezone_subpage.m.js"
-           use_base_dir="false"
-           compress="false"
-           type="BINDATA" />
-</grit-part>
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd
deleted file mode 100644
index 1db3d8b2..0000000
--- a/chrome/browser/resources/settings/os_settings_resources.grd
+++ /dev/null
@@ -1,1648 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
-  <outputs>
-    <output filename="grit/os_settings_resources.h" type="rc_header">
-      <emit emit_type='prepend'></emit>
-    </output>
-    <output filename="grit/os_settings_resources_map.cc"
-            type="resource_file_map_source" />
-    <output filename="grit/os_settings_resources_map.h"
-            type="resource_map_header" />
-    <output filename="os_settings_resources.pak" type="data_package" />
-  </outputs>
-  <release seq="1">
-    <includes>
-      <part file="chromeos/os_settings_resources_v3.grdp" />
-
-      <!-- Constants -->
-      <include name="IDR_OS_SETTINGS_ROUTES_MOJOM_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\settings\chromeos\constants\routes.mojom-lite.js"
-               use_base_dir="false"
-               compress="false" type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_SETTING_MOJOM_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\settings\chromeos\constants\setting.mojom-lite.js"
-               use_base_dir="false"
-               compress="false" type="BINDATA" />
-
-      <!-- App Management -->
-      <include name="IDR_OS_SETTINGS_APP_MANAGEMENT_FILE_PATH_MOJO_LITE_JS"
-               file="${root_gen_dir}\mojo\public\mojom\base\file_path.mojom-lite.js"
-               use_base_dir="false"
-               compress="false" type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_APP_MANAGEMENT_IMAGE_MOJO_LITE_JS"
-               file="${root_gen_dir}\ui\gfx\image\mojom\image.mojom-lite.js"
-               use_base_dir="false"
-               compress="false" type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_APP_MANAGEMENT_MOJO_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\app_management\app_management.mojom-lite.js"
-               use_base_dir="false"
-               compress="false" type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_APP_MANAGEMENT_TYPES_MOJO_LITE_JS"
-               file="${root_gen_dir}\components\services\app_service\public\mojom\types.mojom-lite.js"
-               use_base_dir="false"
-               compress="false" type="BINDATA" />
-
-      <!-- Search -->
-      <include name="IDR_OS_SETTINGS_SEARCH_MOJOM_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\settings\chromeos\search\search.mojom-lite.js"
-               use_base_dir="false"
-               compress="false" type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_SEARCH_RESULT_ICON_MOJOM_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\settings\chromeos\search\search_result_icon.mojom-lite.js"
-               use_base_dir="false"
-               compress="false" type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_USER_ACTION_RECORDER_MOJOM_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\settings\chromeos\search\user_action_recorder.mojom-lite.js"
-               use_base_dir="false"
-               compress="false" type="BINDATA" />
-    </includes>
-    <structures>
-      <structure name="IDR_OS_SETTINGS_LOCALIZED_LINK_JS"
-                 file="chromeos/localized_link/localized_link.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LOCALIZED_LINK_HTML"
-                 file="chromeos/localized_link/localized_link.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_A11Y_PAGE_JS"
-                 file="chromeos/os_a11y_page/os_a11y_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_A11Y_PAGE_HTML"
-                 file="chromeos/os_a11y_page/os_a11y_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_A11Y_PAGE_BROWSER_PROXY_JS"
-                 file="chromeos/os_a11y_page/os_a11y_page_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_A11Y_PAGE_BROWSER_PROXY_HTML"
-                 file="chromeos/os_a11y_page/os_a11y_page_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_MODE_PAGE_JS"
-                 file="chromeos/ambient_mode_page/ambient_mode_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_MODE_PAGE_HTML"
-                 file="chromeos/ambient_mode_page/ambient_mode_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_MODE_PHOTOS_PAGE_JS"
-                 file="chromeos/ambient_mode_page/ambient_mode_photos_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_MODE_PHOTOS_PAGE_HTML"
-                 file="chromeos/ambient_mode_page/ambient_mode_photos_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_MODE_PAGE_BROWSER_PROXY_JS"
-                 file="chromeos/ambient_mode_page/ambient_mode_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_MODE_PAGE_BROWSER_PROXY_HTML"
-                 file="chromeos/ambient_mode_page/ambient_mode_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_CONSTANTS_JS"
-                 file="chromeos/ambient_mode_page/constants.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_CONSTANTS_HTML"
-                 file="chromeos/ambient_mode_page/constants.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_TOPIC_SOURCE_ITEM_JS"
-                 file="chromeos/ambient_mode_page/topic_source_item.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_TOPIC_SOURCE_ITEM_HTML"
-                 file="chromeos/ambient_mode_page/topic_source_item.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_TOPIC_SOURCE_LIST_JS"
-                 file="chromeos/ambient_mode_page/topic_source_list.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_TOPIC_SOURCE_LIST_HTML"
-                 file="chromeos/ambient_mode_page/topic_source_list.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_ALBUM_ITEM_JS"
-                 file="chromeos/ambient_mode_page/album_item.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_ALBUM_ITEM_HTML"
-                 file="chromeos/ambient_mode_page/album_item.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_ALBUM_LIST_JS"
-                 file="chromeos/ambient_mode_page/album_list.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_AMBIENT_ALBUM_LIST_HTML"
-                 file="chromeos/ambient_mode_page/album_list.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APPS_PAGE_JS"
-                 file="chromeos/os_apps_page/os_apps_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APPS_PAGE_HTML"
-                 file="chromeos/os_apps_page/os_apps_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_JS"
-                 file="chromeos/os_apps_page/app_management_page/app_management_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_HTML"
-                 file="chromeos/os_apps_page/app_management_page/app_management_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_CONSTANTS_JS"
-                 file="chromeos/os_apps_page/app_management_page/constants.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_CONSTANTS_HTML"
-                 file="chromeos/os_apps_page/app_management_page/constants.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_STORE_CLIENT_JS"
-                 file="chromeos/os_apps_page/app_management_page/store_client.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_STORE_CLIENT_HTML"
-                 file="chromeos/os_apps_page/app_management_page/store_client.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_STORE_JS"
-                 file="chromeos/os_apps_page/app_management_page/store.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_STORE_HTML"
-                 file="chromeos/os_apps_page/app_management_page/store.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_ACTIONS_JS"
-                 file="chromeos/os_apps_page/app_management_page/actions.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_ACTIONS_HTML"
-                 file="chromeos/os_apps_page/app_management_page/actions.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_APP_ITEM_JS"
-                 file="chromeos/os_apps_page/app_management_page/app_item.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_APP_ITEM_HTML"
-                 file="chromeos/os_apps_page/app_management_page/app_item.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_BROWSER_PROXY_JS"
-                 file="chromeos/os_apps_page/app_management_page/browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_BROWSER_PROXY_HTML"
-                 file="chromeos/os_apps_page/app_management_page/browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_FAKE_PAGE_HANDLER_JS"
-                 file="chromeos/os_apps_page/app_management_page/fake_page_handler.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_MAIN_VIEW_JS"
-                 file="chromeos/os_apps_page/app_management_page/main_view.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_MAIN_VIEW_HTML"
-                 file="chromeos/os_apps_page/app_management_page/main_view.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_TYPES_JS"
-                 file="chromeos/os_apps_page/app_management_page/types.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_UTIL_JS"
-                 file="chromeos/os_apps_page/app_management_page/util.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_UTIL_HTML"
-                 file="chromeos/os_apps_page/app_management_page/util.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_SHARED_STYLE_HTML"
-                 file="chromeos/os_apps_page/app_management_page/shared_style.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_SHARED_VARS_HTML"
-                 file="chromeos/os_apps_page/app_management_page/shared_vars.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_REDUCERS_JS"
-                 file="chromeos/os_apps_page/app_management_page/reducers.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_REDUCERS_HTML"
-                 file="chromeos/os_apps_page/app_management_page/reducers.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_API_LISTENER_JS"
-                 file="chromeos/os_apps_page/app_management_page/api_listener.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_API_LISTENER_HTML"
-                 file="chromeos/os_apps_page/app_management_page/api_listener.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_DOM_SWITCH_JS"
-                 file="chromeos/os_apps_page/app_management_page/dom_switch.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_DOM_SWITCH_HTML"
-                 file="chromeos/os_apps_page/app_management_page/dom_switch.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_PWA_DETAIL_VIEW_JS"
-                 file="chromeos/os_apps_page/app_management_page/pwa_detail_view.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_PWA_DETAIL_VIEW_HTML"
-                 file="chromeos/os_apps_page/app_management_page/pwa_detail_view.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_PERMISSION_ITEM_JS"
-                 file="chromeos/os_apps_page/app_management_page/permission_item.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_PERMISSION_ITEM_HTML"
-                 file="chromeos/os_apps_page/app_management_page/permission_item.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_PIN_TO_SHELF_ITEM_JS"
-                 file="chromeos/os_apps_page/app_management_page/pin_to_shelf_item.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_PIN_TO_SHELF_ITEM_HTML"
-                 file="chromeos/os_apps_page/app_management_page/pin_to_shelf_item.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_TOGGLE_ROW_JS"
-                 file="chromeos/os_apps_page/app_management_page/toggle_row.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_TOGGLE_ROW_HTML"
-                 file="chromeos/os_apps_page/app_management_page/toggle_row.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_APP_DETAIL_VIEW_JS"
-                 file="chromeos/os_apps_page/app_management_page/app_detail_view.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_APP_DETAIL_VIEW_HTML"
-                 file="chromeos/os_apps_page/app_management_page/app_detail_view.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_ARC_DETAIL_VIEW_JS"
-                 file="chromeos/os_apps_page/app_management_page/arc_detail_view.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_ARC_DETAIL_VIEW_HTML"
-                 file="chromeos/os_apps_page/app_management_page/arc_detail_view.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_CHROME_APP_DETAIL_VIEW_JS"
-                 file="chromeos/os_apps_page/app_management_page/chrome_app_detail_view.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_CHROME_APP_DETAIL_VIEW_HTML"
-                 file="chromeos/os_apps_page/app_management_page/chrome_app_detail_view.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_ICONS_HTML"
-                 file="chromeos/os_apps_page/app_management_page/icons.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_UNINSTALL_BUTTON_JS"
-                 file="chromeos/os_apps_page/app_management_page/uninstall_button.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PAGE_APP_UNINSTALL_BUTTON_HTML"
-                 file="chromeos/os_apps_page/app_management_page/uninstall_button.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PLUGIN_VM_DETAIL_VIEW_JS"
-                 file="chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_detail_view.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PLUGIN_VM_DETAIL_VIEW_HTML"
-                file="chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_detail_view.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PLUGIN_VM_SHARED_PATHS_HTML"
-                file="chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_paths.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PLUGIN_VM_SHARED_PATHS_JS"
-                file="chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_paths.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PLUGIN_VM_SHARED_USB_DEVICES_HTML"
-                file="chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_usb_devices.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PLUGIN_VM_SHARED_USB_DEVICES_JS"
-                file="chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_shared_usb_devices.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PLUGIN_VM_BROWSER_PROXY_JS"
-                file="chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_APP_MANAGEMENT_PLUGIN_VM_BROWSER_PROXY_HTML"
-                file="chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CAPTIONS_SUBPAGE_JS"
-                 file="a11y_page/captions_subpage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CAPTIONS_SUBPAGE_HTML"
-                 file="a11y_page/captions_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_FONTS_BROWSER_PROXY_HTML"
-                 file="appearance_page/fonts_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_FONTS_BROWSER_PROXY_JS"
-                 file="appearance_page/fonts_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MANAGE_A11Y_PAGE_JS"
-                 file="chromeos/os_a11y_page/manage_a11y_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MANAGE_A11Y_PAGE_HTML"
-                 file="chromeos/os_a11y_page/manage_a11y_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MANAGE_A11Y_PAGE_BROWSER_PROXY_JS"
-                 file="chromeos/os_a11y_page/manage_a11y_page_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MANAGE_A11Y_PAGE_BROWSER_PROXY_HTML"
-                 file="chromeos/os_a11y_page/manage_a11y_page_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_JS"
-                 file="chromeos/os_a11y_page/switch_access_action_assignment_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_HTML"
-                 file="chromeos/os_a11y_page/switch_access_action_assignment_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SWITCH_ACCESS_CONSTANTS_JS"
-                 file="chromeos/os_a11y_page/switch_access_constants.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SWITCH_ACCESS_CONSTANTS_HTML"
-                 file="chromeos/os_a11y_page/switch_access_constants.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SWITCH_ACCESS_SUBPAGE_JS"
-                 file="chromeos/os_a11y_page/switch_access_subpage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SWITCH_ACCESS_SUBPAGE_HTML"
-                 file="chromeos/os_a11y_page/switch_access_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SWITCH_ACCESS_SUBPAGE_BROWSER_PROXY_JS"
-                 file="chromeos/os_a11y_page/switch_access_subpage_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SWITCH_ACCESS_SUBPAGE_BROWSER_PROXY_HTML"
-                 file="chromeos/os_a11y_page/switch_access_subpage_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TTS_SUBPAGE_JS"
-                 file="chromeos/os_a11y_page/tts_subpage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TTS_SUBPAGE_HTML"
-                 file="chromeos/os_a11y_page/tts_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TTS_SUBPAGE_BROWSER_PROXY_JS"
-                 file="chromeos/os_a11y_page/tts_subpage_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TTS_SUBPAGE_BROWSER_PROXY_HTML"
-                 file="chromeos/os_a11y_page/tts_subpage_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ABOUT_PAGE_BROWSER_PROXY_HTML"
-                 file="about_page/about_page_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ABOUT_PAGE_BROWSER_PROXY_JS"
-                 file="about_page/about_page_browser_proxy.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_ABOUT_PAGE_JS"
-                 file="chromeos/os_about_page/os_about_page.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_ABOUT_PAGE_HTML"
-                 file="chromeos/os_about_page/os_about_page.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_CHANNEL_SWITCHER_DIALOG_HTML"
-                 file="chromeos/os_about_page/channel_switcher_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CHANNEL_SWITCHER_DIALOG_JS"
-                 file="chromeos/os_about_page/channel_switcher_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DETAILED_BUILD_INFO_JS"
-                 file="chromeos/os_about_page/detailed_build_info.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DETAILED_BUILD_INFO_HTML"
-                 file="chromeos/os_about_page/detailed_build_info.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_EDIT_HOSTNAME_DIALOG_HTML"
-                 file="chromeos/os_about_page/edit_hostname_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_EDIT_HOSTNAME_DIALOG_JS"
-                 file="chromeos/os_about_page/edit_hostname_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_UPDATE_WARNING_DIALOG_HTML"
-                 file="chromeos/os_about_page/update_warning_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_UPDATE_WARNING_DIALOG_JS"
-                 file="chromeos/os_about_page/update_warning_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CR_SETTINGS_ANIMATED_PAGES_HTML"
-                 file="settings_page/settings_animated_pages.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CR_SETTINGS_ANIMATED_PAGES_JS"
-                 file="settings_page/settings_animated_pages.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PERSONALIZATION_PAGE_HTML"
-                 file="chromeos/personalization_page/personalization_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PERSONALIZATION_PAGE_JS"
-                 file="chromeos/personalization_page/personalization_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_SETTINGS_PAGE_JS"
-                 file="chromeos/os_settings_page/os_settings_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_SETTINGS_PAGE_HTML"
-                 file="chromeos/os_settings_page/os_settings_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ENSURE_LAZY_LOADED_HTML"
-                 file="chromeos/ensure_lazy_loaded.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_EXTENSION_CONTROL_BROWSER_PROXY_JS"
-                 file="extension_control_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_EXTENSION_CONTROL_BROWSER_PROXY_HTML"
-                 file="extension_control_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LIFETIME_BROWSER_PROXY_HTML"
-                 file="lifetime_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LIFETIME_BROWSER_PROXY_JS"
-                 file="lifetime_browser_proxy.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_SEARCH_SETTINGS_HTML"
-                 file="search_settings.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SEARCH_SETTINGS_JS"
-                 file="search_settings.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SETTING_ID_PARAM_UTIL_HTML"
-                 file="setting_id_param_util.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SETTING_ID_PARAM_UTIL_JS"
-                 file="setting_id_param_util.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CR_OS_SETTINGS_MAIN_HTML"
-                 file="chromeos/os_settings_main/os_settings_main.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CR_OS_SETTINGS_MAIN_JS"
-                 file="chromeos/os_settings_main/os_settings_main.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CR_OS_SETTINGS_MENU_HTML"
-                 file="chromeos/os_settings_menu/os_settings_menu.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CR_OS_SETTINGS_MENU_JS"
-                 file="chromeos/os_settings_menu/os_settings_menu.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CR_SETTINGS_SECTION_HTML"
-                 file="settings_page/settings_section.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CR_SETTINGS_SECTION_JS"
-                 file="settings_page/settings_section.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CR_SETTINGS_SUBPAGE_HTML"
-                 file="settings_page/settings_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CR_SETTINGS_SUBPAGE_JS"
-                 file="settings_page/settings_subpage.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_CR_SETTINGS_PAGE_CSS_HTML"
-                 file="settings_page_css.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MAIN_PAGE_BEHAVIOR_HTML"
-                 file="chromeos/os_settings_page/main_page_behavior.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MAIN_PAGE_BEHAVIOR_JS"
-                 file="chromeos/os_settings_page/main_page_behavior.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_SETTINGS_VARS_CSS_HTML"
-                 file="settings_vars_css.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SETTINGS_SHARED_CSS_HTML"
-                 file="settings_shared_css.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_CR_OS_SETTINGS_UI_HTML"
-                 file="chromeos/os_settings_ui/os_settings_ui.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CR_OS_SETTINGS_UI_JS"
-                 file="chromeos/os_settings_ui/os_settings_ui.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_GLOBAL_SCROLL_TARGET_BEHAVIOR_HTML"
-                 file="global_scroll_target_behavior.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_GLOBAL_SCROLL_TARGET_BEHAVIOR_JS"
-                 file="global_scroll_target_behavior.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_BOOLEAN_CONTROL_BEHAVIOR_HTML"
-                 file="controls/settings_boolean_control_behavior.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_BOOLEAN_CONTROL_BEHAVIOR_JS"
-                 file="controls/settings_boolean_control_behavior.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_CONTROLLED_BUTTON_JS"
-                 file="controls/controlled_button.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_CONTROLLED_BUTTON_HTML"
-                 file="controls/controlled_button.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_CONTROLLED_RADIO_BUTTON_JS"
-                 file="controls/controlled_radio_button.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_CONTROLLED_RADIO_BUTTON_HTML"
-                 file="controls/controlled_radio_button.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_EXTENSION_CONTROLLED_INDICATOR_JS"
-                 file="controls/extension_controlled_indicator.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_EXTENSION_CONTROLLED_INDICATOR_HTML"
-                 file="controls/extension_controlled_indicator.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_DROPDOWN_MENU_HTML"
-                 file="controls/settings_dropdown_menu.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_DROPDOWN_MENU_JS"
-                 file="controls/settings_dropdown_menu.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_PASSWORD_PROMPT_DIALOG_JS"
-                 file="controls/password_prompt_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_PASSWORD_PROMPT_DIALOG_HTML"
-                 file="controls/password_prompt_dialog.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_PREF_CONTROL_BEHAVIOR_HTML"
-                 file="controls/pref_control_behavior.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_PREF_CONTROL_BEHAVIOR_JS"
-                 file="controls/pref_control_behavior.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_RADIO_GROUP_HTML"
-                 file="controls/settings_radio_group.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_RADIO_GROUP_JS"
-                 file="controls/settings_radio_group.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_SLIDER_HTML"
-                 file="controls/settings_slider.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_SLIDER_JS"
-                 file="controls/settings_slider.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_TEXTAREA_HTML"
-                 file="controls/settings_textarea.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_TEXTAREA_JS"
-                 file="controls/settings_textarea.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_TOGGLE_BUTTON_HTML"
-                 file="controls/settings_toggle_button.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CONTROLS_TOGGLE_BUTTON_JS"
-                 file="controls/settings_toggle_button.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEEP_LINKING_BEHAVIOR_HTML"
-                 file="chromeos/deep_linking_behavior.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEEP_LINKING_BEHAVIOR_JS"
-                 file="chromeos/deep_linking_behavior.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_BROWSER_PROXY_HTML"
-                 file="chromeos/device_page/device_page_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_BROWSER_PROXY_JS"
-                 file="chromeos/device_page/device_page_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_DISPLAY_HTML"
-                 file="chromeos/device_page/display.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_DISPLAY_JS"
-                 file="chromeos/device_page/display.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_DISPLAY_LAYOUT_HTML"
-                 file="chromeos/device_page/display_layout.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_DISPLAY_LAYOUT_JS"
-                 file="chromeos/device_page/display_layout.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_DISPLAY_OVERSCAN_DIALOG_HTML"
-                 file="chromeos/device_page/display_overscan_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_DISPLAY_OVERSCAN_DIALOG_JS"
-                 file="chromeos/device_page/display_overscan_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_KEYBOARD_HTML"
-                 file="chromeos/device_page/keyboard.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_KEYBOARD_JS"
-                 file="chromeos/device_page/keyboard.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_POWER_HTML"
-                 file="chromeos/device_page/power.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_POWER_JS"
-                 file="chromeos/device_page/power.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_STORAGE_HTML"
-                 file="chromeos/device_page/storage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_STORAGE_JS"
-                 file="chromeos/device_page/storage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_SETTINGS_DEVICE_STORAGE_EXTERNAL_ENTRY_HTML"
-                 file="chromeos/device_page/storage_external_entry.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_SETTINGS_DEVICE_STORAGE_EXTERNAL_ENTRY_JS"
-                 file="chromeos/device_page/storage_external_entry.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_SETTINGS_DEVICE_STORAGE_EXTERNAL_HTML"
-                 file="chromeos/device_page/storage_external.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_SETTINGS_DEVICE_STORAGE_EXTERNAL_JS"
-                 file="chromeos/device_page/storage_external.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_STYLUS_HTML"
-                 file="chromeos/device_page/stylus.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_STYLUS_JS"
-                 file="chromeos/device_page/stylus.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_PAGE_HTML"
-                 file="chromeos/device_page/device_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_PAGE_JS"
-                 file="chromeos/device_page/device_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_POINTERS_HTML"
-                 file="chromeos/device_page/pointers.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_POINTERS_JS"
-                 file="chromeos/device_page/pointers.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_DRAG_BEHAVIOR_HTML"
-                 file="chromeos/device_page/drag_behavior.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_DRAG_BEHAVIOR_JS"
-                 file="chromeos/device_page/drag_behavior.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_LAYOUT_BEHAVIOR_HTML"
-                 file="chromeos/device_page/layout_behavior.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_LAYOUT_BEHAVIOR_JS"
-                 file="chromeos/device_page/layout_behavior.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_NIGHT_LIGHT_SLIDER_HTML"
-                 file="chromeos/device_page/night_light_slider.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DEVICE_NIGHT_LIGHT_SLIDER_JS"
-                 file="chromeos/device_page/night_light_slider.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_FILES_PAGE_HTML"
-                 file="chromeos/os_files_page/os_files_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_FILES_PAGE_JS"
-                 file="chromeos/os_files_page/os_files_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SMB_SHARES_PAGE_HTML"
-                 file="chromeos/os_files_page/smb_shares_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SMB_SHARES_PAGE_JS"
-                 file="chromeos/os_files_page/smb_shares_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_I18n_SETUP_HTML"
-                 file="i18n_setup.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ICONS"
-                 file="icons.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_OS_ICONS"
-                 file="chromeos/os_icons.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_OS_SETTINGS_ICONS_CSS_HTML"
-                 file="chromeos/os_settings_icons_css.html"
-                 flattenhtml="true"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_SETTINGS_PAGE_SETTINGS_IDLE_LOAD_HTML"
-                 file="chromeos/os_settings_page/settings_idle_load.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_SETTINGS_PAGE_SETTINGS_IDLE_LOAD_JS"
-                 file="chromeos/os_settings_page/settings_idle_load.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_POWERWASH_DIALOG_HTML"
-                 file="chromeos/os_reset_page/os_powerwash_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_POWERWASH_DIALOG_JS"
-                 file="chromeos/os_reset_page/os_powerwash_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_RESET_PAGE_HTML"
-                 file="chromeos/os_reset_page/os_reset_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_RESET_PAGE_JS"
-                 file="chromeos/os_reset_page/os_reset_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_RESET_BROWSER_PROXY_JS"
-                 file="chromeos/os_reset_page/os_reset_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_RESET_BROWSER_PROXY_HTML"
-                 file="chromeos/os_reset_page/os_reset_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_HTML"
-                 file="languages_page/languages.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_JS"
-                 file="languages_page/languages.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_BROWSER_PROXY_HTML"
-                 file="languages_page/languages_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_BROWSER_PROXY_JS"
-                 file="languages_page/languages_browser_proxy.js"
-                 preprocess="true"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_ADD_INPUT_METHODS_DIALOG_HTML"
-                 file="chromeos/os_languages_page/add_input_methods_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_ADD_INPUT_METHODS_DIALOG_JS"
-                 file="chromeos/os_languages_page/add_input_methods_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_ADD_LANGUAGES_DIALOG_HTML"
-                 file="chromeos/os_languages_page/os_add_languages_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_ADD_LANGUAGES_DIALOG_JS"
-                 file="chromeos/os_languages_page/os_add_languages_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_CHANGE_DEVICE_LANGUAGE_DIALOG_HTML"
-                 file="chromeos/os_languages_page/change_device_language_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_CHANGE_DEVICE_LANGUAGE_DIALOG_JS"
-                 file="chromeos/os_languages_page/change_device_language_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_METRICS_PROXY_HTML"
-                 file="chromeos/os_languages_page/languages_metrics_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_METRICS_PROXY_JS"
-                 file="chromeos/os_languages_page/languages_metrics_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_HTML"
-                 file="chromeos/os_languages_page/os_languages_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_JS"
-                 file="chromeos/os_languages_page/os_languages_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_INPUT_PAGE_HTML"
-                 file="chromeos/os_languages_page/input_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_INPUT_PAGE_JS"
-                 file="chromeos/os_languages_page/input_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_EDIT_DICTIONARY_PAGE_HTML"
-                 file="chromeos/os_languages_page/os_edit_dictionary_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_EDIT_DICTIONARY_PAGE_JS"
-                 file="chromeos/os_languages_page/os_edit_dictionary_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_LANGUAGES_PAGE_V2_HTML"
-                 file="chromeos/os_languages_page/os_languages_page_v2.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_LANGUAGES_PAGE_V2_JS"
-                 file="chromeos/os_languages_page/os_languages_page_v2.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_SECTION_HTML"
-                 file="chromeos/os_languages_page/os_languages_section.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_SECTION_JS"
-                 file="chromeos/os_languages_page/os_languages_section.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_MANAGE_INPUT_METHODS_PAGE_HTML"
-                 file="chromeos/os_languages_page/manage_input_methods_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_MANAGE_INPUT_METHODS_PAGE_JS"
-                 file="chromeos/os_languages_page/manage_input_methods_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_INPUT_METHOD_OPTIONS_PAGE_HTML"
-                 file="chromeos/os_languages_page/input_method_options_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_INPUT_METHOD_OPTIONS_PAGE_JS"
-                 file="chromeos/os_languages_page/input_method_options_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_INPUT_METHOD_UTIL_HTML"
-                 file="chromeos/os_languages_page/input_method_util.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_INPUT_METHOD_UTIL_JS"
-                 file="chromeos/os_languages_page/input_method_util.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_SHARED_STYLE_HTML"
-                 file="chromeos/os_languages_page/shared_style.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_SHARED_VARS_HTML"
-                 file="chromeos/os_languages_page/shared_vars.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_SMART_INPUTS_PAGE_HTML"
-                 file="chromeos/os_languages_page/smart_inputs_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LANGUAGES_SMART_INPUTS_PAGE_JS"
-                 file="chromeos/os_languages_page/smart_inputs_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_SEARCH_RESULT_ROW_JS"
-                 file="chromeos/os_settings_search_box/os_search_result_row.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_SEARCH_RESULT_ROW_HTML"
-                 file="chromeos/os_settings_search_box/os_search_result_row.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_SETTINGS_SEARCH_BOX_JS"
-                 file="chromeos/os_settings_search_box/os_settings_search_box.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_SETTINGS_SEARCH_BOX_HTML"
-                 file="chromeos/os_settings_search_box/os_settings_search_box.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_TOOLBAR_JS"
-                 file="chromeos/os_toolbar/os_toolbar.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_TOOLBAR_HTML"
-                 file="chromeos/os_toolbar/os_toolbar.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_HTML"
-                 file="chromeos/os_people_page/os_people_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_JS"
-                 file="chromeos/os_people_page/os_people_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_SYNC_BROWSER_PROXY_HTML"
-                 file="chromeos/os_people_page/os_sync_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_SYNC_BROWSER_PROXY_JS"
-                 file="chromeos/os_people_page/os_sync_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_SYNC_CONTROLS_JS"
-                 file="chromeos/os_people_page/os_sync_controls.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_OS_SYNC_CONTROLS_HTML"
-                 file="chromeos/os_people_page/os_sync_controls.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_SIGNOUT_DIALOG_HTML"
-                 file="people_page/signout_dialog.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_SIGNOUT_DIALOG_JS"
-                 file="people_page/signout_dialog.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_PROFILE_INFO_BROWSER_PROXY_HTML"
-                 file="people_page/profile_info_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_PROFILE_INFO_BROWSER_PROXY_JS"
-                 file="people_page/profile_info_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_SYNC_BROWSER_PROXY_HTML"
-                 file="people_page/sync_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_SYNC_BROWSER_PROXY_JS"
-                 file="people_page/sync_browser_proxy.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PREF_UTIL_HTML"
-                 file="prefs/pref_util.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PREF_UTIL_JS"
-                 file="prefs/pref_util.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PREFS_HTML"
-                 file="prefs/prefs.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PREFS_JS"
-                 file="prefs/prefs.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PREFS_BEHAVIOR_HTML"
-                 file="prefs/prefs_behavior.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PREFS_BEHAVIOR_JS"
-                 file="prefs/prefs_behavior.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PREFS_TYPES_HTML"
-                 file="prefs/prefs_types.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PREFS_TYPES_JS"
-                 file="prefs/prefs_types.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PRINTING_PAGE_HTML"
-                 file="chromeos/os_printing_page/os_printing_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PRINTING_PAGE_JS"
-                 file="chromeos/os_printing_page/os_printing_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTER_TYPES_HTML"
-                 file="chromeos/os_printing_page/cups_printer_types.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTER_TYPES_JS"
-                 file="chromeos/os_printing_page/cups_printer_types.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTER_SHARED_CSS_HTML"
-                 file="chromeos/os_printing_page/cups_printer_shared_css.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTING_PAGE_HTML"
-                 file="chromeos/os_printing_page/cups_printers.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTING_PAGE_JS"
-                 file="chromeos/os_printing_page/cups_printers.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_BROWSER_PROXY_HTML"
-                 file="chromeos/os_printing_page/cups_printers_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_BROWSER_PROXY_JS"
-                 file="chromeos/os_printing_page/cups_printers_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_ENTRY_HTML"
-                 file="chromeos/os_printing_page/cups_printers_entry.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_ENTRY_JS"
-                 file="chromeos/os_printing_page/cups_printers_entry.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_ENTRY_LIST_BEHAVIOR_HTML"
-                 file="chromeos/os_printing_page/cups_printers_entry_list_behavior.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_ENTRY_LIST_BEHAVIOR_JS"
-                 file="chromeos/os_printing_page/cups_printers_entry_list_behavior.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_ENTRY_MANAGER_HTML"
-                 file="chromeos/os_printing_page/cups_printers_entry_manager.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_ENTRY_MANAGER_JS"
-                 file="chromeos/os_printing_page/cups_printers_entry_manager.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_EDIT_PRINTER_DIALOG_HTML"
-                 file="chromeos/os_printing_page/cups_edit_printer_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_EDIT_PRINTER_DIALOG_JS"
-                 file="chromeos/os_printing_page/cups_edit_printer_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_SETTINGS_ADD_PRINTER_DIALOG_HTML"
-                 file="chromeos/os_printing_page/cups_settings_add_printer_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_SETTINGS_ADD_PRINTER_DIALOG_JS"
-                 file="chromeos/os_printing_page/cups_settings_add_printer_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_ADD_PRINTER_DIALOG_HTML"
-                 file="chromeos/os_printing_page/cups_add_printer_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_ADD_PRINTER_DIALOG_JS"
-                 file="chromeos/os_printing_page/cups_add_printer_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_ADD_PRINT_SERVER_DIALOG_HTML"
-                 file="chromeos/os_printing_page/cups_add_print_server_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_ADD_PRINT_SERVER_DIALOG_JS"
-                 file="chromeos/os_printing_page/cups_add_print_server_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTER_DIALOG_ERROR_HTML"
-                 file="chromeos/os_printing_page/cups_printer_dialog_error.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTER_DIALOG_ERROR_JS"
-                 file="chromeos/os_printing_page/cups_printer_dialog_error.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_ADD_PRINTER_MANUFACTURER_MODEL_DIALOG_HTML"
-                 file="chromeos/os_printing_page/cups_add_printer_manufacturer_model_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_ADD_PRINTER_MANUFACTURER_MODEL_DIALOG_JS"
-                 file="chromeos/os_printing_page/cups_add_printer_manufacturer_model_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_ADD_PRINTER_MANUALLY_DIALOG_HTML"
-                 file="chromeos/os_printing_page/cups_add_printer_manually_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_ADD_PRINTER_MANUALLY_DIALOG_JS"
-                 file="chromeos/os_printing_page/cups_add_printer_manually_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTER_DIALOG_UTIL_HTML"
-                 file="chromeos/os_printing_page/cups_printer_dialog_util.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_PRINTER_DIALOG_UTIL_JS"
-                 file="chromeos/os_printing_page/cups_printer_dialog_util.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_SAVED_PRINTERS_HTML"
-                 file="chromeos/os_printing_page/cups_saved_printers.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_SAVED_PRINTERS_JS"
-                 file="chromeos/os_printing_page/cups_saved_printers.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_NEARBY_PRINTERS_HTML"
-                 file="chromeos/os_printing_page/cups_nearby_printers.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CUPS_NEARBY_PRINTERS_JS"
-                 file="chromeos/os_printing_page/cups_nearby_printers.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_PAGE_VISIBILITY_HTML"
-                 file="chromeos/os_page_visibility.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_PAGE_VISIBILITY_JS"
-                 file="chromeos/os_page_visibility.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PREF_TO_SETTING_METRIC_CONVERTER_HTML"
-                 file="chromeos/pref_to_setting_metric_converter.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PREF_TO_SETTING_METRIC_CONVERTER_JS"
-                 file="chromeos/pref_to_setting_metric_converter.js"
-                 compress="false" type="chrome_html" />
-      <!-- TODO(jamescook): Remove after sync settings is forked. -->
-      <structure name="IDR_OS_SETTINGS_PERSONALIZATION_OPTIONS_HTML"
-                 file="privacy_page/personalization_options.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PERSONALIZATION_OPTIONS_JS"
-                 file="privacy_page/personalization_options.js"
-                 preprocess="true"
-                 compress="false" type="chrome_html" />
-      <!-- TODO(jamescook): Remove after sync settings is forked. -->
-      <structure name="IDR_OS_SETTINGS_PRIVACY_PAGE_BROWSER_PROXY_HTML"
-                 file="privacy_page/privacy_page_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PRIVACY_PAGE_BROWSER_PROXY_JS"
-                 file="privacy_page/privacy_page_browser_proxy.js"
-                 preprocess="true"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_PRIVACY_PAGE_HTML"
-                 file="chromeos/os_privacy_page/os_privacy_page.html"
-                 compress="false" type="chrome_html"
-                 flattenhtml="true"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_OS_PRIVACY_PAGE_JS"
-                 file="chromeos/os_privacy_page/os_privacy_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_ROUTE_HTML"
-                 file="chromeos/os_route.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS__SETTINGS_ROUTES_HTML"
-                 file="chromeos/os_settings_routes.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS__SETTINGS_ROUTES_JS"
-                 file="chromeos/os_settings_routes.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_OS_ROUTE_JS"
-                 file="chromeos/os_route.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ROUTER_HTML"
-                 file="router.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ROUTER_JS"
-                 file="router.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ROUTE_ORIGIN_BEHAVIOR_HTML"
-                 file="chromeos/route_origin_behavior.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ROUTE_ORIGIN_BEHAVIOR_JS"
-                 file="chromeos/route_origin_behavior.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SEARCH_ENGINES_BROWSER_PROXY_JS"
-                 file="search_engines_page/search_engines_browser_proxy.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_SEARCH_ENGINES_BROWSER_PROXY_HTML"
-                 file="search_engines_page/search_engines_browser_proxy.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_GOOGLE_ASSISTANT_PAGE_GOOGLE_ASSISTANT_PAGE_JS"
-                 file="chromeos/google_assistant_page/google_assistant_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_GOOGLE_ASSISTANT_PAGE_GOOGLE_ASSISTANT_PAGE_HTML"
-                 file="chromeos/google_assistant_page/google_assistant_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_GOOGLE_ASSISTANT_PAGE_GOOGLE_ASSISTANT_BROWSER_PROXY_JS"
-                 file="chromeos/google_assistant_page/google_assistant_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_GOOGLE_ASSISTANT_PAGE_GOOGLE_ASSISTANT_BROWSER_PROXY_HTML"
-                 file="chromeos/google_assistant_page/google_assistant_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SEARCH_PAGE_JS"
-                 file="chromeos/os_search_page/os_search_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SEARCH_PAGE_HTML"
-                 file="chromeos/os_search_page/os_search_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SEARCH_SELECTION_DIALOG_JS"
-                 file="chromeos/os_search_page/os_search_selection_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SEARCH_SELECTION_DIALOG_HTML"
-                 file="chromeos/os_search_page/os_search_selection_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SYNC_CONTROLS_JS"
-                 file="people_page/sync_controls.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_SYNC_CONTROLS_HTML"
-                 file="people_page/sync_controls.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <!-- TODO(jamescook): Remove when SplitSettingsSync is the default. -->
-      <structure name="IDR_OS_SETTINGS_SYNC_ENCRYPTION_OPTIONS_JS"
-                 file="people_page/sync_encryption_options.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SYNC_ENCRYPTION_OPTIONS_HTML"
-                 file="people_page/sync_encryption_options.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SYNC_PAGE_JS"
-                 file="people_page/sync_page.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_SYNC_PAGE_HTML"
-                 file="people_page/sync_page.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_SETTINGS_PEOPLE_PAGE_SYNC_ACCOUNT_CONTROL_HTML"
-                  file="people_page/sync_account_control.html"
-                  compress="false" type="chrome_html"
-                  flattenhtml="true"
-                  allowexternalscript="true" />
-      <structure name="IDR_SETTINGS_PEOPLE_PAGE_SYNC_ACCOUNT_CONTROL_JS"
-                  file="people_page/sync_account_control.js"
-                  compress="false" type="chrome_html"
-                  preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_SETTINGS_HTML"
-                 file="chromeos/os_settings.html"
-                 preprocess="true"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_LAZY_LOAD_HTML"
-                 file="chromeos/lazy_load.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ANDROID_APPS_SUBPAGE_HTML"
-                 file="chromeos/os_apps_page/android_apps_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ANDROID_APPS_SUBPAGE_JS"
-                 file="chromeos/os_apps_page/android_apps_subpage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ANDROID_APPS_BROWSER_PROXY_JS"
-                 file="chromeos/os_apps_page/android_apps_browser_proxy.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_ANDROID_APPS_BROWSER_PROXY_HTML"
-                 file="chromeos/os_apps_page/android_apps_browser_proxy.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_PAGE_HTML"
-                 file="chromeos/crostini_page/crostini_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_PAGE_JS"
-                 file="chromeos/crostini_page/crostini_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_SUBPAGE_HTML"
-                 file="chromeos/crostini_page/crostini_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_SUBPAGE_JS"
-                 file="chromeos/crostini_page/crostini_subpage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_ARC_ADB_HTML"
-                 file="chromeos/crostini_page/crostini_arc_adb.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_ARC_ADB_JS"
-                 file="chromeos/crostini_page/crostini_arc_adb.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_ARC_ADB_CONFIRMATION_DIALOG_HTML"
-                 file="chromeos/crostini_page/crostini_arc_adb_confirmation_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_ARC_ADB_CONFIRMATION_DIALOG_JS"
-                 file="chromeos/crostini_page/crostini_arc_adb_confirmation_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_DISK_RESIZE_DIALOG_HTML"
-                 file="chromeos/crostini_page/crostini_disk_resize_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_DISK_RESIZE_DIALOG_JS"
-                 file="chromeos/crostini_page/crostini_disk_resize_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_DISK_RESIZE_CONFIRMATION_DIALOG_HTML"
-                 file="chromeos/crostini_page/crostini_disk_resize_confirmation_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_DISK_RESIZE_CONFIRMATION_DIALOG_JS"
-                 file="chromeos/crostini_page/crostini_disk_resize_confirmation_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_EXPORT_IMPORT_HTML"
-                 file="chromeos/crostini_page/crostini_export_import.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_EXPORT_IMPORT_JS"
-                 file="chromeos/crostini_page/crostini_export_import.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_PORT_FORWARDING_HTML"
-                  file="chromeos/crostini_page/crostini_port_forwarding.html"
-                  compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_PORT_FORWARDING_ADD_PORT_DIALOG_HTML"
-                  file="chromeos/crostini_page/crostini_port_forwarding_add_port_dialog.html"
-                  compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_PORT_FORWARDING_ADD_PORT_DIALOG_JS"
-                  file="chromeos/crostini_page/crostini_port_forwarding_add_port_dialog.js"
-                  compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_PORT_FORWARDING_JS"
-                  file="chromeos/crostini_page/crostini_port_forwarding.js"
-                  compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_MIC_SHARING_DIALOG_HTML"
-                 file="chromeos/crostini_page/crostini_mic_sharing_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_MIC_SHARING_DIALOG_JS"
-                 file="chromeos/crostini_page/crostini_mic_sharing_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_SHARED_PATHS_HTML"
-                 file="chromeos/crostini_page/crostini_shared_paths.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_SHARED_PATHS_JS"
-                 file="chromeos/crostini_page/crostini_shared_paths.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_HTML"
-                 file="chromeos/crostini_page/crostini_shared_usb_devices.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_JS"
-                 file="chromeos/crostini_page/crostini_shared_usb_devices.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_BROWSER_PROXY_JS"
-                 file="chromeos/crostini_page/crostini_browser_proxy.js"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_CROSTINI_BROWSER_PROXY_HTML"
-                 file="chromeos/crostini_page/crostini_browser_proxy.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_SETTINGS_CROSTINI_IMPORT_CONFIRMATION_DIALOG_HTML"
-                 file="chromeos/crostini_page/crostini_import_confirmation_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_SETTINGS_CROSTINI_IMPORT_CONFIRMATION_DIALOG_JS"
-                 file="chromeos/crostini_page/crostini_import_confirmation_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_BLUETOOTH_DEVICE_LIST_ITEM_HTML"
-                 file="chromeos/bluetooth_page/bluetooth_device_list_item.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_BLUETOOTH_DEVICE_LIST_ITEM_JS"
-                 file="chromeos/bluetooth_page/bluetooth_device_list_item.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_BLUETOOTH_PAGE_HTML"
-                 file="chromeos/bluetooth_page/bluetooth_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_BLUETOOTH_PAGE_JS"
-                 file="chromeos/bluetooth_page/bluetooth_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_BLUETOOTH_SUBPAGE_HTML"
-                 file="chromeos/bluetooth_page/bluetooth_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_BLUETOOTH_SUBPAGE_JS"
-                 file="chromeos/bluetooth_page/bluetooth_subpage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DATE_TIME_PAGE_HTML"
-                 file="chromeos/date_time_page/date_time_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DATE_TIME_PAGE_JS"
-                 file="chromeos/date_time_page/date_time_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DATE_TIME_TYPES_HTML"
-                 file="chromeos/date_time_page/date_time_types.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_DATE_TIME_TYPES_JS"
-                 file="chromeos/date_time_page/date_time_types.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TIMEZONE_BROWSER_PROXY_JS"
-                 file="chromeos/date_time_page/timezone_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TIMEZONE_BROWSER_PROXY_HTML"
-                 file="chromeos/date_time_page/timezone_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TIMEZONE_SELECTOR_HTML"
-                 file="chromeos/date_time_page/timezone_selector.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TIMEZONE_SELECTOR_JS"
-                 file="chromeos/date_time_page/timezone_selector.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TIMEZONE_SUBPAGE_HTML"
-                 file="chromeos/date_time_page/timezone_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TIMEZONE_SUBPAGE_JS"
-                 file="chromeos/date_time_page/timezone_subpage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_CONFIG_HTML"
-                 file="chromeos/internet_page/internet_config.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_CONFIG_JS"
-                 file="chromeos/internet_page/internet_config.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_DETAIL_MENU_HTML"
-                 file="chromeos/internet_page/internet_detail_menu.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_DETAIL_MENU_JS"
-                 file="chromeos/internet_page/internet_detail_menu.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_DETAIL_PAGE_HTML"
-                 file="chromeos/internet_page/internet_detail_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_DETAIL_PAGE_JS"
-                 file="chromeos/internet_page/internet_detail_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_KNOWN_NETWORKS_PAGE_HTML"
-                 file="chromeos/internet_page/internet_known_networks_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_KNOWN_NETWORKS_PAGE_JS"
-                 file="chromeos/internet_page/internet_known_networks_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_PAGE_BROWSER_PROXY_HTML"
-                 file="chromeos/internet_page/internet_page_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_PAGE_BROWSER_PROXY_JS"
-                 file="chromeos/internet_page/internet_page_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CELLULAR_SETUP_SETTINGS_DELEGATE_HTML"
-                 file="chromeos/internet_page/cellular_setup_settings_delegate.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CELLULAR_SETUP_SETTINGS_DELEGATE_JS"
-                 file="chromeos/internet_page/cellular_setup_settings_delegate.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_PAGE_HTML"
-                 file="chromeos/internet_page/internet_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_PAGE_JS"
-                 file="chromeos/internet_page/internet_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_SHARED_CSS_HTML"
-                 file="chromeos/internet_page/internet_shared_css.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_SUBPAGE_HTML"
-                 file="chromeos/internet_page/internet_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_INTERNET_SUBPAGE_JS"
-                 file="chromeos/internet_page/internet_subpage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_BROWSER_PROXY_HTML"
-                 file="chromeos/multidevice_page/multidevice_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_BROWSER_PROXY_JS"
-                 file="chromeos/multidevice_page/multidevice_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_CONSTANTS_HTML"
-                 file="chromeos/multidevice_page/multidevice_constants.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_CONSTANTS_JS"
-                 file="chromeos/multidevice_page/multidevice_constants.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_FEATURE_BEHAVIOR_HTML"
-                 file="chromeos/multidevice_page/multidevice_feature_behavior.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_FEATURE_BEHAVIOR_JS"
-                 file="chromeos/multidevice_page/multidevice_feature_behavior.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_FEATURE_ITEM_HTML"
-                 file="chromeos/multidevice_page/multidevice_feature_item.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_FEATURE_ITEM_JS"
-                 file="chromeos/multidevice_page/multidevice_feature_item.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_FEATURE_TOGGLE_HTML"
-                 file="chromeos/multidevice_page/multidevice_feature_toggle.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_FEATURE_TOGGLE_JS"
-                 file="chromeos/multidevice_page/multidevice_feature_toggle.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_PAGE_HTML"
-                 file="chromeos/multidevice_page/multidevice_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_PAGE_JS"
-                 file="chromeos/multidevice_page/multidevice_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_NOTIFICATIONS_ACCESS_SETUP_DIALOG_HTML"
-                 file="chromeos/multidevice_page/multidevice_notification_access_setup_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_NOTIFICATIONS_ACCESS_SETUP_DIALOG_JS"
-                 file="chromeos/multidevice_page/multidevice_notification_access_setup_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_RADIO_BUTTON_HTML"
-                 file="chromeos/multidevice_page/multidevice_radio_button.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_RADIO_BUTTON_JS"
-                 file="chromeos/multidevice_page/multidevice_radio_button.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_SMARTLOCK_SUBPAGE_HTML"
-                 file="chromeos/multidevice_page/multidevice_smartlock_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_SMARTLOCK_SUBPAGE_JS"
-                 file="chromeos/multidevice_page/multidevice_smartlock_subpage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_SUBPAGE_HTML"
-                 file="chromeos/multidevice_page/multidevice_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_SUBPAGE_JS"
-                 file="chromeos/multidevice_page/multidevice_subpage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_TETHER_ITEM_HTML"
-                 file="chromeos/multidevice_page/multidevice_tether_item.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_TETHER_ITEM_JS"
-                 file="chromeos/multidevice_page/multidevice_tether_item.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_multidevice_wifi_sync_item_HTML"
-                 file="chromeos/multidevice_page/multidevice_wifi_sync_item.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_multidevice_wifi_sync_item_JS"
-                 file="chromeos/multidevice_page/multidevice_wifi_sync_item.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_WIFI_SYNC_DISABLED_LINK_HTML"
-                 file="chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_MULTIDEVICE_WIFI_SYNC_DISABLED_LINK_JS"
-                 file="chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_CONFIRM_PAGE_HTML"
-                 file="chromeos/nearby_share_page/nearby_share_confirm_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_CONFIRM_PAGE_JS"
-                 file="chromeos/nearby_share_page/nearby_share_confirm_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_DIALOG_HTML"
-                 file="chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_DIALOG_JS"
-                 file="chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_ACCOUNT_MANAGER_BROWSER_PROXY_HTML"
-                 file="chromeos/nearby_share_page/nearby_account_manager_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_ACCOUNT_MANAGER_BROWSER_PROXY_JS"
-                 file="chromeos/nearby_share_page/nearby_account_manager_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_DIALOG_HTML"
-                 file="chromeos/nearby_share_page/nearby_share_device_name_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_DIALOG_JS"
-                 file="chromeos/nearby_share_page/nearby_share_device_name_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_HIGH_VISIBILITY_PAGE_HTML"
-                 file="chromeos/nearby_share_page/nearby_share_high_visibility_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_HIGH_VISIBILITY_PAGE_JS"
-                 file="chromeos/nearby_share_page/nearby_share_high_visibility_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_RECEIVE_DIALOG_HTML"
-                 file="chromeos/nearby_share_page/nearby_share_receive_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_RECEIVE_DIALOG_JS"
-                 file="chromeos/nearby_share_page/nearby_share_receive_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_RECEIVE_MANAGER_HTML"
-                 file="chromeos/nearby_share_page/nearby_share_receive_manager.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_RECEIVE_MANAGER_JS"
-                 file="chromeos/nearby_share_page/nearby_share_receive_manager.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_DATA_USAGE_DIALOG_HTML"
-                 file="chromeos/nearby_share_page/nearby_share_data_usage_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_DATA_USAGE_DIALOG_JS"
-                 file="chromeos/nearby_share_page/nearby_share_data_usage_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_TYPES_HTML"
-                 file="chromeos/nearby_share_page/types.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_TYPES_JS"
-                 file="chromeos/nearby_share_page/types.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_SUBPAGE_HTML"
-                 file="chromeos/nearby_share_page/nearby_share_subpage.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_SUBPAGE_JS"
-                 file="chromeos/nearby_share_page/nearby_share_subpage.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NETWORK_PROXY_SECTION_HTML"
-                 file="chromeos/internet_page/network_proxy_section.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NETWORK_PROXY_SECTION_JS"
-                 file="chromeos/internet_page/network_proxy_section.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NETWORK_SUMMARY_HTML"
-                 file="chromeos/internet_page/network_summary.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NETWORK_SUMMARY_JS"
-                 file="chromeos/internet_page/network_summary.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NETWORK_SUMMARY_ITEM_HTML"
-                 file="chromeos/internet_page/network_summary_item.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_NETWORK_SUMMARY_ITEM_JS"
-                 file="chromeos/internet_page/network_summary_item.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TETHER_CONNECTION_DIALOG_HTML"
-                 file="chromeos/internet_page/tether_connection_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_TETHER_CONNECTION_DIALOG_JS"
-                 file="chromeos/internet_page/tether_connection_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CELLULAR_SETUP_DIALOG_HTML"
-                 file="chromeos/internet_page/cellular_setup_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_CELLULAR_SETUP_DIALOG_JS"
-                 file="chromeos/internet_page/cellular_setup_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PARENTAL_CONTROLS_BROWSER_PROXY_HTML"
-                 file="chromeos/parental_controls_page/parental_controls_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PARENTAL_CONTROLS_BROWSER_PROXY_JS"
-                 file="chromeos/parental_controls_page/parental_controls_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PARENTAL_CONTROLS_PAGE_HTML"
-                 file="chromeos/parental_controls_page/parental_controls_page.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PARENTAL_CONTROLS_PAGE_JS"
-                 file="chromeos/parental_controls_page/parental_controls_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_ACCOUNT_MANAGER_HTML"
-                 file="chromeos/os_people_page/account_manager.html"
-                 compress="false" type="chrome_html"/>
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_ACCOUNT_MANAGER_JS"
-                 file="chromeos/os_people_page/account_manager.js"
-                 compress="false" type="chrome_html"/>
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_ACCOUNT_MANAGER_BROWSER_PROXY_HTML"
-                 file="people_page/account_manager_browser_proxy.html"
-                 compress="false" type="chrome_html"/>
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_ACCOUNT_MANAGER_BROWSER_PROXY_JS"
-                 file="people_page/account_manager_browser_proxy.js"
-                 compress="false" type="chrome_html"/>
-      <structure name="IDR_OS_SETTINGS_PERSONALIZATION_PAGE_CHANGE_PICTURE_HTML"
-                 file="chromeos/personalization_page/change_picture.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PERSONALIZATION_PAGE_CHANGE_PICTURE_JS"
-                 file="chromeos/personalization_page/change_picture.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PERSONALIZATION_PAGE_CHANGE_PICTURE_BROWSER_PROXY_JS"
-                 file="chromeos/personalization_page/change_picture_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PERSONALIZATION_PAGE_CHANGE_PICTURE_BROWSER_PROXY_HTML"
-                 file="chromeos/personalization_page/change_picture_browser_proxy.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_KERBEROS_ACCOUNTS_HTML"
-                 file="chromeos/os_people_page/kerberos_accounts.html"
-                 compress="false" type="chrome_html"/>
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_KERBEROS_ACCOUNTS_JS"
-                 file="chromeos/os_people_page/kerberos_accounts.js"
-                 compress="false" type="chrome_html"/>
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_KERBEROS_ADD_ACCOUNT_DIALOG_HTML"
-                 file="chromeos/os_people_page/kerberos_add_account_dialog.html"
-                 compress="false" type="chrome_html"/>
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_KERBEROS_ADD_ACCOUNT_DIALOG_JS"
-                 file="chromeos/os_people_page/kerberos_add_account_dialog.js"
-                 compress="false" type="chrome_html"/>
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_KEREROS_ACCOUNTS_BROWSER_PROXY_HTML"
-                 file="chromeos/os_people_page/kerberos_accounts_browser_proxy.html"
-                 compress="false" type="chrome_html"/>
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_KEREROS_ACCOUNTS_BROWSER_PROXY_JS"
-                 file="chromeos/os_people_page/kerberos_accounts_browser_proxy.js"
-                 compress="false" type="chrome_html"/>
-      <structure name="IDR_OS_SETTINGS_PEOPLE_LOCK_SCREEN_PASSWORD_PROMPT_DIALOG_JS"
-                 file="chromeos/os_people_page/lock_screen_password_prompt_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_LOCK_SCREEN_PASSWORD_PROMPT_DIALOG_HTML"
-                 file="chromeos/os_people_page/lock_screen_password_prompt_dialog.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_LOCK_SCREEN_JS"
-                 file="chromeos/os_people_page/lock_screen.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_LOCK_SCREEN_HTML"
-                 file="chromeos/os_people_page/lock_screen.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_LOCK_STATE_BEHAVIOR_JS"
-                 file="chromeos/os_people_page/lock_state_behavior.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_LOCK_STATE_BEHAVIOR_HTML"
-                 file="chromeos/os_people_page/lock_state_behavior.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PIN_AUTOSUBMIT_DIALOG_JS"
-                 file="chromeos/os_people_page/pin_autosubmit_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_PIN_AUTOSUBMIT_DIALOG_HTML"
-                 file="chromeos/os_people_page/pin_autosubmit_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_SETUP_PIN_DIALOG_JS"
-                 file="chromeos/os_people_page/setup_pin_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_SETUP_PIN_DIALOG_HTML"
-                 file="chromeos/os_people_page/setup_pin_dialog.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_FINGERPRINT_LIST_JS"
-                 file="chromeos/os_people_page/fingerprint_list.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_FINGERPRINT_LIST_HTML"
-                 file="chromeos/os_people_page/fingerprint_list.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_SETUP_FINGERPRINT_DIALOG_JS"
-                 file="chromeos/os_people_page/setup_fingerprint_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_SETUP_FINGERPRINT_DIALOG_HTML"
-                 file="chromeos/os_people_page/setup_fingerprint_dialog.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_FINGERPRINT_BROWSER_PROXY_JS"
-                 file="chromeos/os_people_page/fingerprint_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_PEOPLE_FINGERPRINT_BROWSER_PROXY_HTML"
-                 file="chromeos/os_people_page/fingerprint_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_USERS_PAGE_ADD_USER_DIALOG_JS"
-                 file="chromeos/os_people_page/users_add_user_dialog.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_USERS_PAGE_ADD_USER_DIALOG_HTML"
-                 file="chromeos/os_people_page/users_add_user_dialog.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_USERS_PAGE_USER_LIST_JS"
-                 file="chromeos/os_people_page/user_list.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_USERS_PAGE_USER_LIST_HTML"
-                 file="chromeos/os_people_page/user_list.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_USERS_PAGE_JS"
-                 file="chromeos/os_people_page/users_page.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_USERS_PAGE_HTML"
-                 file="chromeos/os_people_page/users_page.html"
-                 compress="false" type="chrome_html"
-                 preprocess="true" />
-      <structure name="IDR_OS_SETTINGS_WALLPAPER_BROWSER_PROXY_HTML"
-                 file="chromeos/personalization_page/wallpaper_browser_proxy.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_WALLPAPER_BROWSER_PROXY_JS"
-                 file="chromeos/personalization_page/wallpaper_browser_proxy.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_METRICS_RECORDER_HTML"
-                 file="chromeos/metrics_recorder.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_METRICS_RECORDER_JS"
-                 file="chromeos/metrics_recorder.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SEARCH_HANDLER_HTML"
-                 file="chromeos/search_handler.html"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_SEARCH_HANDLER_JS"
-                 file="chromeos/search_handler.js"
-                 compress="false" type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ICON_ADD_CIRCLE_SVG"
-                 file="chromeos/images/icon_add_circle.svg"
-                 type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ICON_ADD_WIFI_SVG"
-                 file="chromeos/images/icon_add_wifi.svg"
-                 type="chrome_html" />
-      <structure name="IDR_OS_SETTINGS_ICON_ADD_CELLULAR_SVG"
-                 file="chromeos/images/icon_add_cellular.svg"
-                 type="chrome_html" />
-    </structures>
-  </release>
-</grit>
diff --git a/chrome/browser/resources/settings/os_settings_resources_vulcanized.grd b/chrome/browser/resources/settings/os_settings_resources_vulcanized.grd
deleted file mode 100644
index 5722db0..0000000
--- a/chrome/browser/resources/settings/os_settings_resources_vulcanized.grd
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
-  <outputs>
-    <output filename="grit/os_settings_resources.h" type="rc_header">
-      <emit emit_type='prepend'></emit>
-    </output>
-    <output filename="grit/os_settings_resources_map.cc"
-            type="resource_map_source" />
-    <output filename="grit/os_settings_resources_map.h"
-            type="resource_map_header" />
-    <output filename="os_settings_resources.pak" type="data_package" />
-  </outputs>
-  <release seq="1">
-    <includes>
-      <include name="IDR_OS_SETTINGS_VULCANIZED_HTML"
-               file="${root_gen_dir}\chrome\browser\resources\settings\chromeos\vulcanized.html"
-               use_base_dir="false"
-               flattenhtml="true"
-               allowexternalscript="true"
-               type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_CRISPER_JS"
-               file="${root_gen_dir}\chrome\browser\resources\settings\chromeos\crisper.js"
-               use_base_dir="false"
-               flattenhtml="true"
-               type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_LAZY_LOAD_VULCANIZED_HTML"
-               file="${root_gen_dir}\chrome\browser\resources\settings\chromeos\lazy_load.vulcanized.html"
-               use_base_dir="false"
-               flattenhtml="true"
-               allowexternalscript="true"
-               type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_LAZY_LOAD_CRISPER_JS"
-               file="${root_gen_dir}\chrome\browser\resources\settings\chromeos\lazy_load.crisper.js"
-               use_base_dir="false"
-               flattenhtml="true"
-               type="BINDATA" />
-
-      <!-- Constants -->
-      <include name="IDR_OS_SETTINGS_ROUTES_MOJOM_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\settings\chromeos\constants\routes.mojom-lite.js"
-               use_base_dir="false"
-               type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_SETTING_MOJOM_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\settings\chromeos\constants\setting.mojom-lite.js"
-               use_base_dir="false"
-               type="BINDATA" />
-
-      <!-- App Management -->
-      <include name="IDR_OS_SETTINGS_APP_MANAGEMENT_FILE_PATH_MOJO_LITE_JS"
-               file="${root_gen_dir}\mojo\public\mojom\base\file_path.mojom-lite.js"
-               use_base_dir="false"
-               type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_APP_MANAGEMENT_IMAGE_MOJO_LITE_JS"
-               file="${root_gen_dir}\ui\gfx\image\mojom\image.mojom-lite.js"
-               use_base_dir="false"
-               type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_APP_MANAGEMENT_MOJO_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\app_management\app_management.mojom-lite.js"
-               use_base_dir="false"
-               type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_APP_MANAGEMENT_TYPES_MOJO_LITE_JS"
-               file="${root_gen_dir}\components\services\app_service\public\mojom\types.mojom-lite.js"
-               use_base_dir="false"
-               type="BINDATA" />
-
-      <!-- Search -->
-      <include name="IDR_OS_SETTINGS_SEARCH_MOJOM_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\settings\chromeos\search\search.mojom-lite.js"
-               use_base_dir="false"
-               type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_SEARCH_RESULT_ICON_MOJOM_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\settings\chromeos\search\search_result_icon.mojom-lite.js"
-               use_base_dir="false"
-               type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_USER_ACTION_RECORDER_MOJOM_LITE_JS"
-               file="${root_gen_dir}\chrome\browser\ui\webui\settings\chromeos\search\user_action_recorder.mojom-lite.js"
-               use_base_dir="false"
-               type="BINDATA" />
-
-      <!-- Polymer3 related files-->
-      <include name="IDR_OS_SETTINGS_OS_SETTINGS_ROLLUP_JS"
-               file="${root_gen_dir}\chrome\browser\resources\settings\chromeos\os_settings.rollup.js"
-               use_base_dir="false"
-               type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_OS_SETTINGS_V3_HTML"
-               file="chromeos/os_settings_v3.html"
-               type="BINDATA" />
-      <include name="IDR_OS_SETTINGS_LAZY_LOAD_ROLLUP_JS"
-               file="${root_gen_dir}\chrome\browser\resources\settings\chromeos\lazy_load.rollup.js"
-               type="BINDATA"
-               use_base_dir="false" />
-      <include name="IDR_OS_SETTINGS_SHARED_ROLLUP_JS"
-               file="${root_gen_dir}\chrome\browser\resources\settings\chromeos\shared.rollup.js"
-               type="BINDATA"
-               use_base_dir="false" />
-
-      <!-- SVG assets -->
-      <include name="IDR_OS_SETTINGS_ICON_ADD_CIRCLE_SVG"
-               file="chromeos/images/icon_add_circle.svg"
-               type="BINDATA"
-               compress="gzip" />
-      <include name="IDR_OS_SETTINGS_ICON_ADD_WIFI_SVG"
-               file="chromeos/images/icon_add_wifi.svg"
-               type="BINDATA"
-               compress="gzip" />
-      <include name="IDR_OS_SETTINGS_ICON_ADD_CELLULAR_SVG"
-               file="chromeos/images/icon_add_cellular.svg"
-               type="BINDATA"
-               compress="gzip" />
-    </includes>
-  </release>
-</grit>
diff --git a/chrome/browser/safe_browsing/mock_report_sender.cc b/chrome/browser/safe_browsing/mock_report_sender.cc
deleted file mode 100644
index 2aace2f2..0000000
--- a/chrome/browser/safe_browsing/mock_report_sender.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/safe_browsing/mock_report_sender.h"
-
-#include "base/bind.h"
-#include "base/run_loop.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-
-namespace safe_browsing {
-
-MockReportSender::MockReportSender()
-    : net::ReportSender(nullptr, TRAFFIC_ANNOTATION_FOR_TESTS),
-      number_of_reports_(0) {
-  DCHECK(quit_closure_.is_null());
-}
-
-MockReportSender::~MockReportSender() {}
-
-void MockReportSender::Send(
-    const GURL& report_uri,
-    base::StringPiece content_type,
-    base::StringPiece report,
-    base::OnceCallback<void()> success_callback,
-    base::OnceCallback<void(const GURL&, int, int)> error_callback) {
-  latest_report_uri_ = report_uri;
-  latest_report_.assign(report.data(), report.size());
-  latest_content_type_.assign(content_type.data(), content_type.size());
-  number_of_reports_++;
-
-  // BrowserThreads aren't initialized in the unittest, so don't post tasks
-  // to them.
-  if (!content::BrowserThread::IsThreadInitialized(content::BrowserThread::UI))
-    return;
-
-  content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&MockReportSender::NotifyReportSentOnUIThread,
-                                base::Unretained(this)));
-}
-
-void MockReportSender::WaitForReportSent() {
-  base::RunLoop run_loop;
-  quit_closure_ = run_loop.QuitClosure();
-  run_loop.Run();
-}
-
-void MockReportSender::NotifyReportSentOnUIThread() {
-  if (!quit_closure_.is_null()) {
-    quit_closure_.Run();
-    quit_closure_.Reset();
-  }
-}
-
-const GURL& MockReportSender::latest_report_uri() {
-  return latest_report_uri_;
-}
-
-const std::string& MockReportSender::latest_report() {
-  return latest_report_;
-}
-
-const std::string& MockReportSender::latest_content_type() {
-  return latest_content_type_;
-}
-
-int MockReportSender::GetAndResetNumberOfReportsSent() {
-  int new_reports = number_of_reports_;
-  number_of_reports_ = 0;
-  return new_reports;
-}
-
-}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/mock_report_sender.h b/chrome/browser/safe_browsing/mock_report_sender.h
deleted file mode 100644
index f604958..0000000
--- a/chrome/browser/safe_browsing/mock_report_sender.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SAFE_BROWSING_MOCK_REPORT_SENDER_H_
-#define CHROME_BROWSER_SAFE_BROWSING_MOCK_REPORT_SENDER_H_
-
-#include "net/url_request/report_sender.h"
-
-namespace safe_browsing {
-
-// A mock ReportSender that keeps track of the last report sent and the number
-// of reports sent.
-class MockReportSender : public net::ReportSender {
- public:
-  MockReportSender();
-
-  ~MockReportSender() override;
-
-  void Send(
-      const GURL& report_uri,
-      base::StringPiece content_type,
-      base::StringPiece report,
-      base::OnceCallback<void()> success_callback,
-      base::OnceCallback<void(const GURL&, int, int)> error_callback) override;
-
-  const GURL& latest_report_uri();
-
-  const std::string& latest_report();
-
-  const std::string& latest_content_type();
-
-  int GetAndResetNumberOfReportsSent();
-
-  void WaitForReportSent();
-
- private:
-  GURL latest_report_uri_;
-  std::string latest_report_;
-  std::string latest_content_type_;
-  int number_of_reports_;
-  base::Closure quit_closure_;
-
-  void NotifyReportSentOnUIThread();
-
-  DISALLOW_COPY_AND_ASSIGN(MockReportSender);
-};
-
-}  // namespace safe_browsing
-
-#endif  // CHROME_BROWSER_SAFE_BROWSING_MOCK_REPORT_SENDER_H_
diff --git a/chrome/browser/search/background/ntp_background_service_factory.cc b/chrome/browser/search/background/ntp_background_service_factory.cc
index f136176e..7cc8686 100644
--- a/chrome/browser/search/background/ntp_background_service_factory.cc
+++ b/chrome/browser/search/background/ntp_background_service_factory.cc
@@ -12,8 +12,8 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/background/ntp_background_service.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/search/ntp_features.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
 
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index de4385bb..96dee7a 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -29,7 +29,6 @@
 #include "chrome/browser/search/instant_service_observer.h"
 #include "chrome/browser/search/local_ntp_source.h"
 #include "chrome/browser/search/most_visited_iframe_source.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/ntp_icon_source.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
@@ -48,6 +47,7 @@
 #include "components/ntp_tiles/constants.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
 #include "components/search/search_provider_observer.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "content/public/browser/browser_context.h"
diff --git a/chrome/browser/search/instant_service_unittest.cc b/chrome/browser/search/instant_service_unittest.cc
index 10a5c79..422034d 100644
--- a/chrome/browser/search/instant_service_unittest.cc
+++ b/chrome/browser/search/instant_service_unittest.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/search/background/ntp_background_service.h"
 #include "chrome/browser/search/instant_service_observer.h"
 #include "chrome/browser/search/instant_unittest_base.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
@@ -25,6 +24,7 @@
 #include "components/ntp_tiles/features.h"
 #include "components/ntp_tiles/ntp_tile.h"
 #include "components/ntp_tiles/section_type.h"
+#include "components/search/ntp_features.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/search/local_ntp_navigation_browsertest.cc b/chrome/browser/search/local_ntp_navigation_browsertest.cc
index 4619ca6..84e42ad 100644
--- a/chrome/browser/search/local_ntp_navigation_browsertest.cc
+++ b/chrome/browser/search/local_ntp_navigation_browsertest.cc
@@ -4,13 +4,13 @@
 
 #include "base/feature_list.h"
 #include "base/strings/strcat.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/search/ntp_features.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index 7dca2792..845a8cf 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -31,7 +31,6 @@
 #include "chrome/browser/search/background/ntp_background_service_factory.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/local_ntp_js_integrity.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/one_google_bar/one_google_bar_data.h"
 #include "chrome/browser/search/one_google_bar/one_google_bar_service_factory.h"
 #include "chrome/browser/search/promos/promo_data.h"
@@ -56,6 +55,7 @@
 #include "components/omnibox/common/omnibox_features.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
 #include "components/search/search.h"
 #include "components/search_engines/search_terms_data.h"
 #include "components/search_engines/template_url_service.h"
diff --git a/chrome/browser/search/most_visited_iframe_source.cc b/chrome/browser/search/most_visited_iframe_source.cc
index 7aa5ccb..4a05a8b 100644
--- a/chrome/browser/search/most_visited_iframe_source.cc
+++ b/chrome/browser/search/most_visited_iframe_source.cc
@@ -9,9 +9,9 @@
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "chrome/browser/search/instant_service.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/local_ntp_resources.h"
+#include "components/search/ntp_features.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/chrome/browser/search/ntp_features_unittest.cc b/chrome/browser/search/ntp_features_unittest.cc
index 56b2379..351e66df 100644
--- a/chrome/browser/search/ntp_features_unittest.cc
+++ b/chrome/browser/search/ntp_features_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/search/ntp_features.h"
+#include "components/search/ntp_features.h"
 
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/search/promos/promo_service.cc b/chrome/browser/search/promos/promo_service.cc
index 317c487..e6c464a3 100644
--- a/chrome/browser/search/promos/promo_service.cc
+++ b/chrome/browser/search/promos/promo_service.cc
@@ -17,13 +17,13 @@
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_checkup.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/google/core/common/google_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "components/search/ntp_features.h"
 #include "content/public/browser/system_connector.h"
 #include "extensions/common/extension_features.h"
 #include "net/base/load_flags.h"
diff --git a/chrome/browser/search/promos/promo_service_unittest.cc b/chrome/browser/search/promos/promo_service_unittest.cc
index 8008b22..3d6e9f3 100644
--- a/chrome/browser/search/promos/promo_service_unittest.cc
+++ b/chrome/browser/search/promos/promo_service_unittest.cc
@@ -13,13 +13,13 @@
 #include "base/test/task_environment.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/promos/promo_data.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "components/search/ntp_features.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "content/public/test/browser_task_environment.h"
 #include "extensions/common/extension.h"
diff --git a/chrome/browser/search/search.cc b/chrome/browser/search/search.cc
index 6470261..8b94562f 100644
--- a/chrome/browser/search/search.cc
+++ b/chrome/browser/search/search.cc
@@ -11,12 +11,12 @@
 #include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "components/google/core/common/google_util.h"
+#include "components/search/ntp_features.h"
 #include "components/search/search.h"
 #include "components/search_engines/search_engine_type.h"
 #include "components/search_engines/template_url_service.h"
diff --git a/chrome/browser/search/search_suggest/search_suggest_service.cc b/chrome/browser/search/search_suggest/search_suggest_service.cc
index f25849b4..8bdec16 100644
--- a/chrome/browser/search/search_suggest/search_suggest_service.cc
+++ b/chrome/browser/search/search_suggest/search_suggest_service.cc
@@ -12,13 +12,13 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search/search_suggest/search_suggest_loader.h"
 #include "chrome/common/pref_names.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/common/omnibox_features.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "components/search/ntp_features.h"
 #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "third_party/re2/src/re2/re2.h"
diff --git a/chrome/browser/search/search_suggest/search_suggest_service_factory.cc b/chrome/browser/search/search_suggest/search_suggest_service_factory.cc
index 080e40a..d5159f2 100644
--- a/chrome/browser/search/search_suggest/search_suggest_service_factory.cc
+++ b/chrome/browser/search/search_suggest/search_suggest_service_factory.cc
@@ -12,12 +12,12 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search_suggest/search_suggest_loader_impl.h"
 #include "chrome/browser/search/search_suggest/search_suggest_service.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/search/ntp_features.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
 
diff --git a/chrome/browser/search/search_suggest/search_suggest_service_unittest.cc b/chrome/browser/search/search_suggest/search_suggest_service_unittest.cc
index c474898..a79af5b7 100644
--- a/chrome/browser/search/search_suggest/search_suggest_service_unittest.cc
+++ b/chrome/browser/search/search_suggest/search_suggest_service_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search_suggest/search_suggest_data.h"
 #include "chrome/browser/search/search_suggest/search_suggest_loader.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
@@ -20,6 +19,7 @@
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/search_test_utils.h"
 #include "components/omnibox/common/omnibox_features.h"
+#include "components/search/ntp_features.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/signin/public/base/test_signin_client.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc
index e19249a0..cf82c4b 100644
--- a/chrome/browser/signin/dice_browsertest.cc
+++ b/chrome/browser/signin/dice_browsertest.cc
@@ -30,7 +30,6 @@
 #include "chrome/browser/policy/cloud/user_policy_signin_service_internal.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/signin/account_reconcilor_factory.h"
 #include "chrome/browser/signin/chrome_device_id_helper.h"
@@ -53,6 +52,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
 #include "components/signin/core/browser/account_reconcilor.h"
 #include "components/signin/core/browser/dice_header_helper.h"
 #include "components/signin/core/browser/signin_header_helper.h"
diff --git a/chrome/browser/subresource_filter/ads_intervention_manager_browsertest.cc b/chrome/browser/subresource_filter/ads_intervention_manager_browsertest.cc
index 8eeef753..e4d790f 100644
--- a/chrome/browser/subresource_filter/ads_intervention_manager_browsertest.cc
+++ b/chrome/browser/subresource_filter/ads_intervention_manager_browsertest.cc
@@ -24,6 +24,11 @@
 namespace {
 
 const char kSubresourceFilterActionsHistogram[] = "SubresourceFilter.Actions2";
+const char kAdsInterventionRecordedHistogram[] =
+    "SubresourceFilter.PageLoad.AdsInterventionTriggered";
+const char kTimeSinceAdsInterventionTriggeredHistogram[] =
+    "SubresourceFilter.PageLoad."
+    "TimeSinceLastActiveAdsIntervention";
 
 }  // namespace
 
@@ -60,6 +65,9 @@
   histogram_tester.ExpectBucketCount(
       kSubresourceFilterActionsHistogram,
       subresource_filter::SubresourceFilterAction::kUIShown, 0);
+  histogram_tester.ExpectTotalCount(kAdsInterventionRecordedHistogram, 0);
+  histogram_tester.ExpectTotalCount(kTimeSinceAdsInterventionTriggeredHistogram,
+                                    0);
   auto entries = ukm_recorder.GetEntriesByName(
       ukm::builders::AdsIntervention_LastIntervention::kEntryName);
   EXPECT_EQ(0u, entries.size());
@@ -75,6 +83,12 @@
   histogram_tester.ExpectBucketCount(
       kSubresourceFilterActionsHistogram,
       subresource_filter::SubresourceFilterAction::kUIShown, 1);
+  histogram_tester.ExpectBucketCount(
+      kAdsInterventionRecordedHistogram,
+      static_cast<int>(mojom::AdsViolation::kMobileAdDensityByHeightAbove30),
+      1);
+  histogram_tester.ExpectBucketCount(
+      kTimeSinceAdsInterventionTriggeredHistogram, 0, 1);
   entries = ukm_recorder.GetEntriesByName(
       ukm::builders::AdsIntervention_LastIntervention::kEntryName);
   EXPECT_EQ(1u, entries.size());
@@ -92,6 +106,13 @@
   ui_test_utils::NavigateToURL(browser(), url);
 
   EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
+  histogram_tester.ExpectBucketCount(
+      kAdsInterventionRecordedHistogram,
+      static_cast<int>(mojom::AdsViolation::kMobileAdDensityByHeightAbove30),
+      1);
+  histogram_tester.ExpectBucketCount(
+      kTimeSinceAdsInterventionTriggeredHistogram,
+      subresource_filter::kAdsInterventionDuration.Get().InHours(), 1);
   entries = ukm_recorder.GetEntriesByName(
       ukm::builders::AdsIntervention_LastIntervention::kEntryName);
   EXPECT_EQ(2u, entries.size());
@@ -131,6 +152,9 @@
   histogram_tester.ExpectBucketCount(
       kSubresourceFilterActionsHistogram,
       subresource_filter::SubresourceFilterAction::kUIShown, 0);
+  histogram_tester.ExpectTotalCount(kAdsInterventionRecordedHistogram, 0);
+  histogram_tester.ExpectTotalCount(kTimeSinceAdsInterventionTriggeredHistogram,
+                                    0);
   auto entries = ukm_recorder.GetEntriesByName(
       ukm::builders::AdsIntervention_LastIntervention::kEntryName);
   EXPECT_EQ(0u, entries.size());
@@ -146,6 +170,12 @@
   histogram_tester.ExpectBucketCount(
       kSubresourceFilterActionsHistogram,
       subresource_filter::SubresourceFilterAction::kUIShown, 1);
+  histogram_tester.ExpectBucketCount(
+      kAdsInterventionRecordedHistogram,
+      static_cast<int>(mojom::AdsViolation::kMobileAdDensityByHeightAbove30),
+      1);
+  histogram_tester.ExpectBucketCount(
+      kTimeSinceAdsInterventionTriggeredHistogram, 0, 1);
   entries = ukm_recorder.GetEntriesByName(
       ukm::builders::AdsIntervention_LastIntervention::kEntryName);
   EXPECT_EQ(1u, entries.size());
@@ -172,6 +202,13 @@
   ui_test_utils::NavigateToURL(browser(), url);
 
   EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
+  histogram_tester.ExpectBucketCount(
+      kAdsInterventionRecordedHistogram,
+      static_cast<int>(mojom::AdsViolation::kMobileAdDensityByHeightAbove30),
+      1);
+  histogram_tester.ExpectBucketCount(
+      kTimeSinceAdsInterventionTriggeredHistogram,
+      subresource_filter::kAdsInterventionDuration.Get().InHours(), 1);
   entries = ukm_recorder.GetEntriesByName(
       ukm::builders::AdsIntervention_LastIntervention::kEntryName);
   EXPECT_EQ(2u, entries.size());
@@ -240,6 +277,13 @@
   histogram_tester.ExpectBucketCount(
       kSubresourceFilterActionsHistogram,
       subresource_filter::SubresourceFilterAction::kUIShown, 0);
+  histogram_tester.ExpectBucketCount(
+      kAdsInterventionRecordedHistogram,
+      static_cast<int>(mojom::AdsViolation::kMobileAdDensityByHeightAbove30),
+      1);
+  histogram_tester.ExpectBucketCount(
+      kTimeSinceAdsInterventionTriggeredHistogram, kRenavigationDelay.InHours(),
+      1);
   entries = ukm_recorder.GetEntriesByName(
       ukm::builders::AdsIntervention_LastIntervention::kEntryName);
   EXPECT_EQ(1u, entries.size());
diff --git a/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc b/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc
index b6a855f..17fca96 100644
--- a/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc
+++ b/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc
@@ -85,6 +85,14 @@
   }
 }
 
+void ChromeSubresourceFilterClient::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (navigation_handle->HasCommitted() && navigation_handle->IsInMainFrame() &&
+      !navigation_handle->IsSameDocument()) {
+    ads_violation_triggered_for_last_committed_navigation_ = false;
+  }
+}
+
 void ChromeSubresourceFilterClient::OnReloadRequested() {
   // TODO(crbug.com/1116095): Once ContentSubresourceFilterThrottleManager knows
   // about content settings, this method can move entirely into
@@ -154,15 +162,25 @@
   return effective_activation_level;
 }
 
+// TODO(https://crbug.com/1131969): Consider adding reporting when
+// ads violations are triggered.
 void ChromeSubresourceFilterClient::OnAdsViolationTriggered(
     content::RenderFrameHost* rfh,
     subresource_filter::mojom::AdsViolation triggered_violation) {
+  // Only trigger violations once per navigation. The ads intervention
+  // manager ignores all interventions after recording an intervention
+  // for the intervention duration, however, a page that began a navigation
+  // before the intervention duration and was still alive after the duration
+  // could re-trigger an ads intervention.
+  if (ads_violation_triggered_for_last_committed_navigation_)
+    return;
+
   // If the feature is disabled, simulate ads interventions as if we were
   // enforcing on ads: do not record new interventions if we would be enforcing
   // an intervention on ads already.
   //
-  // TODO(https://crbug/1107998): Verify this behavior when violation signals
-  // and histograms are added.
+  // TODO(https://crbug.com/1131971): Add support for enabling ads interventions
+  // separately for different ads violations.
   const GURL& url = rfh->GetLastCommittedURL();
   base::Optional<
       subresource_filter::AdsInterventionManager::LastAdsIntervention>
@@ -176,6 +194,8 @@
 
   profile_context_->ads_intervention_manager()
       ->TriggerAdsInterventionForUrlOnSubsequentLoads(url, triggered_violation);
+
+  ads_violation_triggered_for_last_committed_navigation_ = true;
 }
 
 void ChromeSubresourceFilterClient::AllowlistByContentSettings(
diff --git a/chrome/browser/subresource_filter/chrome_subresource_filter_client.h b/chrome/browser/subresource_filter/chrome_subresource_filter_client.h
index 76e9d63..30a17dca 100644
--- a/chrome/browser/subresource_filter/chrome_subresource_filter_client.h
+++ b/chrome/browser/subresource_filter/chrome_subresource_filter_client.h
@@ -49,6 +49,8 @@
   // content::WebContentsObserver:
   void DidStartNavigation(
       content::NavigationHandle* navigation_handle) override;
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
 
   // SubresourceFilterClient:
   void ShowNotification() override;
@@ -85,6 +87,8 @@
 
   bool did_show_ui_for_navigation_ = false;
 
+  bool ads_violation_triggered_for_last_committed_navigation_ = false;
+
   // Corresponds to a devtools command which triggers filtering on all page
   // loads. We must be careful to ensure this boolean does not persist after the
   // devtools window is closed, which should be handled by the devtools system.
diff --git a/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc b/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc
index 82d46a2..d1bada7 100644
--- a/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc
@@ -16,12 +16,12 @@
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/test_safe_browsing_database_helper.h"
 #include "chrome/browser/subresource_filter/subresource_filter_profile_context_factory.h"
 #include "chrome/browser/subresource_filter/test_ruleset_publisher.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/test/base/chrome_test_utils.h"
 #include "components/blocked_content/safe_browsing_triggered_popup_blocker.h"
 #include "components/safe_browsing/core/db/v4_protocol_manager_util.h"
 #include "components/safe_browsing/core/db/v4_test_util.h"
@@ -47,12 +47,12 @@
 
 void SubresourceFilterBrowserTest::SetUp() {
   database_helper_ = CreateTestDatabase();
-  InProcessBrowserTest::SetUp();
+  PlatformBrowserTest::SetUp();
 }
 
 void SubresourceFilterBrowserTest::TearDown() {
-  InProcessBrowserTest::TearDown();
-  // Unregister test factories after InProcessBrowserTest::TearDown
+  PlatformBrowserTest::TearDown();
+  // Unregister test factories after PlatformBrowserTest::TearDown
   // (which destructs SafeBrowsingService).
   database_helper_.reset();
 }
@@ -72,8 +72,9 @@
 
   ASSERT_TRUE(embedded_test_server()->Start());
 
+  auto* web_contents = chrome_test_utils::GetActiveWebContents(this);
   profile_context_ = SubresourceFilterProfileContextFactory::GetForProfile(
-      browser()->profile());
+      Profile::FromBrowserContext(web_contents->GetBrowserContext()));
 }
 
 std::unique_ptr<TestSafeBrowsingDatabaseHelper>
@@ -112,12 +113,12 @@
       url, safe_browsing::GetUrlSubresourceFilterId(), metadata);
 }
 
-content::WebContents* SubresourceFilterBrowserTest::web_contents() const {
-  return browser()->tab_strip_model()->GetActiveWebContents();
+content::WebContents* SubresourceFilterBrowserTest::web_contents() {
+  return chrome_test_utils::GetActiveWebContents(this);
 }
 
 content::RenderFrameHost* SubresourceFilterBrowserTest::FindFrameByName(
-    const std::string& name) const {
+    const std::string& name) {
   return content::FrameMatchingPredicate(
       web_contents(), base::BindRepeating(&content::FrameMatchesName, name));
 }
diff --git a/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h b/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h
index b07f8d9..d8a23f2 100644
--- a/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h
+++ b/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h
@@ -11,8 +11,8 @@
 
 #include "base/macros.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
 #include "chrome/browser/subresource_filter/test_ruleset_publisher.h"
-#include "chrome/test/base/in_process_browser_test.h"
 #include "components/safe_browsing/core/db/util.h"
 #include "components/subresource_filter/content/browser/subresource_filter_profile_context.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h"
@@ -20,6 +20,12 @@
 #include "components/url_pattern_index/proto/rules.pb.h"
 #include "url/gurl.h"
 
+#if defined(OS_ANDROID)
+#include "chrome/test/base/android/android_browser_test.h"
+#else
+#include "chrome/test/base/in_process_browser_test.h"
+#endif
+
 namespace proto = url_pattern_index::proto;
 
 using subresource_filter::testing::ScopedSubresourceFilterConfigurator;
@@ -40,7 +46,7 @@
 class SubresourceFilterContentSettingsManager;
 class RulesetService;
 
-class SubresourceFilterBrowserTest : public InProcessBrowserTest {
+class SubresourceFilterBrowserTest : public PlatformBrowserTest {
  public:
   SubresourceFilterBrowserTest();
   ~SubresourceFilterBrowserTest() override;
@@ -63,7 +69,7 @@
       const GURL& url,
       std::vector<safe_browsing::SubresourceFilterType> filter_types);
 
-  content::WebContents* web_contents() const;
+  content::WebContents* web_contents();
 
   SubresourceFilterContentSettingsManager* settings_manager() const {
     return profile_context_->settings_manager();
@@ -73,7 +79,7 @@
     return profile_context_->ads_intervention_manager();
   }
 
-  content::RenderFrameHost* FindFrameByName(const std::string& name) const;
+  content::RenderFrameHost* FindFrameByName(const std::string& name);
 
   bool WasParsedScriptElementLoaded(content::RenderFrameHost* rfh);
 
diff --git a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
index 6641589..98d4481 100644
--- a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
@@ -1969,6 +1969,8 @@
   // Make sure the first Profile has an overridden policy provider.
   EXPECT_CALL(policy_provider_, IsInitializationComplete(testing::_))
       .WillRepeatedly(testing::Return(true));
+  EXPECT_CALL(policy_provider_, IsFirstPolicyLoadComplete(testing::_))
+      .WillRepeatedly(testing::Return(true));
   policy::PushProfilePolicyConnectorProviderForTesting(&policy_provider_);
 
   // Set up sync.
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
index 73c5285d..436f97d 100644
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -272,4 +272,11 @@
      */
     void setAddApi2TransitionToFutureNavigations(boolean shouldAdd);
     boolean getAddApi2TransitionToFutureNavigations();
+
+    /**
+     * If true, all future navigations are hidden. See |HistoryTabHelper::hide_navigations_|
+     * for the specifics on this.
+     */
+    public void setHideFutureNavigations(boolean hide);
+    public boolean getHideFutureNavigations();
 }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 1f18795..7f062dc 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2602,6 +2602,7 @@
       "//chromeos/components/bloom/public/cpp:bloom_controller_factory",
       "//chromeos/components/camera_app_ui",
       "//chromeos/components/connectivity_diagnostics",
+      "//chromeos/components/connectivity_diagnostics:network_diagnostics_strings",
       "//chromeos/components/diagnostics_ui",
       "//chromeos/components/drivefs/mojom:mojom",
       "//chromeos/components/help_app_ui",
diff --git a/chrome/browser/ui/ash/login_screen_client.cc b/chrome/browser/ui/ash/login_screen_client.cc
index 0337c40..f8bfbd5 100644
--- a/chrome/browser/ui/ash/login_screen_client.cc
+++ b/chrome/browser/ui/ash/login_screen_client.cc
@@ -182,8 +182,11 @@
           supervised_action)) {
     // Show the client native parent access widget and processed to GAIA signin
     // flow in |OnParentAccessValidation| when validation success.
+    // On login screen we want to validate parent access code for the
+    // device owner. Device owner might be different than the account that
+    // requires reauth, so we are passing an empty |account_id|.
     ash::ParentAccessController::Get()->ShowWidget(
-        prefilled_account,
+        AccountId(),
         base::BindOnce(&LoginScreenClient::OnParentAccessValidation,
                        weak_ptr_factory_.GetWeakPtr(), prefilled_account),
         supervised_action, false /* extra_dimmer */, base::Time::Now());
diff --git a/chrome/browser/ui/search/instant_theme_browsertest.cc b/chrome/browser/ui/search/instant_theme_browsertest.cc
index b9697c5..9be30e4 100644
--- a/chrome/browser/ui/search/instant_theme_browsertest.cc
+++ b/chrome/browser/ui/search/instant_theme_browsertest.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/instant_service_observer.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -24,6 +23,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/search/ntp_features.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/ui/search/local_ntp_browsertest.cc b/chrome/browser/ui/search/local_ntp_browsertest.cc
index 54a68925..d9d1673 100644
--- a/chrome/browser/ui/search/local_ntp_browsertest.cc
+++ b/chrome/browser/ui/search/local_ntp_browsertest.cc
@@ -23,7 +23,6 @@
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/instant_service_observer.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -43,6 +42,7 @@
 #include "components/omnibox/browser/omnibox_view.h"
 #include "components/omnibox/common/omnibox_features.h"
 #include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
diff --git a/chrome/browser/ui/search/local_ntp_test_utils.cc b/chrome/browser/ui/search/local_ntp_test_utils.cc
index 42586e9f..48b46c3 100644
--- a/chrome/browser/ui/search/local_ntp_test_utils.cc
+++ b/chrome/browser/ui/search/local_ntp_test_utils.cc
@@ -9,7 +9,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -21,6 +20,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_data.h"
 #include "components/search_engines/template_url_service.h"
diff --git a/chrome/browser/ui/search/ntp_user_data_logger.cc b/chrome/browser/ui/search/ntp_user_data_logger.cc
index be890d922..cd4f9303 100644
--- a/chrome/browser/ui/search/ntp_user_data_logger.cc
+++ b/chrome/browser/ui/search/ntp_user_data_logger.cc
@@ -13,13 +13,13 @@
 #include "chrome/browser/after_startup_task_utils.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/search/ntp_user_data_types.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/ntp_tiles/metrics.h"
 #include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc b/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc
index a9f7692..69dea96 100644
--- a/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc
+++ b/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc
@@ -12,12 +12,12 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/metrics/user_action_tester.h"
 #include "base/time/time.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/ui/search/ntp_user_data_types.h"
 #include "chrome/common/search/ntp_logging_events.h"
 #include "chrome/common/url_constants.h"
 #include "components/favicon_base/favicon_types.h"
 #include "components/ntp_tiles/constants.h"
+#include "components/search/ntp_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index 6ece891..be2d4e5 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -31,7 +31,6 @@
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/local_ntp_source.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/promos/promo_service.h"
 #include "chrome/browser/search/promos/promo_service_factory.h"
 #include "chrome/browser/search/search.h"
@@ -76,6 +75,7 @@
 #include "components/omnibox/browser/suggestion_answer.h"
 #include "components/omnibox/browser/vector_icons.h"
 #include "components/omnibox/common/omnibox_features.h"
+#include "components/search/ntp_features.h"
 #include "components/search/search.h"
 #include "components/search_engines/omnibox_focus_type.h"
 #include "components/search_engines/template_url_service.h"
diff --git a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
index e7fe4c9..2e0a004 100644
--- a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
+++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
@@ -24,6 +23,7 @@
 #include "components/omnibox/browser/omnibox_prefs.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
 #include "components/security_interstitials/content/security_interstitial_tab_helper.h"
 #include "components/security_state/core/security_state.h"
 #include "content/public/browser/navigation_controller.h"
diff --git a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate_unittest.cc b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate_unittest.cc
index 3db3a917..0d921cc 100644
--- a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate_unittest.cc
+++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate_unittest.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "base/test/scoped_feature_list.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -16,6 +15,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/search_test_utils.h"
+#include "components/search/ntp_features.h"
 #include "components/search_engines/template_url_service.h"
 
 // Concrete implementation of ChromeLocationBarModelDelegate.
diff --git a/chrome/browser/ui/views/media_router/cast_toolbar_button.cc b/chrome/browser/ui/views/media_router/cast_toolbar_button.cc
index f236785..aef9be4 100644
--- a/chrome/browser/ui/views/media_router/cast_toolbar_button.cc
+++ b/chrome/browser/ui/views/media_router/cast_toolbar_button.cc
@@ -170,14 +170,17 @@
     icon_color = gfx::kGoogleBlue500;
   }
 
+  // This function is called when system theme changes. If an idle icon is
+  // present, its color needs update.
+  if (icon_color == gfx::kPlaceholderColor) {
+    UpdateIconsWithStandardColors(*new_icon);
+  }
   if (icon_ == new_icon)
     return;
 
   icon_ = new_icon;
   LogIconChange(icon_);
-  if (icon_color == gfx::kPlaceholderColor) {
-    UpdateIconsWithStandardColors(*icon_);
-  } else {
+  if (icon_color != gfx::kPlaceholderColor) {
     for (auto state : kButtonStates)
       SetImageModel(state, ui::ImageModel::FromVectorIcon(*icon_, icon_color));
   }
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
index 65a4509..7418e23 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
@@ -107,6 +107,9 @@
     columns = origin_layout->AddColumnSet(0);
     columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
                        1.0, views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
+    if (PaymentsExperimentalFeatures::IsEnabled(
+            features::kPaymentHandlerSecurityIcon))
+      columns->AddPaddingColumn(views::GridLayout::kFixedSize, 4);
     columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING,
                        1.0, views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
     origin_layout->StartRow(views::GridLayout::kFixedSize, 0);
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc
index 7cb1ee9..08e2d3e 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -71,7 +71,6 @@
       model_(std::move(model)),
       tab_strip_model_(tab_strip_model),
       trigger_menu_on_long_press_(trigger_menu_on_long_press),
-      layout_insets_(::GetLayoutInsets(TOOLBAR_BUTTON)),
       highlight_color_animation_(this) {
   SetHasInkDropActionOnClick(true);
   set_context_menu_controller(this);
@@ -150,8 +149,9 @@
     SetBackground(nullptr);
   }
 
-  gfx::Insets target_insets = layout_insets_ + layout_inset_delta_ +
-                              *GetProperty(views::kInternalPaddingKey);
+  gfx::Insets target_insets =
+      layout_insets_.value_or(::GetLayoutInsets(TOOLBAR_BUTTON)) +
+      layout_inset_delta_ + *GetProperty(views::kInternalPaddingKey);
   base::Optional<SkColor> border_color =
       highlight_color_animation_.GetBorderColor();
   if (!border() || target_insets != border()->GetInsets() ||
@@ -268,11 +268,11 @@
   return menu_showing_;
 }
 
-gfx::Insets ToolbarButton::GetLayoutInsets() const {
+base::Optional<gfx::Insets> ToolbarButton::GetLayoutInsets() const {
   return layout_insets_;
 }
 
-void ToolbarButton::SetLayoutInsets(const gfx::Insets& insets) {
+void ToolbarButton::SetLayoutInsets(const base::Optional<gfx::Insets>& insets) {
   if (layout_insets_ == insets)
     return;
   layout_insets_ = insets;
@@ -654,5 +654,5 @@
 }
 
 BEGIN_METADATA(ToolbarButton, views::LabelButton)
-ADD_PROPERTY_METADATA(gfx::Insets, LayoutInsets)
+ADD_PROPERTY_METADATA(base::Optional<gfx::Insets>, LayoutInsets)
 END_METADATA
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.h b/chrome/browser/ui/views/toolbar/toolbar_button.h
index 4208da08..7e03ddff 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.h
@@ -88,8 +88,8 @@
   virtual void UpdateIcon() {}
 
   // Gets/Sets |layout_insets_|, see comment there.
-  gfx::Insets GetLayoutInsets() const;
-  void SetLayoutInsets(const gfx::Insets& insets);
+  base::Optional<gfx::Insets> GetLayoutInsets() const;
+  void SetLayoutInsets(const base::Optional<gfx::Insets>& insets);
 
   // views::LabelButton:
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
@@ -254,11 +254,11 @@
   // Menu runner to display drop down menu.
   std::unique_ptr<views::MenuRunner> menu_runner_;
 
-  // Layout insets to use.
-  // The default value is GetLayoutInsets(TOOLBAR_BUTTON) which is only
-  // appropriate inside the toolbar. When it is hosted outside the toolbar, use
-  // SetLayoutInsets() to supply the proper value.
-  gfx::Insets layout_insets_;
+  // Layout insets to use. This is used when the ToolbarButton is not actually
+  // hosted inside the toolbar. If not supplied,
+  // |GetLayoutInsets(TOOLBAR_BUTTON)| is used instead which is not appropriate
+  // outside the toolbar.
+  base::Optional<gfx::Insets> layout_insets_;
 
   // Delta from regular toolbar-button insets. This is necessary for buttons
   // that use smaller or larger icons than regular ToolbarButton instances.
@@ -290,7 +290,7 @@
 };
 
 BEGIN_VIEW_BUILDER(CHROME_VIEWS_EXPORT, ToolbarButton, views::LabelButton)
-VIEW_BUILDER_PROPERTY(gfx::Insets, LayoutInsets)
+VIEW_BUILDER_PROPERTY(base::Optional<gfx::Insets>, LayoutInsets)
 END_VIEW_BUILDER(CHROME_VIEWS_EXPORT, ToolbarButton)
 
 #endif  // CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_BUTTON_H_
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button_unittest.cc b/chrome/browser/ui/views/toolbar/toolbar_button_unittest.cc
index 25ed4ced..498d0b8 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button_unittest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button_unittest.cc
@@ -95,10 +95,10 @@
 
 using ToolbarButtonViewsTest = ChromeViewsTestBase;
 
-TEST_F(ToolbarButtonViewsTest, DefaultLayoutInsets) {
+TEST_F(ToolbarButtonViewsTest, NoDefaultLayoutInsets) {
   ToolbarButton button;
   gfx::Insets default_insets = ::GetLayoutInsets(TOOLBAR_BUTTON);
-  EXPECT_EQ(default_insets, button.GetLayoutInsets());
+  EXPECT_FALSE(button.GetLayoutInsets().has_value());
   EXPECT_EQ(default_insets, button.GetInsets());
 }
 
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 33ca8f1..4d932c7 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/media/media_engagement_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/suggestions/suggestions_ui.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/browser/ui/webui/about_ui.h"
@@ -91,6 +90,7 @@
 #include "components/safe_browsing/buildflags.h"
 #include "components/safe_browsing/content/web_ui/safe_browsing_ui.h"
 #include "components/safe_browsing/core/web_ui/constants.h"
+#include "components/search/ntp_features.h"
 #include "components/security_interstitials/content/connection_help_ui.h"
 #include "components/security_interstitials/content/known_interception_disclosure_ui.h"
 #include "components/security_interstitials/content/urls.h"
diff --git a/chrome/browser/ui/webui/chromeos/network_ui.cc b/chrome/browser/ui/webui/chromeos/network_ui.cc
index d0d7e10..e9348c4 100644
--- a/chrome/browser/ui/webui/chromeos/network_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/network_ui.cc
@@ -27,6 +27,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/generated_resources.h"
+#include "chromeos/components/connectivity_diagnostics/network_diagnostics_localized_strings.h"
 #include "chromeos/network/device_state.h"
 #include "chromeos/network/network_configuration_handler.h"
 #include "chromeos/network/network_device_handler.h"
@@ -524,6 +525,7 @@
 
   html->AddLocalizedStrings(localized_strings);
   network_health::AddLocalizedStrings(html);
+  network_diagnostics::AddLocalizedStrings(html);
 
   network_element::AddLocalizedStrings(html);
   network_element::AddOncLocalizedStrings(html);
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
index 1c6f2827..cf1f33ed 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
@@ -34,7 +34,6 @@
 #include "chrome/browser/search/background/ntp_background_service.h"
 #include "chrome/browser/search/background/ntp_background_service_factory.h"
 #include "chrome/browser/search/instant_service.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/one_google_bar/one_google_bar_service_factory.h"
 #include "chrome/browser/search/promos/promo_service_factory.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
@@ -58,6 +57,7 @@
 #include "components/omnibox/browser/omnibox_log.h"
 #include "components/omnibox/browser/omnibox_prefs.h"
 #include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
 #include "components/search_engines/omnibox_focus_type.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/search_provider_logos/logo_service.h"
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
index 5c05f930..6eaf5c4 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/task_module/task_module_handler.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/search/ntp_user_data_logger.h"
@@ -34,6 +33,7 @@
 #include "chrome/grit/new_tab_page_resources_map.h"
 #include "components/favicon_base/favicon_url_parser.h"
 #include "components/google/core/common/google_util.h"
+#include "components/search/ntp_features.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/navigation_handle.h"
diff --git a/chrome/browser/ui/webui/new_tab_page/untrusted_source.cc b/chrome/browser/ui/webui/new_tab_page/untrusted_source.cc
index e868748e..41d892c2 100644
--- a/chrome/browser/ui/webui/new_tab_page/untrusted_source.cc
+++ b/chrome/browser/ui/webui/new_tab_page/untrusted_source.cc
@@ -20,12 +20,12 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/one_google_bar/one_google_bar_data.h"
 #include "chrome/browser/search/one_google_bar/one_google_bar_service_factory.h"
 #include "chrome/browser/ui/search/ntp_user_data_logger.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/new_tab_page_resources.h"
+#include "components/search/ntp_features.h"
 #include "content/public/common/url_constants.h"
 #include "net/base/url_util.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
diff --git a/chrome/browser/ui/webui/new_tab_page/webui_ntp_browsertest.cc b/chrome/browser/ui/webui/new_tab_page/webui_ntp_browsertest.cc
index 2cbf858..bf0b031 100644
--- a/chrome/browser/ui/webui/new_tab_page/webui_ntp_browsertest.cc
+++ b/chrome/browser/ui/webui/new_tab_page/webui_ntp_browsertest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/search/ntp_features.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/apps_section.cc b/chrome/browser/ui/webui/settings/chromeos/apps_section.cc
index d8641245..bde3ac47 100644
--- a/chrome/browser/ui/webui/settings/chromeos/apps_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/apps_section.cc
@@ -181,18 +181,6 @@
   };
   AddLocalizedStringsBulk(html_source, kLocalizedStrings);
 
-  html_source->AddResourcePath("app-management/app_management.mojom-lite.js",
-                               IDR_OS_SETTINGS_APP_MANAGEMENT_MOJO_LITE_JS);
-  html_source->AddResourcePath(
-      "app-management/types.mojom-lite.js",
-      IDR_OS_SETTINGS_APP_MANAGEMENT_TYPES_MOJO_LITE_JS);
-  html_source->AddResourcePath(
-      "app-management/file_path.mojom-lite.js",
-      IDR_OS_SETTINGS_APP_MANAGEMENT_FILE_PATH_MOJO_LITE_JS);
-  html_source->AddResourcePath(
-      "app-management/image.mojom-lite.js",
-      IDR_OS_SETTINGS_APP_MANAGEMENT_IMAGE_MOJO_LITE_JS);
-
   // We have 2 variants of Android apps settings. Default case, when the Play
   // Store app exists we show expandable section that allows as to
   // enable/disable the Play Store and link to Android settings which is
diff --git a/chrome/browser/ui/webui/settings/chromeos/main_section.cc b/chrome/browser/ui/webui/settings/chromeos/main_section.cc
index ba36c9d..cd5997e 100644
--- a/chrome/browser/ui/webui/settings/chromeos/main_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/main_section.cc
@@ -173,20 +173,6 @@
   // Add the System Web App resources for Settings.
   html_source->AddResourcePath("icon-192.png", IDR_SETTINGS_LOGO_192);
 
-  html_source->AddResourcePath("constants/routes.mojom-lite.js",
-                               IDR_OS_SETTINGS_ROUTES_MOJOM_LITE_JS);
-  html_source->AddResourcePath("constants/setting.mojom-lite.js",
-                               IDR_OS_SETTINGS_SETTING_MOJOM_LITE_JS);
-
-  html_source->AddResourcePath(
-      "search/user_action_recorder.mojom-lite.js",
-      IDR_OS_SETTINGS_USER_ACTION_RECORDER_MOJOM_LITE_JS);
-  html_source->AddResourcePath(
-      "search/search_result_icon.mojom-lite.js",
-      IDR_OS_SETTINGS_SEARCH_RESULT_ICON_MOJOM_LITE_JS);
-  html_source->AddResourcePath("search/search.mojom-lite.js",
-                               IDR_OS_SETTINGS_SEARCH_MOJOM_LITE_JS);
-
   AddSearchInSettingsStrings(html_source);
   AddChromeOSUserStrings(html_source);
   AddUpdateRequiredEolStrings(html_source);
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
index 3c4ea80..58389443 100644
--- a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
@@ -36,13 +36,6 @@
 namespace chromeos {
 namespace settings {
 
-#if !BUILDFLAG(OPTIMIZE_WEBUI)
-namespace {
-const char kOsGeneratedPath[] =
-    "@out_folder@/gen/chrome/browser/resources/settings/";
-}
-#endif
-
 // static
 void OSSettingsUI::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
@@ -70,54 +63,32 @@
       std::make_unique<chromeos::settings::StorageHandler>(profile,
                                                            html_source));
 
-#if BUILDFLAG(OPTIMIZE_WEBUI)
-  if (base::FeatureList::IsEnabled(::chromeos::features::kOsSettingsPolymer3)) {
-    // Polymer3 Source files
-    webui::SetupBundledWebUIDataSource(html_source, "chromeos/os_settings.js",
-                                       IDR_OS_SETTINGS_OS_SETTINGS_ROLLUP_JS,
-                                       IDR_OS_SETTINGS_OS_SETTINGS_V3_HTML);
-    html_source->AddResourcePath("chromeos/shared.rollup.js",
-                                 IDR_OS_SETTINGS_SHARED_ROLLUP_JS);
-    html_source->AddResourcePath("chromeos/lazy_load.js",
-                                 IDR_OS_SETTINGS_LAZY_LOAD_ROLLUP_JS);
-  } else {
-    // Polymer2 Source files
-    html_source->AddResourcePath("crisper.js", IDR_OS_SETTINGS_CRISPER_JS);
-    html_source->AddResourcePath("lazy_load.crisper.js",
-                                 IDR_OS_SETTINGS_LAZY_LOAD_CRISPER_JS);
-    html_source->AddResourcePath("chromeos/lazy_load.html",
-                                 IDR_OS_SETTINGS_LAZY_LOAD_VULCANIZED_HTML);
-    html_source->SetDefaultResource(IDR_OS_SETTINGS_VULCANIZED_HTML);
-  }
-
   // We only need to register the mojo resources here because the rest are
-  // bundled in.
+  // bundled or included in the grd.
   RegisterNearbySharedMojoResources(html_source);
+
+  int default_resource =
+      base::FeatureList::IsEnabled(chromeos::features::kOsSettingsPolymer3)
+          ? IDR_OS_SETTINGS_OS_SETTINGS_V3_HTML
+#if BUILDFLAG(OPTIMIZE_WEBUI)
+          : IDR_OS_SETTINGS_VULCANIZED_HTML;
 #else
+          : IDR_OS_SETTINGS_CHROMEOS_OS_SETTINGS_HTML;
+#endif
+
   webui::SetupWebUIDataSource(
       html_source,
       base::make_span(kOsSettingsResources, kOsSettingsResourcesSize),
-      kOsGeneratedPath,
-      base::FeatureList::IsEnabled(chromeos::features::kOsSettingsPolymer3)
-          ? IDR_OS_SETTINGS_OS_SETTINGS_V3_HTML
-          : IDR_OS_SETTINGS_SETTINGS_HTML);
+      /*generated_path=*/std::string(), default_resource);
 
-  // Register chrome://nearby resources so they are available at
-  // chrome://os-settings. This allows the sharing of resources without having
-  // to put everything in chrome://resources. This is necessary because portions
-  // of the nearby UI need to be re-used in both places.
-  // This is not nessary when OPTIMIZE_WEBUI is true because the files will be
-  // added to the optimized bundles.
-  RegisterNearbySharedResources(html_source);
+  // For Polymer 2 optimized builds that rely on loading individual subpages,
+  // set the default resource for tests.
+#if BUILDFLAG(OPTIMIZE_WEBUI)
+  if (!base::FeatureList::IsEnabled(chromeos::features::kOsSettingsPolymer3)) {
+    html_source->SetDefaultResource(default_resource);
+  }
 #endif
 
-  html_source->AddResourcePath("images/icon_add_circle.svg",
-                               IDR_OS_SETTINGS_ICON_ADD_CIRCLE_SVG);
-  html_source->AddResourcePath("images/icon_add_wifi.svg",
-                               IDR_OS_SETTINGS_ICON_ADD_WIFI_SVG);
-  html_source->AddResourcePath("images/icon_add_cellular.svg",
-                               IDR_OS_SETTINGS_ICON_ADD_CELLULAR_SVG);
-
   ManagedUIHandler::Initialize(web_ui, html_source);
 
   content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(),
diff --git a/chrome/browser/ui/webui/webui_util.cc b/chrome/browser/ui/webui/webui_util.cc
index f4b8af5..6dea85d 100644
--- a/chrome/browser/ui/webui/webui_util.cc
+++ b/chrome/browser/ui/webui/webui_util.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/ui/webui/webui_util.h"
 
 #include "build/build_config.h"
-#include "chrome/common/buildflags.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "ui/base/webui/web_ui_util.h"
@@ -57,17 +56,6 @@
   source->AddResourcePath("", default_resource);
 }
 
-#if BUILDFLAG(OPTIMIZE_WEBUI)
-void SetupBundledWebUIDataSource(content::WebUIDataSource* source,
-                                 base::StringPiece bundled_path,
-                                 int bundle,
-                                 int default_resource) {
-  SetupPolymer3Defaults(source);
-  source->AddResourcePath(bundled_path, bundle);
-  source->AddResourcePath("", default_resource);
-}
-#endif
-
 void AddLocalizedStringsBulk(content::WebUIDataSource* html_source,
                              base::span<const LocalizedString> strings) {
   for (const auto& str : strings)
diff --git a/chrome/browser/ui/webui/webui_util.h b/chrome/browser/ui/webui/webui_util.h
index 86c42db..79148416 100644
--- a/chrome/browser/ui/webui/webui_util.h
+++ b/chrome/browser/ui/webui/webui_util.h
@@ -9,7 +9,6 @@
 
 #include "base/containers/span.h"
 #include "base/strings/string_piece.h"
-#include "chrome/common/buildflags.h"
 
 struct GritResourceMap;
 
@@ -35,15 +34,6 @@
                           const std::string& generated_path,
                           int default_resource);
 
-#if BUILDFLAG(OPTIMIZE_WEBUI)
-// Same as SetupWebUIDataSource, but for a bundled page; this adds only the
-// bundle and the default resource to |source|.
-void SetupBundledWebUIDataSource(content::WebUIDataSource* source,
-                                 base::StringPiece bundled_path,
-                                 int bundle,
-                                 int default_resource);
-#endif
-
 // Calls content::WebUIDataSource::AddLocalizedString() in a for-loop for
 // |strings|. Reduces code size vs. reimplementing the same for-loop.
 void AddLocalizedStringsBulk(content::WebUIDataSource* html_source,
diff --git a/chrome/browser/ui/webui/welcome/helpers.cc b/chrome/browser/ui/webui/welcome/helpers.cc
index bd99755..52e2eb38 100644
--- a/chrome/browser/ui/webui/welcome/helpers.cc
+++ b/chrome/browser/ui/webui/welcome/helpers.cc
@@ -23,7 +23,6 @@
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
@@ -31,6 +30,7 @@
 #include "components/policy/core/common/policy_service.h"
 #include "components/policy/policy_constants.h"
 #include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
 
 namespace welcome {
 
diff --git a/chrome/browser/webauthn/android/cable_module_android.cc b/chrome/browser/webauthn/android/cable_module_android.cc
index 9a3c20344..e73c6236b 100644
--- a/chrome/browser/webauthn/android/cable_module_android.cc
+++ b/chrome/browser/webauthn/android/cable_module_android.cc
@@ -2,16 +2,74 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/bind.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "components/gcm_driver/instance_id/instance_id_profile_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "device/fido/cable/v2_registration.h"
 
 // This "header" actually contains function definitions and thus can only be
 // included once across Chromium.
 #include "chrome/browser/webauthn/android/jni_headers/CableAuthenticatorModuleProvider_jni.h"
 
+using device::cablev2::authenticator::Registration;
+
+namespace webauthn {
+namespace authenticator {
+
+namespace {
+
+// OnEvent is called when a GCM message is received.
+void OnEvent(std::unique_ptr<Registration::Event> event) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  Java_CableAuthenticatorModuleProvider_onCloudMessage(
+      base::android::AttachCurrentThread(),
+      static_cast<jlong>(reinterpret_cast<uintptr_t>(event.release())));
+}
+
+// RegistrationHolder owns a |Registration|. It's needed because we don't want
+// to have to gather the arguments for |base::NoDestructor| each time because
+// they usually won't be needed.
+class RegistrationHolder {
+ public:
+  RegistrationHolder() {
+    instance_id::InstanceIDDriver* const driver =
+        instance_id::InstanceIDProfileServiceFactory::GetForProfile(
+            g_browser_process->profile_manager()->GetPrimaryUserProfile())
+            ->driver();
+    registration_ = device::cablev2::authenticator::Register(
+        driver, base::BindRepeating(OnEvent));
+  }
+
+  Registration* get() const { return registration_.get(); }
+
+ private:
+  std::unique_ptr<Registration> registration_;
+};
+
+Registration* GetRegistration() {
+  static base::NoDestructor<RegistrationHolder> registration;
+  return registration->get();
+}
+
+}  // namespace
+
+void RegisterForCloudMessages() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  GetRegistration();
+}
+
+}  // namespace authenticator
+}  // namespace webauthn
+
+// JNI callbacks.
+
 static jlong JNI_CableAuthenticatorModuleProvider_GetSystemNetworkContext(
     JNIEnv* env) {
   static_assert(sizeof(jlong) >= sizeof(uintptr_t),
@@ -20,12 +78,18 @@
       SystemNetworkContextManager::GetInstance()->GetContext()));
 }
 
-static jlong JNI_CableAuthenticatorModuleProvider_GetInstanceIDDriver(
-    JNIEnv* env) {
+static jlong JNI_CableAuthenticatorModuleProvider_GetRegistration(JNIEnv* env) {
   static_assert(sizeof(jlong) >= sizeof(uintptr_t),
                 "Java longs are too small to contain pointers");
-  return static_cast<jlong>(reinterpret_cast<uintptr_t>(
-      instance_id::InstanceIDProfileServiceFactory::GetForProfile(
-          g_browser_process->profile_manager()->GetPrimaryUserProfile())
-          ->driver()));
+  return static_cast<jlong>(
+      reinterpret_cast<uintptr_t>(webauthn::authenticator::GetRegistration()));
+}
+
+static void JNI_CableAuthenticatorModuleProvider_FreeEvent(JNIEnv* env,
+                                                           jlong event_long) {
+  static_assert(sizeof(jlong) >= sizeof(uintptr_t),
+                "Java longs are too small to contain pointers");
+  Registration::Event* event =
+      reinterpret_cast<Registration::Event*>(event_long);
+  delete event;
 }
diff --git a/chrome/browser/webauthn/android/cable_module_android.h b/chrome/browser/webauthn/android/cable_module_android.h
new file mode 100644
index 0000000..454cdf7
--- /dev/null
+++ b/chrome/browser/webauthn/android/cable_module_android.h
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium 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_WEBAUTHN_ANDROID_CABLE_MODULE_ANDROID_H_
+#define CHROME_BROWSER_WEBAUTHN_ANDROID_CABLE_MODULE_ANDROID_H_
+
+namespace webauthn {
+namespace authenticator {
+
+// RegisterForCloudMessages installs a |GCMAppHandler| that handles caBLEv2
+// message in the |GCMDriver| connected to the primary profile. This should be
+// called during browser startup to ensure that the |GCMAppHandler| is
+// registered before any GCM messages are processed. (Otherwise they will be
+// dropped.)
+void RegisterForCloudMessages();
+
+}  // namespace authenticator
+}  // namespace webauthn
+
+#endif
diff --git a/chrome/browser/webauthn/android/java/src/org/chromium/chrome/browser/webauthn/CableAuthenticatorModuleProvider.java b/chrome/browser/webauthn/android/java/src/org/chromium/chrome/browser/webauthn/CableAuthenticatorModuleProvider.java
index 99ff909..3e3796e 100644
--- a/chrome/browser/webauthn/android/java/src/org/chromium/chrome/browser/webauthn/CableAuthenticatorModuleProvider.java
+++ b/chrome/browser/webauthn/android/java/src/org/chromium/chrome/browser/webauthn/CableAuthenticatorModuleProvider.java
@@ -17,6 +17,7 @@
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentTransaction;
 
+import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.modules.cablev2_authenticator.Cablev2AuthenticatorModule;
 
@@ -35,10 +36,12 @@
     // Fragment} in the module.
     private static final String NETWORK_CONTEXT_KEY =
             "org.chromium.chrome.modules.cablev2_authenticator.NetworkContext";
-    private static final String INSTANCE_ID_DRIVER_KEY =
-            "org.chromium.chrome.modules.cablev2_authenticator.InstanceIDDriver";
-    private static final String ACTIVITY_CLASS_NAME =
+    private static final String REGISTRATION_KEY =
+            "org.chromium.chrome.modules.cablev2_authenticator.Registration";
+    private static final String ACTIVITY_CLASS_NAME_KEY =
             "org.chromium.chrome.modules.cablev2_authenticator.ActivityClassName";
+    private static final String ACTIVITY_CLASS_NAME =
+            "org.chromium.chrome.browser.webauth.authenticator.CableAuthenticatorActivity";
     private TextView mStatus;
 
     @Override
@@ -90,16 +93,9 @@
         }
         arguments.putLong(NETWORK_CONTEXT_KEY,
                 CableAuthenticatorModuleProviderJni.get().getSystemNetworkContext());
-        arguments.putLong(INSTANCE_ID_DRIVER_KEY,
-                CableAuthenticatorModuleProviderJni.get().getInstanceIDDriver());
-        // SettingsActivity has to be named as a string here because it cannot
-        // be depended upon without creating a cycle in the deps graph. It's
-        // used as the target of a notification and, in time we'll need our own
-        // top-level Activity in order to handle USB devices. For now, though,
-        // it serves for testing.
-        // TODO(agl): replace with custom top-level Activity.
-        arguments.putString(ACTIVITY_CLASS_NAME,
-                "org.chromium.chrome.browser.webauth.authenticator.CableAuthenticatorActivity");
+        arguments.putLong(
+                REGISTRATION_KEY, CableAuthenticatorModuleProviderJni.get().getRegistration());
+        arguments.putString(ACTIVITY_CLASS_NAME_KEY, ACTIVITY_CLASS_NAME);
         fragment.setArguments(arguments);
         transaction.replace(getId(), fragment);
         // This fragment is deliberately not added to the back-stack here so
@@ -107,6 +103,34 @@
         transaction.commit();
     }
 
+    /**
+     * onCloudMessage is called by native code when a GCM message is received.
+     *
+     * @param event a pointer to a |device::cablev2::authenticator::Registration::Event| which this
+     *         code takes ownership of.
+     */
+    @CalledByNative
+    public static void onCloudMessage(long event) {
+        final long networkContext =
+                CableAuthenticatorModuleProviderJni.get().getSystemNetworkContext();
+        final long registration = CableAuthenticatorModuleProviderJni.get().getRegistration();
+
+        if (Cablev2AuthenticatorModule.isInstalled()) {
+            Cablev2AuthenticatorModule.getImpl().onCloudMessage(
+                    event, networkContext, registration, ACTIVITY_CLASS_NAME);
+            return;
+        }
+
+        Cablev2AuthenticatorModule.install((success) -> {
+            if (!success) {
+                CableAuthenticatorModuleProviderJni.get().freeEvent(event);
+                return;
+            }
+            Cablev2AuthenticatorModule.getImpl().onCloudMessage(
+                    event, networkContext, registration, ACTIVITY_CLASS_NAME);
+        });
+    }
+
     @NativeMethods
     interface Natives {
         // getSystemNetworkContext returns a pointer, encoded in a long, to the
@@ -115,6 +139,10 @@
         // static_library, cannot be depended on by another component thus we
         // pass this value into the feature module.
         long getSystemNetworkContext();
-        long getInstanceIDDriver();
+        // getRegistration returns a pointer to the global
+        // device::cablev2::authenticator::Registration.
+        long getRegistration();
+        // freeEvent releases resources used by the given event.
+        void freeEvent(long event);
     }
 }
diff --git a/chrome/browser/webshare/share_service_browsertest.cc b/chrome/browser/webshare/share_service_browsertest.cc
index ff77ffe7..5d41efa6 100644
--- a/chrome/browser/webshare/share_service_browsertest.cc
+++ b/chrome/browser/webshare/share_service_browsertest.cc
@@ -13,17 +13,47 @@
 #include "content/public/test/browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
+#if defined(OS_WIN)
+#include "chrome/browser/webshare/win/scoped_share_operation_fake_components.h"
+#endif
+
 class ShareServiceBrowserTest : public InProcessBrowserTest {
  public:
   ShareServiceBrowserTest() {
     feature_list_.InitAndEnableFeature(features::kWebShare);
   }
 
+#if defined(OS_WIN)
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+    if (!IsSupportedEnvironment())
+      return;
+
+    ASSERT_NO_FATAL_FAILURE(scoped_fake_components_.SetUp());
+  }
+#endif
+
+ protected:
+#if defined(OS_WIN)
+  bool IsSupportedEnvironment() {
+    return webshare::ScopedShareOperationFakeComponents::
+        IsSupportedEnvironment();
+  }
+#endif
+
  private:
   base::test::ScopedFeatureList feature_list_;
+#if defined(OS_WIN)
+  webshare::ScopedShareOperationFakeComponents scoped_fake_components_;
+#endif
 };
 
 IN_PROC_BROWSER_TEST_F(ShareServiceBrowserTest, Text) {
+#if defined(OS_WIN)
+  if (!IsSupportedEnvironment())
+    return;
+#endif
+
   ASSERT_TRUE(embedded_test_server()->Start());
   ui_test_utils::NavigateToURL(
       browser(), embedded_test_server()->GetURL("/webshare/index.html"));
diff --git a/chrome/browser/webshare/share_service_impl.cc b/chrome/browser/webshare/share_service_impl.cc
index bf2a4ff..fbbcaad6 100644
--- a/chrome/browser/webshare/share_service_impl.cc
+++ b/chrome/browser/webshare/share_service_impl.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/webshare/share_service_impl.h"
 
 #include <algorithm>
+#include <memory>
 
 #include "base/feature_list.h"
 #include "base/strings/string_piece.h"
@@ -13,6 +14,10 @@
 #include "content/public/browser/web_contents.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 
+#if defined(OS_WIN)
+#include "chrome/browser/webshare/win/share_operation.h"
+#endif
+
 // IsDangerousFilename() and IsDangerousMimeType() should be kept in sync with
 // //third_party/blink/renderer/modules/webshare/FILE_TYPES.md
 // //components/browser_ui/webshare/android/java/src/org/chromium/components/browser_ui/webshare/ShareServiceImpl.java
@@ -165,10 +170,17 @@
 #if defined(OS_CHROMEOS)
   sharesheet_client_.Share(title, text, share_url, std::move(files),
                            std::move(callback));
+#elif defined(OS_WIN)
+  auto share_operation = std::make_unique<webshare::ShareOperation>(
+      title, text, share_url, std::move(files), web_contents);
+  share_operation->Run(base::BindOnce(
+      [](std::unique_ptr<webshare::ShareOperation> share_operation,
+         ShareCallback callback,
+         blink::mojom::ShareError result) { std::move(callback).Run(result); },
+      std::move(share_operation), std::move(callback)));
 #else
-  // TODO(crbug.com/1035527): Add implementation for OS_WIN
-  NOTIMPLEMENTED();
-  std::move(callback).Run(blink::mojom::ShareError::OK);
+  NOTREACHED();
+  std::move(callback).Run(blink::mojom::ShareError::INTERNAL_ERROR);
 #endif
 }
 
diff --git a/chrome/browser/webshare/share_service_unittest.cc b/chrome/browser/webshare/share_service_unittest.cc
index 4b909d2..3ce3024a 100644
--- a/chrome/browser/webshare/share_service_unittest.cc
+++ b/chrome/browser/webshare/share_service_unittest.cc
@@ -29,6 +29,9 @@
 #include "chrome/browser/sharesheet/sharesheet_types.h"
 #include "chrome/browser/webshare/chromeos/sharesheet_client.h"
 #endif
+#if defined(OS_WIN)
+#include "chrome/browser/webshare/win/scoped_share_operation_fake_components.h"
+#endif
 
 class ShareServiceUnitTest : public ChromeRenderViewHostTestHarness {
  public:
@@ -45,8 +48,21 @@
     webshare::SharesheetClient::SetSharesheetCallbackForTesting(
         base::BindRepeating(&ShareServiceUnitTest::AcceptShareRequest));
 #endif
+#if defined(OS_WIN)
+    if (!IsSupportedEnvironment())
+      return;
+
+    ASSERT_NO_FATAL_FAILURE(scoped_fake_components_.SetUp());
+#endif
   }
 
+#if defined(OS_WIN)
+  bool IsSupportedEnvironment() {
+    return webshare::ScopedShareOperationFakeComponents::
+        IsSupportedEnvironment();
+  }
+#endif
+
   ShareError ShareGeneratedFileData(const std::string& extension,
                                     const std::string& content_type,
                                     unsigned file_length = 100,
@@ -123,11 +139,19 @@
   }
 #endif
 
+#if defined(OS_WIN)
+  webshare::ScopedShareOperationFakeComponents scoped_fake_components_;
+#endif
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<ShareServiceImpl> share_service_;
 };
 
 TEST_F(ShareServiceUnitTest, FileCount) {
+#if defined(OS_WIN)
+  if (!IsSupportedEnvironment())
+    return;
+#endif
+
   EXPECT_EQ(ShareError::OK, ShareGeneratedFileData(".txt", "text/plain", 1234,
                                                    kMaxSharedFileCount));
   EXPECT_EQ(ShareError::PERMISSION_DENIED,
@@ -165,6 +189,11 @@
 }
 
 TEST_F(ShareServiceUnitTest, Multimedia) {
+#if defined(OS_WIN)
+  if (!IsSupportedEnvironment())
+    return;
+#endif
+
   EXPECT_EQ(ShareError::OK, ShareGeneratedFileData(".bmp", "image/bmp"));
   EXPECT_EQ(ShareError::OK, ShareGeneratedFileData(".xbm", "image/x-xbitmap"));
   EXPECT_EQ(ShareError::OK, ShareGeneratedFileData(".flac", "audio/flac"));
@@ -172,6 +201,11 @@
 }
 
 TEST_F(ShareServiceUnitTest, PortableDocumentFormat) {
+#if defined(OS_WIN)
+  if (!IsSupportedEnvironment())
+    return;
+#endif
+
   // TODO(crbug.com/1006055): Support sharing of pdf files.
   // The URL will be checked using Safe Browsing.
   EXPECT_EQ(ShareError::PERMISSION_DENIED,
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 7b2b13a..aed9d854 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1603972752-7774997975c1fc77dd139039f32c4c5217a4f93d.profdata
+chrome-linux-master-1603994501-28d36cf57d6466dbb811553e28b04bff48def90b.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index ec92848c..dd91759 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -199,9 +199,9 @@
         "//chrome/browser/resources:nearby_share_dialog_resources",
         "//chrome/browser/resources:nearby_shared_resources",
         "//chrome/browser/resources:nearby_shared_resources_v3",
-        "//chrome/browser/resources:os_settings_resources",
         "//chrome/browser/resources/chromeos:cellular_setup_resources",
         "//chrome/browser/resources/chromeos:multidevice_setup_resources",
+        "//chrome/browser/resources/settings/chromeos:os_settings_resources",
         "//chrome/browser/supervised_user:supervised_user_unscaled_resources",
         "//chromeos/resources",
         "//chromeos/resources:camera_app_resources",
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 8569b3e..f5a1ea2 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -347,6 +347,7 @@
       "//components/crash/core/app",
       "//third_party/wtl",
     ]
+    libs = [ "runtimeobject.lib" ]
   }
 
   if (is_chromeos) {
@@ -541,6 +542,7 @@
       "//components/crash/android:crashpad_main",
       "//components/games/core/test:test_support",
       "//components/metrics/demographics:test_support",
+      "//components/page_load_metrics/browser:test_support",
       "//components/ukm:ukm_test_helper",
 
       # TODO(crbug.com/961849): This is needed for ShellManager which is what
@@ -560,9 +562,14 @@
       "../browser/metrics/metrics_service_user_demographics_browsertest.cc",
       "../browser/metrics/ukm_browsertest.cc",
       "../browser/net/cert_verify_proc_browsertest.cc",
+      "../browser/page_load_metrics/observers/ad_metrics/ad_density_intervention_android_browsertest.cc",
       "../browser/profiles/profile_browsertest_android.cc",
+      "../browser/safe_browsing/test_safe_browsing_database_helper.cc",
+      "../browser/safe_browsing/test_safe_browsing_database_helper.h",
       "../browser/ssl/chrome_security_state_client_browsertest.cc",
       "../browser/ssl/crlset_browsertest.cc",
+      "../browser/subresource_filter/subresource_filter_browser_test_harness.cc",
+      "../browser/subresource_filter/subresource_filter_browser_test_harness.h",
       "android/browsertests_apk/android_browsertests_jni_onload.cc",
       "base/android/android_browser_test_browsertest_android.cc",
     ]
@@ -598,6 +605,8 @@
       "//chrome/test/data/banners/",
       "//chrome/test/data/android/customtabs/",
       "//chrome/test/data/ssl/",
+      "//chrome/test/data/ads_observer/",
+      "//content/test/data/",
     ]
   }
 
@@ -1162,6 +1171,7 @@
       "../browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc",
       "../browser/optimization_guide/prediction/machine_learning_service_browsertest.cc",
       "../browser/optimization_guide/prediction/prediction_manager_browsertest.cc",
+      "../browser/page_load_metrics/observers/ad_metrics/ad_density_intervention_browsertest.cc",
       "../browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc",
       "../browser/page_load_metrics/observers/back_forward_cache_page_load_metrics_observer_browsertest.cc",
       "../browser/page_load_metrics/observers/core/amp_page_load_metrics_observer_browsertest.cc",
@@ -2117,6 +2127,8 @@
           "../browser/extensions/api/terminal/terminal_private_browsertest.cc",
           "../browser/extensions/clipboard_extension_apitest_chromeos.cc",
         ]
+
+        deps += [ "//chrome/browser/error_reporting:test_support" ]
       }
 
       deps += [
@@ -5016,6 +5028,10 @@
     ]
   }
 
+  if (is_linux || is_chromeos) {
+    deps += [ "//chrome/browser/error_reporting:unit_test" ]
+  }
+
   if (use_x11 || use_ozone) {
     deps += [ "//ui/events/devices:test_support" ]
   }
diff --git a/chrome/test/data/ads_observer/ad_iframe_writer.js b/chrome/test/data/ads_observer/ad_iframe_writer.js
index b49e3a29..d340ff6 100644
--- a/chrome/test/data/ads_observer/ad_iframe_writer.js
+++ b/chrome/test/data/ads_observer/ad_iframe_writer.js
@@ -32,3 +32,5 @@
   document.body.appendChild(frame);
   return frame;
 }
+
+document.scriptExecuted = true;
\ No newline at end of file
diff --git a/chrome/test/data/extensions/context_menus/persistent/event_page.crx b/chrome/test/data/extensions/context_menus/persistent/event_page.crx
new file mode 100644
index 0000000..10d86f7
--- /dev/null
+++ b/chrome/test/data/extensions/context_menus/persistent/event_page.crx
Binary files differ
diff --git a/chrome/test/data/extensions/context_menus/persistent/event_page/manifest.json b/chrome/test/data/extensions/context_menus/persistent/event_page/manifest.json
new file mode 100644
index 0000000..f04d0f4
--- /dev/null
+++ b/chrome/test/data/extensions/context_menus/persistent/event_page/manifest.json
@@ -0,0 +1,7 @@
+{
+  "name" : "Context Menus Test Extension",
+  "version" : "0.1",
+  "manifest_version": 2,
+  "permissions": [ "contextMenus", "tabs" ],
+  "background": { "persistent": false, "scripts": ["test.js"] }
+}
diff --git a/chrome/test/data/extensions/context_menus/persistent/event_page/test.js b/chrome/test/data/extensions/context_menus/persistent/event_page/test.js
new file mode 100644
index 0000000..aa9ca5c7
--- /dev/null
+++ b/chrome/test/data/extensions/context_menus/persistent/event_page/test.js
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium 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 menuId = 'my_id'
+
+chrome.runtime.onInstalled.addListener(function(details) {
+  if (details.reason == 'install') {
+    chrome.contextMenus.create(
+        {title: 'Extension Item', id: menuId},
+        function() {
+          if (!chrome.runtime.lastError) {
+            chrome.test.notifyPass();
+          } else {
+            chrome.test.notifyFail(chrome.runtime.lastError.message);
+          }
+        }
+    );
+  }
+});
+
+chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
+  // The C++ test creates a tab at chrome://version as a signal to the
+  // extension to update the menu item.
+  if (tab.url != 'chrome://version/')
+   return;
+  chrome.contextMenus.update(
+      menuId, {title: 'Extension Item Updated'},
+      function() {
+        if (!chrome.runtime.lastError) {
+          chrome.test.notifyPass();
+        } else {
+          chrome.test.notifyFail(chrome.runtime.lastError.message);
+        }
+      }
+  );
+});
diff --git a/chrome/test/data/extensions/context_menus/persistent/persistent.pem b/chrome/test/data/extensions/context_menus/persistent/persistent.pem
new file mode 100644
index 0000000..0abec696
--- /dev/null
+++ b/chrome/test/data/extensions/context_menus/persistent/persistent.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8PhT/gPpbk9uL
+/xUvylB0QyIlr/zU9+UtYCDsiT0KqouuusP8FtOex4pyt+be6/xljjtcw5j/WRmk
+zK+UOT2HfpKTqiFnPkHAmMycEPzaYeJWskiGSY/8pHiD2x4hQBqgZTg7q+4iUNMo
+psH7uKVrXJqvbzqqYM0aZPL9mj+wTrnR9jcoknaRUil/liFBPm5+lhok9LwRtyzg
+Qd3zUnhegYDJ5tv4P3Wl76uSGDWXXTKjg8BMyoCCFH9/QJmFAXvsrrynwaE/PDAJ
+ieGR1qcMOy3kHBGQjaEebmTNaxjBcKc8iuP/mCYANQ4ktWwdn8ikTJdrogsL2lIv
+v9FUIx/7AgMBAAECggEAF1qxGo/4alMvn7ClLW7cHh3UHI6Mf37v689rgPJ35HJg
+mRbVHi9WJZ1brmblhE5ihoD9GWxaTNfTktAi5RtYPblfhbrLoSD8DGEzWsDQILyY
+gFQRzmNNs1+pD1wojUyENoEdrGg6HP91FdaL5jyJfVvvBF6i4yTWXXTHzDHjvpjs
+rrW143b4LbcpstBatgNHefBPvJL9bBdqvBpceREWE4HIXtj1B3Ac8vhnvNcH3eZF
+909/VO4Xugp+8MHm+m2onFTvRkDkl/JWSPmJHmftuwMxBP2JcarZfcaJ0V568jrZ
+Op1IA/y+PasowN3zHX2lAFnkkpvtza1JGm1qWjpllQKBgQDb1rMFd3Tge4oA+/YL
+UGEZMf2PfgZkSLIt1Q0PxvvRO4ybau/MTeNkEp7wig0mE+WIP7s3ebdhlY+jBoNg
+qDvS3LWzKkL1jNsy1jqGqwYxuEmq1c9QO3GlfBV1+b96s2JWm8fdoiWoMTkBU7i0
+cimuYMMCOQa5aKM7sJHUcSo2/wKBgQDbNOIw0gxWowYSNoRF6Z+R/t8BRT8k7dNN
+cj5SbF8+agnlKC5jvpQ/MdjsXF9werR2V6BBXGOHXcDbTHiHrMYnBic887CXAXIC
+jF8GxnpE0l0d0Kkmd3SedJKILYkBX40QkUas+GynfgjIchcIyFCCeBbhOT6pOcox
+cPqx7+TzBQKBgQC1sFf8qKG79d40ugi7iQ72184MDcgSkdJQ9sf4xifQ4TpwKI1P
+eP/58TnS6wW69q65UJLWYo4g5I712agy9lebCjZRgRgeAPAYr91m92oDJaAcxOC2
+GqrubgL+og6Sxjb8BXvFvQEKZMQMSLlayQ+Rwv7ok2DvU3+1EVU1EuIk2QKBgBQG
+cb9qAOyNOgnB5zWH0ScCNJcmH02dWFdT33OiKNVH1J2VnR9JkrtvL1TwX1ukKgZB
+nQc7jHAaVXrzMnOaigOYoU8FKBWzcRngfvHcgeD1osINhNZZxVKQba55EnIIq5de
+3ikBDNQERIMjQQ1xV0GD/PsYQqws9lar7osA0laNAoGANs4auFpqjoaRNypgO2G2
+GqQV/Y4GAqZRxjsceZNdJ0wa+h5fkYpCEadIDQtL76hpX84opbhTuoBGNpkMeRAH
+y+zRRRUqBB/dG/95C5gboEDfDYbTYvJLHFPIJ/uYyh77QoKIZdHmCKGO2VR/xur/
+psX82yq4i8lQnwaFyiZM0Cw=
+-----END PRIVATE KEY-----
diff --git a/chrome/test/data/extensions/context_menus/persistent/service_worker.crx b/chrome/test/data/extensions/context_menus/persistent/service_worker.crx
new file mode 100644
index 0000000..c6ee85fe
--- /dev/null
+++ b/chrome/test/data/extensions/context_menus/persistent/service_worker.crx
Binary files differ
diff --git a/chrome/test/data/extensions/context_menus/persistent/service_worker/manifest.json b/chrome/test/data/extensions/context_menus/persistent/service_worker/manifest.json
new file mode 100644
index 0000000..cd5e0b4
--- /dev/null
+++ b/chrome/test/data/extensions/context_menus/persistent/service_worker/manifest.json
@@ -0,0 +1,7 @@
+{
+  "name" : "Context Menus Test Extension",
+  "version" : "0.1",
+  "manifest_version": 2,
+  "permissions": [ "contextMenus", "tabs" ],
+  "background": { "service_worker": "test.js" }
+}
diff --git a/chrome/test/data/extensions/context_menus/persistent/service_worker/test.js b/chrome/test/data/extensions/context_menus/persistent/service_worker/test.js
new file mode 100644
index 0000000..aa9ca5c7
--- /dev/null
+++ b/chrome/test/data/extensions/context_menus/persistent/service_worker/test.js
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium 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 menuId = 'my_id'
+
+chrome.runtime.onInstalled.addListener(function(details) {
+  if (details.reason == 'install') {
+    chrome.contextMenus.create(
+        {title: 'Extension Item', id: menuId},
+        function() {
+          if (!chrome.runtime.lastError) {
+            chrome.test.notifyPass();
+          } else {
+            chrome.test.notifyFail(chrome.runtime.lastError.message);
+          }
+        }
+    );
+  }
+});
+
+chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
+  // The C++ test creates a tab at chrome://version as a signal to the
+  // extension to update the menu item.
+  if (tab.url != 'chrome://version/')
+   return;
+  chrome.contextMenus.update(
+      menuId, {title: 'Extension Item Updated'},
+      function() {
+        if (!chrome.runtime.lastError) {
+          chrome.test.notifyPass();
+        } else {
+          chrome.test.notifyFail(chrome.runtime.lastError.message);
+        }
+      }
+  );
+});
diff --git a/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js b/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js
index 2aa4ce11..6903b97 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/battery_status_card.js';
 
 import {fakeBatteryChargeStatus, fakeBatteryHealth, fakeBatteryInfo} from 'chrome://diagnostics/fake_data.js';
@@ -12,7 +10,7 @@
 import {flushTasks} from 'chrome://test/test_util.m.js';
 import * as dx_utils from './diagnostics_test_utils.js';
 
-suite('BatteryStatusCardTest', () => {
+export function batteryStatusCardTestSuite() {
   /** @type {?HTMLElement} */
   let batteryStatusElement = null;
 
@@ -94,4 +92,4 @@
               barChart.value);
         });
   });
-});
\ No newline at end of file
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/cpu_card_test.js b/chrome/test/data/webui/chromeos/diagnostics/cpu_card_test.js
index 6f5a712..3d10496 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/cpu_card_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/cpu_card_test.js
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/cpu_card.js';
 
 import {fakeCpuUsage} from 'chrome://diagnostics/fake_data.js';
@@ -12,7 +10,7 @@
 import {flushTasks} from 'chrome://test/test_util.m.js';
 import * as dx_utils from './diagnostics_test_utils.js';
 
-suite('CpuCardTest', () => {
+export function cpuCardTestSuite() {
   /** @type {?HTMLElement} */
   let cpuElement = null;
 
@@ -101,4 +99,4 @@
       assertFalse(isRunTestsButtonDisabled());
     });
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/data_point_test.js b/chrome/test/data/webui/chromeos/diagnostics/data_point_test.js
index 9c9a525..2eca5b1 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/data_point_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/data_point_test.js
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/data_point.js';
 
 import {flushTasks} from 'chrome://test/test_util.m.js';
 
-
-suite('DataPointTest', () => {
+export function dataPointTestSuite() {
   /** @type {?HTMLElement} */
   let dataPointElement = null;
 
@@ -49,4 +46,4 @@
       assertEquals(value, dataPointElement.$$('.value').textContent.trim());
     });
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_app_test.js b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_app_test.js
index 5706e649d..e3f4892c 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_app_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_app_test.js
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/diagnostics_app.js';
 
 import {fakeBatteryChargeStatus, fakeBatteryHealth, fakeBatteryInfo, fakeCpuUsage, fakeMemoryUsage, fakeSystemInfo, fakeSystemInfoWithoutBattery} from 'chrome://diagnostics/fake_data.js';
@@ -11,7 +9,7 @@
 import {setSystemDataProviderForTesting} from 'chrome://diagnostics/mojo_interface_provider.js';
 import {flushTasks} from 'chrome://test/test_util.m.js';
 
-suite('DiagnosticsAppTest', () => {
+export function appTestSuite() {
   /** @type {?DiagnosticsApp} */
   let page = null;
 
@@ -100,4 +98,4 @@
           assertFalse(!!batteryStatus);
         });
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_app_unified_test.js b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_app_unified_test.js
new file mode 100644
index 0000000..2a59dc4
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_app_unified_test.js
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
+import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
+
+import {batteryStatusCardTestSuite} from './battery_status_card_test.js';
+import {cpuCardTestSuite} from './cpu_card_test.js';
+import {dataPointTestSuite} from './data_point_test.js';
+import {appTestSuite} from './diagnostics_app_test.js';
+import {fakeMethodResolverTestSuite} from './fake_method_provider_test.js';
+import {fakeObservablesTestSuite} from './fake_observables_test.js';
+import {fakeSystemDataProviderTestSuite} from './fake_system_data_provider_test.js';
+import {fakeSystemRoutineContollerTestSuite} from './fake_system_routine_controller_test.js';
+import {memoryCardTestSuite} from './memory_card_test.js';
+import {fakeMojoProviderTestSuite} from './mojo_interface_provider_test.js';
+import {overviewCardTestSuite} from './overview_card_test.js';
+import {percentBarChartTestSuite} from './percent_bar_chart_test.js';
+import {realtimeCpuChartTestSuite} from './realtime_cpu_chart_test.js';
+import {fakeRoutineListExecutorTestSuite} from './routine_list_executor_test.js';
+import {routineResultEntryTestSuite} from './routine_result_entry_test.js';
+import {routineResultListTestSuite} from './routine_result_list_test.js';
+import {routineSectionTestSuite} from './routine_section_test.js';
+
+suite('App', appTestSuite);
+suite('BatteryStatusCard', batteryStatusCardTestSuite);
+suite('CpuCard', cpuCardTestSuite);
+suite('DataPoint', dataPointTestSuite);
+suite('FakeMethodProvider', fakeMethodResolverTestSuite);
+suite('FakeMojoInterface', fakeMojoProviderTestSuite);
+suite('FakeObservables', fakeObservablesTestSuite);
+suite('FakeSystemDataProvider', fakeSystemDataProviderTestSuite);
+suite('FakeSystemRoutineContoller', fakeSystemRoutineContollerTestSuite);
+suite('MemoryCard', memoryCardTestSuite);
+suite('OverviewCard', overviewCardTestSuite);
+suite('PercentBarChart', percentBarChartTestSuite);
+suite('RealtimeCpuChart', realtimeCpuChartTestSuite);
+suite('RoutineListExecutor', fakeRoutineListExecutorTestSuite);
+suite('RoutineResultEntry', routineResultEntryTestSuite);
+suite('RoutineResultList', routineResultListTestSuite);
+suite('RoutineSection', routineSectionTestSuite);
diff --git a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js
index 7b93b07..701f9d0 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview Test suite for chrome://diagnostics.
+ * @fileoverview Test fixture for chrome://diagnostics.
  */
 
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
@@ -11,51 +11,32 @@
 GEN('#include "chromeos/constants/chromeos_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
 
-[['Test', 'diagnostics/diagnostics_app_test.js'],
- ['CpuCard', 'diagnostics/cpu_card_test.js'],
- ['DataPoint', 'diagnostics/data_point_test.js'],
- ['OverviewCard', 'diagnostics/overview_card_test.js'],
- ['MemoryCard', 'diagnostics/memory_card_test.js'],
- ['BatteryStatusCard', 'diagnostics/battery_status_card_test.js'],
- ['FakeObservables', 'diagnostics/fake_observables_test.js'],
- ['FakeMojoInterface', 'diagnostics/mojo_interface_provider_test.js'],
- ['FakeSystemDataProvider', 'diagnostics/fake_system_data_provider_test.js'],
- ['FakeMethodProvider', 'diagnostics/fake_method_provider_test.js'],
- ['RealtimeCpuChart', 'diagnostics/realtime_cpu_chart_test.js'],
- ['RoutineListExecutor', 'diagnostics/routine_list_executor_test.js'],
- ['RoutineResultEntry', 'diagnostics/routine_result_entry_test.js'],
- ['RoutineResultList', 'diagnostics/routine_result_list_test.js'],
- ['RoutineSection', 'diagnostics/routine_section_test.js'],
- ['PercentBarChart', 'diagnostics/percent_bar_chart_test.js'], [
-   'FakeSystemRoutineController',
-   'diagnostics/fake_system_routine_controller_test.js'
- ]].forEach(test => registerTest(...test));
+const dxTestSuites = 'chromeos/diagnostics/diagnostics_app_unified_test.js';
 
-function registerTest(testName, module) {
-  const className = `DiagnosticsApp${testName}`;
-  this[className] = class extends PolymerTest {
-    /** @override */
-    get browsePreload() {
-      return `chrome://diagnostics/test_loader.html?module=chromeos/${module}`;
-    }
+this['DiagnosticsAppTest'] = class extends PolymerTest {
+  /** @override */
+  get browsePreload() {
+    return `chrome://diagnostics/test_loader.html?module=${dxTestSuites}`;
+  }
 
-    /** @override */
-    get extraLibraries() {
-      return [
-        '//third_party/mocha/mocha.js',
-        '//chrome/test/data/webui/mocha_adapter.js',
-      ];
-    }
+  /** @override */
+  get extraLibraries() {
+    return [
+      '//third_party/mocha/mocha.js',
+      '//chrome/test/data/webui/mocha_adapter.js',
+    ];
+  }
 
-    /** @override */
-    get featureList() {
-      return {
-        enabled: [
-          'chromeos::features::kDiagnosticsApp',
-        ],
-      };
-    }
-  };
+  /** @override */
+  get featureList() {
+    return {
+      enabled: [
+        'chromeos::features::kDiagnosticsApp',
+      ],
+    };
+  }
+};
 
-  TEST_F(className, 'All', () => mocha.run());
-}
+TEST_F('DiagnosticsAppTest', 'All', function() {
+  mocha.run();
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/diagnostics/fake_method_provider_test.js b/chrome/test/data/webui/chromeos/diagnostics/fake_method_provider_test.js
index 197e24c..dfb3dcf 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/fake_method_provider_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/fake_method_provider_test.js
@@ -2,12 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
-
 import {FakeMethodResolver} from 'chrome://diagnostics/fake_method_resolver.js';
 
-suite('DiagnosticsFakeMethodResolver', () => {
+export function fakeMethodResolverTestSuite() {
   /** @type {?FakeMethodResolver} */
   let resolver = null;
 
@@ -44,4 +41,4 @@
       assertEquals(expected, result);
     });
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/fake_observables_test.js b/chrome/test/data/webui/chromeos/diagnostics/fake_observables_test.js
index 066705f3..f9488e15 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/fake_observables_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/fake_observables_test.js
@@ -2,13 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
-
 import {FakeObservables} from 'chrome://diagnostics/fake_observables.js';
 import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
 
-suite('FakeObservablesTest', () => {
+export function fakeObservablesTestSuite() {
   /** @type {?FakeObservables} */
   let observables = null;
 
@@ -85,4 +82,4 @@
     observables.trigger('ObserveFoo_OnFooUpdated');
     return resolver.promise;
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/fake_system_data_provider_test.js b/chrome/test/data/webui/chromeos/diagnostics/fake_system_data_provider_test.js
index f4600ab..acf0890f 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/fake_system_data_provider_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/fake_system_data_provider_test.js
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
-
 import {fakeBatteryChargeStatus, fakeBatteryHealth, fakeBatteryInfo, fakeBatteryInfo2, fakeCpuUsage, fakeMemoryUsage} from 'chrome://diagnostics/fake_data.js';
 import {FakeSystemDataProvider} from 'chrome://diagnostics/fake_system_data_provider.js';
 import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
 
-suite('FakeSystemDataProviderTest', () => {
+export function fakeSystemDataProviderTestSuite() {
   /** @type {?FakeSystemDataProvider} */
   let provider = null;
 
@@ -356,4 +353,4 @@
           return completeResolver.promise;
         });
   });
-});
\ No newline at end of file
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/fake_system_routine_controller_test.js b/chrome/test/data/webui/chromeos/diagnostics/fake_system_routine_controller_test.js
index 125c4b6..0aad9e9 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/fake_system_routine_controller_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/fake_system_routine_controller_test.js
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
-
 import {RoutineName, StandardRoutineResult} from 'chrome://diagnostics/diagnostics_types.js';
 import {FakeSystemRoutineController} from 'chrome://diagnostics/fake_system_routine_controller.js';
 import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
 
-suite('FakeSystemRoutineContollerTest', () => {
+export function fakeSystemRoutineContollerTestSuite() {
   /** @type {?FakeSystemRoutineController} */
   let controller = null;
 
@@ -144,4 +141,4 @@
     return runRoutineAndAssertStandardResultManualResolve(
         routineName, expectedResult);
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/memory_card_test.js b/chrome/test/data/webui/chromeos/diagnostics/memory_card_test.js
index 60378eb..2a4424b 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/memory_card_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/memory_card_test.js
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/memory_card.js';
 
 import {fakeMemoryUsage} from 'chrome://diagnostics/fake_data.js';
@@ -12,7 +10,7 @@
 import {flushTasks} from 'chrome://test/test_util.m.js';
 import * as dx_utils from './diagnostics_test_utils.js';
 
-suite('MemoryCardTest', () => {
+export function memoryCardTestSuite() {
   /** @type {?HTMLElement} */
   let memoryElement = null;
 
@@ -68,4 +66,4 @@
       assertEquals(memInUse, barChart.value);
     });
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/mojo_interface_provider_test.js b/chrome/test/data/webui/chromeos/diagnostics/mojo_interface_provider_test.js
index 5b69d10..fdd05a9 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/mojo_interface_provider_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/mojo_interface_provider_test.js
@@ -2,13 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
-
 import {FakeSystemRoutineController} from 'chrome://diagnostics/fake_system_routine_controller.js';
 import {getSystemDataProvider, getSystemRoutineController, setSystemDataProviderForTesting, setSystemRoutineControllerForTesting} from 'chrome://diagnostics/mojo_interface_provider.js';
 
-suite('FakeMojoProviderTest', () => {
+export function fakeMojoProviderTestSuite() {
   test('SettingGettingTestProvider', () => {
     // TODO(zentaro): Replace with fake when built.
     let fake_provider =
@@ -22,4 +19,4 @@
     setSystemRoutineControllerForTesting(fake_controller);
     assertEquals(fake_controller, getSystemRoutineController());
   });
-});
\ No newline at end of file
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/overview_card_test.js b/chrome/test/data/webui/chromeos/diagnostics/overview_card_test.js
index b9121b04..385c92a 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/overview_card_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/overview_card_test.js
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/overview_card.js';
 
 import {fakeSystemInfo} from 'chrome://diagnostics/fake_data.js';
@@ -11,7 +9,7 @@
 import {getSystemDataProvider, setSystemDataProviderForTesting} from 'chrome://diagnostics/mojo_interface_provider.js';
 import {flushTasks} from 'chrome://test/test_util.m.js';
 
-suite('OverviewCardTest', () => {
+export function overviewCardTestSuite() {
   /** @type {?HTMLElement} */
   let overviewElement = null;
 
@@ -64,4 +62,4 @@
           overviewElement.$$('#version').textContent);
     });
   });
-});
\ No newline at end of file
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/percent_bar_chart_test.js b/chrome/test/data/webui/chromeos/diagnostics/percent_bar_chart_test.js
index 7f42cf7..ecf25e8b 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/percent_bar_chart_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/percent_bar_chart_test.js
@@ -2,14 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/percent_bar_chart.js';
 
 import {flushTasks} from 'chrome://test/test_util.m.js';
 import * as diagnostics_test_utils from './diagnostics_test_utils.js';
 
-suite('PercentBarChartTest', () => {
+export function percentBarChartTestSuite() {
   /** @type {?HTMLElement} */
   let percentBarChartElement = null;
 
@@ -74,4 +72,4 @@
       assertTrue(!!percentBarChartElement.$$('#headerIcon'));
     });
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/realtime_cpu_chart_test.js b/chrome/test/data/webui/chromeos/diagnostics/realtime_cpu_chart_test.js
index 24e5df7..3c0eec38a 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/realtime_cpu_chart_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/realtime_cpu_chart_test.js
@@ -2,14 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/realtime_cpu_chart.js';
 
 import {flushTasks} from 'chrome://test/test_util.m.js';
 import * as diagnostics_test_utils from './diagnostics_test_utils.js';
 
-suite('RealtimeCpuChartTest', () => {
+export function realtimeCpuChartTestSuite() {
   /** @type {?HTMLElement} */
   let realtimeCpuChartElement = null;
 
@@ -119,4 +117,4 @@
                        .getAttribute('d'));
     });
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/routine_list_executor_test.js b/chrome/test/data/webui/chromeos/diagnostics/routine_list_executor_test.js
index 50f7670..2e9404a 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/routine_list_executor_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/routine_list_executor_test.js
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
-
 import {RoutineName, RoutineResultInfo, StandardRoutineResult} from 'chrome://diagnostics/diagnostics_types.js';
 import {FakeSystemRoutineController} from 'chrome://diagnostics/fake_system_routine_controller.js';
 import {ExecutionProgress, ResultStatusItem, RoutineListExecutor} from 'chrome://diagnostics/routine_list_executor.js';
 
-suite('FakeRoutineListExecutorTest', () => {
+export function fakeRoutineListExecutorTestSuite() {
   /** @type {?FakeSystemRoutineController} */
   let controller = null;
 
@@ -115,4 +112,4 @@
 
     return runRoutinesAndAssertResults(routines);
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/routine_result_entry_test.js b/chrome/test/data/webui/chromeos/diagnostics/routine_result_entry_test.js
index 979dd69..f447e2f 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/routine_result_entry_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/routine_result_entry_test.js
@@ -2,15 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/routine_result_entry.js';
 
 import {RoutineName, RoutineResult, StandardRoutineResult} from 'chrome://diagnostics/diagnostics_types.js';
 import {ExecutionProgress, ResultStatusItem} from 'chrome://diagnostics/routine_list_executor.js';
 import {flushTasks} from 'chrome://test/test_util.m.js';
 
-suite('RoutineResultEntryTest', () => {
+export function routineResultEntryTestSuite() {
   /** @type {?HTMLElement} */
   let routineResultEntryElement = null;
 
@@ -158,4 +156,4 @@
       assertEquals(getStatusText(), 'kTestFailed');
     });
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js b/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js
index 2f252f7a0..e763b90 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/routine_result_list.js';
 
 import {RoutineName} from 'chrome://diagnostics/diagnostics_types.js';
@@ -12,7 +10,7 @@
 
 import * as dx_utils from './diagnostics_test_utils.js';
 
-suite('RoutineResultListTest', () => {
+export function routineResultListTestSuite() {
   /** @type {?HTMLElement} */
   let routineResultListElement = null;
 
@@ -112,4 +110,4 @@
           assertEquals(0, getEntries().length);
         });
   });
-});
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/routine_section_test.js b/chrome/test/data/webui/chromeos/diagnostics/routine_section_test.js
index 3d83dea6..a7e626d2 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/routine_section_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/routine_section_test.js
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/routine_result_entry.js';
 import 'chrome://diagnostics/routine_section.js';
 
@@ -13,7 +11,7 @@
 
 import * as dx_utils from './diagnostics_test_utils.js';
 
-suite('RoutineSectionTest', () => {
+export function routineSectionTestSuite() {
   /** @type {?HTMLElement} */
   let routineSectionElement = null;
 
@@ -137,4 +135,4 @@
           });
         });
   });
-});
+}
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index 2cfeb7c..debe292 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -1873,7 +1873,7 @@
 var OSSettingsInputPageTest = class extends OSSettingsBrowserTest {
   /** @override */
   get browsePreload() {
-    return super.browsePreload + 'chromeos/os_language_page/input_page.html';
+    return super.browsePreload + 'chromeos/os_languages_page/input_page.html';
   }
 
   /** @override */
diff --git a/chrome/test/data/webui/tab_search_merge/tab_search_interactive_ui_tests.js b/chrome/test/data/webui/tab_search_merge/tab_search_interactive_ui_tests.js
index a9c89e3..24d7dc38 100644
--- a/chrome/test/data/webui/tab_search_merge/tab_search_interactive_ui_tests.js
+++ b/chrome/test/data/webui/tab_search_merge/tab_search_interactive_ui_tests.js
@@ -34,6 +34,11 @@
   }
 };
 
-TEST_F('TabSearchInteractiveUITest', 'All', function() {
+GEN('#if defined(OS_MAC)');
+GEN('#define MAYBE_All DISABLED_All');
+GEN('#else');
+GEN('#define MAYBE_All All');
+GEN('#endif');
+TEST_F('TabSearchInteractiveUITest', 'MAYBE_All', function() {
   mocha.run();
 });
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index c3f5883..d26410e 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -275,7 +275,11 @@
 #endif
 PPAPI_SOCKET_TEST(TCPSocket_Listen)
 PPAPI_SOCKET_TEST(TCPSocket_Interface_1_0)
+
+// Flaky on Windows https://crbug.com/1143728
+#if !defined(OS_WIN)
 PPAPI_SOCKET_TEST(TCPSocket_UnexpectedCalls)
+#endif
 
 TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(TCPServerSocketPrivate_Listen)
 TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(TCPServerSocketPrivate_Backlog)
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index b01650f..66957fc 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-13560.0.0
\ No newline at end of file
+13562.0.0
\ No newline at end of file
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 88b974a..e6311ca 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -580,7 +580,99 @@
       <message name="IDS_CONNECTIVITY_DIAGNOSTICS_TITLE" desc="The label for connectivity diagnostics application that shows potential issues with the network connections">
         Connectivity Diagnostics
       </message>
-
+      <message name="IDS_NETWORK_DIAGNOSTICS_LAN_CONNECTIVITY" desc="Label for Network diagnostics `LAN connectivity` test. This test determines if the device is connected to a Local Area Network (LAN)">
+        Lan Connectivity
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH" desc="Label for Network diagnostics `signal strength` test. This test ensures that a WiFi signal is strong enough for a stable connection.">
+        Signal Strength
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED" desc="Label for Network diagnostics `gateway can be pinged` test. This test ensures that there is a connection to the network gateway.">
+        Gateway can be Pinged
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_HAS_SECURE_WIFI_CONNECTION" desc="Label for Network diagnostics `has secure WiFi connection` test. This test ensures that the WiFi connection is properly secure.">
+        Secure WiFi Connection
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PRESENT" desc="Label for Network diagnostics `DNS resolver present` test. This test ensures that the Domain Name Service (DNS) exists.">
+        DNS Resolver Present
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY" desc="Label for Network diagnostics `DNS latency` test. This test makes sure the latency between the device and the Domain Name Server (DNS) is acceptable.">
+        DNS Latency
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION" desc="Label for Network diagnostics `DNS resolution` test. This test ensures that the Domain Name Server (DNS) can resolve network requests.">
+        DNS Resolution
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_PASSED" desc="Label shown when a Network diagnostics routine passed">
+        Passed
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_FAILED" desc="Label shown when a Network diagnostics routine failed">
+        Failed
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_NOT_RUN" desc="Label shown when a Network diagnostics routine did not run">
+        Not Run
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_RUN" desc="Label for Network diagnostics run routine button">
+        Run
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_RUN_ALL" desc="Label for Network diagnostics run all routines button">
+        Run All Routines
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_SEND_FEEDBACK" desc="Label for Network diagnostics send feedback report button">
+        Send Feedback Report
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_NOT_FOUND" desc="Error message shown when a WiFi signal could not be detected">
+        Signal not found
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_WEAK" desc="Error message shown when a only a weak WiFi signal could be detected">
+        Weak signal
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_UNREACHABLE" desc="Error message shown when a network gateway is not reachable">
+        Gateway is unreachable
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_DEFAULT_FAILED" desc="Error message shown when the default network gateway cannot be pinged">
+        Failed to ping the default network gateway
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_DEFAULT_ABOVE_LATENCY" desc="Error message shown when the latency of the default network gateway is too high">
+        Default network above latency threshold
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_NON_DEFAULT_FAILED" desc="Error message shown when the non-default network gateway cannot be pinged">
+        Failed to ping the non-default network gateway
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_NON_DEFAULT_ABOVE_LATENCY" desc="Error message shown when the latency of the non-default network gateway is too high">
+        Non-default network above latency threshold
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_NOT_SECURE" desc="Error message shown when the current WiFi network is not secure">
+        WiFi network is not secure
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_8021x" desc="Error message shown when the current WiFi network is secured with the weak protocol WEP 802.1x">
+        WiFi network is secured with weak protocol WEP 802.1x
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_PSK" desc="Error message shown when the current WiFi network is secured with the weak protocol WEP PSK">
+        WiFi network is secured with weak protocol WEP PSK
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_UNKNOWN" desc="Error message shown when the current WiFi network is secured with an unknown protocol">
+        Unknown WiFi security protocol
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_NO_NAME_SERVERS" desc="Error message shown when the no domain name servers (DNS) are found">
+        No name servers found
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_MALFORMED_NAME_SERVERS" desc="Error message shown when the domain name servers (DNS) are malformed">
+        Malformed name servers
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_EMPTY_NAME_SERVERS" desc="Error message shown when the domain name servers (DNS) are empty">
+        Empty name servers
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_FAILED_TO_RESOLVE_ALL_HOSTS" desc="Error message shown when the domain name servers (DNS) failed to resolve all hosts">
+        Failed to resolve all hosts
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SLIGHTLY_ABOVE_THRESHOLD" desc="Error message shown when the latency for the domain name server (DNS) is slightly above an allowable threshold">
+        DNS latency slightly above allowable threshold
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SIGNIFICANTLY_ABOVE_THRESHOLD" desc="Error message shown when the latency for the domain name server (DNS) is significantly above an allowable threshold">
+        DNS latency significantly above allowable threshold
+      </message>
+      <message name="IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION_PROBLEM_FAILED_TO_RESOLVE_HOST" desc="Error message shown when the domain name server (DNS) failed to resolve a host">
+        Failed to resolve host
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_FAILED_TO_RESOLVE_ALL_HOSTS.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_FAILED_TO_RESOLVE_ALL_HOSTS.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_FAILED_TO_RESOLVE_ALL_HOSTS.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_FAILED_TO_RESOLVE_ALL_HOSTS.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SIGNIFICANTLY_ABOVE_THRESHOLD.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SIGNIFICANTLY_ABOVE_THRESHOLD.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SIGNIFICANTLY_ABOVE_THRESHOLD.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SIGNIFICANTLY_ABOVE_THRESHOLD.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SLIGHTLY_ABOVE_THRESHOLD.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SLIGHTLY_ABOVE_THRESHOLD.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SLIGHTLY_ABOVE_THRESHOLD.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SLIGHTLY_ABOVE_THRESHOLD.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION_PROBLEM_FAILED_TO_RESOLVE_HOST.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION_PROBLEM_FAILED_TO_RESOLVE_HOST.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION_PROBLEM_FAILED_TO_RESOLVE_HOST.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION_PROBLEM_FAILED_TO_RESOLVE_HOST.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PRESENT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PRESENT.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PRESENT.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PRESENT.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_EMPTY_NAME_SERVERS.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_EMPTY_NAME_SERVERS.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_EMPTY_NAME_SERVERS.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_EMPTY_NAME_SERVERS.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_MALFORMED_NAME_SERVERS.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_MALFORMED_NAME_SERVERS.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_MALFORMED_NAME_SERVERS.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_MALFORMED_NAME_SERVERS.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_NO_NAME_SERVERS.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_NO_NAME_SERVERS.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_NO_NAME_SERVERS.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_NO_NAME_SERVERS.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_FAILED.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_FAILED.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_FAILED.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_FAILED.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_DEFAULT_ABOVE_LATENCY.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_DEFAULT_ABOVE_LATENCY.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_DEFAULT_ABOVE_LATENCY.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_DEFAULT_ABOVE_LATENCY.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_NON_DEFAULT_ABOVE_LATENCY.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_NON_DEFAULT_ABOVE_LATENCY.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_NON_DEFAULT_ABOVE_LATENCY.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_NON_DEFAULT_ABOVE_LATENCY.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_DEFAULT_FAILED.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_DEFAULT_FAILED.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_DEFAULT_FAILED.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_DEFAULT_FAILED.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_NON_DEFAULT_FAILED.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_NON_DEFAULT_FAILED.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_NON_DEFAULT_FAILED.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_NON_DEFAULT_FAILED.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_UNREACHABLE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_UNREACHABLE.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_UNREACHABLE.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_UNREACHABLE.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_HAS_SECURE_WIFI_CONNECTION.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_HAS_SECURE_WIFI_CONNECTION.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_HAS_SECURE_WIFI_CONNECTION.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_HAS_SECURE_WIFI_CONNECTION.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_LAN_CONNECTIVITY.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_LAN_CONNECTIVITY.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_LAN_CONNECTIVITY.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_LAN_CONNECTIVITY.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_NOT_RUN.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_NOT_RUN.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_NOT_RUN.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_NOT_RUN.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_PASSED.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_PASSED.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_PASSED.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_PASSED.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_RUN.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_RUN.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_RUN.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_RUN.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_RUN_ALL.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_RUN_ALL.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_RUN_ALL.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_RUN_ALL.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_NOT_SECURE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_NOT_SECURE.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_NOT_SECURE.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_NOT_SECURE.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_UNKNOWN.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_UNKNOWN.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_UNKNOWN.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_UNKNOWN.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_8021x.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_8021x.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_8021x.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_8021x.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_PSK.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_PSK.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_PSK.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_PSK.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SEND_FEEDBACK.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SEND_FEEDBACK.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SEND_FEEDBACK.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SEND_FEEDBACK.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_NOT_FOUND.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_NOT_FOUND.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_NOT_FOUND.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_NOT_FOUND.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_WEAK.png.sha1 b/chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_WEAK.png.sha1
similarity index 100%
rename from chrome/app/chromeos_strings_grdp/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_WEAK.png.sha1
rename to chromeos/chromeos_strings_grd/IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_WEAK.png.sha1
diff --git a/chromeos/components/connectivity_diagnostics/BUILD.gn b/chromeos/components/connectivity_diagnostics/BUILD.gn
index ecab6de..4d47fe1 100644
--- a/chromeos/components/connectivity_diagnostics/BUILD.gn
+++ b/chromeos/components/connectivity_diagnostics/BUILD.gn
@@ -13,6 +13,7 @@
   ]
 
   deps = [
+    ":network_diagnostics_strings",
     "//chromeos/components/web_applications",
     "//chromeos/constants",
     "//chromeos/resources:connectivity_diagnostics_resources",
@@ -27,3 +28,17 @@
 group("closure_compile") {
   deps = [ "resources:closure_compile_module" ]
 }
+
+source_set("network_diagnostics_strings") {
+  sources = [
+    "network_diagnostics_localized_strings.cc",
+    "network_diagnostics_localized_strings.h",
+  ]
+
+  deps = [
+    "//chromeos/strings/",
+    "//content/public/browser",
+    "//ui/base",
+    "//ui/webui",
+  ]
+}
diff --git a/chromeos/components/connectivity_diagnostics/network_diagnostics_localized_strings.cc b/chromeos/components/connectivity_diagnostics/network_diagnostics_localized_strings.cc
new file mode 100644
index 0000000..9842832
--- /dev/null
+++ b/chromeos/components/connectivity_diagnostics/network_diagnostics_localized_strings.cc
@@ -0,0 +1,82 @@
+// Copyright 2020 The Chromium 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 "chromeos/components/connectivity_diagnostics/network_diagnostics_localized_strings.h"
+
+#include "chromeos/strings/grit/chromeos_strings.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "ui/base/webui/web_ui_util.h"
+
+namespace chromeos {
+namespace network_diagnostics {
+
+namespace {
+
+constexpr webui::LocalizedString kLocalizedStrings[] = {
+    // Network Diagnostics Strings
+    {"NetworkDiagnosticsLanConnectivity",
+     IDS_NETWORK_DIAGNOSTICS_LAN_CONNECTIVITY},
+    {"NetworkDiagnosticsSignalStrength",
+     IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH},
+    {"NetworkDiagnosticsGatewayCanBePinged",
+     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED},
+    {"NetworkDiagnosticsHasSecureWiFiConnection",
+     IDS_NETWORK_DIAGNOSTICS_HAS_SECURE_WIFI_CONNECTION},
+    {"NetworkDiagnosticsDnsResolverPresent",
+     IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PRESENT},
+    {"NetworkDiagnosticsDnsLatency", IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY},
+    {"NetworkDiagnosticsDnsResolution", IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION},
+    {"NetworkDiagnosticsPassed", IDS_NETWORK_DIAGNOSTICS_PASSED},
+    {"NetworkDiagnosticsFailed", IDS_NETWORK_DIAGNOSTICS_FAILED},
+    {"NetworkDiagnosticsNotRun", IDS_NETWORK_DIAGNOSTICS_NOT_RUN},
+    {"NetworkDiagnosticsRun", IDS_NETWORK_DIAGNOSTICS_RUN},
+    {"NetworkDiagnosticsRunAll", IDS_NETWORK_DIAGNOSTICS_RUN_ALL},
+    {"NetworkDiagnosticsSendFeedback", IDS_NETWORK_DIAGNOSTICS_SEND_FEEDBACK},
+    {"SignalStrengthProblem_NotFound",
+     IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_NOT_FOUND},
+    {"SignalStrengthProblem_Weak",
+     IDS_NETWORK_DIAGNOSTICS_SIGNAL_STRENGTH_PROBLEM_WEAK},
+    {"GatewayPingProblem_Unreachable",
+     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_UNREACHABLE},
+    {"GatewayPingProblem_NoDefaultPing",
+     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_DEFAULT_FAILED},
+    {"GatewayPingProblem_DefaultLatency",
+     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_DEFAULT_ABOVE_LATENCY},
+    {"GatewayPingProblem_NoNonDefaultPing",
+     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_PING_NON_DEFAULT_FAILED},
+    {"GatewayPingProblem_NonDefaultLatency",
+     IDS_NETWORK_DIAGNOSTICS_GATEWAY_CAN_BE_PINGED_PROBLEM_NON_DEFAULT_ABOVE_LATENCY},
+    {"SecureWifiProblem_None",
+     IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_NOT_SECURE},
+    {"SecureWifiProblem_8021x",
+     IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_8021x},
+    {"SecureWifiProblem_PSK",
+     IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_WEP_PSK},
+    {"SecureWifiProblem_Unknown",
+     IDS_NETWORK_DIAGNOSTICS_SECURE_WIFI_PROBLEM_UNKNOWN},
+    {"DnsResolverProblem_NoNameServers",
+     IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_NO_NAME_SERVERS},
+    {"DnsResolverProblem_MalformedNameServers",
+     IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_MALFORMED_NAME_SERVERS},
+    {"DnsResolverProblem_EmptyNameServers",
+     IDS_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PROBLEM_EMPTY_NAME_SERVERS},
+    {"DnsLatencyProblem_FailedResolveHosts",
+     IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_FAILED_TO_RESOLVE_ALL_HOSTS},
+    {"DnsLatencyProblem_LatencySlightlyAbove",
+     IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SLIGHTLY_ABOVE_THRESHOLD},
+    {"DnsLatencyProblem_LatencySignificantlyAbove",
+     IDS_NETWORK_DIAGNOSTICS_DNS_LATENCY_PROBLEM_SIGNIFICANTLY_ABOVE_THRESHOLD},
+    {"DnsResolutionProblem_FailedResolve",
+     IDS_NETWORK_DIAGNOSTICS_DNS_RESOLUTION_PROBLEM_FAILED_TO_RESOLVE_HOST},
+};
+
+}  // namespace
+
+void AddLocalizedStrings(content::WebUIDataSource* html_source) {
+  for (const auto& str : kLocalizedStrings)
+    html_source->AddLocalizedString(str.name, str.id);
+}
+
+}  // namespace network_diagnostics
+}  // namespace chromeos
diff --git a/chromeos/components/connectivity_diagnostics/network_diagnostics_localized_strings.h b/chromeos/components/connectivity_diagnostics/network_diagnostics_localized_strings.h
new file mode 100644
index 0000000..64d794c
--- /dev/null
+++ b/chromeos/components/connectivity_diagnostics/network_diagnostics_localized_strings.h
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium 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 CHROMEOS_COMPONENTS_CONNECTIVITY_DIAGNOSTICS_NETWORK_DIAGNOSTICS_LOCALIZED_STRINGS_H_
+#define CHROMEOS_COMPONENTS_CONNECTIVITY_DIAGNOSTICS_NETWORK_DIAGNOSTICS_LOCALIZED_STRINGS_H_
+
+namespace content {
+class WebUIDataSource;
+}
+
+namespace chromeos {
+namespace network_diagnostics {
+
+// Adds the strings needed for network health elements to |html_source|.
+void AddLocalizedStrings(content::WebUIDataSource* html_source);
+
+}  // namespace network_diagnostics
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_CONNECTIVITY_DIAGNOSTICS_NETWORK_DIAGNOSTICS_LOCALIZED_STRINGS_H_
diff --git a/chromeos/components/print_management/resources/print_job_entry.js b/chromeos/components/print_management/resources/print_job_entry.js
index fc13d677..8b9f18d2 100644
--- a/chromeos/components/print_management/resources/print_job_entry.js
+++ b/chromeos/components/print_management/resources/print_job_entry.js
@@ -16,16 +16,17 @@
 import './print_management_fonts_css.js';
 import './print_management_shared_css.js';
 import './printing_manager.mojom-lite.js';
+import './strings.m.js';
 
-import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
-import {getMetadataProvider} from './mojo_interface_provider.js';
 import {assertNotReached} from 'chrome://resources/js/assert.m.js';
-import {FocusRowBehavior} from 'chrome://resources/js/cr/ui/focus_row_behavior.m.js';
-import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
+import {FocusRowBehavior} from 'chrome://resources/js/cr/ui/focus_row_behavior.m.js';
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
-import './strings.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getMetadataProvider} from './mojo_interface_provider.js';
 
 (function() {
 
diff --git a/chromeos/components/print_management/resources/print_management.js b/chromeos/components/print_management/resources/print_management.js
index 3214aa7..0e7de9b 100644
--- a/chromeos/components/print_management/resources/print_management.js
+++ b/chromeos/components/print_management/resources/print_management.js
@@ -17,12 +17,14 @@
 import './print_job_entry.js';
 import './print_management_fonts_css.js';
 import './print_management_shared_css.js';
+import './strings.m.js';
 
-import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {getMetadataProvider} from './mojo_interface_provider.js';
+import {assert} from 'chrome://resources/js/assert.m.js';
 import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {assert} from 'chrome://resources/js/assert.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getMetadataProvider} from './mojo_interface_provider.js';
 
 const METADATA_STORED_INDEFINITELY = -1;
 const METADATA_STORED_FOR_ONE_DAY = 1;
diff --git a/chromeos/components/scanning/resources/BUILD.gn b/chromeos/components/scanning/resources/BUILD.gn
index 56cf92d..1942c766 100644
--- a/chromeos/components/scanning/resources/BUILD.gn
+++ b/chromeos/components/scanning/resources/BUILD.gn
@@ -156,6 +156,7 @@
     "scanner_select.js",
     "scan_to_select.js",
     "scanning_app.js",
+    "scanning_fonts_css.js",
     "scanning_shared_css.js",
     "source_select.js",
     "throbber_css.js",
diff --git a/chromeos/components/scanning/resources/color_mode_select.html b/chromeos/components/scanning/resources/color_mode_select.html
index af9fe96..35627b9 100644
--- a/chromeos/components/scanning/resources/color_mode_select.html
+++ b/chromeos/components/scanning/resources/color_mode_select.html
@@ -1,3 +1,4 @@
+<style include="scanning-shared"></style>
 <scan-settings-section>
   <span id="colorModeLabel" slot="label">[[i18n('colorModeDropdownLabel')]]</span>
   <div slot="settings">
diff --git a/chromeos/components/scanning/resources/file_type_select.html b/chromeos/components/scanning/resources/file_type_select.html
index a6d1b988..377e6b5 100644
--- a/chromeos/components/scanning/resources/file_type_select.html
+++ b/chromeos/components/scanning/resources/file_type_select.html
@@ -1,3 +1,4 @@
+<style include="scanning-shared"></style>
 <scan-settings-section>
   <span id="fileTypeLabel" slot="label">[[i18n('fileTypeDropdownLabel')]]</span>
   <div slot="settings">
diff --git a/chromeos/components/scanning/resources/page_size_select.html b/chromeos/components/scanning/resources/page_size_select.html
index fe14837..9cc226a 100644
--- a/chromeos/components/scanning/resources/page_size_select.html
+++ b/chromeos/components/scanning/resources/page_size_select.html
@@ -1,3 +1,4 @@
+<style include="scanning-shared"></style>
 <scan-settings-section>
   <span id="pageSizeLabel" slot="label">[[i18n('pageSizeDropdownLabel')]]</span>
   <div slot="settings">
diff --git a/chromeos/components/scanning/resources/resolution_select.html b/chromeos/components/scanning/resources/resolution_select.html
index 171cda74..b04c4bed 100644
--- a/chromeos/components/scanning/resources/resolution_select.html
+++ b/chromeos/components/scanning/resources/resolution_select.html
@@ -1,3 +1,4 @@
+<style include="scanning-shared"></style>
 <scan-settings-section>
   <span id="resolutionLabel" slot="label">[[i18n('resolutionDropdownLabel')]]</span>
   <div slot="settings">
diff --git a/chromeos/components/scanning/resources/scan_settings_section.html b/chromeos/components/scanning/resources/scan_settings_section.html
index 46d8c5b6..131e63a 100644
--- a/chromeos/components/scanning/resources/scan_settings_section.html
+++ b/chromeos/components/scanning/resources/scan_settings_section.html
@@ -1,29 +1,33 @@
 <!-- TODO(jschettler): Update styling to match the spec. -->
-<style>
+<style include="scanning-shared scanning-fonts">
   :host {
     display: flex;
   }
 
   ::slotted([slot=label]),
   ::slotted([slot=settings]) {
+    @apply --scanning-select-font;
+    color: var(--scanning-select-text-color);
     display: flex;
     flex-direction: column;
-    min-height: 38px;
+    min-height: 32px;
   }
 
   ::slotted([slot=label]) {
     flex: none;
-    flex-basis: 100px;
+    flex-basis: 68px;
     flex-grow: 0;
     flex-shrink: 0;
-    padding-inline-end: 10px;
+    margin-top: 5px;
+    padding-inline-end: 20px;
   }
 
   ::slotted([slot=settings]) {
     flex: 1;
-    flex-basis: 250px;
+    flex-basis: 192px;
     flex-grow: 0;
     flex-shrink: 0;
+    margin-bottom: 8px;
   }
 </style>
 <slot name="label"></slot>
diff --git a/chromeos/components/scanning/resources/scan_settings_section.js b/chromeos/components/scanning/resources/scan_settings_section.js
index 0fa252a3..6bdac77 100644
--- a/chromeos/components/scanning/resources/scan_settings_section.js
+++ b/chromeos/components/scanning/resources/scan_settings_section.js
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import './scanning_fonts_css.js';
+import './scanning_shared_css.js';
+
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 Polymer({
diff --git a/chromeos/components/scanning/resources/scanner_select.html b/chromeos/components/scanning/resources/scanner_select.html
index 90797cb..80b8c2f 100644
--- a/chromeos/components/scanning/resources/scanner_select.html
+++ b/chromeos/components/scanning/resources/scanner_select.html
@@ -1,4 +1,4 @@
-<style include="throbber"></style>
+<style include="throbber scanning-shared"></style>
 <scan-settings-section>
   <span id="scannerLabel" slot="label">[[i18n('scannerDropdownLabel')]]</span>
   <div slot="settings">
diff --git a/chromeos/components/scanning/resources/scanning_app.js b/chromeos/components/scanning/resources/scanning_app.js
index 967f983c..b6d200f 100644
--- a/chromeos/components/scanning/resources/scanning_app.js
+++ b/chromeos/components/scanning/resources/scanning_app.js
@@ -50,8 +50,11 @@
       value: () => [],
     },
 
-    /** @type (?string) */
-    selectedScannerId: String,
+    /** @type {string} */
+    selectedScannerId: {
+      type: String,
+      observer: 'onSelectedScannerIdChange_'
+    },
 
     /**
      * @type {?chromeos.scanning.mojom.ScannerCapabilities}
@@ -109,8 +112,6 @@
     },
   },
 
-  observers: ['onSelectedScannerIdChange_(selectedScannerId)'],
-
   /** @override */
   created() {
     this.scanService_ = getScanService();
@@ -183,19 +184,16 @@
     this.selectedScannerId = tokenToString(this.scanners_[0].id);
   },
 
-  /**
-   * @param {!string} selectedScannerId
-   * @private
-   */
-  onSelectedScannerIdChange_(selectedScannerId) {
-    if (!this.scannerIds_.has(selectedScannerId)) {
+  /** @private */
+  onSelectedScannerIdChange_() {
+    if (!this.scannerIds_.has(this.selectedScannerId)) {
       return;
     }
 
     this.scanButtonDisabled_ = true;
 
     this.scanService_
-        .getScannerCapabilities(this.scannerIds_.get(selectedScannerId))
+        .getScannerCapabilities(this.scannerIds_.get(this.selectedScannerId))
         .then(
             /*@type {!{capabilities:
                    !chromeos.scanning.mojom.ScannerCapabilities}}*/
diff --git a/chromeos/components/scanning/resources/scanning_app_resources.grd b/chromeos/components/scanning/resources/scanning_app_resources.grd
index 1edcf38e..a867756 100644
--- a/chromeos/components/scanning/resources/scanning_app_resources.grd
+++ b/chromeos/components/scanning/resources/scanning_app_resources.grd
@@ -33,6 +33,7 @@
       <include name="IDR_SCANNING_APP_SCAN_SETTINGS_SECTION_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scan_settings_section.js" use_base_dir="false" type="BINDATA"/>
       <include name="IDR_SCANNING_APP_THROBBER_CSS_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/throbber_css.js" use_base_dir="false" type="BINDATA"/>
       <include name="IDR_SCANNING_APP_SCANNING_SHARED_CSS_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scanning_shared_css.js" use_base_dir="false" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_SCANNING_FONTS_CSS_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scanning_fonts_css.js" use_base_dir="false" type="BINDATA"/>
       <include name="IDR_SCANNING_APP_SCAN_PREVIEW_HTML" file="scan_preview.html" type="BINDATA"/>
       <include name="IDR_SCANNING_APP_SCAN_PREVIEW_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scan_preview.js" use_base_dir="false" type="BINDATA"/>
       <include name="IDR_SCANNING_APP_ICON_16" file="scanning_app_icon_16.png" type="BINDATA" />
diff --git a/chromeos/components/scanning/resources/scanning_fonts_css.html b/chromeos/components/scanning/resources/scanning_fonts_css.html
new file mode 100644
index 0000000..abeabb4
--- /dev/null
+++ b/chromeos/components/scanning/resources/scanning_fonts_css.html
@@ -0,0 +1,15 @@
+<template>
+  <style>
+    :host {
+      --scanning-select-font-family: Roboto;
+      --scanning-select-font-size: 13px;
+
+      --scanning-select-text-color: var(--google-grey-900);
+
+      --scanning-select-font: {
+          font-family: var(--scanning-select-font-family);
+          font-size: var(--scanning-select-font-size);
+      };
+    }
+  </style>
+</template>
\ No newline at end of file
diff --git a/chromeos/components/scanning/resources/scanning_fonts_css.js b/chromeos/components/scanning/resources/scanning_fonts_css.js
new file mode 100644
index 0000000..3e348f3
--- /dev/null
+++ b/chromeos/components/scanning/resources/scanning_fonts_css.js
@@ -0,0 +1,11 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+const template = document.createElement('template');
+template.innerHTML = `
+<dom-module id="scanning-fonts">{__html_template__}</dom-module>
+`;
+document.body.appendChild(template.content.cloneNode(true));
\ No newline at end of file
diff --git a/chromeos/components/scanning/resources/scanning_shared_css.html b/chromeos/components/scanning/resources/scanning_shared_css.html
index 488a2b0..1be011c 100644
--- a/chromeos/components/scanning/resources/scanning_shared_css.html
+++ b/chromeos/components/scanning/resources/scanning_shared_css.html
@@ -2,8 +2,10 @@
     href="chrome://resources/chromeos/colors/cros_colors.generated.css">
 <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
 <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
+<link rel="stylesheet" href="chrome://resources/cr_elements/md_select_css.html">
+
 <template>
-  <style include="cr-shared-style">
+  <style include="cr-shared-style md-select">
     /* TODO(michaelcheco): Add media queries that update css vars to match the
      * values found in the spec. */
     :host {
diff --git a/chromeos/components/scanning/resources/scanning_shared_css.js b/chromeos/components/scanning/resources/scanning_shared_css.js
index c0a4849..b52597b 100644
--- a/chromeos/components/scanning/resources/scanning_shared_css.js
+++ b/chromeos/components/scanning/resources/scanning_shared_css.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'chrome://resources/cr_elements/md_select_css.m.js';
 import 'chrome://resources/cr_elements/shared_style_css.m.js';
 import 'chrome://resources/cr_elements/shared_vars_css.m.js';
 import 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chromeos/components/scanning/resources/source_select.html b/chromeos/components/scanning/resources/source_select.html
index 82769d5..cc0af37 100644
--- a/chromeos/components/scanning/resources/source_select.html
+++ b/chromeos/components/scanning/resources/source_select.html
@@ -1,3 +1,4 @@
+<style include="scanning-shared"></style>
 <scan-settings-section>
   <span id="sourceLabel" slot="label">[[i18n('sourceDropdownLabel')]]</span>
   <div slot="settings">
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index add2f4ab..355ad5b 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-88-4296.0-1603709458-benchmark-88.0.4305.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-88-4296.0-1603709458-benchmark-88.0.4306.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index f378a36..48fb0d0 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-88-4296.0-1603705354-benchmark-88.0.4305.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-88-4296.0-1603705354-benchmark-88.0.4306.0-r1-redacted.afdo.xz
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 3cce2d8..a757b18 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -311,7 +311,6 @@
     if (!is_fuchsia) {  # !iOS and !Fuchsia
       deps += [
         "//components/crash/content/browser:unit_tests",
-        "//components/crash/content/browser/error_reporting:unit_tests",
         "//components/crash/core/app:unit_tests",
         "//components/data_reduction_proxy/core/browser:unit_tests",
         "//components/data_reduction_proxy/core/common:unit_tests",
diff --git a/components/autofill_assistant/browser/model.proto b/components/autofill_assistant/browser/model.proto
index 022daaf..8dcf4de 100644
--- a/components/autofill_assistant/browser/model.proto
+++ b/components/autofill_assistant/browser/model.proto
@@ -261,14 +261,17 @@
 enum ChipIcon {
   NO_ICON = 0;
 
-  // https://icons.googleplex.com/#icon=ic_clear
+  // https://icons.googleplex.com/#icon=clear
   ICON_CLEAR = 1;
 
-  // https://icons.googleplex.com/#icon=ic_done
+  // https://icons.googleplex.com/#icon=done
   ICON_DONE = 2;
 
-  // https://icons.googleplex.com/#icon=ic_refresh
+  // https://icons.googleplex.com/#icon=refresh
   ICON_REFRESH = 3;
+
+  // https://icons.googleplex.com/#icon=more_vert
+  ICON_OVERFLOW = 4;
 }
 
 // Defines a mapping to an Android Q direct action.
diff --git a/components/bookmarks/browser/titled_url_index.cc b/components/bookmarks/browser/titled_url_index.cc
index 9e3d887..5352023f 100644
--- a/components/bookmarks/browser/titled_url_index.cc
+++ b/components/bookmarks/browser/titled_url_index.cc
@@ -60,25 +60,13 @@
 }
 
 void TitledUrlIndex::Add(const TitledUrlNode* node) {
-  std::vector<base::string16> terms =
-      ExtractQueryWords(Normalize(node->GetTitledUrlNodeTitle()));
-  for (size_t i = 0; i < terms.size(); ++i)
-    RegisterNode(terms[i], node);
-  terms = ExtractQueryWords(
-      CleanUpUrlForMatching(node->GetTitledUrlNodeUrl(), nullptr));
-  for (size_t i = 0; i < terms.size(); ++i)
-    RegisterNode(terms[i], node);
+  for (const base::string16& term : ExtractIndexTerms(node))
+    RegisterNode(term, node);
 }
 
 void TitledUrlIndex::Remove(const TitledUrlNode* node) {
-  std::vector<base::string16> terms =
-      ExtractQueryWords(Normalize(node->GetTitledUrlNodeTitle()));
-  for (size_t i = 0; i < terms.size(); ++i)
-    UnregisterNode(terms[i], node);
-  terms = ExtractQueryWords(
-      CleanUpUrlForMatching(node->GetTitledUrlNodeUrl(), nullptr));
-  for (size_t i = 0; i < terms.size(); ++i)
-    UnregisterNode(terms[i], node);
+  for (const base::string16& term : ExtractIndexTerms(node))
+    UnregisterNode(term, node);
 }
 
 std::vector<TitledUrlMatch> TitledUrlIndex::GetResultsMatching(
@@ -87,16 +75,11 @@
     query_parser::MatchingAlgorithm matching_algorithm) {
   const base::string16 query = Normalize(input_query);
   std::vector<base::string16> terms = ExtractQueryWords(query);
-  if (terms.empty())
-    return {};
 
-  TitledUrlNodeSet matches;
-  for (size_t i = 0; i < terms.size(); ++i) {
-    if (!GetResultsMatchingTerm(terms[i], i == 0, matching_algorithm,
-                                &matches)) {
-      return {};
-    }
-  }
+  TitledUrlNodeSet matches =
+      RetrieveNodesMatchingAllTerms(terms, matching_algorithm);
+  if (matches.empty())
+    return {};
 
   TitledUrlNodes sorted_nodes;
   SortMatches(matches, &sorted_nodes);
@@ -183,49 +166,52 @@
   return match;
 }
 
-bool TitledUrlIndex::GetResultsMatchingTerm(
+TitledUrlIndex::TitledUrlNodeSet TitledUrlIndex::RetrieveNodesMatchingAllTerms(
+    const std::vector<base::string16>& terms,
+    query_parser::MatchingAlgorithm matching_algorithm) const {
+  if (terms.empty())
+    return {};
+
+  TitledUrlNodeSet matches =
+      RetrieveNodesMatchingTerm(terms[0], matching_algorithm);
+  for (size_t i = 1; i < terms.size() && !matches.empty(); ++i) {
+    TitledUrlNodeSet term_matches =
+        RetrieveNodesMatchingTerm(terms[i], matching_algorithm);
+    // Compute intersection between the two sets.
+    base::EraseIf(matches, base::IsNotIn<TitledUrlNodeSet>(term_matches));
+  }
+
+  return matches;
+}
+
+TitledUrlIndex::TitledUrlNodeSet TitledUrlIndex::RetrieveNodesMatchingTerm(
     const base::string16& term,
-    bool first_term,
-    query_parser::MatchingAlgorithm matching_algorithm,
-    TitledUrlNodeSet* matches) {
+    query_parser::MatchingAlgorithm matching_algorithm) const {
   Index::const_iterator i = index_.lower_bound(term);
   if (i == index_.end())
-    return false;
+    return {};
 
   if (!query_parser::QueryParser::IsWordLongEnoughForPrefixSearch(
       term, matching_algorithm)) {
     // Term is too short for prefix match, compare using exact match.
     if (i->first != term)
-      return false;  // No title/URL pairs with this term.
-
-    if (first_term) {
-      (*matches) = i->second;
-      return true;
-    }
-    base::EraseIf(*matches, base::IsNotIn<TitledUrlNodeSet>(i->second));
-  } else {
-    // Loop through index adding all entries that start with term to
-    // |prefix_matches|.
-    TitledUrlNodeSet tmp_prefix_matches;
-    // If this is the first term, then store the result directly in |matches|
-    // to avoid calling stl intersection (which requires a copy).
-    TitledUrlNodeSet* prefix_matches =
-        first_term ? matches : &tmp_prefix_matches;
-    while (i != index_.end() &&
-           i->first.size() >= term.size() &&
-           term.compare(0, term.size(), i->first, 0, term.size()) == 0) {
-      for (auto n = i->second.begin(); n != i->second.end(); ++n) {
-        prefix_matches->insert(prefix_matches->end(), *n);
-      }
-      ++i;
-    }
-    if (!first_term) {
-      base::EraseIf(*matches, base::IsNotIn<TitledUrlNodeSet>(*prefix_matches));
-    }
+      return {};  // No title/URL pairs with this term.
+    return i->second;
   }
-  return !matches->empty();
+
+  // Loop through index adding all entries that start with term to
+  // |prefix_matches|.
+  TitledUrlNodes prefix_matches;
+  while (i != index_.end() && i->first.size() >= term.size() &&
+         term.compare(0, term.size(), i->first, 0, term.size()) == 0) {
+    prefix_matches.insert(prefix_matches.end(), i->second.begin(),
+                          i->second.end());
+    ++i;
+  }
+  return prefix_matches;
 }
 
+// static
 std::vector<base::string16> TitledUrlIndex::ExtractQueryWords(
     const base::string16& query) {
   std::vector<base::string16> terms;
@@ -238,6 +224,24 @@
   return terms;
 }
 
+// static
+std::vector<base::string16> TitledUrlIndex::ExtractIndexTerms(
+    const TitledUrlNode* node) {
+  std::vector<base::string16> terms;
+
+  for (const base::string16& term :
+       ExtractQueryWords(Normalize(node->GetTitledUrlNodeTitle()))) {
+    terms.push_back(term);
+  }
+
+  for (const base::string16& term : ExtractQueryWords(CleanUpUrlForMatching(
+           node->GetTitledUrlNodeUrl(), /*adjustments=*/nullptr))) {
+    terms.push_back(term);
+  }
+
+  return terms;
+}
+
 void TitledUrlIndex::RegisterNode(const base::string16& term,
                                  const TitledUrlNode* node) {
   index_[term].insert(node);
diff --git a/components/bookmarks/browser/titled_url_index.h b/components/bookmarks/browser/titled_url_index.h
index f32ce5a..5657f44 100644
--- a/components/bookmarks/browser/titled_url_index.h
+++ b/components/bookmarks/browser/titled_url_index.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/containers/flat_set.h"
+#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/strings/string16.h"
@@ -31,6 +32,8 @@
 // TitledUrlNodes that contain that string in their title or URL.
 class TitledUrlIndex {
  public:
+  using TitledUrlNodeSet = base::flat_set<const TitledUrlNode*>;
+
   // Constructs a TitledUrlIndex. |sorter| is used to construct a sorted list
   // of matches when matches are returned from the index. If null, matches are
   // returned unsorted.
@@ -54,9 +57,15 @@
       size_t max_count,
       query_parser::MatchingAlgorithm matching_algorithm);
 
+  // For testing only.
+  TitledUrlNodeSet RetrieveNodesMatchingAllTermsForTesting(
+      const std::vector<base::string16>& terms,
+      query_parser::MatchingAlgorithm matching_algorithm) const {
+    return RetrieveNodesMatchingAllTerms(terms, matching_algorithm);
+  }
+
  private:
   using TitledUrlNodes = std::vector<const TitledUrlNode*>;
-  using TitledUrlNodeSet = base::flat_set<const TitledUrlNode*>;
   using Index = std::map<base::string16, TitledUrlNodeSet>;
 
   // Constructs |sorted_nodes| by copying the matches in |matches| and sorting
@@ -71,17 +80,24 @@
       query_parser::QueryParser* parser,
       const query_parser::QueryNodeVector& query_nodes);
 
-  // Populates |matches| for the specified term. If |first_term| is true, this
-  // is the first term in the query. Returns true if there is at least one node
-  // matching the term.
-  bool GetResultsMatchingTerm(
+  // Return matches for the specified |terms|. This is an intersection of each
+  // term's matches.
+  TitledUrlNodeSet RetrieveNodesMatchingAllTerms(
+      const std::vector<base::string16>& terms,
+      query_parser::MatchingAlgorithm matching_algorithm) const;
+
+  // Return matches for the specified |term|.
+  TitledUrlNodeSet RetrieveNodesMatchingTerm(
       const base::string16& term,
-      bool first_term,
-      query_parser::MatchingAlgorithm matching_algorithm,
-      TitledUrlNodeSet* matches);
+      query_parser::MatchingAlgorithm matching_algorithm) const;
 
   // Returns the set of query words from |query|.
-  std::vector<base::string16> ExtractQueryWords(const base::string16& query);
+  static std::vector<base::string16> ExtractQueryWords(
+      const base::string16& query);
+
+  // Return the index terms for |node|.
+  static std::vector<base::string16> ExtractIndexTerms(
+      const TitledUrlNode* node);
 
   // Adds |node| to |index_|.
   void RegisterNode(const base::string16& term, const TitledUrlNode* node);
diff --git a/components/bookmarks/browser/titled_url_index_unittest.cc b/components/bookmarks/browser/titled_url_index_unittest.cc
index ea11d67..3356f8a 100644
--- a/components/bookmarks/browser/titled_url_index_unittest.cc
+++ b/components/bookmarks/browser/titled_url_index_unittest.cc
@@ -53,7 +53,7 @@
   DISALLOW_COPY_AND_ASSIGN(BookmarkClientMock);
 };
 
-// Minimalistic implementatio of TitledUrlNode.
+// Minimal implementation of TitledUrlNode.
 class TestTitledUrlNode : public TitledUrlNode {
  public:
   TestTitledUrlNode(const base::string16& title, const GURL& url)
@@ -544,5 +544,36 @@
   EXPECT_EQ(data[3].url, matches[1].node->GetTitledUrlNodeUrl());
 }
 
+TEST_F(TitledUrlIndexTest, RetrieveNodesMatchingAllTerms) {
+  TitledUrlNode* node =
+      AddNode("termA termB otherTerm xyz ab", GURL("http://foo.com"));
+
+  struct TestData {
+    const std::string query;
+    const bool should_be_retrieved;
+  } data[] = {// Should return matches if all input terms match, even if not all
+              // node terms match.
+              {"term other", true},
+              // Should not match midword.
+              {"term ther", false},
+              // Short input terms should only return exact matches.
+              {"xy", false},
+              {"ab", true}};
+
+  for (const TestData& test_data : data) {
+    SCOPED_TRACE("Query: " + test_data.query);
+    std::vector<base::string16> terms = base::SplitString(
+        base::UTF8ToUTF16(test_data.query), base::UTF8ToUTF16(" "),
+        base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+    auto matches = index()->RetrieveNodesMatchingAllTermsForTesting(
+        terms, query_parser::MatchingAlgorithm::DEFAULT);
+    if (test_data.should_be_retrieved) {
+      EXPECT_TRUE(matches.contains(node));
+      EXPECT_EQ(matches.size(), 1u);
+    } else
+      EXPECT_TRUE(matches.empty());
+  };
+}
+
 }  // namespace
 }  // namespace bookmarks
diff --git a/components/crash/content/browser/error_reporting/BUILD.gn b/components/crash/content/browser/error_reporting/BUILD.gn
index e7c4d7d..c37d3191 100644
--- a/components/crash/content/browser/error_reporting/BUILD.gn
+++ b/components/crash/content/browser/error_reporting/BUILD.gn
@@ -2,31 +2,17 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# Error reporting is not enabled on Fuchsia, so there is no consent checking
-# function. TODO(crbug.com/753619): Enable crash reporting on Fuchsia.
-assert(!is_fuchsia)
-
-# Javascript Error reporting is not currently used on iOS
-assert(!is_ios)
-
-static_library("error_reporting") {
+component("error_reporting") {
   sources = [
     "javascript_error_report.cc",
     "javascript_error_report.h",
-    "send_javascript_error_report.cc",
-    "send_javascript_error_report.h",
+    "js_error_report_processor.cc",
+    "js_error_report_processor.h",
   ]
 
-  deps = [
-    "//base",
-    "//components/crash/core/app",
-    "//components/feedback",
-    "//components/startup_metric_utils/browser",
-    "//content/public/browser",
-    "//net",
-    "//services/network:network_service",
-    "//services/network/public/cpp",
-  ]
+  defines = [ "IS_JS_ERROR_REPORTING_IMPL" ]
+
+  deps = [ "//base" ]
 }
 
 source_set("mock_crash_endpoint") {
@@ -45,17 +31,3 @@
     "//url",
   ]
 }
-
-source_set("unit_tests") {
-  testonly = true
-  sources = [ "send_javascript_error_report_unittest.cc" ]
-  deps = [
-    ":error_reporting",
-    ":mock_crash_endpoint",
-    "//base",
-    "//components/crash/core/app",
-    "//content/test:test_support",
-    "//net:test_support",
-    "//testing/gtest",
-  ]
-}
diff --git a/components/crash/content/browser/error_reporting/DEPS b/components/crash/content/browser/error_reporting/DEPS
index cd6777c..8fa9d48 100644
--- a/components/crash/content/browser/error_reporting/DEPS
+++ b/components/crash/content/browser/error_reporting/DEPS
@@ -1,6 +1,3 @@
 include_rules = [
-  "+components/feedback",
-  "+components/startup_metric_utils",
   "+net",
-  "+services/network",
 ]
diff --git a/components/crash/content/browser/error_reporting/javascript_error_report.h b/components/crash/content/browser/error_reporting/javascript_error_report.h
index 7b2e507..9748a558 100644
--- a/components/crash/content/browser/error_reporting/javascript_error_report.h
+++ b/components/crash/content/browser/error_reporting/javascript_error_report.h
@@ -7,12 +7,13 @@
 
 #include <string>
 
+#include "base/component_export.h"
 #include "base/optional.h"
 
 // A report about a JavaScript error that we might want to send back to Google
 // so it can be fixed. Fill in the fields and then call
 // SendJavaScriptErrorReport.
-struct JavaScriptErrorReport {
+struct COMPONENT_EXPORT(JS_ERROR_REPORTING) JavaScriptErrorReport {
   JavaScriptErrorReport();
   JavaScriptErrorReport(const JavaScriptErrorReport& rhs);
   JavaScriptErrorReport(JavaScriptErrorReport&& rhs) noexcept;
diff --git a/components/crash/content/browser/error_reporting/js_error_report_processor.cc b/components/crash/content/browser/error_reporting/js_error_report_processor.cc
new file mode 100644
index 0000000..087bd0b
--- /dev/null
+++ b/components/crash/content/browser/error_reporting/js_error_report_processor.cc
@@ -0,0 +1,29 @@
+// Copyright 2020 The Chromium 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/crash/content/browser/error_reporting/js_error_report_processor.h"
+
+#include "base/no_destructor.h"
+
+namespace {
+scoped_refptr<JsErrorReportProcessor>& GetPointer() {
+  static base::NoDestructor<scoped_refptr<JsErrorReportProcessor>>
+      default_processor;
+  return *default_processor;
+}
+}  // namespace
+
+JsErrorReportProcessor::JsErrorReportProcessor() = default;
+JsErrorReportProcessor::~JsErrorReportProcessor() = default;
+
+// static
+scoped_refptr<JsErrorReportProcessor> JsErrorReportProcessor::Get() {
+  return GetPointer();
+}
+
+// static
+void JsErrorReportProcessor::SetDefault(
+    scoped_refptr<JsErrorReportProcessor> processor) {
+  GetPointer() = processor;
+}
diff --git a/components/crash/content/browser/error_reporting/js_error_report_processor.h b/components/crash/content/browser/error_reporting/js_error_report_processor.h
new file mode 100644
index 0000000..924b0a6
--- /dev/null
+++ b/components/crash/content/browser/error_reporting/js_error_report_processor.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium 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_CRASH_CONTENT_BROWSER_ERROR_REPORTING_JS_ERROR_REPORT_PROCESSOR_H_
+#define COMPONENTS_CRASH_CONTENT_BROWSER_ERROR_REPORTING_JS_ERROR_REPORT_PROCESSOR_H_
+
+#include "base/callback_forward.h"
+#include "base/component_export.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
+
+namespace content {
+class BrowserContext;
+}
+struct JavaScriptErrorReport;
+
+// Interface class that exposes the SendErrorReport function.
+// We use RefCountedThreadSafe instead of the more normal RefCounted or WeakPtrs
+// because multiple reports can be in-flight at the same time, each on a
+// different sequence, but still using the same JsErrorReportProcessor.
+class COMPONENT_EXPORT(JS_ERROR_REPORTING) JsErrorReportProcessor
+    : public base::RefCountedThreadSafe<JsErrorReportProcessor> {
+ public:
+  REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
+  // Returns the current implementation of JsErrorReportProcessor. Callers
+  // should check for nullptr.
+  static scoped_refptr<JsErrorReportProcessor> Get();
+
+  // Sends a report of an error in JavaScript (such as an unhandled exception)
+  // to Google's error collection service. This should be called on the UI
+  // thread; it will return after the report sending is started.
+  // |completion_callback| is called when the report send completes or fails.
+  virtual void SendErrorReport(JavaScriptErrorReport error_report,
+                               base::OnceClosure completion_callback,
+                               content::BrowserContext* browser_context) = 0;
+
+ protected:
+  friend class base::RefCountedThreadSafe<JsErrorReportProcessor>;
+  JsErrorReportProcessor();
+  virtual ~JsErrorReportProcessor();
+
+  // Sets the JsErrorReportProcessor pointer than should be returned by Get().
+  static void SetDefault(scoped_refptr<JsErrorReportProcessor> processor);
+};
+
+#endif  // COMPONENTS_CRASH_CONTENT_BROWSER_ERROR_REPORTING_JS_ERROR_REPORT_PROCESSOR_H_
diff --git a/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc b/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc
index 2e8aae4..259b72b 100644
--- a/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc
+++ b/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc
@@ -7,7 +7,6 @@
 #include "base/run_loop.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "build/build_config.h"
-#include "components/crash/content/browser/error_reporting/send_javascript_error_report.h"
 #include "components/crash/core/app/crash_reporter_client.h"
 #include "net/http/http_status_code.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -55,7 +54,6 @@
       &MockCrashEndpoint::HandleRequest, base::Unretained(this)));
   EXPECT_TRUE(test_server->Start());
 
-  SetCrashEndpointForTesting(test_server->GetURL(kTestCrashEndpoint).spec());
   client_ = std::make_unique<Client>(this);
   crash_reporter::SetCrashReporterClient(client_.get());
 }
@@ -64,6 +62,10 @@
   crash_reporter::SetCrashReporterClient(nullptr);
 }
 
+std::string MockCrashEndpoint::GetCrashEndpointURL() const {
+  return test_server_->GetURL(kTestCrashEndpoint).spec();
+}
+
 MockCrashEndpoint::Report MockCrashEndpoint::WaitForReport() {
   if (last_report_) {
     return *last_report_;
diff --git a/components/crash/content/browser/error_reporting/mock_crash_endpoint.h b/components/crash/content/browser/error_reporting/mock_crash_endpoint.h
index 53b1184..b76ac964 100644
--- a/components/crash/content/browser/error_reporting/mock_crash_endpoint.h
+++ b/components/crash/content/browser/error_reporting/mock_crash_endpoint.h
@@ -20,7 +20,7 @@
 }  // namespace test_server
 }  // namespace net
 
-// Installs a mock crash server endpoint into chrome.crashReportPrivate.
+// Installs a mock crash server endpoint.
 class MockCrashEndpoint {
  public:
   struct Report {
@@ -44,6 +44,9 @@
   // submitting crash reports.
   void set_consented(bool consented) { consented_ = consented; }
 
+  // Returns the URL that tests should send crash reports to.
+  std::string GetCrashEndpointURL() const;
+
  private:
   class Client;
 
diff --git a/components/crash/content/browser/error_reporting/send_javascript_error_report.h b/components/crash/content/browser/error_reporting/send_javascript_error_report.h
deleted file mode 100644
index 70ab3b36..0000000
--- a/components/crash/content/browser/error_reporting/send_javascript_error_report.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2020 The Chromium 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_CRASH_CONTENT_BROWSER_ERROR_REPORTING_SEND_JAVASCRIPT_ERROR_REPORT_H_
-#define COMPONENTS_CRASH_CONTENT_BROWSER_ERROR_REPORTING_SEND_JAVASCRIPT_ERROR_REPORT_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/callback_forward.h"
-#include "build/build_config.h"
-
-namespace content {
-class BrowserContext;
-}
-struct JavaScriptErrorReport;
-
-// TODO(crbug.com/1129544) This is currently disabled due to Windows DLL
-// thunking issues. Fix & re-enable.
-#if !defined(OS_WIN)
-
-// Sends a report of an error in JavaScript (such as an unhandled exception) to
-// Google's error collection service. This should be called on the UI thread;
-// it will return after the report sending is started. |completion_callback| is
-// called when the report send completes or fails.
-void SendJavaScriptErrorReport(JavaScriptErrorReport error_report,
-                               base::OnceClosure completion_callback,
-                               content::BrowserContext* browser_context);
-
-#endif  // !defined(OS_WIN)
-
-// Override the URL we send the crashes to.
-void SetCrashEndpointForTesting(const std::string& endpoint);
-
-// Override the OS Version.
-void SetOsVersionForTesting(int32_t os_major_version,
-                            int32_t os_minor_version,
-                            int32_t os_bugfix_version);
-// Go back to the default behavior of getting the OS version from the OS.
-void ClearOsVersionTestingOverride();
-
-#endif  // COMPONENTS_CRASH_CONTENT_BROWSER_ERROR_REPORTING_SEND_JAVASCRIPT_ERROR_REPORT_H_
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 7172105..f94b76c 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -1015,6 +1015,7 @@
     # it depends on basically all source files.
     enable_lint = true
     lint_suppressions_file = "lint-suppressions.xml"
+    lint_baseline_file = "lint-baseline.xml"
 
     # Still needs to support Jelly Bean. See crbug.com/922656.
     lint_min_sdk_version = 16
diff --git a/components/cronet/android/lint-baseline.xml b/components/cronet/android/lint-baseline.xml
new file mode 100644
index 0000000..1f61f00
--- /dev/null
+++ b/components/cronet/android/lint-baseline.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+
+    <issue
+        id="ScopedStorage"
+        message="WRITE_EXTERNAL_STORAGE no longer provides write access when targeting Android 10+"
+        errorLine1="  &lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot;/>"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="gen/components/cronet/android/cronet_test_instrumentation_apk__test_apk__lint/../../components/cronet/android/test/javatests/AndroidManifest.xml"
+            line="12"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="QueryPermissionsNeeded"
+        message="As of Android 11, this method no longer returns information about all apps; \&#xA;see https://g.co/dev/packagevisibility for details"
+        errorLine1="        return mWrapped.getInstalledPackages(flags);"
+        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="../../third_party/android_sdk/public/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java"
+            line="115"
+            column="25"/>
+    </issue>
+
+    <issue
+        id="QueryPermissionsNeeded"
+        message="As of Android 11, this method no longer returns information about all apps; \&#xA;see https://g.co/dev/packagevisibility for details"
+        errorLine1="        return mWrapped.getInstalledApplications(flags);"
+        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="../../third_party/android_sdk/public/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java"
+            line="210"
+            column="25"/>
+    </issue>
+
+    <issue
+        id="QueryPermissionsNeeded"
+        message="Consider adding a `&lt;queries>` declaration to your manifest when calling this \&#xA;method; see https://g.co/dev/packagevisibility for details"
+        errorLine1="        return mWrapped.queryIntentActivities(intent, flags);"
+        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="../../third_party/android_sdk/public/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java"
+            line="240"
+            column="25"/>
+    </issue>
+
+    <issue
+        id="QueryPermissionsNeeded"
+        message="Consider adding a `&lt;queries>` declaration to your manifest when calling this \&#xA;method; see https://g.co/dev/packagevisibility for details"
+        errorLine1="        return mWrapped.queryBroadcastReceivers(intent, flags);"
+        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="../../third_party/android_sdk/public/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java"
+            line="251"
+            column="25"/>
+    </issue>
+
+    <issue
+        id="QueryPermissionsNeeded"
+        message="Consider adding a `&lt;queries>` declaration to your manifest when calling this \&#xA;method; see https://g.co/dev/packagevisibility for details"
+        errorLine1="        return mWrapped.queryIntentServices(intent, flags);"
+        errorLine2="                        ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="../../third_party/android_sdk/public/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java"
+            line="261"
+            column="25"/>
+    </issue>
+
+    <issue
+        id="QueryPermissionsNeeded"
+        message="Consider adding a `&lt;queries>` declaration to your manifest when calling this \&#xA;method; see https://g.co/dev/packagevisibility for details"
+        errorLine1="        return mWrapped.queryContentProviders(processName, uid, flags);"
+        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="../../third_party/android_sdk/public/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java"
+            line="276"
+            column="25"/>
+    </issue>
+
+</issues>
diff --git a/components/embedder_support/android/metrics/BUILD.gn b/components/embedder_support/android/metrics/BUILD.gn
index 7a0e269..387ffd0d 100644
--- a/components/embedder_support/android/metrics/BUILD.gn
+++ b/components/embedder_support/android/metrics/BUILD.gn
@@ -30,7 +30,6 @@
     "//components/version_info/android:channel_getter",
     "//content/public/browser",
     "//services/resource_coordinator/public/cpp/memory_instrumentation:browser",
-    "//third_party/metrics_proto",
   ]
 }
 
@@ -43,6 +42,8 @@
   deps = [
     "//base:base_java",
     "//base:jni_java",
+    "//third_party/android_deps:protobuf_lite_runtime_java",
+    "//third_party/metrics_proto:metrics_proto_java",
   ]
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
 }
diff --git a/components/embedder_support/android/metrics/android_metrics_log_uploader.cc b/components/embedder_support/android/metrics/android_metrics_log_uploader.cc
index 18dabda..a737dc5 100644
--- a/components/embedder_support/android/metrics/android_metrics_log_uploader.cc
+++ b/components/embedder_support/android/metrics/android_metrics_log_uploader.cc
@@ -5,10 +5,8 @@
 #include "components/embedder_support/android/metrics/android_metrics_log_uploader.h"
 
 #include "base/android/jni_array.h"
-#include "base/check.h"
 #include "components/embedder_support/android/metrics/jni/AndroidMetricsLogUploader_jni.h"
 #include "components/metrics/log_decoder.h"
-#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
 
 using base::android::ScopedJavaLocalRef;
 using base::android::ToJavaByteArray;
@@ -36,16 +34,6 @@
     return;
   }
 
-  // Speculative CHECKs to see why WebView UMA (and probably other embedders of
-  // this component) are missing system_profiles for a small fraction of
-  // records. TODO(https://crbug.com/1081925): downgrade these to DCHECKs or
-  // remove entirely when we figure out the issue.
-  CHECK(!log_data.empty());
-  metrics::ChromeUserMetricsExtension uma_log;
-  bool can_parse = uma_log.ParseFromString(log_data);
-  CHECK(can_parse);
-  CHECK(uma_log.has_system_profile());
-
   JNIEnv* env = base::android::AttachCurrentThread();
   ScopedJavaLocalRef<jbyteArray> java_data = ToJavaByteArray(
       env, reinterpret_cast<const uint8_t*>(log_data.data()), log_data.size());
diff --git a/components/embedder_support/android/metrics/java/src/org/chromium/components/metrics/AndroidMetricsLogUploader.java b/components/embedder_support/android/metrics/java/src/org/chromium/components/metrics/AndroidMetricsLogUploader.java
index 58f9a2e5..351c8be 100644
--- a/components/embedder_support/android/metrics/java/src/org/chromium/components/metrics/AndroidMetricsLogUploader.java
+++ b/components/embedder_support/android/metrics/java/src/org/chromium/components/metrics/AndroidMetricsLogUploader.java
@@ -4,9 +4,12 @@
 
 package org.chromium.components.metrics;
 
+import com.google.protobuf.InvalidProtocolBufferException;
+
 import org.chromium.base.Consumer;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.components.metrics.ChromeUserMetricsExtensionProtos.ChromeUserMetricsExtension;
 
 /**
  * Passes UMA logs from native to a java uploader.
@@ -26,9 +29,19 @@
     }
 
     @CalledByNative
-    public static void uploadLog(byte[] data) {
+    public static void uploadLog(byte[] data) throws InvalidProtocolBufferException {
         final Consumer<byte[]> uploader = sUploader;
         if (uploader != null) {
+            // Speculative validity checks to see why WebView UMA (and probably other embedders of
+            // this component) are missing system_profiles for a small fraction of records.
+            // TODO(https://crbug.com/1081925): remove entirely when we figure out the issue.
+            if (data.length == 0) {
+                throw new RuntimeException("UMA log is completely empty");
+            }
+            ChromeUserMetricsExtension log = ChromeUserMetricsExtension.parseFrom(data);
+            if (!log.hasSystemProfile()) {
+                throw new RuntimeException("UMA log is missing a system_profile");
+            }
             uploader.accept(data);
         }
     }
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index e41a7da..f7a36f2 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -1154,9 +1154,10 @@
 
   viz::SharedQuadState* quad_state =
       render_pass->CreateAndAppendSharedQuadState();
+
   quad_state->SetAll(quad_to_target_transform, quad_rect /*quad_layer_rect=*/,
                      quad_rect /*visible_quad_layer_rect=*/,
-                     gfx::RRectF() /*rounded_corner_bounds=*/,
+                     gfx::MaskFilterInfo() /*mask_filter_info=*/,
                      gfx::Rect() /*clip_rect=*/, false /*is_clipped=*/,
                      are_contents_opaque, state_.basic_state.alpha /*opacity=*/,
                      SkBlendMode::kSrcOver /*blend_mode=*/,
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc
index ceb5e06a..d125275 100644
--- a/components/exo/surface_tree_host.cc
+++ b/components/exo/surface_tree_host.cc
@@ -300,7 +300,7 @@
   quad_state->SetAll(
       gfx::Transform(), /*quad_layer_rect=*/quad_rect,
       /*visible_quad_layer_rect=*/quad_rect,
-      /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/gfx::Rect(),
+      /*mask_filter_info=*/gfx::MaskFilterInfo(), /*clip_rect=*/gfx::Rect(),
       /*is_clipped=*/false, /*are_contents_opaque=*/true, /*opacity=*/1.f,
       /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
 
diff --git a/components/history/core/browser/BUILD.gn b/components/history/core/browser/BUILD.gn
index 6753c31a..d48bff9 100644
--- a/components/history/core/browser/BUILD.gn
+++ b/components/history/core/browser/BUILD.gn
@@ -20,6 +20,8 @@
     "download_types.h",
     "expire_history_backend.cc",
     "expire_history_backend.h",
+    "features.cc",
+    "features.h",
     "history_backend.cc",
     "history_backend.h",
     "history_backend_client.h",
diff --git a/components/history/core/browser/features.cc b/components/history/core/browser/features.cc
new file mode 100644
index 0000000..0c47cee
--- /dev/null
+++ b/components/history/core/browser/features.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 The Chromium 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/history/core/browser/features.h"
+
+namespace history {
+
+const base::Feature kHideFromApi3Transitions{
+    "HideFromApi3TransitionsFromHistory", base::FEATURE_ENABLED_BY_DEFAULT};
+
+}  // namespace history
diff --git a/components/history/core/browser/features.h b/components/history/core/browser/features.h
new file mode 100644
index 0000000..2f06c90
--- /dev/null
+++ b/components/history/core/browser/features.h
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium 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_HISTORY_CORE_BROWSER_FEATURES_H_
+#define COMPONENTS_HISTORY_CORE_BROWSER_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace history {
+
+// If true, navigations with a transition qualifier of
+// PAGE_TRANSITION_FROM_API_3 are not returned from queries for visible rows.
+extern const base::Feature kHideFromApi3Transitions;
+
+}  // namespace history
+
+#endif  // COMPONENTS_HISTORY_CORE_BROWSER_FEATURES_H_
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 91a6e97..3053907 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -129,6 +129,13 @@
 };
 #endif
 
+bool HasApiTransition2or3(ui::PageTransition transition) {
+  return (ui::PageTransitionGetQualifier(transition) &
+          (ui::PageTransitionGetQualifier(ui::PAGE_TRANSITION_FROM_API_2) |
+           ui::PageTransitionGetQualifier(ui::PAGE_TRANSITION_FROM_API_3))) !=
+         0;
+}
+
 void RunUnlessCanceled(
     base::OnceClosure closure,
     const base::CancelableTaskTracker::IsCanceledCallback& is_canceled) {
@@ -541,12 +548,14 @@
 
   // If the user is navigating to a not-previously-typed intranet hostname,
   // change the transition to TYPED so that the omnibox will learn that this is
-  // a known host.
+  // a known host. This logic is disabled if API_2/API_3 is present as such
+  // visits are not intended to influence the omnibox, and shouldn't be
+  // changed to TYPED. (API_2/API_3 are not used with TYPED transitions).
   bool has_redirects = request.redirects.size() > 1;
   if (ui::PageTransitionIsMainFrame(request_transition) &&
       !ui::PageTransitionCoreTypeIs(request_transition,
                                     ui::PAGE_TRANSITION_TYPED) &&
-      !is_keyword_generated) {
+      !is_keyword_generated && !HasApiTransition2or3(request_transition)) {
     // Check both the start and end of a redirect chain, since the user will
     // consider both to have been "navigated to".
     if (IsUntypedIntranetHost(request.url) ||
@@ -557,6 +566,11 @@
     }
   }
 
+  // FROM_API_2/FROM_API_3 should never be used with a transition type that
+  // increments the typed-count as that defeats the purpose.
+  DCHECK(!IsTypedIncrement(request_transition) ||
+         !HasApiTransition2or3(request_transition));
+
   if (!has_redirects) {
     // The single entry is both a chain start and end.
     ui::PageTransition t = ui::PageTransitionFromInt(
diff --git a/components/history/core/browser/visit_database.cc b/components/history/core/browser/visit_database.cc
index a6ec38fc1..490b1205 100644
--- a/components/history/core/browser/visit_database.cc
+++ b/components/history/core/browser/visit_database.cc
@@ -14,10 +14,12 @@
 #include <string>
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
 #include "components/google/core/common/google_util.h"
+#include "components/history/core/browser/features.h"
 #include "components/history/core/browser/history_backend.h"
 #include "components/history/core/browser/url_database.h"
 #include "sql/statement.h"
@@ -27,6 +29,19 @@
 
 namespace history {
 
+namespace {
+
+// This is called from functions that are testing for the absence of
+// PAGE_TRANSITION_FROM_API_3 in transitions. It is expected this is used
+// with a database query of '& FromApi3QualifierForQuery() == 0'.
+int32_t FromApi3QualifierForQuery() {
+  return base::FeatureList::IsEnabled(kHideFromApi3Transitions)
+             ? ui::PAGE_TRANSITION_FROM_API_3
+             : 0;
+}
+
+}  // namespace
+
 VisitDatabase::VisitDatabase() {}
 
 VisitDatabase::~VisitDatabase() {}
@@ -283,6 +298,7 @@
       "FROM visits "
       "WHERE url=? AND visit_time >= ? AND visit_time < ? "
       "AND (transition & ?) != 0 "              // CHAIN_END
+      "AND (transition & ?) == 0 "              // FROM_API_3
       "AND (transition & ?) NOT IN (?, ?, ?) "  // NO SUBFRAME or
                                                 // KEYWORD_GENERATED
       "ORDER BY visit_time DESC"));
@@ -290,10 +306,11 @@
   statement.BindInt64(1, options.EffectiveBeginTime());
   statement.BindInt64(2, options.EffectiveEndTime());
   statement.BindInt64(3, ui::PAGE_TRANSITION_CHAIN_END);
-  statement.BindInt64(4, ui::PAGE_TRANSITION_CORE_MASK);
-  statement.BindInt64(5, ui::PAGE_TRANSITION_AUTO_SUBFRAME);
-  statement.BindInt64(6, ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
-  statement.BindInt64(7, ui::PAGE_TRANSITION_KEYWORD_GENERATED);
+  statement.BindInt64(4, FromApi3QualifierForQuery());
+  statement.BindInt64(5, ui::PAGE_TRANSITION_CORE_MASK);
+  statement.BindInt64(6, ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+  statement.BindInt64(7, ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
+  statement.BindInt64(8, ui::PAGE_TRANSITION_KEYWORD_GENERATED);
 
   return FillVisitVectorWithOptions(statement, options, visits);
 }
@@ -389,6 +406,7 @@
       "FROM visits "
       "WHERE visit_time >= ? AND visit_time < ? "
       "AND (transition & ?) != 0 "              // CHAIN_END
+      "AND (transition & ?) == 0 "              // FROM_API_3
       "AND (transition & ?) NOT IN (?, ?, ?) "  // NO SUBFRAME or
                                                 // KEYWORD_GENERATED
       "ORDER BY visit_time DESC, id DESC"));
@@ -396,10 +414,11 @@
   statement.BindInt64(0, options.EffectiveBeginTime());
   statement.BindInt64(1, options.EffectiveEndTime());
   statement.BindInt64(2, ui::PAGE_TRANSITION_CHAIN_END);
-  statement.BindInt64(3, ui::PAGE_TRANSITION_CORE_MASK);
-  statement.BindInt64(4, ui::PAGE_TRANSITION_AUTO_SUBFRAME);
-  statement.BindInt64(5, ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
-  statement.BindInt64(6, ui::PAGE_TRANSITION_KEYWORD_GENERATED);
+  statement.BindInt64(3, FromApi3QualifierForQuery());
+  statement.BindInt64(4, ui::PAGE_TRANSITION_CORE_MASK);
+  statement.BindInt64(5, ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+  statement.BindInt64(6, ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
+  statement.BindInt64(7, ui::PAGE_TRANSITION_KEYWORD_GENERATED);
 
   return FillVisitVectorWithOptions(statement, options, visits);
 }
@@ -516,15 +535,17 @@
       "FROM visits v INNER JOIN urls u ON v.url = u.id "
       "WHERE u.url >= ? AND u.url < ? "
       "AND (transition & ?) != 0 "
+      "AND (transition & ?) == 0 "
       "AND (transition & ?) NOT IN (?, ?, ?)"));
   statement.BindString(0, host_query_min);
   statement.BindString(
       1, host_query_min.substr(0, host_query_min.size() - 1) + '0');
   statement.BindInt64(2, ui::PAGE_TRANSITION_CHAIN_END);
-  statement.BindInt64(3, ui::PAGE_TRANSITION_CORE_MASK);
-  statement.BindInt64(4, ui::PAGE_TRANSITION_AUTO_SUBFRAME);
-  statement.BindInt64(5, ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
-  statement.BindInt64(6, ui::PAGE_TRANSITION_KEYWORD_GENERATED);
+  statement.BindInt64(3, FromApi3QualifierForQuery());
+  statement.BindInt64(4, ui::PAGE_TRANSITION_CORE_MASK);
+  statement.BindInt64(5, ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+  statement.BindInt64(6, ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
+  statement.BindInt64(7, ui::PAGE_TRANSITION_KEYWORD_GENERATED);
 
   if (!statement.Step()) {
     // We've never been to this page before.
@@ -554,6 +575,7 @@
       "DATE((visit_time - ?) / ?, 'unixepoch', 'localtime')"
       "FROM visits "
       "WHERE (transition & ?) != 0 "            // CHAIN_END
+      "AND (transition & ?) == 0 "              // FROM_API_3
       "AND (transition & ?) NOT IN (?, ?, ?) "  // NO SUBFRAME or
                                                 // KEYWORD_GENERATED
       "AND visit_time >= ? AND visit_time < ?"
@@ -562,12 +584,13 @@
   statement.BindInt64(0, base::Time::kTimeTToMicrosecondsOffset);
   statement.BindInt64(1, base::Time::kMicrosecondsPerSecond);
   statement.BindInt64(2, ui::PAGE_TRANSITION_CHAIN_END);
-  statement.BindInt64(3, ui::PAGE_TRANSITION_CORE_MASK);
-  statement.BindInt64(4, ui::PAGE_TRANSITION_AUTO_SUBFRAME);
-  statement.BindInt64(5, ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
-  statement.BindInt64(6, ui::PAGE_TRANSITION_KEYWORD_GENERATED);
-  statement.BindInt64(7, begin_time.ToInternalValue());
-  statement.BindInt64(8, end_time.ToInternalValue());
+  statement.BindInt64(3, FromApi3QualifierForQuery());
+  statement.BindInt64(4, ui::PAGE_TRANSITION_CORE_MASK);
+  statement.BindInt64(5, ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+  statement.BindInt64(6, ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
+  statement.BindInt64(7, ui::PAGE_TRANSITION_KEYWORD_GENERATED);
+  statement.BindInt64(8, begin_time.ToInternalValue());
+  statement.BindInt64(9, end_time.ToInternalValue());
 
   if (!statement.Step())
     return false;
diff --git a/components/history/core/browser/visit_database_unittest.cc b/components/history/core/browser/visit_database_unittest.cc
index ef682fe..42f6283 100644
--- a/components/history/core/browser/visit_database_unittest.cc
+++ b/components/history/core/browser/visit_database_unittest.cc
@@ -10,7 +10,9 @@
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/strings/string_util.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
+#include "components/history/core/browser/features.h"
 #include "components/history/core/browser/url_database.h"
 #include "components/history/core/browser/visit_database.h"
 #include "sql/database.h"
@@ -433,6 +435,50 @@
   EXPECT_TRUE(IsVisitInfoEqual(results[2], test_visit_rows[0]));
 }
 
+TEST_F(VisitDatabaseTest, Api3HandledCorrectly) {
+  const ui::PageTransition transition_link_and_api3 = ui::PageTransitionFromInt(
+      ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FROM_API_3 |
+      ui::PAGE_TRANSITION_CHAIN_END);
+  const URLID url_id = 1;
+  VisitRow visit(url_id, Time::Now(), 0, transition_link_and_api3, 0, false,
+                 false);
+  EXPECT_TRUE(AddVisit(&visit, SOURCE_BROWSED));
+
+  // Query the visits for the first url id. FROM_API_3 is not considered visible
+  // and should be excluded.
+  VisitVector results;
+  QueryOptions options;
+  GetVisibleVisitsForURL(url_id, options, &results);
+  ASSERT_EQ(0u, results.size());
+
+  GetVisitsForURL(url_id, &results);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_TRUE(IsVisitInfoEqual(results[0], visit));
+}
+
+TEST_F(VisitDatabaseTest, Api3TransitionFeatureDisabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(kHideFromApi3Transitions);
+  const ui::PageTransition transition_link_and_api3 = ui::PageTransitionFromInt(
+      ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FROM_API_3 |
+      ui::PAGE_TRANSITION_CHAIN_END);
+  const URLID url_id = 1;
+  VisitRow visit(url_id, Time::Now(), 0, transition_link_and_api3, 0, false,
+                 false);
+  EXPECT_TRUE(AddVisit(&visit, SOURCE_BROWSED));
+
+  // Query the visits for the first url id, as kHideFromApi3Transitions is
+  // disabled FROM_API_3 should not be excluded.
+  VisitVector results;
+  QueryOptions options;
+  GetVisibleVisitsForURL(url_id, options, &results);
+  ASSERT_EQ(1u, results.size());
+
+  GetVisitsForURL(url_id, &results);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_TRUE(IsVisitInfoEqual(results[0], visit));
+}
+
 TEST_F(VisitDatabaseTest, GetHistoryCount) {
   // Start with a day in the middle of summer, so that we are nowhere near
   // DST shifts.
diff --git a/components/lookalikes/core/features.cc b/components/lookalikes/core/features.cc
index 86803b1..410daa2 100644
--- a/components/lookalikes/core/features.cc
+++ b/components/lookalikes/core/features.cc
@@ -11,7 +11,7 @@
     "TargetEmbeddingLookalikes", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kLookalikeInterstitialForPunycode{
-    "LookalikeInterstitialForPunycode", base::FEATURE_DISABLED_BY_DEFAULT};
+    "LookalikeInterstitialForPunycode", base::FEATURE_ENABLED_BY_DEFAULT};
 
 }  // namespace features
 }  // namespace lookalikes
diff --git a/components/media_router/browser/android/BUILD.gn b/components/media_router/browser/android/BUILD.gn
index 4cd48f57d..298969a 100644
--- a/components/media_router/browser/android/BUILD.gn
+++ b/components/media_router/browser/android/BUILD.gn
@@ -94,6 +94,7 @@
     ":java",
     ":test_jni_headers",
     "//base:base_java",
+    "//base:base_java_test_support",
     "//components/browser_ui/media/android:java",
     "//content/public/android:content_java",
     "//content/public/test/android:content_java_test_support",
diff --git a/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java b/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java
index c2e20fe..63de6b76 100644
--- a/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java
+++ b/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java
@@ -13,9 +13,9 @@
 import org.hamcrest.Matchers;
 
 import org.chromium.base.Log;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.third_party.android.media.R;
 
 import java.util.ArrayList;
diff --git a/components/metrics/metrics_log.cc b/components/metrics/metrics_log.cc
index 5aeefc9..ed6b3db 100644
--- a/components/metrics/metrics_log.cc
+++ b/components/metrics/metrics_log.cc
@@ -163,6 +163,7 @@
   UserActionEventProto* user_action = uma_proto_.add_user_action_event();
   user_action->set_name_hash(Hash(key));
   user_action->set_time_sec(ToMonotonicSeconds(action_time));
+  base::UmaHistogramBoolean("UMA.UserActionsCount", true);
 }
 
 // static
diff --git a/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java b/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java
index 515a147..f159a42 100644
--- a/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java
+++ b/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java
@@ -109,7 +109,18 @@
                 ensureNativeLoaded();
             }
 
-            mImpl = mInterfaceClass.cast(instantiateReflectively(mName, mImplClassName));
+            Object impl = instantiateReflectively(mName, mImplClassName);
+            try {
+                mImpl = mInterfaceClass.cast(impl);
+            } catch (ClassCastException e) {
+                ClassLoader interfaceClassLoader = mInterfaceClass.getClassLoader();
+                ClassLoader implClassLoader = impl.getClass().getClassLoader();
+                throw new RuntimeException("Failure casting " + mName
+                                + " module class, interface ClassLoader: " + interfaceClassLoader
+                                + ", impl ClassLoader: " + implClassLoader
+                                + ", equal: " + interfaceClassLoader.equals(implClassLoader),
+                        e);
+            }
             return mImpl;
         }
     }
diff --git a/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc b/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
index 0dac2b43..6bfde8c 100644
--- a/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
+++ b/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
@@ -40,6 +40,10 @@
   expected_main_frame_intersection_ = rect;
 }
 
+void PageLoadMetricsTestWaiter::AddMainFrameIntersectionExpectation() {
+  expected_main_frame_intersection_update_ = true;
+}
+
 void PageLoadMetricsTestWaiter::AddSubFrameExpectation(TimingField field) {
   CHECK_NE(field, TimingField::kLoadTimingInfo)
       << "LOAD_TIMING_INFO should only be used as a page-level expectation";
@@ -200,6 +204,9 @@
     content::RenderFrameHost* rfh,
     const page_load_metrics::mojom::FrameIntersectionUpdate&
         frame_intersection_update) {
+  if (frame_intersection_update.main_frame_intersection_rect)
+    expected_main_frame_intersection_update_ = false;
+
   if (expected_main_frame_intersection_ &&
       expected_main_frame_intersection_ ==
           frame_intersection_update.main_frame_intersection_rect) {
@@ -349,7 +356,8 @@
          SubframeNavigationExpectationsSatisfied() &&
          SubframeDataExpectationsSatisfied() && expected_frame_sizes_.empty() &&
          CpuTimeExpectationsSatisfied() &&
-         !expected_main_frame_intersection_.has_value();
+         !expected_main_frame_intersection_.has_value() &&
+         !expected_main_frame_intersection_update_;
 }
 
 PageLoadMetricsTestWaiter::WaiterMetricsObserver::~WaiterMetricsObserver() =
diff --git a/components/page_load_metrics/browser/page_load_metrics_test_waiter.h b/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
index fd9dbfa..bf2267b7 100644
--- a/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
+++ b/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
@@ -57,6 +57,10 @@
   // of |rect|. Subsequent calls overwrite unmet expectations.
   void AddMainFrameIntersectionExpectation(const gfx::Rect& rect);
 
+  // Adds a main frame intersection expectation for any main frame
+  // intersection update for the page load.
+  void AddMainFrameIntersectionExpectation();
+
   // Add a single WebFeature expectation.
   void AddWebFeatureExpectation(blink::mojom::WebFeature web_feature);
 
@@ -266,6 +270,7 @@
   // Expectation for the main frame intersection. Has a value when
   // an expectation has not been met.
   base::Optional<gfx::Rect> expected_main_frame_intersection_;
+  bool expected_main_frame_intersection_update_ = false;
 
   int current_complete_resources_ = 0;
   int64_t current_network_bytes_ = 0;
diff --git a/components/performance_manager/public/v8_memory/v8_detailed_memory.h b/components/performance_manager/public/v8_memory/v8_detailed_memory.h
index e748906..3036450 100644
--- a/components/performance_manager/public/v8_memory/v8_detailed_memory.h
+++ b/components/performance_manager/public/v8_memory/v8_detailed_memory.h
@@ -14,6 +14,7 @@
 #include "base/optional.h"
 #include "base/sequence_checker.h"
 #include "base/sequenced_task_runner.h"
+#include "base/threading/sequence_bound.h"
 #include "base/time/time.h"
 #include "base/util/type_safety/pass_key.h"
 #include "components/performance_manager/public/graph/frame_node.h"
@@ -429,9 +430,11 @@
 
   // Private constructor for V8DetailedMemoryRequestOneShot. Sets
   // min_time_between_requests_ to 0, which is not allowed for repeating
-  // requests.
+  // requests, and registers |on_owner_unregistered_closure| to be called from
+  // OnOwnerUnregistered.
   V8DetailedMemoryRequest(util::PassKey<V8DetailedMemoryRequestOneShot>,
-                          MeasurementMode mode);
+                          MeasurementMode mode,
+                          base::OnceClosure on_owner_unregistered_closure);
 
   // V8DetailedMemoryDecorator::MeasurementRequestQueue calls
   // OnOwnerUnregistered for all requests in the queue when the owning
@@ -463,6 +466,11 @@
   // Sequence that |off_sequence_request_| lives on.
   scoped_refptr<base::SequencedTaskRunner> off_sequence_request_sequence_;
 
+  // Additional closure that will be called from OnOwnerUnregistered for
+  // one-shot requests. Used to clean up resources in the
+  // V8DetailedMemoryRequestOneShot wrapper.
+  base::OnceClosure on_owner_unregistered_closure_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
@@ -477,10 +485,12 @@
 
   using MeasurementMode = V8DetailedMemoryRequest::MeasurementMode;
 
-  // Creates a one-shot memory measurement request that will immediately be
-  // sent to |process| (which must be a renderer process). The process will
-  // perform the measurement during a GC as determined by |mode|, and
-  // |callback| will be called with the results.
+  // Creates a one-shot memory measurement request that will be sent when
+  // StartMeasurement is called.
+  explicit V8DetailedMemoryRequestOneShot(
+      MeasurementMode mode = MeasurementMode::kDefault);
+
+  // Creates a one-shot memory measurement request and calls StartMeasurement.
   V8DetailedMemoryRequestOneShot(
       const ProcessNode* process,
       MeasurementCallback callback,
@@ -493,6 +503,20 @@
   V8DetailedMemoryRequestOneShot& operator=(
       const V8DetailedMemoryRequestOneShot&) = delete;
 
+  // Sends the measurement request to |process| (which must be a renderer
+  // process). The process will perform the measurement during a GC as
+  // determined by the MeasurementMode, and |callback| will be called with the
+  // results.
+  //
+  // |callback| is owned by the request object but will be destroyed after it
+  // is called or once no response can be received (such as if the ProcessNode
+  // is destroyed). It is safe for the callback to own resources that will be
+  // freed when the callback is destroyed. It is even safe for the callback to
+  // own |this|, making the V8DetailedMemoryRequestOneShot self-owning (it will
+  // be deleted along with the callback).
+  void StartMeasurement(const ProcessNode* process,
+                        MeasurementCallback callback);
+
   MeasurementMode mode() const { return mode_; }
 
   // V8DetailedMemoryObserver implementation.
@@ -512,10 +536,11 @@
       MeasurementMode mode = MeasurementMode::kDefault);
 
  private:
-  void InitializeRequest(const ProcessNode* process, MeasurementMode mode);
-  void InitializeRequestFromOffSequence(base::WeakPtr<ProcessNode> process,
-                                        MeasurementMode mode);
+  void InitializeRequest();
+  void StartMeasurementFromOffSequence(base::WeakPtr<ProcessNode>,
+                                       MeasurementCallback callback);
   void DeleteRequest();
+  void OnOwnerUnregistered();
 
 #if DCHECK_IS_ON()
   const ProcessNode* process_;
@@ -628,6 +653,9 @@
                               const V8DetailedMemoryProcessData& process_data,
                               const FrameDataMap& frame_data)>;
 
+  explicit V8DetailedMemoryRequestOneShotAnySeq(
+      MeasurementMode mode = MeasurementMode::kDefault);
+
   V8DetailedMemoryRequestOneShotAnySeq(
       RenderProcessHostId process_id,
       MeasurementCallback callback,
@@ -640,23 +668,23 @@
   V8DetailedMemoryRequestOneShotAnySeq& operator=(
       const V8DetailedMemoryRequestOneShotAnySeq&) = delete;
 
+  void StartMeasurement(RenderProcessHostId process_id,
+                        MeasurementCallback callback);
+
  private:
-  void InitializeWrappedRequest(MeasurementMode mode,
+  void InitializeWrappedRequest(MeasurementCallback callback,
+                                MeasurementMode mode,
                                 base::WeakPtr<ProcessNode>);
 
-  // Called on the PM sequence when a measurement is available. It will call
-  // request->InvokeWrappedCallback on |task_runner|.
+  // Called on the PM sequence when a measurement is available.
+  // |sequence_bound_callback| will wrap the callback passed to the
+  // constructor, so it is both called and freed on the request's sequence.
   static void OnMeasurementAvailable(
-      scoped_refptr<base::SequencedTaskRunner> task_runner,
-      base::WeakPtr<V8DetailedMemoryRequestOneShotAnySeq> request,
+      base::SequenceBound<MeasurementCallback> sequence_bound_callback,
       const ProcessNode* process_node,
       const V8DetailedMemoryProcessData* process_data);
 
-  void InvokeWrappedCallback(RenderProcessHostId process_id,
-                             const V8DetailedMemoryProcessData& process_data,
-                             const FrameDataMap& frame_data);
-
-  MeasurementCallback wrapped_callback_;
+  MeasurementMode mode_;
 
   // The wrapped request. Must only be accessed from the PM sequence.
   std::unique_ptr<V8DetailedMemoryRequestOneShot> request_;
@@ -692,6 +720,9 @@
 // be enabled in tests.
 void SetEagerMemoryMeasurementEnabledForTesting(bool enable);
 
+// Destroys the V8DetailedMemoryDecorator. Exposed for testing.
+void DestroyV8DetailedMemoryDecoratorForTesting(Graph* graph);
+
 }  // namespace internal
 
 }  // namespace v8_memory
diff --git a/components/performance_manager/v8_memory/v8_detailed_memory.cc b/components/performance_manager/v8_memory/v8_detailed_memory.cc
index c093e0d..0d3fdacf 100644
--- a/components/performance_manager/v8_memory/v8_detailed_memory.cc
+++ b/components/performance_manager/v8_memory/v8_detailed_memory.cc
@@ -55,6 +55,9 @@
   void Validate();
 
  private:
+  void ApplyToAllRequests(
+      base::RepeatingCallback<void(V8DetailedMemoryRequest*)> callback) const;
+
   // Lists of requests sorted by min_time_between_requests (lowest first).
   std::vector<V8DetailedMemoryRequest*> bounded_measurement_requests_;
   std::vector<V8DetailedMemoryRequest*> lazy_measurement_requests_;
@@ -551,6 +554,12 @@
 #endif
 }
 
+void DestroyV8DetailedMemoryDecoratorForTesting(Graph* graph) {
+  auto* decorator = V8DetailedMemoryDecorator::GetFromGraph(graph);
+  if (decorator)
+    graph->TakeFromGraph(decorator);
+}
+
 }  // namespace internal
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -606,8 +615,11 @@
 
 V8DetailedMemoryRequest::V8DetailedMemoryRequest(
     util::PassKey<V8DetailedMemoryRequestOneShot>,
-    MeasurementMode mode)
-    : min_time_between_requests_(base::TimeDelta()), mode_(mode) {
+    MeasurementMode mode,
+    base::OnceClosure on_owner_unregistered_closure)
+    : min_time_between_requests_(base::TimeDelta()),
+      mode_(mode),
+      on_owner_unregistered_closure_(std::move(on_owner_unregistered_closure)) {
   // Do not forward to the standard constructor because it disallows the empty
   // TimeDelta.
 }
@@ -651,6 +663,8 @@
     util::PassKey<V8DetailedMemoryDecorator::MeasurementRequestQueue>) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   decorator_ = nullptr;
+  if (on_owner_unregistered_closure_)
+    std::move(on_owner_unregistered_closure_).Run();
 }
 
 void V8DetailedMemoryRequest::NotifyObserversOnMeasurementAvailable(
@@ -735,11 +749,18 @@
 // V8DetailedMemoryRequestOneShot
 
 V8DetailedMemoryRequestOneShot::V8DetailedMemoryRequestOneShot(
+    MeasurementMode mode)
+    : mode_(mode) {
+  InitializeRequest();
+}
+
+V8DetailedMemoryRequestOneShot::V8DetailedMemoryRequestOneShot(
     const ProcessNode* process,
     MeasurementCallback callback,
     MeasurementMode mode)
-    : callback_(std::move(callback)), mode_(mode) {
-  InitializeRequest(process, mode);
+    : mode_(mode) {
+  InitializeRequest();
+  StartMeasurement(process, std::move(callback));
 }
 
 V8DetailedMemoryRequestOneShot::~V8DetailedMemoryRequestOneShot() {
@@ -747,6 +768,21 @@
   DeleteRequest();
 }
 
+void V8DetailedMemoryRequestOneShot::StartMeasurement(
+    const ProcessNode* process,
+    MeasurementCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(request_);
+  DCHECK(process);
+  DCHECK_EQ(process->GetProcessType(), content::PROCESS_TYPE_RENDERER);
+#if DCHECK_IS_ON()
+  process_ = process;
+#endif
+
+  callback_ = std::move(callback);
+  request_->StartMeasurementForProcess(process);
+}
+
 void V8DetailedMemoryRequestOneShot::OnV8MemoryMeasurementAvailable(
     const ProcessNode* process_node,
     const V8DetailedMemoryProcessData* process_data) {
@@ -769,39 +805,38 @@
     base::WeakPtr<ProcessNode> process,
     MeasurementCallback callback,
     MeasurementMode mode)
-    : callback_(std::move(callback)), mode_(mode) {
+    : mode_(mode) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
   // Unretained is safe since |this| will be destroyed on the graph sequence
   // from an async task posted after this.
   PerformanceManager::CallOnGraph(
       FROM_HERE,
+      base::BindOnce(&V8DetailedMemoryRequestOneShot::InitializeRequest,
+                     base::Unretained(this)));
+  PerformanceManager::CallOnGraph(
+      FROM_HERE,
       base::BindOnce(
-          &V8DetailedMemoryRequestOneShot::InitializeRequestFromOffSequence,
-          base::Unretained(this), std::move(process), mode));
+          &V8DetailedMemoryRequestOneShot::StartMeasurementFromOffSequence,
+          base::Unretained(this), std::move(process), std::move(callback)));
 }
 
-void V8DetailedMemoryRequestOneShot::InitializeRequest(
-    const ProcessNode* process,
-    MeasurementMode mode) {
+void V8DetailedMemoryRequestOneShot::InitializeRequest() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(process);
-  DCHECK_EQ(process->GetProcessType(), content::PROCESS_TYPE_RENDERER);
   request_ = std::make_unique<V8DetailedMemoryRequest>(
-      util::PassKey<V8DetailedMemoryRequestOneShot>(), mode);
+      util::PassKey<V8DetailedMemoryRequestOneShot>(), mode_,
+      base::BindOnce(&V8DetailedMemoryRequestOneShot::OnOwnerUnregistered,
+                     // Unretained is safe because |this| owns the request
+                     // object that will invoke the closure.
+                     base::Unretained(this)));
   request_->AddObserver(this);
-  request_->StartMeasurementForProcess(process);
-
-#if DCHECK_IS_ON()
-  process_ = process;
-#endif
 }
 
-void V8DetailedMemoryRequestOneShot::InitializeRequestFromOffSequence(
+void V8DetailedMemoryRequestOneShot::StartMeasurementFromOffSequence(
     base::WeakPtr<ProcessNode> process,
-    MeasurementMode mode) {
+    MeasurementCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (process)
-    InitializeRequest(process.get(), mode);
+    StartMeasurement(process.get(), std::move(callback));
 }
 
 void V8DetailedMemoryRequestOneShot::DeleteRequest() {
@@ -811,6 +846,14 @@
   request_.reset();
 }
 
+void V8DetailedMemoryRequestOneShot::OnOwnerUnregistered() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // No results will arrive so clean up the request and callback. This frees
+  // any resources that were owned by the callback.
+  DeleteRequest();
+  std::move(callback_).Reset();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // V8DetailedMemoryFrameData
 
@@ -963,13 +1006,13 @@
   // Attempt to remove this request from all process-specific queues and the
   // global queue. It will only be in one of them.
   size_t removal_count = 0;
-  // Unretained is safe because this callback is synchronous.
   ApplyToAllRequestQueues(base::BindRepeating(
+      // Raw pointers are safe because this callback is synchronous.
       [](V8DetailedMemoryRequest* request, size_t* removal_count,
          MeasurementRequestQueue* queue) {
         (*removal_count) += queue->RemoveMeasurementRequest(request);
       },
-      base::Unretained(request), base::Unretained(&removal_count)));
+      request, &removal_count));
   DCHECK_EQ(removal_count, 1ULL);
   UpdateProcessMeasurementSchedules();
 }
@@ -1065,33 +1108,21 @@
         const ProcessNode* process_node) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  // First collect all requests with observers to notify. The observer
-  // implementations may add or remove requests from the queue, invalidating
-  // iterators.
-  std::vector<V8DetailedMemoryRequest*> requests_to_notify;
-  requests_to_notify.insert(requests_to_notify.end(),
-                            bounded_measurement_requests_.begin(),
-                            bounded_measurement_requests_.end());
-  requests_to_notify.insert(requests_to_notify.end(),
-                            lazy_measurement_requests_.begin(),
-                            lazy_measurement_requests_.end());
-  for (const V8DetailedMemoryRequest* request : requests_to_notify) {
-    request->NotifyObserversOnMeasurementAvailable(
-        util::PassKey<MeasurementRequestQueue>(), process_node);
-    // The observer may have deleted |request| so it is no longer safe to
-    // reference.
-  }
+  // Raw pointers are safe because the callback is synchronous.
+  ApplyToAllRequests(base::BindRepeating(
+      [](const ProcessNode* process_node, V8DetailedMemoryRequest* request) {
+        request->NotifyObserversOnMeasurementAvailable(
+            util::PassKey<MeasurementRequestQueue>(), process_node);
+      },
+      process_node));
 }
 
 void V8DetailedMemoryDecorator::MeasurementRequestQueue::OnOwnerUnregistered() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  for (V8DetailedMemoryRequest* request : bounded_measurement_requests_) {
+  ApplyToAllRequests(base::BindRepeating([](V8DetailedMemoryRequest* request) {
     request->OnOwnerUnregistered(util::PassKey<MeasurementRequestQueue>());
-  }
+  }));
   bounded_measurement_requests_.clear();
-  for (V8DetailedMemoryRequest* request : lazy_measurement_requests_) {
-    request->OnOwnerUnregistered(util::PassKey<MeasurementRequestQueue>());
-  }
   lazy_measurement_requests_.clear();
 }
 
@@ -1117,6 +1148,24 @@
 #endif
 }
 
+void V8DetailedMemoryDecorator::MeasurementRequestQueue::ApplyToAllRequests(
+    base::RepeatingCallback<void(V8DetailedMemoryRequest*)> callback) const {
+  // First collect all requests to notify. The callback may add or remove
+  // requests from the queue, invalidating iterators.
+  std::vector<V8DetailedMemoryRequest*> requests_to_notify;
+  requests_to_notify.insert(requests_to_notify.end(),
+                            bounded_measurement_requests_.begin(),
+                            bounded_measurement_requests_.end());
+  requests_to_notify.insert(requests_to_notify.end(),
+                            lazy_measurement_requests_.begin(),
+                            lazy_measurement_requests_.end());
+  for (V8DetailedMemoryRequest* request : requests_to_notify) {
+    callback.Run(request);
+    // The callback may have deleted |request| so it is no longer safe to
+    // reference.
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // V8DetailedMemoryRequestAnySeq
 
@@ -1203,26 +1252,15 @@
 // V8DetailedMemoryRequestOneShotAnySeq
 
 V8DetailedMemoryRequestOneShotAnySeq::V8DetailedMemoryRequestOneShotAnySeq(
+    MeasurementMode mode)
+    : mode_(mode) {}
+
+V8DetailedMemoryRequestOneShotAnySeq::V8DetailedMemoryRequestOneShotAnySeq(
     RenderProcessHostId process_id,
     MeasurementCallback callback,
     MeasurementMode mode)
-    : wrapped_callback_(std::move(callback)) {
-  // GetProcessNodeForRenderProcessHostId must be called from the UI thread.
-  auto ui_task_runner = content::GetUIThreadTaskRunner({});
-  if (ui_task_runner->RunsTasksInCurrentSequence()) {
-    InitializeWrappedRequest(
-        mode,
-        PerformanceManager::GetProcessNodeForRenderProcessHostId(process_id));
-  } else {
-    ui_task_runner->PostTaskAndReplyWithResult(
-        FROM_HERE,
-        base::BindOnce(
-            &PerformanceManager::GetProcessNodeForRenderProcessHostId,
-            process_id),
-        base::BindOnce(
-            &V8DetailedMemoryRequestOneShotAnySeq::InitializeWrappedRequest,
-            weak_factory_.GetWeakPtr(), mode));
-  }
+    : mode_(mode) {
+  StartMeasurement(process_id, std::move(callback));
 }
 
 V8DetailedMemoryRequestOneShotAnySeq::~V8DetailedMemoryRequestOneShotAnySeq() {
@@ -1236,26 +1274,52 @@
           std::move(request_)));
 }
 
+void V8DetailedMemoryRequestOneShotAnySeq::StartMeasurement(
+    RenderProcessHostId process_id,
+    MeasurementCallback callback) {
+  // GetProcessNodeForRenderProcessHostId must be called from the UI thread.
+  auto ui_task_runner = content::GetUIThreadTaskRunner({});
+  if (ui_task_runner->RunsTasksInCurrentSequence()) {
+    InitializeWrappedRequest(
+        std::move(callback), mode_,
+        PerformanceManager::GetProcessNodeForRenderProcessHostId(process_id));
+  } else {
+    ui_task_runner->PostTaskAndReplyWithResult(
+        FROM_HERE,
+        base::BindOnce(
+            &PerformanceManager::GetProcessNodeForRenderProcessHostId,
+            process_id),
+        base::BindOnce(
+            &V8DetailedMemoryRequestOneShotAnySeq::InitializeWrappedRequest,
+            weak_factory_.GetWeakPtr(), std::move(callback), mode_));
+  }
+}
+
 void V8DetailedMemoryRequestOneShotAnySeq::InitializeWrappedRequest(
+    MeasurementCallback callback,
     MeasurementMode mode,
     base::WeakPtr<ProcessNode> process_node) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Pass ownership of |callback| to a wrapper, |wrapped_callback|, that will
+  // be owned by the wrapped request. The wrapper will be invoked and destroyed
+  // on the PM sequence. However, |callback| must be both called and destroyed
+  // on this sequence, so indirect all accesses to it through SequenceBound.
+  auto wrapped_callback = base::BindOnce(
+      &V8DetailedMemoryRequestOneShotAnySeq::OnMeasurementAvailable,
+      base::SequenceBound<MeasurementCallback>(
+          base::SequencedTaskRunnerHandle::Get(), std::move(callback)));
+
   // Can't use make_unique since this calls the private any-sequence
   // constructor. After construction the V8DetailedMemoryRequestOneShot must
   // only be accessed on the graph sequence.
   request_ = base::WrapUnique(new V8DetailedMemoryRequestOneShot(
       util::PassKey<V8DetailedMemoryRequestOneShotAnySeq>(),
-      std::move(process_node),
-      base::BindOnce(
-          &V8DetailedMemoryRequestOneShotAnySeq::OnMeasurementAvailable,
-          base::SequencedTaskRunnerHandle::Get(), weak_factory_.GetWeakPtr()),
-      mode));
+      std::move(process_node), std::move(wrapped_callback), mode));
 }
 
 // static
 void V8DetailedMemoryRequestOneShotAnySeq::OnMeasurementAvailable(
-    scoped_refptr<base::SequencedTaskRunner> task_runner,
-    base::WeakPtr<V8DetailedMemoryRequestOneShotAnySeq> request,
+    base::SequenceBound<MeasurementCallback> sequence_bound_callback,
     const ProcessNode* process_node,
     const V8DetailedMemoryProcessData* process_data) {
   DCHECK(process_node);
@@ -1278,20 +1342,16 @@
       },
       base::Unretained(&all_frame_data)));
 
-  task_runner->PostTask(
+  sequence_bound_callback.PostTaskWithThisObject(
       FROM_HERE,
       base::BindOnce(
-          &V8DetailedMemoryRequestOneShotAnySeq::InvokeWrappedCallback,
-          std::move(request), process_node->GetRenderProcessHostId(),
-          *process_data, std::move(all_frame_data)));
-}
-
-void V8DetailedMemoryRequestOneShotAnySeq::InvokeWrappedCallback(
-    RenderProcessHostId process_id,
-    const V8DetailedMemoryProcessData& process_data,
-    const FrameDataMap& frame_data) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  std::move(wrapped_callback_).Run(process_id, process_data, frame_data);
+          [](RenderProcessHostId process_id,
+             const V8DetailedMemoryProcessData& process_data,
+             const FrameDataMap& frame_data, MeasurementCallback* callback) {
+            std::move(*callback).Run(process_id, process_data, frame_data);
+          },
+          process_node->GetRenderProcessHostId(), *process_data,
+          std::move(all_frame_data)));
 }
 
 }  // namespace v8_memory
diff --git a/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc b/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc
index 1e30ac3f..ee2f95d 100644
--- a/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc
+++ b/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/bind_test_util.h"
@@ -190,12 +191,9 @@
                 expected_mode);
   }
 
-  void ExpectBindAndRespondToQuery(
+  void ExpectBindReceiver(
       MockV8DetailedMemoryReporter* mock_reporter,
-      blink::mojom::PerProcessV8MemoryUsagePtr data,
-      RenderProcessHostId expected_process_id = kTestProcessID,
-      ExpectedMode expected_mode = ExpectedMode::DEFAULT) {
-    InSequence seq;
+      RenderProcessHostId expected_process_id = kTestProcessID) {
     // Arg 0 is a
     // mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>. Pass it
     // to mock_reporter->Bind().
@@ -208,6 +206,16 @@
                                 Eq(expected_process_id))))
         .WillOnce(WithArg<0>(
             Invoke(mock_reporter, &MockV8DetailedMemoryReporter::Bind)));
+  }
+
+  // Helper that expects a bind and the initial query in sequence.
+  void ExpectBindAndRespondToQuery(
+      MockV8DetailedMemoryReporter* mock_reporter,
+      blink::mojom::PerProcessV8MemoryUsagePtr data,
+      RenderProcessHostId expected_process_id = kTestProcessID,
+      ExpectedMode expected_mode = ExpectedMode::DEFAULT) {
+    InSequence seq;
+    ExpectBindReceiver(mock_reporter, expected_process_id);
     ExpectQueryAndReply(mock_reporter, std::move(data), expected_mode);
   }
 
@@ -235,6 +243,13 @@
   base::TimeTicks last_query_time_;
 };
 
+// An arbitrary object used to test object lifetimes with WeakPtr.
+class LifetimeTestObject : public base::SupportsWeakPtr<LifetimeTestObject> {
+ public:
+  LifetimeTestObject() = default;
+  ~LifetimeTestObject() = default;
+};
+
 blink::mojom::PerProcessV8MemoryUsagePtr NewPerProcessV8MemoryUsage(
     size_t number_of_isolates) {
   auto data = blink::mojom::PerProcessV8MemoryUsage::New();
@@ -315,6 +330,13 @@
     : public PerformanceManagerTestHarness,
       public V8DetailedMemoryDecoratorTestBase {
  public:
+  V8DetailedMemoryRequestAnySeqTest()
+      : PerformanceManagerTestHarness(
+            base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+
+  static constexpr char kMainFrameUrl[] = "http://a.com/";
+  static constexpr char kChildFrameUrl[] = "http://b.com/";
+
   void SetUp() override {
     PerformanceManagerTestHarness::SetUp();
 
@@ -330,14 +352,50 @@
           run_loop.Quit();
         }));
     run_loop.Run();
+
+    // Set the active contents and simulate a navigation, which adds nodes to
+    // the graph.
+    content::IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
+    SetContents(CreateTestWebContents());
+    main_frame_ = content::NavigationSimulator::NavigateAndCommitFromBrowser(
+        web_contents(), GURL(kMainFrameUrl));
+    main_process_id_ = RenderProcessHostId(main_frame_->GetProcess()->GetID());
+  }
+
+  void CreateCrossProcessChildFrame() {
+    // Since kMainFrameUrl has a different domain than kChildFrameUrl, the main
+    // and child frames should end up in different processes.
+    child_frame_ =
+        content::RenderFrameHostTester::For(main_frame_)->AppendChild("frame1");
+    child_frame_ = content::NavigationSimulator::NavigateAndCommitFromDocument(
+        GURL(kChildFrameUrl), child_frame_);
+    child_process_id_ =
+        RenderProcessHostId(child_frame_->GetProcess()->GetID());
+    ASSERT_NE(main_process_id_, child_process_id_);
   }
 
   scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner()
       override {
     return task_environment()->GetMainThreadTaskRunner();
   }
+
+  content::RenderFrameHost* main_frame() const { return main_frame_; }
+  content::RenderFrameHost* child_frame() const { return child_frame_; }
+
+  RenderProcessHostId main_process_id() const { return main_process_id_; }
+  RenderProcessHostId child_process_id() const { return child_process_id_; }
+
+ private:
+  content::RenderFrameHost* main_frame_ = nullptr;
+  content::RenderFrameHost* child_frame_ = nullptr;
+  RenderProcessHostId main_process_id_;
+  RenderProcessHostId child_process_id_;
 };
 
+// Storage for static members of V8DetailedMemoryRequestAnySeqTest.
+constexpr char V8DetailedMemoryRequestAnySeqTest::kMainFrameUrl[];
+constexpr char V8DetailedMemoryRequestAnySeqTest::kChildFrameUrl[];
+
 constexpr base::TimeDelta
     V8DetailedMemoryDecoratorTestBase::kMinTimeBetweenRequests;
 
@@ -456,7 +514,8 @@
   }
 
   uint64_t unassociated_v8_bytes_used = 0;
-  V8DetailedMemoryRequestOneShot process1_request(
+  V8DetailedMemoryRequestOneShot process1_request;
+  process1_request.StartMeasurement(
       process1.get(), base::BindLambdaForTesting(
                           [&unassociated_v8_bytes_used, &process1](
                               const ProcessNode* process_node,
@@ -470,29 +529,132 @@
   Mock::VerifyAndClearExpectations(&mock_reporter1);
   Mock::VerifyAndClearExpectations(&mock_reporter2);
   EXPECT_EQ(unassociated_v8_bytes_used, 3ULL);
+}
 
-  // Create another request, but delete it before the result arrives.
+TEST_F(V8DetailedMemoryDecoratorTest, OneShotLifetime) {
+  auto process = CreateNode<ProcessNodeImpl>(
+      content::PROCESS_TYPE_RENDERER,
+      RenderProcessHostProxy::CreateForTesting(kTestProcessID));
+
+  MockV8DetailedMemoryReporter mock_reporter;
   {
+    InSequence seq;
+    ExpectBindReceiver(&mock_reporter);
+
     auto data = NewPerProcessV8MemoryUsage(1);
-    data->isolates[0]->unassociated_bytes_used = 4ULL;
-    ExpectQueryAndDelayReply(&mock_reporter1, base::TimeDelta::FromSeconds(10),
+    data->isolates[0]->unassociated_bytes_used = 1ULL;
+    ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
                              std::move(data));
   }
 
+  // Create a one-shot request, but delete it before the result arrives.
   auto doomed_request = std::make_unique<V8DetailedMemoryRequestOneShot>(
-      process1.get(),
+      process.get(),
       base::BindOnce([](const ProcessNode* process_node,
                         const V8DetailedMemoryProcessData* process_data) {
         FAIL() << "Callback called after request deleted.";
       }));
 
-  // Verify that requests are sent but reply is not yet received.
+  // Verify that the request is sent but the reply is not yet received.
   task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
-  Mock::VerifyAndClearExpectations(&mock_reporter1);
-  Mock::VerifyAndClearExpectations(&mock_reporter2);
+  Mock::VerifyAndClearExpectations(&mock_reporter);
 
   doomed_request.reset();
+  task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
+
+  // Create a request that is deleted from within its own callback and make
+  // sure nothing explodes.
+  {
+    auto data = NewPerProcessV8MemoryUsage(1);
+    data->isolates[0]->unassociated_bytes_used = 2ULL;
+    ExpectQueryAndReply(&mock_reporter, std::move(data));
+  }
+  uint64_t unassociated_v8_bytes_used = 0;
+  doomed_request = std::make_unique<V8DetailedMemoryRequestOneShot>(
+      process.get(), base::BindLambdaForTesting(
+                         [&](const ProcessNode* process_node,
+                             const V8DetailedMemoryProcessData* process_data) {
+                           doomed_request.reset();
+                           ASSERT_TRUE(process_data);
+                           unassociated_v8_bytes_used =
+                               process_data->unassociated_v8_bytes_used();
+                         }));
   task_env().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(&mock_reporter);
+  EXPECT_EQ(unassociated_v8_bytes_used, 2ULL);
+
+  // Ensure that resource-owning callbacks are freed when there is no response
+  // because the process dies.
+  {
+    auto data = NewPerProcessV8MemoryUsage(1);
+    data->isolates[0]->unassociated_bytes_used = 3ULL;
+    ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
+                             std::move(data));
+  }
+  auto lifetime_test = std::make_unique<LifetimeTestObject>();
+  auto weak_lifetime_test = lifetime_test->AsWeakPtr();
+  V8DetailedMemoryRequestOneShot unfinished_request(
+      process.get(),
+      base::BindOnce(
+          [](std::unique_ptr<LifetimeTestObject>, const ProcessNode*,
+             const V8DetailedMemoryProcessData*) {
+            FAIL() << "Callback called after process deleted.";
+          },
+          // Pass ownership to the callback. The object should be deleted if the
+          // callback is not called.
+          std::move(lifetime_test)));
+
+  // Verify that requests are sent but reply is not yet received.
+  task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
+  Mock::VerifyAndClearExpectations(&mock_reporter);
+  ASSERT_TRUE(weak_lifetime_test);
+
+  process.reset();
+
+  task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
+  EXPECT_FALSE(weak_lifetime_test);
+}
+
+TEST_F(V8DetailedMemoryDecoratorTest, OneShotLifetimeAtExit) {
+  auto process = CreateNode<ProcessNodeImpl>(
+      content::PROCESS_TYPE_RENDERER,
+      RenderProcessHostProxy::CreateForTesting(kTestProcessID));
+
+  // Ensure that resource-owning callbacks are freed when there is no response
+  // because the browser is exiting (simulated by destroying the decorator).
+  MockV8DetailedMemoryReporter mock_reporter;
+  {
+    InSequence seq;
+    ExpectBindReceiver(&mock_reporter);
+
+    auto data = NewPerProcessV8MemoryUsage(1);
+    data->isolates[0]->unassociated_bytes_used = 1ULL;
+    ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
+                             std::move(data));
+  }
+
+  auto lifetime_test = std::make_unique<LifetimeTestObject>();
+  auto weak_lifetime_test = lifetime_test->AsWeakPtr();
+  V8DetailedMemoryRequestOneShot unfinished_request(
+      process.get(),
+      base::BindOnce(
+          [](std::unique_ptr<LifetimeTestObject>, const ProcessNode*,
+             const V8DetailedMemoryProcessData*) {
+            FAIL() << "Callback called after measurements cancelled.";
+          },
+          // Pass ownership to the callback. The object should be deleted if the
+          // callback is not called.
+          std::move(lifetime_test)));
+
+  // Verify that requests are sent but reply is not yet received.
+  task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
+  Mock::VerifyAndClearExpectations(&mock_reporter);
+  ASSERT_TRUE(weak_lifetime_test);
+
+  internal::DestroyV8DetailedMemoryDecoratorForTesting(graph());
+
+  task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
+  EXPECT_FALSE(weak_lifetime_test);
 }
 
 TEST_F(V8DetailedMemoryDecoratorTest, QueryRateIsLimited) {
@@ -1646,20 +1808,11 @@
 }
 
 TEST_F(V8DetailedMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
-  // Set the active contents and simulate a navigation, which adds nodes to the
-  // graph.
-  SetContents(CreateTestWebContents());
-  content::NavigationSimulator::NavigateAndCommitFromBrowser(
-      web_contents(), GURL("https://www.foo.com/"));
-
   // Create some test data to return for a measurement request.
   constexpr uint64_t kAssociatedBytes = 0x123;
-  content::RenderFrameHost* main_frame = web_contents()->GetMainFrame();
-  ASSERT_NE(nullptr, main_frame);
-  const RenderProcessHostId process_id(main_frame->GetProcess()->GetID());
-  const blink::LocalFrameToken frame_token(main_frame->GetFrameToken());
-  const content::GlobalFrameRoutingId frame_id(process_id.value(),
-                                               main_frame->GetRoutingID());
+  const blink::LocalFrameToken frame_token(main_frame()->GetFrameToken());
+  const content::GlobalFrameRoutingId frame_id(main_process_id().value(),
+                                               main_frame()->GetRoutingID());
 
   V8DetailedMemoryProcessData expected_process_data;
   expected_process_data.set_unassociated_v8_bytes_used(kUnassociatedBytes);
@@ -1672,7 +1825,7 @@
     data->isolates[0]->unassociated_bytes_used = kUnassociatedBytes;
     AddIsolateMemoryUsage(frame_token, kAssociatedBytes,
                           data->isolates[0].get());
-    ExpectBindAndRespondToQuery(&reporter, std::move(data), process_id);
+    ExpectBindAndRespondToQuery(&reporter, std::move(data), main_process_id());
   }
 
   // Decorator should not exist before creating a request.
@@ -1703,9 +1856,9 @@
   // The observer should be invoked on the main sequence when a measurement is
   // available. Exit the RunLoop when this happens.
   base::RunLoop run_loop;
-  EXPECT_CALL(observer,
-              OnV8MemoryMeasurementAvailable(process_id, expected_process_data,
-                                             expected_frame_data))
+  EXPECT_CALL(observer, OnV8MemoryMeasurementAvailable(main_process_id(),
+                                                       expected_process_data,
+                                                       expected_frame_data))
       .WillOnce([&]() {
         run_loop.Quit();
         ASSERT_TRUE(
@@ -1714,8 +1867,8 @@
         // Verify that the notification parameters can be used to retrieve a
         // RenderFrameHost and RenderProcessHost. This is safe on the main
         // thread.
-        EXPECT_NE(nullptr,
-                  content::RenderProcessHost::FromID(process_id.value()));
+        EXPECT_NE(nullptr, content::RenderProcessHost::FromID(
+                               main_process_id().value()));
         const content::GlobalFrameRoutingId frame_id =
             expected_frame_data.cbegin()->first;
         EXPECT_NE(nullptr, content::RenderFrameHost::FromID(frame_id));
@@ -1758,24 +1911,7 @@
 }
 
 TEST_F(V8DetailedMemoryRequestAnySeqTest, SingleProcessRequest) {
-  content::IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
-  SetContents(CreateTestWebContents());
-
-  // Set up a page at a.com with a subframe at b.com. These should be in
-  // different processes.
-  const GURL kUrlA("http://a.com/");
-  const GURL kUrlB("http://b.com/");
-  content::RenderFrameHost* main_frame =
-      content::NavigationSimulator::NavigateAndCommitFromBrowser(
-          web_contents(), GURL("http://a.com"));
-  content::RenderFrameHost* child_frame =
-      content::RenderFrameHostTester::For(main_frame)->AppendChild("frame1");
-  child_frame = content::NavigationSimulator::NavigateAndCommitFromDocument(
-      GURL("http://b.com"), child_frame);
-
-  const RenderProcessHostId process_id1(main_frame->GetProcess()->GetID());
-  const RenderProcessHostId process_id2(child_frame->GetProcess()->GetID());
-  ASSERT_NE(process_id1, process_id2);
+  CreateCrossProcessChildFrame();
 
   V8DetailedMemoryProcessData expected_process_data1;
   expected_process_data1.set_unassociated_v8_bytes_used(1U);
@@ -1787,11 +1923,13 @@
   {
     auto data = NewPerProcessV8MemoryUsage(1);
     data->isolates[0]->unassociated_bytes_used = 1U;
-    ExpectBindAndRespondToQuery(&mock_reporter1, std::move(data), process_id1);
+    ExpectBindAndRespondToQuery(&mock_reporter1, std::move(data),
+                                main_process_id());
 
     data = NewPerProcessV8MemoryUsage(1);
     data->isolates[0]->unassociated_bytes_used = 2U;
-    ExpectBindAndRespondToQuery(&mock_reporter2, std::move(data), process_id2);
+    ExpectBindAndRespondToQuery(&mock_reporter2, std::move(data),
+                                child_process_id());
   }
 
   // Create one request that measures both processes, and one request that
@@ -1803,21 +1941,21 @@
 
   V8DetailedMemoryRequestAnySeq single_process_request(
       V8DetailedMemoryDecoratorTest::kMinTimeBetweenRequests,
-      MeasurementMode::kBounded, process_id1);
+      MeasurementMode::kBounded, main_process_id());
   MockV8DetailedMemoryObserverAnySeq single_process_observer;
   single_process_request.AddObserver(&single_process_observer);
 
   // When a measurement is available the all process observer should be invoked
   // for both processes, and the single process observer only for process 1.
-  EXPECT_CALL(
-      all_process_observer,
-      OnV8MemoryMeasurementAvailable(process_id1, expected_process_data1, _));
-  EXPECT_CALL(
-      all_process_observer,
-      OnV8MemoryMeasurementAvailable(process_id2, expected_process_data2, _));
-  EXPECT_CALL(
-      single_process_observer,
-      OnV8MemoryMeasurementAvailable(process_id1, expected_process_data1, _));
+  EXPECT_CALL(all_process_observer,
+              OnV8MemoryMeasurementAvailable(main_process_id(),
+                                             expected_process_data1, _));
+  EXPECT_CALL(all_process_observer,
+              OnV8MemoryMeasurementAvailable(child_process_id(),
+                                             expected_process_data2, _));
+  EXPECT_CALL(single_process_observer,
+              OnV8MemoryMeasurementAvailable(main_process_id(),
+                                             expected_process_data1, _));
 
   // Now execute all the above tasks.
   task_environment()->RunUntilIdle();
@@ -1833,25 +1971,7 @@
 }
 
 TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShot) {
-  content::IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
-  SetContents(CreateTestWebContents());
-
-  // Set up a page at a.com with a subframe at b.com. These should be in
-  // different processes. We will create one request that measures both
-  // processes, and a one-shot request that measures only one.
-  const GURL kUrlA("http://a.com/");
-  const GURL kUrlB("http://b.com/");
-  content::RenderFrameHost* main_frame =
-      content::NavigationSimulator::NavigateAndCommitFromBrowser(
-          web_contents(), GURL("http://a.com"));
-  content::RenderFrameHost* child_frame =
-      content::RenderFrameHostTester::For(main_frame)->AppendChild("frame1");
-  child_frame = content::NavigationSimulator::NavigateAndCommitFromDocument(
-      GURL("http://b.com"), child_frame);
-
-  const RenderProcessHostId process_id1(main_frame->GetProcess()->GetID());
-  const RenderProcessHostId process_id2(child_frame->GetProcess()->GetID());
-  ASSERT_NE(process_id1, process_id2);
+  CreateCrossProcessChildFrame();
 
   // Set the all process request to only send once within the test.
   V8DetailedMemoryRequestAnySeq all_process_request(
@@ -1864,14 +1984,16 @@
   {
     auto data = NewPerProcessV8MemoryUsage(1);
     data->isolates[0]->unassociated_bytes_used = 1ULL;
-    ExpectBindAndRespondToQuery(&mock_reporter1, std::move(data), process_id1);
+    ExpectBindAndRespondToQuery(&mock_reporter1, std::move(data),
+                                main_process_id());
   }
 
   MockV8DetailedMemoryReporter mock_reporter2;
   {
     auto data = NewPerProcessV8MemoryUsage(1);
     data->isolates[0]->unassociated_bytes_used = 2ULL;
-    ExpectBindAndRespondToQuery(&mock_reporter2, std::move(data), process_id2);
+    ExpectBindAndRespondToQuery(&mock_reporter2, std::move(data),
+                                child_process_id());
   }
 
   task_environment()->RunUntilIdle();
@@ -1887,14 +2009,15 @@
   }
 
   uint64_t unassociated_v8_bytes_used = 0;
-  V8DetailedMemoryRequestOneShotAnySeq process1_request(
-      process_id1,
+  V8DetailedMemoryRequestOneShotAnySeq process1_request;
+  process1_request.StartMeasurement(
+      main_process_id(),
       base::BindLambdaForTesting(
           [&](RenderProcessHostId process_id,
               const V8DetailedMemoryProcessData& process_data,
               const V8DetailedMemoryRequestOneShotAnySeq::FrameDataMap&
                   frame_data) {
-            EXPECT_EQ(process_id, process_id1);
+            EXPECT_EQ(process_id, main_process_id());
             unassociated_v8_bytes_used =
                 process_data.unassociated_v8_bytes_used();
           }));
@@ -1902,17 +2025,26 @@
   Mock::VerifyAndClearExpectations(&mock_reporter1);
   Mock::VerifyAndClearExpectations(&mock_reporter2);
   EXPECT_EQ(unassociated_v8_bytes_used, 3ULL);
+}
 
-  // Create another request, but delete it before the result arrives.
+TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShotLifetime) {
+  // Measure a child frame so that it can be detached.
+  CreateCrossProcessChildFrame();
+
+  // Create a one-shot request, but delete it before the result arrives.
+  MockV8DetailedMemoryReporter mock_reporter;
   {
+    InSequence seq;
+    ExpectBindReceiver(&mock_reporter, child_process_id());
+
     auto data = NewPerProcessV8MemoryUsage(1);
-    data->isolates[0]->unassociated_bytes_used = 4ULL;
-    ExpectQueryAndDelayReply(&mock_reporter1, base::TimeDelta::FromSeconds(10),
+    data->isolates[0]->unassociated_bytes_used = 1ULL;
+    ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
                              std::move(data));
   }
 
   auto doomed_request = std::make_unique<V8DetailedMemoryRequestOneShotAnySeq>(
-      process_id1,
+      child_process_id(),
       base::BindOnce(
           [](RenderProcessHostId process_id,
              const V8DetailedMemoryProcessData& process_data,
@@ -1922,33 +2054,123 @@
           }));
 
   // Verify that requests are sent but reply is not received.
-  task_environment()->RunUntilIdle();
-  Mock::VerifyAndClearExpectations(&mock_reporter1);
-  Mock::VerifyAndClearExpectations(&mock_reporter2);
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+  Mock::VerifyAndClearExpectations(&mock_reporter);
 
   doomed_request.reset();
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+
+  // Create a request that is deleted from within its own callback and make
+  // sure nothing explodes.
+  {
+    auto data = NewPerProcessV8MemoryUsage(1);
+    data->isolates[0]->unassociated_bytes_used = 2ULL;
+    ExpectQueryAndReply(&mock_reporter, std::move(data));
+  }
+  uint64_t unassociated_v8_bytes_used = 0;
+  doomed_request = std::make_unique<V8DetailedMemoryRequestOneShotAnySeq>(
+      child_process_id(),
+      base::BindLambdaForTesting(
+          [&](RenderProcessHostId process_id,
+              const V8DetailedMemoryProcessData& process_data,
+              const V8DetailedMemoryRequestOneShotAnySeq::FrameDataMap&
+                  frame_data) {
+            doomed_request.reset();
+            unassociated_v8_bytes_used =
+                process_data.unassociated_v8_bytes_used();
+          }));
   task_environment()->RunUntilIdle();
+  Mock::VerifyAndClearExpectations(&mock_reporter);
+  EXPECT_EQ(unassociated_v8_bytes_used, 2ULL);
+
+  // Ensure that resource-owning callbacks are freed when there is no response
+  // because the process dies.
+  {
+    auto data = NewPerProcessV8MemoryUsage(1);
+    data->isolates[0]->unassociated_bytes_used = 3ULL;
+    ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
+                             std::move(data));
+  }
+  auto lifetime_test = std::make_unique<LifetimeTestObject>();
+  auto weak_lifetime_test = lifetime_test->AsWeakPtr();
+  V8DetailedMemoryRequestOneShotAnySeq unfinished_request(
+      child_process_id(),
+      base::BindOnce(
+          [](std::unique_ptr<LifetimeTestObject>, RenderProcessHostId,
+             const V8DetailedMemoryProcessData&,
+             const V8DetailedMemoryRequestOneShotAnySeq::FrameDataMap&) {
+            FAIL() << "Callback called after process deleted.";
+          },
+          // Pass ownership to the callback. The object should be deleted if the
+          // callback is not called.
+          std::move(lifetime_test)));
+
+  // Verify that requests are sent but reply is not yet received.
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+  Mock::VerifyAndClearExpectations(&mock_reporter);
+  ASSERT_TRUE(weak_lifetime_test);
+
+  content::RenderFrameHostTester::For(child_frame())->Detach();
+
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+  EXPECT_FALSE(weak_lifetime_test);
+}
+
+TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShotLifetimeAtExit) {
+  // Ensure that resource-owning callbacks are freed when there is no response
+  // because the browser is exiting (simulated by destroying the decorator).
+  MockV8DetailedMemoryReporter mock_reporter;
+  {
+    InSequence seq;
+    ExpectBindReceiver(&mock_reporter, main_process_id());
+
+    auto data = NewPerProcessV8MemoryUsage(1);
+    data->isolates[0]->unassociated_bytes_used = 1ULL;
+    ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
+                             std::move(data));
+  }
+
+  auto lifetime_test = std::make_unique<LifetimeTestObject>();
+  auto weak_lifetime_test = lifetime_test->AsWeakPtr();
+  V8DetailedMemoryRequestOneShotAnySeq unfinished_request(
+      main_process_id(),
+      base::BindOnce(
+          [](std::unique_ptr<LifetimeTestObject>, RenderProcessHostId,
+             const V8DetailedMemoryProcessData&,
+             const V8DetailedMemoryRequestOneShotAnySeq::FrameDataMap&) {
+            FAIL() << "Callback called after measurements cancelled.";
+          },
+          // Pass ownership to the callback. The object should be deleted if the
+          // callback is not called.
+          std::move(lifetime_test)));
+
+  // Verify that requests are sent but reply is not yet received.
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+  Mock::VerifyAndClearExpectations(&mock_reporter);
+  ASSERT_TRUE(weak_lifetime_test);
+
+  base::RunLoop run_loop;
+  PerformanceManager::CallOnGraph(
+      FROM_HERE,
+      base::BindOnce(&internal::DestroyV8DetailedMemoryDecoratorForTesting));
+  // Block in the run loop until the destroy task runs on the PM sequence.
+  PerformanceManager::CallOnGraph(FROM_HERE, run_loop.QuitClosure());
+  run_loop.Run();
+
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+  EXPECT_FALSE(weak_lifetime_test);
 }
 
 // TODO(1085129): Move this test to web_memory_aggregator_unittest.cc
 // after extracting the testing infrastructure.
 TEST_F(V8DetailedMemoryRequestAnySeqTest, WebMeasureMemory) {
-  content::IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
-  SetContents(CreateTestWebContents());
-
-  // Create a page with a single frame.
-  content::RenderFrameHost* main_frame =
-      content::NavigationSimulator::NavigateAndCommitFromBrowser(
-          web_contents(), GURL("http://foo.com/"));
-  const RenderProcessHostId process_id(main_frame->GetProcess()->GetID());
-
   blink::LocalFrameToken frame_token =
-      blink::LocalFrameToken(main_frame->GetFrameToken());
+      blink::LocalFrameToken(main_frame()->GetFrameToken());
 
   // Call WebMemory::Measure on the performance manager sequence and verify
   // that the result matches the data provided by the mock reporter.
   base::WeakPtr<FrameNode> frame_node_wrapper =
-      PerformanceManager::GetFrameNodeForRenderFrameHost(main_frame);
+      PerformanceManager::GetFrameNodeForRenderFrameHost(main_frame());
   bool measurement_done = false;
   PerformanceManager::CallOnGraph(
       FROM_HERE,
@@ -1962,7 +2184,7 @@
                   EXPECT_EQ(1u, result->breakdown.size());
                   const auto& entry = result->breakdown[0];
                   EXPECT_EQ(1u, entry->attribution.size());
-                  EXPECT_EQ("http://foo.com/", *(entry->attribution[0]->url));
+                  EXPECT_EQ(kMainFrameUrl, *(entry->attribution[0]->url));
                   EXPECT_EQ(1001u, entry->bytes);
                   measurement_done = true;
                 }));
@@ -1973,7 +2195,8 @@
   {
     auto data = NewPerProcessV8MemoryUsage(1);
     AddIsolateMemoryUsage(frame_token, 1001u, data->isolates[0].get());
-    ExpectBindAndRespondToQuery(&mock_reporter, std::move(data), process_id);
+    ExpectBindAndRespondToQuery(&mock_reporter, std::move(data),
+                                main_process_id());
   }
 
   // Finally, run all tasks and verify that the memory measurement callback
diff --git a/components/policy/core/common/android/android_combined_policy_provider.cc b/components/policy/core/common/android/android_combined_policy_provider.cc
index ddfcd4ee..de66439 100644
--- a/components/policy/core/common/android/android_combined_policy_provider.cc
+++ b/components/policy/core/common/android/android_combined_policy_provider.cc
@@ -61,5 +61,10 @@
   return initialized_;
 }
 
+bool AndroidCombinedPolicyProvider::IsFirstPolicyLoadComplete(
+    PolicyDomain domain) const {
+  return IsInitializationComplete(domain);
+}
+
 }  // namespace android
 }  // namespace policy
diff --git a/components/policy/core/common/android/android_combined_policy_provider.h b/components/policy/core/common/android/android_combined_policy_provider.h
index bafa14a..cc4d6c1 100644
--- a/components/policy/core/common/android/android_combined_policy_provider.h
+++ b/components/policy/core/common/android/android_combined_policy_provider.h
@@ -43,6 +43,7 @@
 
   // ConfigurationPolicyProvider:
   bool IsInitializationComplete(PolicyDomain domain) const override;
+  bool IsFirstPolicyLoadComplete(PolicyDomain domain) const override;
   void RefreshPolicies() override;
 
   // For testing
diff --git a/components/policy/core/common/async_policy_provider.cc b/components/policy/core/common/async_policy_provider.cc
index f15f1b90..98f75ad 100644
--- a/components/policy/core/common/async_policy_provider.cc
+++ b/components/policy/core/common/async_policy_provider.cc
@@ -21,7 +21,7 @@
 AsyncPolicyProvider::AsyncPolicyProvider(
     SchemaRegistry* registry,
     std::unique_ptr<AsyncPolicyLoader> loader)
-    : loader_(std::move(loader)) {
+    : loader_(std::move(loader)), first_policies_loaded_(false) {
   // Make an immediate synchronous load on startup.
   OnLoaderReloaded(loader_->InitialLoad(registry->schema_map()));
 }
@@ -85,6 +85,11 @@
                                            refresh_callback_.callback());
 }
 
+bool AsyncPolicyProvider::IsFirstPolicyLoadComplete(PolicyDomain domain) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return first_policies_loaded_;
+}
+
 void AsyncPolicyProvider::ReloadAfterRefreshSync() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // There can't be another refresh callback pending now, since its creation
@@ -104,6 +109,7 @@
 void AsyncPolicyProvider::OnLoaderReloaded(
     std::unique_ptr<PolicyBundle> bundle) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  first_policies_loaded_ = true;
   // Only propagate policy updates if there are no pending refreshes, and if
   // Shutdown() hasn't been called yet.
   if (refresh_callback_.IsCancelled() && loader_)
diff --git a/components/policy/core/common/async_policy_provider.h b/components/policy/core/common/async_policy_provider.h
index 0c5f117..e78a09d 100644
--- a/components/policy/core/common/async_policy_provider.h
+++ b/components/policy/core/common/async_policy_provider.h
@@ -41,6 +41,7 @@
   void Init(SchemaRegistry* registry) override;
   void Shutdown() override;
   void RefreshPolicies() override;
+  bool IsFirstPolicyLoadComplete(PolicyDomain domain) const override;
 
  private:
   // Helper for RefreshPolicies().
@@ -66,6 +67,8 @@
   // thread. See the implementation for the details.
   base::CancelableOnceClosure refresh_callback_;
 
+  bool first_policies_loaded_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   // Used to get a WeakPtr to |this| for the update callback given to the
diff --git a/components/policy/core/common/cloud/cloud_policy_manager.cc b/components/policy/core/common/cloud/cloud_policy_manager.cc
index 0cef3db..59637e4 100644
--- a/components/policy/core/common/cloud/cloud_policy_manager.cc
+++ b/components/policy/core/common/cloud/cloud_policy_manager.cc
@@ -73,6 +73,10 @@
   return true;
 }
 
+bool CloudPolicyManager::IsFirstPolicyLoadComplete(PolicyDomain domain) const {
+  return store()->first_policies_loaded();
+}
+
 void CloudPolicyManager::RefreshPolicies() {
   if (service()) {
     waiting_for_policy_refresh_ = true;
diff --git a/components/policy/core/common/cloud/cloud_policy_manager.h b/components/policy/core/common/cloud/cloud_policy_manager.h
index 9626b1b8..c095c37 100644
--- a/components/policy/core/common/cloud/cloud_policy_manager.h
+++ b/components/policy/core/common/cloud/cloud_policy_manager.h
@@ -58,6 +58,7 @@
   void Init(SchemaRegistry* registry) override;
   void Shutdown() override;
   bool IsInitializationComplete(PolicyDomain domain) const override;
+  bool IsFirstPolicyLoadComplete(PolicyDomain domain) const override;
   void RefreshPolicies() override;
 
   // CloudPolicyStore::Observer:
diff --git a/components/policy/core/common/cloud/cloud_policy_service.cc b/components/policy/core/common/cloud/cloud_policy_service.cc
index 4cfc856..d6f0fb2 100644
--- a/components/policy/core/common/cloud/cloud_policy_service.cc
+++ b/components/policy/core/common/cloud/cloud_policy_service.cc
@@ -237,6 +237,11 @@
   if (!initial_policy_refresh_result_.has_value())
     initial_policy_refresh_result_ = success;
 
+  // If there was an error while fetching the policies the first time, assume
+  // that there are no policies until the next retry.
+  if (!success)
+    store_->SetFirstPoliciesLoaded(true);
+
   // Clear state and |refresh_callbacks_| before actually invoking them, s.t.
   // triggering new policy fetches behaves as expected.
   std::vector<RefreshPolicyCallback> callbacks;
diff --git a/components/policy/core/common/cloud/cloud_policy_store.cc b/components/policy/core/common/cloud/cloud_policy_store.cc
index 0144de5..69bc1694 100644
--- a/components/policy/core/common/cloud/cloud_policy_store.cc
+++ b/components/policy/core/common/cloud/cloud_policy_store.cc
@@ -12,10 +12,7 @@
 
 CloudPolicyStore::Observer::~Observer() {}
 
-CloudPolicyStore::CloudPolicyStore()
-    : status_(STATUS_OK),
-      invalidation_version_(0),
-      is_initialized_(false) {}
+CloudPolicyStore::CloudPolicyStore() = default;
 
 CloudPolicyStore::~CloudPolicyStore() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -52,6 +49,7 @@
 
 void CloudPolicyStore::NotifyStoreLoaded() {
   is_initialized_ = true;
+  first_policies_loaded_ |= has_policy();
   // The |external_data_manager_| must be notified first so that when other
   // observers are informed about the changed policies and try to fetch external
   // data referenced by these, the |external_data_manager_| has the required
@@ -64,6 +62,7 @@
 
 void CloudPolicyStore::NotifyStoreError() {
   is_initialized_ = true;
+  first_policies_loaded_ |= has_policy();
   for (auto& observer : observers_)
     observer.OnStoreError(this);
 }
@@ -85,4 +84,7 @@
   NotifyStoreLoaded();
 }
 
+void CloudPolicyStore::SetFirstPoliciesLoaded(bool loaded) {
+  first_policies_loaded_ = loaded;
+}
 }  // namespace policy
diff --git a/components/policy/core/common/cloud/cloud_policy_store.h b/components/policy/core/common/cloud/cloud_policy_store.h
index af01fee..9be6d44 100644
--- a/components/policy/core/common/cloud/cloud_policy_store.h
+++ b/components/policy/core/common/cloud/cloud_policy_store.h
@@ -94,6 +94,10 @@
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return status_;
   }
+  bool first_policies_loaded() const {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    return first_policies_loaded_;
+  }
   CloudPolicyValidatorBase::Status validation_status() const {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return validation_result_.get() ? validation_result_->status
@@ -154,6 +158,9 @@
   // tests and remove the override.
   void SetPolicyMapForTesting(const PolicyMap& policy_map);
 
+  // Sets whether or not the first policies for this policy store were loaded.
+  void SetFirstPoliciesLoaded(bool loaded);
+
  protected:
   // Invokes the corresponding callback on all registered observers.
   void NotifyStoreLoaded();
@@ -172,14 +179,16 @@
   std::unique_ptr<enterprise_management::PolicyData> policy_;
 
   // Latest status code.
-  Status status_;
+  Status status_ = STATUS_OK;
+
+  bool first_policies_loaded_ = false;
 
   // Latest validation result.
   std::unique_ptr<CloudPolicyValidatorBase::ValidationResult>
       validation_result_;
 
   // The invalidation version of the last policy stored.
-  int64_t invalidation_version_;
+  int64_t invalidation_version_ = 0;
 
   // The public part of signing key that is used by the currently effective
   // policy. The subclasses should keep its value up to date to correspond to
@@ -191,7 +200,7 @@
  private:
   // Whether the store has completed asynchronous initialization, which is
   // triggered by calling Load().
-  bool is_initialized_;
+  bool is_initialized_ = false;
 
   base::ObserverList<Observer, true>::Unchecked observers_;
 
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager.cc b/components/policy/core/common/cloud/user_cloud_policy_manager.cc
index 4201a729..3a86a3e 100644
--- a/components/policy/core/common/cloud/user_cloud_policy_manager.cc
+++ b/components/policy/core/common/cloud/user_cloud_policy_manager.cc
@@ -52,6 +52,11 @@
   store_->SetSigninAccountId(account_id);
 }
 
+void UserCloudPolicyManager::SetPoliciesRequired(bool required) {
+  policies_required_ = required;
+  RefreshPolicies();
+}
+
 void UserCloudPolicyManager::Connect(
     PrefService* local_state,
     std::unique_ptr<CloudPolicyClient> client) {
@@ -95,6 +100,7 @@
   // all external data references have been removed, causing the
   // |external_data_manager_| to clear its cache as well.
   store_->Clear();
+  SetPoliciesRequired(false);
 }
 
 bool UserCloudPolicyManager::IsClientRegistered() const {
@@ -119,4 +125,10 @@
 #endif
 }
 
+bool UserCloudPolicyManager::IsFirstPolicyLoadComplete(
+    PolicyDomain domain) const {
+  return !policies_required_ ||
+         CloudPolicyManager::IsFirstPolicyLoadComplete(domain);
+}
+
 }  // namespace policy
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager.h b/components/policy/core/common/cloud/user_cloud_policy_manager.h
index d3c188b9..2841f96 100644
--- a/components/policy/core/common/cloud/user_cloud_policy_manager.h
+++ b/components/policy/core/common/cloud/user_cloud_policy_manager.h
@@ -50,6 +50,11 @@
 
   void SetSigninAccountId(const AccountId& account_id);
 
+  // Sets whether or not policies are required for this policy manager.
+  // This might be set to false if the user profile is an unmanaged consumer
+  // profile.
+  void SetPoliciesRequired(bool required);
+
   // Initializes the cloud connection. |local_state| must stay valid until this
   // object is deleted or DisconnectAndRemovePolicy() gets called. Virtual for
   // mocking.
@@ -75,10 +80,15 @@
       DeviceManagementService* device_management_service,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
 
+  // ConfigurationPolicyProvider:
+  bool IsFirstPolicyLoadComplete(PolicyDomain domain) const override;
+
  private:
   // CloudPolicyManager:
   void GetChromePolicy(PolicyMap* policy_map) override;
 
+  bool policies_required_;
+
   // Typed pointer to the store owned by UserCloudPolicyManager. Note that
   // CloudPolicyManager only keeps a plain CloudPolicyStore pointer.
   std::unique_ptr<UserCloudPolicyStore> store_;
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager_unittest.cc b/components/policy/core/common/cloud/user_cloud_policy_manager_unittest.cc
index 001aeef..89fcc7d0 100644
--- a/components/policy/core/common/cloud/user_cloud_policy_manager_unittest.cc
+++ b/components/policy/core/common/cloud/user_cloud_policy_manager_unittest.cc
@@ -82,7 +82,7 @@
   // called.
   CreateManager();
   store_->policy_map_.CopyFrom(policy_map_);
-  EXPECT_CALL(observer_, OnUpdatePolicy(manager_.get()));
+  EXPECT_CALL(observer_, OnUpdatePolicy(manager_.get())).Times(2);
   store_->NotifyStoreLoaded();
   EXPECT_TRUE(expected_bundle_.Equals(manager_->policies()));
   EXPECT_TRUE(manager_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
diff --git a/components/policy/core/common/command_line_policy_provider.cc b/components/policy/core/common/command_line_policy_provider.cc
index 7814a44..7b262cc 100644
--- a/components/policy/core/common/command_line_policy_provider.cc
+++ b/components/policy/core/common/command_line_policy_provider.cc
@@ -48,9 +48,15 @@
 
 void CommandLinePolicyProvider::RefreshPolicies() {
   std::unique_ptr<PolicyBundle> bundle = loader_.Load();
+  first_policies_loaded_ = true;
   UpdatePolicy(std::move(bundle));
 }
 
+bool CommandLinePolicyProvider::IsFirstPolicyLoadComplete(
+    PolicyDomain domain) const {
+  return first_policies_loaded_;
+}
+
 CommandLinePolicyProvider::CommandLinePolicyProvider(
     const base::CommandLine& command_line)
     : loader_(command_line) {
diff --git a/components/policy/core/common/command_line_policy_provider.h b/components/policy/core/common/command_line_policy_provider.h
index b1af43f..fb6cade 100644
--- a/components/policy/core/common/command_line_policy_provider.h
+++ b/components/policy/core/common/command_line_policy_provider.h
@@ -35,10 +35,12 @@
 
   // ConfigurationPolicyProvider implementation.
   void RefreshPolicies() override;
+  bool IsFirstPolicyLoadComplete(PolicyDomain domain) const override;
 
  private:
   explicit CommandLinePolicyProvider(const base::CommandLine& command_line);
 
+  bool first_policies_loaded_;
   PolicyLoaderCommandLine loader_;
 };
 
diff --git a/components/policy/core/common/configuration_policy_provider.cc b/components/policy/core/common/configuration_policy_provider.cc
index 0a3fa12..4396245 100644
--- a/components/policy/core/common/configuration_policy_provider.cc
+++ b/components/policy/core/common/configuration_policy_provider.cc
@@ -41,6 +41,11 @@
   return true;
 }
 
+bool ConfigurationPolicyProvider::IsFirstPolicyLoadComplete(
+    PolicyDomain domain) const {
+  return true;
+}
+
 void ConfigurationPolicyProvider::UpdatePolicy(
     std::unique_ptr<PolicyBundle> bundle) {
   if (bundle) {
diff --git a/components/policy/core/common/configuration_policy_provider.h b/components/policy/core/common/configuration_policy_provider.h
index 9f49b261..f92875c 100644
--- a/components/policy/core/common/configuration_policy_provider.h
+++ b/components/policy/core/common/configuration_policy_provider.h
@@ -60,6 +60,12 @@
   // case implementations need to do asynchronous operations for initialization.
   virtual bool IsInitializationComplete(PolicyDomain domain) const;
 
+  // Check whether this provider has loaded its first policies for the given
+  // policy |domain|. This is used to detect whether policies have been loaded
+  // is done in case implementations need to do asynchronous operations to get
+  // the policies.
+  virtual bool IsFirstPolicyLoadComplete(PolicyDomain domain) const;
+
   // Asks the provider to refresh its policies. All the updates caused by this
   // call will be visible on the next call of OnUpdatePolicy on the observers,
   // which are guaranteed to happen even if the refresh fails.
diff --git a/components/policy/core/common/mock_configuration_policy_provider.h b/components/policy/core/common/mock_configuration_policy_provider.h
index 76dbdb0f..ebba2345 100644
--- a/components/policy/core/common/mock_configuration_policy_provider.h
+++ b/components/policy/core/common/mock_configuration_policy_provider.h
@@ -24,6 +24,7 @@
   ~MockConfigurationPolicyProvider() override;
 
   MOCK_CONST_METHOD1(IsInitializationComplete, bool(PolicyDomain domain));
+  MOCK_CONST_METHOD1(IsFirstPolicyLoadComplete, bool(PolicyDomain domain));
   MOCK_METHOD0(RefreshPolicies, void());
 
   // Make public for tests.
diff --git a/components/policy/core/common/mock_policy_service.h b/components/policy/core/common/mock_policy_service.h
index 9c62bbf5..738be0e 100644
--- a/components/policy/core/common/mock_policy_service.h
+++ b/components/policy/core/common/mock_policy_service.h
@@ -20,6 +20,7 @@
                                      const PolicyMap& previous,
                                      const PolicyMap& current));
   MOCK_METHOD1(OnPolicyServiceInitialized, void(PolicyDomain));
+  MOCK_METHOD1(OnFirstPoliciesLoaded, void(PolicyDomain));
 };
 
 class MockPolicyServiceProviderUpdateObserver
@@ -45,6 +46,7 @@
 
   MOCK_CONST_METHOD1(GetPolicies, const PolicyMap&(const PolicyNamespace&));
   MOCK_CONST_METHOD1(IsInitializationComplete, bool(PolicyDomain domain));
+  MOCK_CONST_METHOD1(IsFirstPolicyLoadComplete, bool(PolicyDomain domain));
   MOCK_METHOD1(RefreshPolicies, void(base::OnceClosure));
 
 #if defined(OS_ANDROID)
diff --git a/components/policy/core/common/policy_service.h b/components/policy/core/common/policy_service.h
index d6eb4bb..a17c497 100644
--- a/components/policy/core/common/policy_service.h
+++ b/components/policy/core/common/policy_service.h
@@ -48,9 +48,19 @@
     // Invoked at most once for each |domain|, when the PolicyService becomes
     // ready. If IsInitializationComplete() is false, then this will be invoked
     // once all the policy providers have finished loading their policies for
-    // |domain|.
+    // |domain|. This does not handle failure to load policies from some
+    // providers, so it is possible for for the policy service to be initialised
+    // if the providers failed for example to load its policies cache.
     virtual void OnPolicyServiceInitialized(PolicyDomain domain) {}
 
+    // Invoked at most once for each |domain|, when the PolicyService becomes
+    // ready. If IsFirstPolicyLoadComplete() is false, then this will be invoked
+    // once all the policy providers have finished loading their policies for
+    // |domain|. The difference from |OnPolicyServiceInitialized| is that this
+    // will wait for cloud policies to be fetched when the local cache is not
+    // available, which may take some time depending on user's network.
+    virtual void OnFirstPoliciesLoaded(PolicyDomain domain) {}
+
    protected:
     virtual ~Observer() {}
   };
@@ -88,7 +98,7 @@
 
   // The PolicyService loads policy from several sources, and some require
   // asynchronous loads. IsInitializationComplete() returns true once all
-  // sources have loaded their policies for the given |domain|.
+  // sources have been initialized for the given |domain|.
   // It is safe to read policy from the PolicyService even if
   // IsInitializationComplete() is false; there will be an OnPolicyUpdated()
   // notification once new policies become available.
@@ -100,6 +110,20 @@
   // OnPolicyServiceInitialized() notification.
   virtual bool IsInitializationComplete(PolicyDomain domain) const = 0;
 
+  // The PolicyService loads policy from several sources, and some require
+  // asynchronous loads. IsFirstPolicyLoadComplete() returns true once all
+  // sources have loaded their initial policies for the given |domain|.
+  // It is safe to read policy from the PolicyService even if
+  // IsFirstPolicyLoadComplete() is false; there will be an OnPolicyUpdated()
+  // notification once new policies become available.
+  //
+  // OnFirstPoliciesLoaded() is called when IsFirstPolicyLoadComplete()
+  // becomes true, which happens at most once for each domain.
+  // If IsFirstPolicyLoadComplete() is already true for |domain| when an
+  // Observer is registered, then that Observer will not receive an
+  // OnFirstPoliciesLoaded() notification.
+  virtual bool IsFirstPolicyLoadComplete(PolicyDomain domain) const = 0;
+
   // Asks the PolicyService to reload policy from all available policy sources.
   // |callback| is invoked once every source has reloaded its policies, and
   // GetPolicies() is guaranteed to return the updated values at that point.
diff --git a/components/policy/core/common/policy_service_impl.cc b/components/policy/core/common/policy_service_impl.cc
index a1055d6..8c42e01 100644
--- a/components/policy/core/common/policy_service_impl.cc
+++ b/components/policy/core/common/policy_service_impl.cc
@@ -102,14 +102,11 @@
       migrators_(std::move(migrators)),
       initialization_throttled_(initialization_throttled) {
   for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain)
-    initialization_complete_[domain] = true;
-  for (auto* provider : providers_) {
+    policy_domain_status_[domain] = PolicyDomainStatus::kUninitialized;
+
+  for (auto* provider : providers_)
     provider->AddObserver(this);
-    for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) {
-      initialization_complete_[domain] &=
-          provider->IsInitializationComplete(static_cast<PolicyDomain>(domain));
-    }
-  }
+  CheckPolicyDomainStatus();
   // There are no observers yet, but calls to GetPolicies() should already get
   // the processed policy values.
   MergeAndTriggerUpdates();
@@ -178,9 +175,15 @@
 bool PolicyServiceImpl::IsInitializationComplete(PolicyDomain domain) const {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(domain >= 0 && domain < POLICY_DOMAIN_SIZE);
-  if (initialization_throttled_)
-    return false;
-  return initialization_complete_[domain];
+  return !initialization_throttled_ &&
+         policy_domain_status_[domain] != PolicyDomainStatus::kUninitialized;
+}
+
+bool PolicyServiceImpl::IsFirstPolicyLoadComplete(PolicyDomain domain) const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(domain >= 0 && domain < POLICY_DOMAIN_SIZE);
+  return !initialization_throttled_ &&
+         policy_domain_status_[domain] == PolicyDomainStatus::kPolicyReady;
 }
 
 void PolicyServiceImpl::RefreshPolicies(base::OnceClosure callback) {
@@ -222,7 +225,7 @@
 
   initialization_throttled_ = false;
   for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain)
-    MaybeNotifyInitializationComplete(static_cast<PolicyDomain>(domain));
+    MaybeNotifyPolicyDomainStatusChange(static_cast<PolicyDomain>(domain));
 }
 
 void PolicyServiceImpl::OnUpdatePolicy(ConfigurationPolicyProvider* provider) {
@@ -357,46 +360,56 @@
   for (; it_old != end_old; ++it_old)
     NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty);
 
-  CheckInitializationComplete();
+  CheckPolicyDomainStatus();
   CheckRefreshComplete();
   NotifyProviderUpdatesPropagated();
 }
 
-void PolicyServiceImpl::CheckInitializationComplete() {
+void PolicyServiceImpl::CheckPolicyDomainStatus() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   // Check if all the providers just became initialized for each domain; if so,
-  // notify that domain's observers.
+  // notify that domain's observers. If they were initialized, check if they had
+  // their first policies loaded.
   for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) {
-    if (initialization_complete_[domain])
+    PolicyDomain policy_domain = static_cast<PolicyDomain>(domain);
+    if (policy_domain_status_[domain] == PolicyDomainStatus::kPolicyReady)
       continue;
 
-    PolicyDomain policy_domain = static_cast<PolicyDomain>(domain);
+    PolicyDomainStatus new_status = PolicyDomainStatus::kPolicyReady;
 
-    bool all_complete = true;
     for (auto* provider : providers_) {
       if (!provider->IsInitializationComplete(policy_domain)) {
-        all_complete = false;
+        new_status = PolicyDomainStatus::kUninitialized;
         break;
+      } else if (!provider->IsFirstPolicyLoadComplete(policy_domain)) {
+        new_status = PolicyDomainStatus::kInitialized;
       }
     }
-    if (all_complete) {
-      initialization_complete_[domain] = true;
-      MaybeNotifyInitializationComplete(policy_domain);
-    }
+
+    if (new_status == policy_domain_status_[domain])
+      continue;
+
+    policy_domain_status_[domain] = new_status;
+    MaybeNotifyPolicyDomainStatusChange(policy_domain);
   }
 }
-
-void PolicyServiceImpl::MaybeNotifyInitializationComplete(
+void PolicyServiceImpl::MaybeNotifyPolicyDomainStatusChange(
     PolicyDomain policy_domain) {
-  if (initialization_throttled_)
+  if (initialization_throttled_ || policy_domain_status_[policy_domain] ==
+                                       PolicyDomainStatus::kUninitialized) {
     return;
-  if (!initialization_complete_[policy_domain])
-    return;
+  }
+
   auto iter = observers_.find(policy_domain);
-  if (iter != observers_.end()) {
-    for (auto& observer : *iter->second)
-      observer.OnPolicyServiceInitialized(policy_domain);
+  if (iter == observers_.end())
+    return;
+
+  for (auto& observer : *iter->second) {
+    observer.OnPolicyServiceInitialized(policy_domain);
+    if (policy_domain_status_[policy_domain] ==
+        PolicyDomainStatus::kPolicyReady)
+      observer.OnFirstPoliciesLoaded(policy_domain);
   }
 }
 
diff --git a/components/policy/core/common/policy_service_impl.h b/components/policy/core/common/policy_service_impl.h
index dde427f..dc7189d 100644
--- a/components/policy/core/common/policy_service_impl.h
+++ b/components/policy/core/common/policy_service_impl.h
@@ -67,6 +67,7 @@
   bool HasProvider(ConfigurationPolicyProvider* provider) const override;
   const PolicyMap& GetPolicies(const PolicyNamespace& ns) const override;
   bool IsInitializationComplete(PolicyDomain domain) const override;
+  bool IsFirstPolicyLoadComplete(PolicyDomain domain) const override;
   void RefreshPolicies(base::OnceClosure callback) override;
 #if defined(OS_ANDROID)
   android::PolicyServiceAndroid* GetPolicyServiceAndroid() override;
@@ -81,6 +82,8 @@
   void UnthrottleInitialization();
 
  private:
+  enum class PolicyDomainStatus { kUninitialized, kInitialized, kPolicyReady };
+
   using Observers =
       base::ObserverList<PolicyService::Observer, true>::Unchecked;
 
@@ -109,16 +112,17 @@
   // of namespaces whose policies have been modified.
   void MergeAndTriggerUpdates();
 
-  // Checks if all providers are initialized and sets |initialization_complete_|
-  // accordingly. If initialization is not throttled, will also notify the
-  // observers if the service just became initialized.
-  void CheckInitializationComplete();
+  // Checks if all providers are initialized or have loaded their policies and
+  // sets |policy_domain_status_| accordingly. If initialization is not
+  // throttled, will also notify the observers of the appropriate status.
+  void CheckPolicyDomainStatus();
 
-  // If initialization is complete for |policy_domain| and initialization is not
-  // throttled, will notify obserers for |policy_domain| that it has been
-  // initialized. This function should only be called when |policy_domain| just
-  // became initialized or when initialization has been unthrottled.
-  void MaybeNotifyInitializationComplete(PolicyDomain policy_domain);
+  // If initialization is not throttled, observers of |policy_domain| of the
+  // initialization will be notified of the domains' initialization and of the
+  // first policies being loaded. This function should only be called when
+  // |policy_domain| just became initialized, just got its first policies or
+  // when initialization has been unthrottled.
+  void MaybeNotifyPolicyDomainStatusChange(PolicyDomain policy_domain);
 
   // Invokes all the refresh callbacks if there are no more refreshes pending.
   void CheckRefreshComplete();
@@ -134,8 +138,8 @@
   // Maps each policy domain to its observer list.
   std::map<PolicyDomain, std::unique_ptr<Observers>> observers_;
 
-  // True if all the providers are initialized for the indexed policy domain.
-  bool initialization_complete_[POLICY_DOMAIN_SIZE];
+  // The status of all the providers for the indexed policy domain.
+  PolicyDomainStatus policy_domain_status_[POLICY_DOMAIN_SIZE];
 
   // Set of providers that have a pending update that was triggered by a
   // call to RefreshPolicies().
diff --git a/components/policy/core/common/policy_service_impl_unittest.cc b/components/policy/core/common/policy_service_impl_unittest.cc
index 704913f..ad388015 100644
--- a/components/policy/core/common/policy_service_impl_unittest.cc
+++ b/components/policy/core/common/policy_service_impl_unittest.cc
@@ -113,6 +113,12 @@
         .WillRepeatedly(Return(true));
     EXPECT_CALL(provider2_, IsInitializationComplete(_))
         .WillRepeatedly(Return(true));
+    EXPECT_CALL(provider0_, IsFirstPolicyLoadComplete(_))
+        .WillRepeatedly(Return(true));
+    EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(_))
+        .WillRepeatedly(Return(true));
+    EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
+        .WillRepeatedly(Return(true));
 
     provider0_.Init();
     provider1_.Init();
@@ -635,6 +641,10 @@
       .WillRepeatedly(Return(false));
   EXPECT_CALL(provider2_, IsInitializationComplete(_))
       .WillRepeatedly(Return(false));
+  EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(_))
+      .WillRepeatedly(Return(false));
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
+      .WillRepeatedly(Return(false));
   PolicyServiceImpl::Providers providers;
   providers.push_back(&provider0_);
   providers.push_back(&provider1_);
@@ -654,6 +664,8 @@
   policy_service_->AddObserver(POLICY_DOMAIN_SIGNIN_EXTENSIONS, &observer);
   EXPECT_CALL(observer, OnPolicyServiceInitialized(_)).Times(0);
   Mock::VerifyAndClearExpectations(&provider1_);
+  EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(_))
+      .WillRepeatedly(Return(false));
   EXPECT_CALL(provider1_, IsInitializationComplete(POLICY_DOMAIN_CHROME))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(provider1_, IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS))
@@ -673,6 +685,8 @@
   // Same if |provider1_| doesn't have POLICY_DOMAIN_EXTENSIONS initialized.
   EXPECT_CALL(observer, OnPolicyServiceInitialized(_)).Times(0);
   Mock::VerifyAndClearExpectations(&provider2_);
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
+      .WillRepeatedly(Return(false));
   EXPECT_CALL(provider2_, IsInitializationComplete(POLICY_DOMAIN_CHROME))
       .WillRepeatedly(Return(false));
   EXPECT_CALL(provider2_, IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS))
@@ -691,6 +705,8 @@
   // Now initialize POLICY_DOMAIN_CHROME on all the providers.
   EXPECT_CALL(observer, OnPolicyServiceInitialized(POLICY_DOMAIN_CHROME));
   Mock::VerifyAndClearExpectations(&provider2_);
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
+      .WillRepeatedly(Return(false));
   EXPECT_CALL(provider2_, IsInitializationComplete(POLICY_DOMAIN_CHROME))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(provider2_, IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS))
@@ -712,6 +728,8 @@
   EXPECT_CALL(observer,
               OnPolicyServiceInitialized(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
   Mock::VerifyAndClearExpectations(&provider1_);
+  EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(_))
+      .WillRepeatedly(Return(false));
   EXPECT_CALL(provider1_, IsInitializationComplete(POLICY_DOMAIN_CHROME))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(provider1_, IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS))
@@ -736,7 +754,7 @@
 // Tests initialization throttling of PolicyServiceImpl.
 // This actually tests two cases:
 // (1) A domain was initialized before UnthrottleInitialization is called.
-//     Observers only get notified after calling UntrhottleInitialization.
+//     Observers only get notified after calling UnthrottleInitialization.
 //     This is tested on POLICY_DOMAIN_CHROME.
 // (2) A domain becomes initialized after UnthrottleInitialization has already
 //     been called. Because initialization is not throttled anymore, observers
@@ -749,6 +767,8 @@
   Mock::VerifyAndClearExpectations(&provider2_);
   EXPECT_CALL(provider2_, IsInitializationComplete(_))
       .WillRepeatedly(Return(false));
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
+      .WillRepeatedly(Return(false));
   PolicyServiceImpl::Providers providers;
   providers.push_back(&provider0_);
   providers.push_back(&provider1_);
@@ -761,6 +781,13 @@
   EXPECT_FALSE(policy_service_->IsInitializationComplete(
       POLICY_DOMAIN_SIGNIN_EXTENSIONS));
 
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
+      POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+
   MockPolicyServiceObserver observer;
   policy_service_->AddObserver(POLICY_DOMAIN_CHROME, &observer);
   policy_service_->AddObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
@@ -768,7 +795,8 @@
 
   // Now additionally initialize POLICY_DOMAIN_CHROME on |provider2_|.
   // Note: VerifyAndClearExpectations is called to reset the previously set
-  // action for IsInitializtionComplete on |provider_2|.
+  // action for IsInitializationComplete and IsFirstPolicyLoadComplete on
+  // |provider_2|.
   Mock::VerifyAndClearExpectations(&provider2_);
   EXPECT_CALL(provider2_, IsInitializationComplete(POLICY_DOMAIN_CHROME))
       .WillRepeatedly(Return(true));
@@ -778,8 +806,17 @@
               IsInitializationComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
       .WillRepeatedly(Return(false));
 
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS))
+      .WillRepeatedly(Return(false));
+  EXPECT_CALL(provider2_,
+              IsFirstPolicyLoadComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
+      .WillRepeatedly(Return(false));
+
   // Nothing will happen because initialization is still throttled.
   EXPECT_CALL(observer, OnPolicyServiceInitialized(_)).Times(0);
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(_)).Times(0);
   const PolicyMap kPolicyMap;
   provider2_.UpdateChromePolicy(kPolicyMap);
   Mock::VerifyAndClearExpectations(&observer);
@@ -789,10 +826,19 @@
   EXPECT_FALSE(policy_service_->IsInitializationComplete(
       POLICY_DOMAIN_SIGNIN_EXTENSIONS));
 
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
+      POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+
   // Unthrottle initialization. This will signal that POLICY_DOMAIN_CHROME is
   // initialized, the other domains should still not be initialized because
-  // |provider2_| is returning false in IsInitializationComplete for them.
+  // |provider2_| is returning false in IsInitializationComplete and
+  // IsFirstPolicyLoadComplete for them.
   EXPECT_CALL(observer, OnPolicyServiceInitialized(POLICY_DOMAIN_CHROME));
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_CHROME));
   policy_service_->UnthrottleInitialization();
   Mock::VerifyAndClearExpectations(&observer);
   EXPECT_TRUE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
@@ -801,16 +847,27 @@
   EXPECT_FALSE(policy_service_->IsInitializationComplete(
       POLICY_DOMAIN_SIGNIN_EXTENSIONS));
 
+  EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
+      POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+
   // Initialize the remaining domains.
   // Note: VerifyAndClearExpectations is called to reset the previously set
-  // action for IsInitializtionComplete on |provider_2|.
+  // action for IsInitializationComplete and IsFirstPolicyLoadComplete on
+  // |provider_2|.
   Mock::VerifyAndClearExpectations(&provider2_);
   EXPECT_CALL(provider2_, IsInitializationComplete(_))
       .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
+      .WillRepeatedly(Return(true));
 
   EXPECT_CALL(observer, OnPolicyServiceInitialized(POLICY_DOMAIN_EXTENSIONS));
   EXPECT_CALL(observer,
               OnPolicyServiceInitialized(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
   provider2_.UpdateChromePolicy(kPolicyMap);
   Mock::VerifyAndClearExpectations(&observer);
   EXPECT_TRUE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
@@ -819,6 +876,12 @@
   EXPECT_TRUE(policy_service_->IsInitializationComplete(
       POLICY_DOMAIN_SIGNIN_EXTENSIONS));
 
+  EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
+  EXPECT_TRUE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(
+      POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+
   // Cleanup.
   policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, &observer);
   policy_service_->RemoveObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
@@ -839,6 +902,13 @@
   EXPECT_FALSE(policy_service_->IsInitializationComplete(
       POLICY_DOMAIN_SIGNIN_EXTENSIONS));
 
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
+      POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+
   MockPolicyServiceObserver observer;
   policy_service_->AddObserver(POLICY_DOMAIN_CHROME, &observer);
   policy_service_->AddObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
@@ -850,6 +920,9 @@
   EXPECT_CALL(observer, OnPolicyServiceInitialized(POLICY_DOMAIN_EXTENSIONS));
   EXPECT_CALL(observer,
               OnPolicyServiceInitialized(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_CHROME));
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
   policy_service_->UnthrottleInitialization();
   Mock::VerifyAndClearExpectations(&observer);
   EXPECT_TRUE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
@@ -858,6 +931,132 @@
   EXPECT_TRUE(policy_service_->IsInitializationComplete(
       POLICY_DOMAIN_SIGNIN_EXTENSIONS));
 
+  EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
+  EXPECT_TRUE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(
+      POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+
+  // Cleanup.
+  policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, &observer);
+  policy_service_->RemoveObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
+  policy_service_->RemoveObserver(POLICY_DOMAIN_SIGNIN_EXTENSIONS, &observer);
+}
+
+TEST_F(PolicyServiceTest, IsFirstPolicyLoadComplete) {
+  // |provider0_| has all domains initialized.
+  Mock::VerifyAndClearExpectations(&provider1_);
+  Mock::VerifyAndClearExpectations(&provider2_);
+  EXPECT_CALL(provider1_, IsInitializationComplete(_))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider2_, IsInitializationComplete(_))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(_))
+      .WillRepeatedly(Return(false));
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
+      .WillRepeatedly(Return(false));
+  PolicyServiceImpl::Providers providers;
+  providers.push_back(&provider0_);
+  providers.push_back(&provider1_);
+  providers.push_back(&provider2_);
+  policy_service_ = std::make_unique<PolicyServiceImpl>(std::move(providers));
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
+      POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+
+  // |provider2_| still doesn't have POLICY_DOMAIN_CHROME initialized, so
+  // the initialization status of that domain won't change.
+  MockPolicyServiceObserver observer;
+  policy_service_->AddObserver(POLICY_DOMAIN_CHROME, &observer);
+  policy_service_->AddObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
+  policy_service_->AddObserver(POLICY_DOMAIN_SIGNIN_EXTENSIONS, &observer);
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(_)).Times(0);
+  Mock::VerifyAndClearExpectations(&provider1_);
+  EXPECT_CALL(provider1_, IsInitializationComplete(_))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS))
+      .WillRepeatedly(Return(false));
+  EXPECT_CALL(provider1_,
+              IsFirstPolicyLoadComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
+      .WillRepeatedly(Return(false));
+  const PolicyMap kPolicyMap;
+  provider1_.UpdateChromePolicy(kPolicyMap);
+  Mock::VerifyAndClearExpectations(&observer);
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
+      POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+
+  // Same if |provider1_| doesn't have POLICY_DOMAIN_EXTENSIONS initialized.
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(_)).Times(0);
+  Mock::VerifyAndClearExpectations(&provider2_);
+  EXPECT_CALL(provider2_, IsInitializationComplete(_))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME))
+      .WillRepeatedly(Return(false));
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider2_,
+              IsFirstPolicyLoadComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
+      .WillRepeatedly(Return(true));
+  provider2_.UpdateChromePolicy(kPolicyMap);
+  Mock::VerifyAndClearExpectations(&observer);
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
+      POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+
+  // Now initialize POLICY_DOMAIN_CHROME on all the providers.
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_CHROME));
+  Mock::VerifyAndClearExpectations(&provider2_);
+  EXPECT_CALL(provider2_, IsInitializationComplete(_))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider2_,
+              IsFirstPolicyLoadComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
+      .WillRepeatedly(Return(true));
+  provider2_.UpdateChromePolicy(kPolicyMap);
+  Mock::VerifyAndClearExpectations(&observer);
+  EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
+  // Other domains are still not initialized.
+  EXPECT_FALSE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
+      POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+
+  // Initialize the remaining domains.
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+  Mock::VerifyAndClearExpectations(&provider1_);
+  EXPECT_CALL(provider1_, IsInitializationComplete(_))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(provider1_,
+              IsFirstPolicyLoadComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
+      .WillRepeatedly(Return(true));
+  provider1_.UpdateChromePolicy(kPolicyMap);
+  Mock::VerifyAndClearExpectations(&observer);
+  EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
+  EXPECT_TRUE(
+      policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(
+      POLICY_DOMAIN_SIGNIN_EXTENSIONS));
+
   // Cleanup.
   policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, &observer);
   policy_service_->RemoveObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
diff --git a/components/policy/core/common/proxy_policy_provider.cc b/components/policy/core/common/proxy_policy_provider.cc
index 6d6072f..a5cf64435 100644
--- a/components/policy/core/common/proxy_policy_provider.cc
+++ b/components/policy/core/common/proxy_policy_provider.cc
@@ -54,6 +54,10 @@
   }
 }
 
+bool ProxyPolicyProvider::IsFirstPolicyLoadComplete(PolicyDomain domain) const {
+  return delegate_ && delegate_->IsInitializationComplete(domain);
+}
+
 void ProxyPolicyProvider::OnUpdatePolicy(
     ConfigurationPolicyProvider* provider) {
   if (block_policy_updates_for_testing_)
diff --git a/components/policy/core/common/proxy_policy_provider.h b/components/policy/core/common/proxy_policy_provider.h
index 683cd13..599de9f 100644
--- a/components/policy/core/common/proxy_policy_provider.h
+++ b/components/policy/core/common/proxy_policy_provider.h
@@ -49,6 +49,7 @@
   // ConfigurationPolicyProvider:
   void Shutdown() override;
   void RefreshPolicies() override;
+  bool IsFirstPolicyLoadComplete(PolicyDomain domain) const override;
 
   // ConfigurationPolicyProvider::Observer:
   void OnUpdatePolicy(ConfigurationPolicyProvider* provider) override;
diff --git a/components/policy/core/common/schema_registry_tracking_policy_provider.cc b/components/policy/core/common/schema_registry_tracking_policy_provider.cc
index 8dc00b93..8af6029 100644
--- a/components/policy/core/common/schema_registry_tracking_policy_provider.cc
+++ b/components/policy/core/common/schema_registry_tracking_policy_provider.cc
@@ -37,6 +37,14 @@
   return state_ == READY;
 }
 
+bool SchemaRegistryTrackingPolicyProvider::IsFirstPolicyLoadComplete(
+    PolicyDomain domain) const {
+  if (domain == POLICY_DOMAIN_CHROME)
+    return delegate_->IsFirstPolicyLoadComplete(domain);
+  // This provider keeps its own state for all the other domains.
+  return state_ == READY;
+}
+
 void SchemaRegistryTrackingPolicyProvider::RefreshPolicies() {
   delegate_->RefreshPolicies();
 }
diff --git a/components/policy/core/common/schema_registry_tracking_policy_provider.h b/components/policy/core/common/schema_registry_tracking_policy_provider.h
index 1ec64c3b..592be9d 100644
--- a/components/policy/core/common/schema_registry_tracking_policy_provider.h
+++ b/components/policy/core/common/schema_registry_tracking_policy_provider.h
@@ -67,6 +67,7 @@
   // provider doesn't have a "real" policy source of its own.
   void Init(SchemaRegistry* registry) override;
   bool IsInitializationComplete(PolicyDomain domain) const override;
+  bool IsFirstPolicyLoadComplete(PolicyDomain domain) const override;
   void RefreshPolicies() override;
   void OnSchemaRegistryReady() override;
   void OnSchemaRegistryUpdated(bool has_new_schemas) override;
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index a5c0cc4..b8f4b85 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -3063,6 +3063,28 @@
     CRX_REQUIRED_PROOF_MISSING = 42;
   }
 
+  // Reason why extension failed due to failure reason MANIFEST_INVALID. See
+  // extensions::ManifestInvalidError for more details.
+  // extensions::ManifestInvalidError is the main enum and this is a
+  // copy used for reporting purposes.
+  enum ManifestInvalidError {
+    MANIFEST_INVALID_ERROR_UNKNOWN = 0;
+    XML_PARSING_FAILED = 1;
+    INVALID_XLMNS_ON_GUPDATE_TAG = 2;
+    MISSING_GUPDATE_TAG = 3;
+    INVALID_PROTOCOL_ON_GUPDATE_TAG = 4;
+    MISSING_APP_ID = 5;
+    MISSING_UPDATE_CHECK_TAGS = 6;
+    MULTIPLE_UPDATE_CHECK_TAGS = 7;
+    INVALID_PRODVERSION_MIN = 8;
+    EMPTY_CODEBASE_URL = 9;
+    INVALID_CODEBASE_URL = 10;
+    MISSING_VERSION_FOR_UPDATE_CHECK = 11;
+    INVALID_VERSION = 12;
+    BAD_UPDATE_SPECIFICATION = 13;
+    BAD_APP_STATUS = 14;
+  };
+
   // Timestamp, in microseconds since epoch. Set for all log
   // events.
   optional int64 timestamp = 1;
@@ -3113,6 +3135,10 @@
 
   // Detailed reason why unpacking of extension failed.
   optional SandboxedUnpackerFailureReason unpacker_failure_reason = 16;
+
+  // Detailed reason why extension failed due to failure reason
+  // MANIFEST_INVALID.
+  optional ManifestInvalidError manifest_invalid_error = 17;
 }
 
 // A single entry in the push-install log for an app.
diff --git a/components/policy/tools/syntax_check_policy_template_json.py b/components/policy/tools/syntax_check_policy_template_json.py
index a75e1bf6..920267b 100755
--- a/components/policy/tools/syntax_check_policy_template_json.py
+++ b/components/policy/tools/syntax_check_policy_template_json.py
@@ -274,7 +274,8 @@
       Error: Value of |key| must be a |value_type|.
       Offending snippet: |container[key]|
 
-    Returns: |container[key]| if the key is present, None otherwise.
+    Returns: |container[key]| if the key is present and there are no errors,
+             None otherwise.
     '''
     if identifier is None:
       try:
@@ -302,10 +303,12 @@
           'Value of "%s" must be one of [ %s ].' % (key, ', '.join(
               [type.__name__ for type in value_types])), container_name,
           identifier, value)
+      return None
     if str in value_types and regexp_check and not regexp_check.match(value):
       self._Error(
           'Value of "%s" must match "%s".' % (key, regexp_check.pattern),
           container_name, identifier, value)
+      return None
     return value
 
   def _AddPolicyID(self, id, policy_ids, policy, deleted_policy_ids):
diff --git a/components/safe_browsing/content/password_protection/BUILD.gn b/components/safe_browsing/content/password_protection/BUILD.gn
index 2f35e59..f78c297e 100644
--- a/components/safe_browsing/content/password_protection/BUILD.gn
+++ b/components/safe_browsing/content/password_protection/BUILD.gn
@@ -14,8 +14,6 @@
       "password_protection_request.h",
       "password_protection_service.cc",
       "password_protection_service.h",
-      "visual_utils.cc",
-      "visual_utils.h",
     ]
 
     public_deps = [ "//google_apis:google_apis" ]
@@ -75,9 +73,7 @@
       "password_protection_navigation_throttle_unittest.cc",
       "password_protection_service_unittest.cc",
     ]
-    if (safe_browsing_mode == 1) {
-      sources += [ "visual_utils_unittest.cc" ]
-    }
+
     deps = [
       ":mock_password_protection",
       ":password_protection",
diff --git a/components/safe_browsing/content/password_protection/password_protection_request.cc b/components/safe_browsing/content/password_protection/password_protection_request.cc
index cb203a15..87844b8 100644
--- a/components/safe_browsing/content/password_protection/password_protection_request.cc
+++ b/components/safe_browsing/content/password_protection/password_protection_request.cc
@@ -18,8 +18,8 @@
 #include "components/safe_browsing/content/common/safe_browsing.mojom.h"
 #include "components/safe_browsing/content/password_protection/metrics_util.h"
 #include "components/safe_browsing/content/password_protection/password_protection_navigation_throttle.h"
-#include "components/safe_browsing/content/password_protection/visual_utils.h"
 #include "components/safe_browsing/content/web_ui/safe_browsing_ui.h"
+#include "components/safe_browsing/core/common/visual_utils.h"
 #include "components/safe_browsing/core/db/allowlist_checker_client.h"
 #include "components/safe_browsing/core/features.h"
 #include "components/safe_browsing/core/proto/csd.pb.h"
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/DEPS b/components/safe_browsing/content/renderer/phishing_classifier/DEPS
index 1d01a3d..a62971e 100644
--- a/components/safe_browsing/content/renderer/phishing_classifier/DEPS
+++ b/components/safe_browsing/content/renderer/phishing_classifier/DEPS
@@ -1,7 +1,6 @@
 include_rules = [
   "+components/paint_preview/common",
   "+components/safe_browsing/content/renderer",
-  "+components/safe_browsing/content/password_protection/visual_utils.h",
   "+components/safe_browsing/core/common",
   "+components/safe_browsing/core/proto/csd.pb.h",
   "+components/safe_browsing/core/proto/client_model.pb.h",
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc b/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc
index 57c776a..d5c75a1 100644
--- a/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc
+++ b/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc
@@ -15,8 +15,8 @@
 #include "base/strings/string_piece.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
-#include "components/safe_browsing/content/password_protection/visual_utils.h"  // nogncheck crbug.com/1138547
 #include "components/safe_browsing/content/renderer/phishing_classifier/features.h"
+#include "components/safe_browsing/core/common/visual_utils.h"
 #include "components/safe_browsing/core/proto/client_model.pb.h"
 #include "components/safe_browsing/core/proto/csd.pb.h"
 #include "content/public/renderer/render_thread.h"
diff --git a/components/safe_browsing/core/common/BUILD.gn b/components/safe_browsing/core/common/BUILD.gn
index 29d87017..4f1a5d6 100644
--- a/components/safe_browsing/core/common/BUILD.gn
+++ b/components/safe_browsing/core/common/BUILD.gn
@@ -45,6 +45,7 @@
     "safe_browsing_policy_handler_unittest.cc",
     "safe_browsing_prefs_unittest.cc",
   ]
+
   deps = [
     ":safe_browsing_policy_handler",
     ":safe_browsing_prefs",
@@ -58,6 +59,14 @@
     "//testing/gtest",
     "//url:url",
   ]
+
+  if (safe_browsing_mode == 1) {
+    sources += [ "visual_utils_unittest.cc" ]
+    deps += [
+      ":common",
+      "//ui/gfx:color_utils",
+    ]
+  }
 }
 
 source_set("common") {
@@ -82,6 +91,18 @@
     "//url/ipc:url_ipc",
   ]
 
+  if (safe_browsing_mode == 1 || safe_browsing_mode == 2) {
+    sources += [
+      "visual_utils.cc",
+      "visual_utils.h",
+    ]
+    deps += [
+      "//components/safe_browsing/core:client_model_proto",
+      "//third_party/opencv:emd",
+      "//ui/gfx:color_utils",
+    ]
+  }
+
   public_deps = [ ":interfaces" ]
 
   if (!is_ios) {
diff --git a/components/safe_browsing/core/common/DEPS b/components/safe_browsing/core/common/DEPS
index bfcfa352..0e74e3e3 100644
--- a/components/safe_browsing/core/common/DEPS
+++ b/components/safe_browsing/core/common/DEPS
@@ -8,5 +8,8 @@
   "+content/public/test",
   "+crypto/sha2.h",
   "+ipc",
+  "+third_party/opencv",
+  "+third_party/skia/include",
+  "+ui/gfx",
   "+url"
 ]
diff --git a/components/safe_browsing/content/password_protection/visual_utils.cc b/components/safe_browsing/core/common/visual_utils.cc
similarity index 98%
rename from components/safe_browsing/content/password_protection/visual_utils.cc
rename to components/safe_browsing/core/common/visual_utils.cc
index c751167b..e064e184 100644
--- a/components/safe_browsing/content/password_protection/visual_utils.cc
+++ b/components/safe_browsing/core/common/visual_utils.cc
@@ -5,7 +5,7 @@
 #include <unordered_map>
 #include <vector>
 
-#include "components/safe_browsing/content/password_protection/visual_utils.h"
+#include "components/safe_browsing/core/common/visual_utils.h"
 
 #include "base/check_op.h"
 #include "base/numerics/checked_math.h"
diff --git a/components/safe_browsing/content/password_protection/visual_utils.h b/components/safe_browsing/core/common/visual_utils.h
similarity index 90%
rename from components/safe_browsing/content/password_protection/visual_utils.h
rename to components/safe_browsing/core/common/visual_utils.h
index 34b6764..7716ca7c 100644
--- a/components/safe_browsing/content/password_protection/visual_utils.h
+++ b/components/safe_browsing/core/common/visual_utils.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_PASSWORD_PROTECTION_VISUAL_UTILS_H_
-#define COMPONENTS_SAFE_BROWSING_CONTENT_PASSWORD_PROTECTION_VISUAL_UTILS_H_
+#ifndef COMPONENTS_SAFE_BROWSING_CORE_COMMON_VISUAL_UTILS_H_
+#define COMPONENTS_SAFE_BROWSING_CORE_COMMON_VISUAL_UTILS_H_
 
 #include <string>
 
@@ -52,4 +52,4 @@
 }  // namespace visual_utils
 }  // namespace safe_browsing
 
-#endif  // COMPONENTS_SAFE_BROWSING_CONTENT_PASSWORD_PROTECTION_VISUAL_UTILS_H_
+#endif  // COMPONENTS_SAFE_BROWSING_CORE_COMMON_VISUAL_UTILS_H_
diff --git a/components/safe_browsing/content/password_protection/visual_utils_unittest.cc b/components/safe_browsing/core/common/visual_utils_unittest.cc
similarity index 99%
rename from components/safe_browsing/content/password_protection/visual_utils_unittest.cc
rename to components/safe_browsing/core/common/visual_utils_unittest.cc
index 752e65dbe..6f6ee6e8 100644
--- a/components/safe_browsing/content/password_protection/visual_utils_unittest.cc
+++ b/components/safe_browsing/core/common/visual_utils_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/safe_browsing/content/password_protection/visual_utils.h"
+#include "components/safe_browsing/core/common/visual_utils.h"
 
 #include "base/test/test_discardable_memory_allocator.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/components/search/BUILD.gn b/components/search/BUILD.gn
index ea67c5c6..8fdf67a 100644
--- a/components/search/BUILD.gn
+++ b/components/search/BUILD.gn
@@ -4,6 +4,8 @@
 
 static_library("search") {
   sources = [
+    "ntp_features.cc",
+    "ntp_features.h",
     "search.cc",
     "search.h",
     "search_provider_observer.cc",
diff --git a/chrome/browser/search/ntp_features.cc b/components/search/ntp_features.cc
similarity index 98%
rename from chrome/browser/search/ntp_features.cc
rename to components/search/ntp_features.cc
index 2a95996..5e12251 100644
--- a/chrome/browser/search/ntp_features.cc
+++ b/components/search/ntp_features.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/search/ntp_features.h"
+#include "components/search/ntp_features.h"
 
 #include "base/feature_list.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/search/ntp_features.h b/components/search/ntp_features.h
similarity index 94%
rename from chrome/browser/search/ntp_features.h
rename to components/search/ntp_features.h
index 553f1c60..9ca7645 100644
--- a/chrome/browser/search/ntp_features.h
+++ b/components/search/ntp_features.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_SEARCH_NTP_FEATURES_H_
-#define CHROME_BROWSER_SEARCH_NTP_FEATURES_H_
+#ifndef COMPONENTS_SEARCH_NTP_FEATURES_H_
+#define COMPONENTS_SEARCH_NTP_FEATURES_H_
 
 #include "base/feature_list.h"
 
@@ -56,4 +56,4 @@
 
 }  // namespace ntp_features
 
-#endif  // CHROME_BROWSER_SEARCH_NTP_FEATURES_H_
+#endif  // COMPONENTS_SEARCH_NTP_FEATURES_H_
diff --git a/components/subresource_filter/content/browser/ads_intervention_manager.cc b/components/subresource_filter/content/browser/ads_intervention_manager.cc
index 051a088..92ef688e 100644
--- a/components/subresource_filter/content/browser/ads_intervention_manager.cc
+++ b/components/subresource_filter/content/browser/ads_intervention_manager.cc
@@ -4,6 +4,7 @@
 
 #include "components/subresource_filter/content/browser/ads_intervention_manager.h"
 
+#include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
 #include "base/values.h"
@@ -22,6 +23,13 @@
 const char kLastAdsViolationTimeKey[] = "LastAdsViolationTime";
 const char kLastAdsViolationKey[] = "LastAdsViolation";
 
+// Histograms
+const char kAdsInterventionRecordedHistogramName[] =
+    "SubresourceFilter.PageLoad.AdsInterventionTriggered";
+
+const char kTimeSinceAdsInterventionTriggeredHistogramName[] =
+    "SubresourceFilter.PageLoad.TimeSinceLastActiveAdsIntervention";
+
 AdsInterventionStatus GetAdsInterventionStatus(bool activation_status,
                                                bool intervention_active) {
   if (!intervention_active)
@@ -59,6 +67,9 @@
       SubresourceFilterContentSettingsManager::ActivationSource::
           kAdsIntervention,
       std::move(additional_metadata));
+
+  UMA_HISTOGRAM_ENUMERATION(kAdsInterventionRecordedHistogramName,
+                            ads_violation);
 }
 
 base::Optional<AdsInterventionManager::LastAdsIntervention>
@@ -99,6 +110,9 @@
       last_intervention->duration_since <
           subresource_filter::kAdsInterventionDuration.Get();
   if (last_intervention) {
+    UMA_HISTOGRAM_COUNTS_1000(kTimeSinceAdsInterventionTriggeredHistogramName,
+                              last_intervention->duration_since.InHours());
+
     auto* ukm_recorder = ukm::UkmRecorder::Get();
     ukm::builders::AdsIntervention_LastIntervention builder(
         ukm::ConvertToSourceId(navigation_handle->GetNavigationId(),
diff --git a/components/subresource_filter/content/browser/ads_intervention_manager.h b/components/subresource_filter/content/browser/ads_intervention_manager.h
index a7c49d4..95fb4d6 100644
--- a/components/subresource_filter/content/browser/ads_intervention_manager.h
+++ b/components/subresource_filter/content/browser/ads_intervention_manager.h
@@ -82,7 +82,9 @@
       mojom::AdsViolation ads_violation);
 
   // Returns the last active ads intervention written to metadata,
-  // otherwise base::nullopt is returned.
+  // otherwise base::nullopt is returned. When retrieving ads interventions
+  // for a navigation, should_record_metrics should be true to record
+  // per-navigation ads intervention metrics.
   base::Optional<LastAdsIntervention> GetLastAdsIntervention(
       const GURL& url) const;
 
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
index 0068bb9..5b5127a3 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -191,7 +191,8 @@
   if (navigation_handle->GetNetErrorCode() != net::OK)
     return;
 
-  auto it = ongoing_activation_throttles_.find(navigation_handle);
+  auto it =
+      ongoing_activation_throttles_.find(navigation_handle->GetNavigationId());
   if (it == ongoing_activation_throttles_.end())
     return;
 
@@ -245,7 +246,8 @@
 void ContentSubresourceFilterThrottleManager::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   ActivationStateComputingNavigationThrottle* throttle = nullptr;
-  auto throttle_it = ongoing_activation_throttles_.find(navigation_handle);
+  auto throttle_it =
+      ongoing_activation_throttles_.find(navigation_handle->GetNavigationId());
   if (throttle_it != ongoing_activation_throttles_.end()) {
     throttle = throttle_it->second;
 
@@ -392,7 +394,8 @@
   DCHECK(navigation_handle->IsInMainFrame());
   DCHECK(!navigation_handle->HasCommitted());
 
-  auto it = ongoing_activation_throttles_.find(navigation_handle);
+  auto it =
+      ongoing_activation_throttles_.find(navigation_handle->GetNavigationId());
   if (it == ongoing_activation_throttles_.end())
     return;
 
@@ -453,10 +456,11 @@
     throttles->push_back(std::move(filtering_throttle));
   }
 
-  DCHECK(!base::Contains(ongoing_activation_throttles_, navigation_handle));
+  DCHECK(!base::Contains(ongoing_activation_throttles_,
+                         navigation_handle->GetNavigationId()));
   if (auto activation_throttle =
           MaybeCreateActivationStateComputingThrottle(navigation_handle)) {
-    ongoing_activation_throttles_[navigation_handle] =
+    ongoing_activation_throttles_[navigation_handle->GetNavigationId()] =
         activation_throttle.get();
     throttles->push_back(std::move(activation_throttle));
   }
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
index 18109fa..21fdb0c 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
@@ -241,10 +241,9 @@
 
   // For each ongoing navigation that requires activation state computation,
   // keeps track of the throttle that is carrying out that computation, so that
-  // the result can be retrieved when the navigation is ready to commit.
-  // TODO(crbug.com/1134311): Key with navigation IDs instead of raw pointers.
-  std::map<content::NavigationHandle*,
-           ActivationStateComputingNavigationThrottle*>
+  // the result can be retrieved when the navigation is ready to commit. Keyed
+  // by navigation id.
+  std::map<int64_t, ActivationStateComputingNavigationThrottle*>
       ongoing_activation_throttles_;
 
   // Set of RenderFrameHosts that have been identified as ads. An RFH is an ad
diff --git a/components/sync_sessions/synced_session.cc b/components/sync_sessions/synced_session.cc
index c381a96..ae3f13f 100644
--- a/components/sync_sessions/synced_session.cc
+++ b/components/sync_sessions/synced_session.cc
@@ -64,6 +64,7 @@
     case ui::PAGE_TRANSITION_HOME_PAGE:
     case ui::PAGE_TRANSITION_FROM_API:
     case ui::PAGE_TRANSITION_FROM_API_2:
+    case ui::PAGE_TRANSITION_FROM_API_3:
     case ui::PAGE_TRANSITION_CHAIN_START:
     case ui::PAGE_TRANSITION_CHAIN_END:
     case ui::PAGE_TRANSITION_CLIENT_REDIRECT:
diff --git a/components/viz/common/quads/compositor_render_pass_unittest.cc b/components/viz/common/quads/compositor_render_pass_unittest.cc
index a3cebaf2..720dfd42 100644
--- a/components/viz/common/quads/compositor_render_pass_unittest.cc
+++ b/components/viz/common/quads/compositor_render_pass_unittest.cc
@@ -85,7 +85,7 @@
   // Stick a quad in the pass, this should not get copied.
   SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(gfx::Transform(), gfx::Rect(), gfx::Rect(),
-                       gfx::RRectF(), gfx::Rect(), false, false, 1,
+                       gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
                        SkBlendMode::kSrcOver, 0);
 
   auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -144,7 +144,7 @@
   // Two quads using one shared state.
   SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
   shared_state1->SetAll(gfx::Transform(), gfx::Rect(0, 0, 1, 1), gfx::Rect(),
-                        gfx::RRectF(), gfx::Rect(), false, false, 1,
+                        gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
                         SkBlendMode::kSrcOver, 0);
 
   auto* color_quad1 = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -160,7 +160,7 @@
   // And two quads using another shared state.
   SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
   shared_state2->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
-                        gfx::RRectF(), gfx::Rect(), false, false, 1,
+                        gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
                         SkBlendMode::kSrcOver, 0);
 
   auto* color_quad3 = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -201,8 +201,8 @@
   SharedQuadState* contrib_shared_state =
       contrib->CreateAndAppendSharedQuadState();
   contrib_shared_state->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2),
-                               gfx::Rect(), gfx::RRectF(), gfx::Rect(), false,
-                               false, 1, SkBlendMode::kSrcOver, 0);
+                               gfx::Rect(), gfx::MaskFilterInfo(), gfx::Rect(),
+                               false, false, 1, SkBlendMode::kSrcOver, 0);
 
   auto* contrib_quad = contrib->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   contrib_quad->SetNew(contrib->shared_quad_state_list.back(),
@@ -254,7 +254,7 @@
   // A shared state with a quad.
   SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
   shared_state1->SetAll(gfx::Transform(), gfx::Rect(0, 0, 1, 1), gfx::Rect(),
-                        gfx::RRectF(), gfx::Rect(), false, false, 1,
+                        gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
                         SkBlendMode::kSrcOver, 0);
 
   auto* color_quad1 = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -265,19 +265,19 @@
   // A shared state with no quads, they were culled.
   SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
   shared_state2->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
-                        gfx::RRectF(), gfx::Rect(), false, false, 1,
+                        gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
                         SkBlendMode::kSrcOver, 0);
 
   // A second shared state with no quads.
   SharedQuadState* shared_state3 = pass->CreateAndAppendSharedQuadState();
   shared_state3->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
-                        gfx::RRectF(), gfx::Rect(), false, false, 1,
+                        gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
                         SkBlendMode::kSrcOver, 0);
 
   // A last shared state with a quad again.
   SharedQuadState* shared_state4 = pass->CreateAndAppendSharedQuadState();
   shared_state4->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
-                        gfx::RRectF(), gfx::Rect(), false, false, 1,
+                        gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
                         SkBlendMode::kSrcOver, 0);
 
   auto* color_quad2 = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
diff --git a/components/viz/common/quads/draw_quad.h b/components/viz/common/quads/draw_quad.h
index 313e208f..4900fb6 100644
--- a/components/viz/common/quads/draw_quad.h
+++ b/components/viz/common/quads/draw_quad.h
@@ -79,7 +79,7 @@
   bool ShouldDrawWithBlending() const {
     return needs_blending || shared_quad_state->opacity < 1.0f ||
            shared_quad_state->blend_mode != SkBlendMode::kSrcOver ||
-           !shared_quad_state->rounded_corner_bounds.IsEmpty();
+           !shared_quad_state->mask_filter_info.IsEmpty();
   }
 
   // Is the left edge of this tile aligned with the originating layer's
diff --git a/components/viz/common/quads/draw_quad_perftest.cc b/components/viz/common/quads/draw_quad_perftest.cc
index 00f0de929..3c0d2e63 100644
--- a/components/viz/common/quads/draw_quad_perftest.cc
+++ b/components/viz/common/quads/draw_quad_perftest.cc
@@ -42,9 +42,9 @@
   SkBlendMode blend_mode = SkBlendMode::kSrcOver;
 
   SharedQuadState* state = render_pass->CreateAndAppendSharedQuadState();
-  state->SetAll(quad_transform, content_rect, visible_layer_rect, gfx::RRectF(),
-                clip_rect, is_clipped, are_contents_opaque, opacity, blend_mode,
-                sorting_context_id);
+  state->SetAll(quad_transform, content_rect, visible_layer_rect,
+                gfx::MaskFilterInfo(), clip_rect, is_clipped,
+                are_contents_opaque, opacity, blend_mode, sorting_context_id);
   return state;
 }
 
diff --git a/components/viz/common/quads/draw_quad_unittest.cc b/components/viz/common/quads/draw_quad_unittest.cc
index c4097751..3cb4975 100644
--- a/components/viz/common/quads/draw_quad_unittest.cc
+++ b/components/viz/common/quads/draw_quad_unittest.cc
@@ -53,9 +53,9 @@
   int sorting_context_id = 65536;
 
   auto state = std::make_unique<SharedQuadState>();
-  state->SetAll(quad_transform, layer_rect, visible_layer_rect, gfx::RRectF(),
-                clip_rect, is_clipped, are_contents_opaque, opacity, blend_mode,
-                sorting_context_id);
+  state->SetAll(quad_transform, layer_rect, visible_layer_rect,
+                gfx::MaskFilterInfo(), clip_rect, is_clipped,
+                are_contents_opaque, opacity, blend_mode, sorting_context_id);
 
   auto copy = std::make_unique<SharedQuadState>(*state);
   EXPECT_EQ(quad_transform, copy->quad_to_target_transform);
@@ -79,9 +79,9 @@
   SkBlendMode blend_mode = SkBlendMode::kSrcOver;
 
   SharedQuadState* state = render_pass->CreateAndAppendSharedQuadState();
-  state->SetAll(quad_transform, layer_rect, visible_layer_rect, gfx::RRectF(),
-                clip_rect, is_clipped, are_contents_opaque, opacity, blend_mode,
-                sorting_context_id);
+  state->SetAll(quad_transform, layer_rect, visible_layer_rect,
+                gfx::MaskFilterInfo(), clip_rect, is_clipped,
+                are_contents_opaque, opacity, blend_mode, sorting_context_id);
   return state;
 }
 
diff --git a/components/viz/common/quads/render_pass_io.cc b/components/viz/common/quads/render_pass_io.cc
index 8bd58e1..0ac1e19 100644
--- a/components/viz/common/quads/render_pass_io.cc
+++ b/components/viz/common/quads/render_pass_io.cc
@@ -1602,7 +1602,8 @@
   dict.SetKey("quad_layer_rect", RectToDict(sqs.quad_layer_rect));
   dict.SetKey("visible_quad_layer_rect",
               RectToDict(sqs.visible_quad_layer_rect));
-  dict.SetKey("rounded_corner_bounds", RRectFToDict(sqs.rounded_corner_bounds));
+  dict.SetKey("rounded_corner_bounds",
+              RRectFToDict(sqs.mask_filter_info.rounded_corner_bounds()));
   dict.SetKey("clip_rect", RectToDict(sqs.clip_rect));
   dict.SetBoolKey("is_clipped", sqs.is_clipped);
   dict.SetBoolKey("are_contents_opaque", sqs.are_contents_opaque);
@@ -1697,9 +1698,9 @@
   if (blend_mode_index < 0)
     return false;
   SkBlendMode t_blend_mode = static_cast<SkBlendMode>(blend_mode_index);
-
+  gfx::MaskFilterInfo mask_filter_info(t_rounded_corner_bounds);
   sqs->SetAll(t_quad_to_target_transform, t_quad_layer_rect,
-              t_visible_quad_layer_rect, t_rounded_corner_bounds, t_clip_rect,
+              t_visible_quad_layer_rect, mask_filter_info, t_clip_rect,
               is_clipped.value(), are_contents_opaque.value(),
               static_cast<float>(opacity.value()), t_blend_mode,
               sorting_context_id.value());
diff --git a/components/viz/common/quads/render_pass_io_unittest.cc b/components/viz/common/quads/render_pass_io_unittest.cc
index e9f8144..6df53eea 100644
--- a/components/viz/common/quads/render_pass_io_unittest.cc
+++ b/components/viz/common/quads/render_pass_io_unittest.cc
@@ -121,11 +121,11 @@
     ASSERT_TRUE(sqs1);
     gfx::Transform transform;
     transform.MakeIdentity();
-    sqs1->SetAll(transform, gfx::Rect(0, 0, 640, 480),
-                 gfx::Rect(10, 10, 600, 400),
-                 gfx::RRectF(gfx::RectF(2.f, 3.f, 4.f, 5.f), 1.5f),
-                 gfx::Rect(5, 20, 1000, 200), true, false, 0.5f,
-                 SkBlendMode::kDstOver, 101);
+    sqs1->SetAll(
+        transform, gfx::Rect(0, 0, 640, 480), gfx::Rect(10, 10, 600, 400),
+        gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(2.f, 3.f, 4.f, 5.f), 1.5f)),
+        gfx::Rect(5, 20, 1000, 200), true, false, 0.5f, SkBlendMode::kDstOver,
+        101);
     sqs1->is_fast_rounded_corner = true;
     sqs1->de_jelly_delta_y = 0.7f;
   }
@@ -141,7 +141,7 @@
     EXPECT_TRUE(sqs0->quad_to_target_transform.IsIdentity());
     EXPECT_EQ(gfx::Rect(), sqs0->quad_layer_rect);
     EXPECT_EQ(gfx::Rect(), sqs0->visible_quad_layer_rect);
-    EXPECT_TRUE(sqs0->rounded_corner_bounds.IsEmpty());
+    EXPECT_FALSE(sqs0->mask_filter_info.HasRoundedCorners());
     EXPECT_EQ(gfx::Rect(), sqs0->clip_rect);
     EXPECT_FALSE(sqs0->is_clipped);
     EXPECT_TRUE(sqs0->are_contents_opaque);
@@ -158,10 +158,10 @@
     EXPECT_EQ(gfx::Rect(0, 0, 640, 480), sqs1->quad_layer_rect);
     EXPECT_EQ(gfx::Rect(10, 10, 600, 400), sqs1->visible_quad_layer_rect);
     EXPECT_EQ(gfx::RRectF::Type::kSingle,
-              sqs1->rounded_corner_bounds.GetType());
-    EXPECT_EQ(1.5f, sqs1->rounded_corner_bounds.GetSimpleRadius());
-    EXPECT_EQ(gfx::RectF(2.f, 3.f, 4.f, 5.f),
-              sqs1->rounded_corner_bounds.rect());
+              sqs1->mask_filter_info.rounded_corner_bounds().GetType());
+    EXPECT_EQ(1.5f,
+              sqs1->mask_filter_info.rounded_corner_bounds().GetSimpleRadius());
+    EXPECT_EQ(gfx::RectF(2.f, 3.f, 4.f, 5.f), sqs1->mask_filter_info.bounds());
     EXPECT_EQ(gfx::Rect(5, 20, 1000, 200), sqs1->clip_rect);
     EXPECT_TRUE(sqs1->is_clipped);
     EXPECT_FALSE(sqs1->are_contents_opaque);
diff --git a/components/viz/common/quads/shared_quad_state.cc b/components/viz/common/quads/shared_quad_state.cc
index 42cab6b..5d7d3b3 100644
--- a/components/viz/common/quads/shared_quad_state.cc
+++ b/components/viz/common/quads/shared_quad_state.cc
@@ -23,7 +23,7 @@
 void SharedQuadState::SetAll(const gfx::Transform& quad_to_target_transform,
                              const gfx::Rect& quad_layer_rect,
                              const gfx::Rect& visible_quad_layer_rect,
-                             const gfx::RRectF& rounded_corner_bounds,
+                             const gfx::MaskFilterInfo& mask_filter_info,
                              const gfx::Rect& clip_rect,
                              bool is_clipped,
                              bool are_contents_opaque,
@@ -33,7 +33,7 @@
   this->quad_to_target_transform = quad_to_target_transform;
   this->quad_layer_rect = quad_layer_rect;
   this->visible_quad_layer_rect = visible_quad_layer_rect;
-  this->rounded_corner_bounds = rounded_corner_bounds;
+  this->mask_filter_info = mask_filter_info;
   this->clip_rect = clip_rect;
   this->is_clipped = is_clipped;
   this->are_contents_opaque = are_contents_opaque;
@@ -47,8 +47,11 @@
   cc::MathUtil::AddToTracedValue("layer_content_rect", quad_layer_rect, value);
   cc::MathUtil::AddToTracedValue("layer_visible_content_rect",
                                  visible_quad_layer_rect, value);
-  cc::MathUtil::AddToTracedValue("rounded_corner_bounds", rounded_corner_bounds,
-                                 value);
+  cc::MathUtil::AddToTracedValue("mask_filter_bounds",
+                                 mask_filter_info.bounds(), value);
+  cc::MathUtil::AddCornerRadiiToTracedValue(
+      "mask_filter_rounded_corners_radii",
+      mask_filter_info.rounded_corner_bounds(), value);
 
   value->SetBoolean("is_clipped", is_clipped);
   cc::MathUtil::AddToTracedValue("clip_rect", clip_rect, value);
diff --git a/components/viz/common/quads/shared_quad_state.h b/components/viz/common/quads/shared_quad_state.h
index 97681e500..a1694be0 100644
--- a/components/viz/common/quads/shared_quad_state.h
+++ b/components/viz/common/quads/shared_quad_state.h
@@ -11,6 +11,7 @@
 #include "components/viz/common/viz_common_export.h"
 #include "third_party/skia/include/core/SkBlendMode.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/mask_filter_info.h"
 #include "ui/gfx/rrect_f.h"
 #include "ui/gfx/transform.h"
 
@@ -36,7 +37,7 @@
   void SetAll(const gfx::Transform& quad_to_target_transform,
               const gfx::Rect& quad_layer_rect,
               const gfx::Rect& visible_layer_rect,
-              const gfx::RRectF& rounded_corner_bounds,
+              const gfx::MaskFilterInfo& mask_filter_info,
               const gfx::Rect& clip_rect,
               bool is_clipped,
               bool are_contents_opaque,
@@ -55,9 +56,9 @@
   // The size of the visible area in the quads' originating layer, in the space
   // of the quad rects.
   gfx::Rect visible_quad_layer_rect;
-  // This rect lives in the target content space. It defines the corner radius
-  // to clip the quads with.
-  gfx::RRectF rounded_corner_bounds;
+  // This mask filter's coordinates is in the target content space. It defines
+  // the corner radius to clip the quads with.
+  gfx::MaskFilterInfo mask_filter_info;
   // This rect lives in the target content space.
   gfx::Rect clip_rect;
   bool is_clipped = false;
diff --git a/components/viz/demo/client/demo_client.cc b/components/viz/demo/client/demo_client.cc
index 75e6f81..6f255f94 100644
--- a/components/viz/demo/client/demo_client.cc
+++ b/components/viz/demo/client/demo_client.cc
@@ -102,7 +102,7 @@
         transform,
         /*quad_layer_rect=*/child_bounds,
         /*visible_quad_layer_rect=*/child_bounds,
-        /*rounded_corner_bounds=*/gfx::RRectF(),
+        /*mask_filter_info=*/gfx::MaskFilterInfo(),
         /*clip_rect=*/gfx::Rect(),
         /*is_clipped=*/false, /*are_contents_opaque=*/false, /*opacity=*/1.f,
         /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
@@ -127,7 +127,7 @@
       gfx::Transform(),
       /*quad_layer_rect=*/output_rect,
       /*visible_quad_layer_rect=*/output_rect,
-      /*rounded_corner_bounds=*/gfx::RRectF(),
+      /*mask_filter_info=*/gfx::MaskFilterInfo(),
       /*clip_rect=*/gfx::Rect(),
       /*is_clipped=*/false, /*are_contents_opaque=*/false, /*opacity=*/1.f,
       /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
diff --git a/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc b/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc
index 6a316432..226e84a89 100644
--- a/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc
+++ b/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc
@@ -15,6 +15,7 @@
 #include "components/viz/common/resources/bitmap_allocation.h"
 #include "components/viz/common/resources/resource_sizes.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/mask_filter_info.h"
 
 namespace viz {
 namespace {
@@ -343,8 +344,8 @@
     shared_quad_state->SetAll(
         GetTransformFromProtobuf(quad_spec.sqs().transform()),
         GetRectFromProtobuf(quad_spec.sqs().layer_rect()),
-        GetRectFromProtobuf(quad_spec.sqs().visible_rect()), gfx::RRectF(),
-        GetRectFromProtobuf(quad_spec.sqs().clip_rect()),
+        GetRectFromProtobuf(quad_spec.sqs().visible_rect()),
+        gfx::MaskFilterInfo(), GetRectFromProtobuf(quad_spec.sqs().clip_rect()),
         quad_spec.sqs().is_clipped(), quad_spec.sqs().are_contents_opaque(),
         Normalize(quad_spec.sqs().opacity()), SkBlendMode::kSrcOver,
         quad_spec.sqs().sorting_context_id());
@@ -360,12 +361,12 @@
                                                .transform_to_root_target());
     }
 
-    shared_quad_state->SetAll(transform, GetRectFromProtobuf(quad_spec.rect()),
-                              GetRectFromProtobuf(quad_spec.visible_rect()),
-                              gfx::RRectF(), gfx::Rect(), /*is_clipped=*/false,
-                              /*are_contents_opaque=*/true, /*opacity=*/1.0,
-                              SkBlendMode::kSrcOver,
-                              /*sorting_context_id=*/0);
+    shared_quad_state->SetAll(
+        transform, GetRectFromProtobuf(quad_spec.rect()),
+        GetRectFromProtobuf(quad_spec.visible_rect()), gfx::MaskFilterInfo(),
+        gfx::Rect(), /*is_clipped=*/false,
+        /*are_contents_opaque=*/true, /*opacity=*/1.0, SkBlendMode::kSrcOver,
+        /*sorting_context_id=*/0);
   }
 }
 
diff --git a/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc b/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc
index 628c046..8820b5c3 100644
--- a/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc
+++ b/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc
@@ -130,7 +130,7 @@
   renderer_sqs->SetAll(gfx::Transform(1.0, 0.0, 0.0, 1.0, 0, 80),
                        gfx::Rect(kRendererFrameSize),
                        gfx::Rect(kRendererFrameSize),
-                       /*rounded_corner_bounds=*/gfx::RRectF(),
+                       /*mask_filter_info=*/gfx::MaskFilterInfo(),
                        gfx::Rect(kRendererFrameSize), /*is_clipped=*/false,
                        /*are_contents_opaque=*/false, /*opacity=*/1,
                        SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
@@ -144,7 +144,7 @@
   auto* toolbar_sqs = pass->CreateAndAppendSharedQuadState();
   toolbar_sqs->SetAll(
       gfx::Transform(), gfx::Rect(kTopBarSize), gfx::Rect(kTopBarSize),
-      /*rounded_corner_bounds=*/gfx::RRectF(), gfx::Rect(kTopBarSize),
+      /*mask_filter_info=*/gfx::MaskFilterInfo(), gfx::Rect(kTopBarSize),
       /*is_clipped=*/false, /*are_contents_opaque=*/false,
       /*opacity=*/1, SkBlendMode::kSrcOver,
       /*sorting_context_id=*/0);
diff --git a/components/viz/service/display/ca_layer_overlay.cc b/components/viz/service/display/ca_layer_overlay.cc
index cf09d0d..72426617 100644
--- a/components/viz/service/display/ca_layer_overlay.cc
+++ b/components/viz/service/display/ca_layer_overlay.cc
@@ -208,10 +208,10 @@
     // possible to make rounded corner rects independent of clip rect (by adding
     // another CALayer to the tree). Handling non-single border radii is also,
     // but requires APIs not supported on all macOS versions.
-    if (!quad->shared_quad_state->rounded_corner_bounds.IsEmpty()) {
+    if (quad->shared_quad_state->mask_filter_info.HasRoundedCorners()) {
       DCHECK(quad->shared_quad_state->is_clipped);
-      if (quad->shared_quad_state->rounded_corner_bounds.GetType() >
-          gfx::RRectF::Type::kSingle) {
+      if (quad->shared_quad_state->mask_filter_info.rounded_corner_bounds()
+              .GetType() > gfx::RRectF::Type::kSingle) {
         return CA_LAYER_FAILED_QUAD_ROUNDED_CORNER_NOT_UNIFORM;
       }
     }
@@ -238,7 +238,7 @@
       most_recent_overlay_shared_state_->clip_rect =
           gfx::RectF(quad->shared_quad_state->clip_rect);
       most_recent_overlay_shared_state_->rounded_corner_bounds =
-          quad->shared_quad_state->rounded_corner_bounds;
+          quad->shared_quad_state->mask_filter_info.rounded_corner_bounds();
 
       most_recent_overlay_shared_state_->opacity =
           quad->shared_quad_state->opacity;
diff --git a/components/viz/service/display/damage_frame_annotator.cc b/components/viz/service/display/damage_frame_annotator.cc
index a65710d..38d85d4e 100644
--- a/components/viz/service/display/damage_frame_annotator.cc
+++ b/components/viz/service/display/damage_frame_annotator.cc
@@ -53,7 +53,7 @@
     SharedQuadState* new_sqs = render_pass->shared_quad_state_list
                                    .AllocateAndConstruct<SharedQuadState>();
     new_sqs->SetAll(annotation.transform, output_rect, output_rect,
-                    gfx::RRectF(), output_rect, true, false, 1.f,
+                    gfx::MaskFilterInfo(), output_rect, true, false, 1.f,
                     SkBlendMode::kSrcOver, 0);
 
     DebugBorderDrawQuad* new_quad =
diff --git a/components/viz/service/display/dc_layer_overlay.cc b/components/viz/service/display/dc_layer_overlay.cc
index 28521c15..9a04a1b 100644
--- a/components/viz/service/display/dc_layer_overlay.cc
+++ b/components/viz/service/display/dc_layer_overlay.cc
@@ -117,7 +117,7 @@
     return DC_LAYER_FAILED_TOO_MANY_OVERLAYS;
 
   // Rounded corner on overlays are not supported.
-  if (!quad->shared_quad_state->rounded_corner_bounds.IsEmpty())
+  if (quad->shared_quad_state->mask_filter_info.HasRoundedCorners())
     return DC_LAYER_FAILED_ROUNDED_CORNERS;
 
   auto quad_target_rect = gfx::ToEnclosingRect(ClippedQuadRectangle(quad));
@@ -185,7 +185,7 @@
   }
 
   // Rounded corner on overlays are not supported.
-  if (!quad->shared_quad_state->rounded_corner_bounds.IsEmpty())
+  if (quad->shared_quad_state->mask_filter_info.HasRoundedCorners())
     return DC_LAYER_FAILED_ROUNDED_CORNERS;
 
   auto quad_target_rect = gfx::ToEnclosingRect(ClippedQuadRectangle(quad));
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index a69732b8..e356f1a 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -920,12 +920,15 @@
 
 bool DirectRenderer::ShouldApplyRoundedCorner(const DrawQuad* quad) const {
   const SharedQuadState* sqs = quad->shared_quad_state;
-  const gfx::RRectF& rounded_corner_bounds = sqs->rounded_corner_bounds;
+  const gfx::MaskFilterInfo& mask_filter_info = sqs->mask_filter_info;
 
   // There is no rounded corner set.
-  if (rounded_corner_bounds.IsEmpty())
+  if (!mask_filter_info.HasRoundedCorners())
     return false;
 
+  const gfx::RRectF& rounded_corner_bounds =
+      mask_filter_info.rounded_corner_bounds();
+
   const gfx::RectF target_quad = cc::MathUtil::MapClippedRect(
       sqs->quad_to_target_transform, gfx::RectF(quad->visible_rect));
 
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index 50deaff..9966b423 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -1111,9 +1111,10 @@
           // If a rounded corner is being applied then the visible rect for the
           // sqs is actually even smaller. Reduce the rect size to get a
           // rounded corner adjusted occluding region.
-          if (!last_sqs->rounded_corner_bounds.IsEmpty()) {
-            sqs_rect_in_target.Intersect(gfx::ToEnclosedRect(
-                GetOccludingRectForRRectF(last_sqs->rounded_corner_bounds)));
+          if (last_sqs->mask_filter_info.HasRoundedCorners()) {
+            sqs_rect_in_target.Intersect(
+                gfx::ToEnclosedRect(GetOccludingRectForRRectF(
+                    last_sqs->mask_filter_info.rounded_corner_bounds())));
           }
 
           if (last_sqs->is_clipped)
diff --git a/components/viz/service/display/display_perftest.cc b/components/viz/service/display/display_perftest.cc
index 37faed27..59e18d36 100644
--- a/components/viz/service/display/display_perftest.cc
+++ b/components/viz/service/display/display_perftest.cc
@@ -98,7 +98,7 @@
 
     SharedQuadState* state = render_pass->CreateAndAppendSharedQuadState();
     state->SetAll(quad_transform, rect, rect,
-                  /*rounded_corner_bounds=*/gfx::RRectF(), rect, is_clipped,
+                  /*mask_filter_info=*/gfx::MaskFilterInfo(), rect, is_clipped,
                   are_contents_opaque, opacity, blend_mode, sorting_context_id);
     return state;
   }
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc
index 3050f3f..4906e605 100644
--- a/components/viz/service/display/display_unittest.cc
+++ b/components/viz/service/display/display_unittest.cc
@@ -773,7 +773,7 @@
       shared_quad_state1->SetAll(
           gfx::Transform(), /*quad_layer_rect=*/sub_surface_rect,
           /*visible_quad_layer_rect=*/sub_surface_rect,
-          /*rounded_corner_bounds=*/gfx::RRectF(),
+          /*mask_filter_info=*/gfx::MaskFilterInfo(),
           /*clip_rect=*/sub_surface_rect, /*is_clipped=*/false,
           /*are_contents_opaque=*/true, /*opacity=*/1.0f, SkBlendMode::kSrcOver,
           /*sorting_context_id=*/0);
@@ -789,7 +789,7 @@
       gfx::Rect rect1(display_size);
       shared_quad_state2->SetAll(gfx::Transform(), /*quad_layer_rect=*/rect1,
                                  /*visible_quad_layer_rect=*/rect1,
-                                 /*rounded_corner_bounds=*/gfx::RRectF(),
+                                 /*mask_filter_info=*/gfx::MaskFilterInfo(),
                                  /*clip_rect=*/rect1, /*is_clipped=*/false,
                                  /*are_contents_opaque=*/true, /*opacity=*/1.0f,
                                  SkBlendMode::kSrcOver,
@@ -929,13 +929,13 @@
 
     auto* src_sqs = render_pass->CreateAndAppendSharedQuadState();
     src_sqs->SetAll(
-        gfx::Transform(), src_rect, src_rect, gfx::RRectF(), src_rect,
+        gfx::Transform(), src_rect, src_rect, gfx::MaskFilterInfo(), src_rect,
         is_clipped, are_contents_opaque, opacity,
         is_root_render_pass ? SkBlendMode::kSrcOver : SkBlendMode::kSrcIn, 0);
     auto* dest_sqs = render_pass->CreateAndAppendSharedQuadState();
     dest_sqs->SetAll(
-        gfx::Transform(), dest_rect, dest_rect, gfx::RRectF(), dest_rect,
-        is_clipped, are_contents_opaque, opacity,
+        gfx::Transform(), dest_rect, dest_rect, gfx::MaskFilterInfo(),
+        dest_rect, is_clipped, are_contents_opaque, opacity,
         is_root_render_pass ? SkBlendMode::kSrcOver : SkBlendMode::kDstIn, 0);
     auto* src_quad =
         render_pass->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
@@ -995,7 +995,7 @@
   for (int i = 0; i < 3; i++) {
     shared_quad_states[i] = root_render_pass->CreateAndAppendSharedQuadState();
     shared_quad_states[i]->SetAll(
-        gfx::Transform(), rects[i], rects[i], gfx::RRectF(), rects[i],
+        gfx::Transform(), rects[i], rects[i], gfx::MaskFilterInfo(), rects[i],
         is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     if (i == 0) {  // Backdrop filter quad
@@ -1060,9 +1060,9 @@
   // |    |
   // +----+
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -1085,13 +1085,13 @@
   // +----+ |
   //   +----+
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
@@ -1120,13 +1120,13 @@
   //   |  |                                    |  |
   //   +--+                                    +--+
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
-                               rect3, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
@@ -1154,13 +1154,13 @@
   // +----+                                      +----+
   //  +--+                                        +--+
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect7, rect7, gfx::RRectF(),
-                              rect7, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect7, rect7, gfx::MaskFilterInfo(), rect7,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(gfx::Transform(), rect6, rect6, gfx::RRectF(),
-                               rect6, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect6, rect6, gfx::MaskFilterInfo(), rect6,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect7, rect7, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect6, rect6, SK_ColorBLACK, false);
@@ -1187,13 +1187,13 @@
   // |    |   +--+
   // +----+
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(gfx::Transform(), rect4, rect4, gfx::RRectF(),
-                               rect4, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect4, rect4, gfx::MaskFilterInfo(), rect4,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect4, rect4, SK_ColorBLACK, false);
@@ -1219,13 +1219,13 @@
   // +-----+|
   // +------+
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(gfx::Transform(), rect5, rect5, gfx::RRectF(),
-                               rect5, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect5, rect5, gfx::MaskFilterInfo(), rect5,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect5, rect5, SK_ColorBLACK, false);
@@ -1277,9 +1277,9 @@
         frame.render_pass_list.front()->CreateAndAppendSharedQuadState();
     auto* quad = frame.render_pass_list.front()
                      ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
-                              is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
   }
 
@@ -1333,9 +1333,9 @@
         frame.render_pass_list.front()->CreateAndAppendSharedQuadState();
     auto* quad = frame.render_pass_list.front()
                      ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
-                              is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
   }
 
@@ -1392,12 +1392,12 @@
   //                         |     |
   //                         +-----+
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                               rect1, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect1, rect1, SK_ColorBLACK, false);
@@ -1417,12 +1417,12 @@
   {
     quad2 = frame.render_pass_list.front()
                 ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
@@ -1443,12 +1443,12 @@
   {
     quad2 = frame.render_pass_list.front()
                 ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
-                               rect3, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
@@ -1469,13 +1469,13 @@
   {
     quad2 = frame.render_pass_list.front()
                 ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(gfx::Transform(), rect4, rect4, gfx::RRectF(),
-                               rect4, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect4, rect4, gfx::MaskFilterInfo(), rect4,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect4, rect4, SK_ColorBLACK, false);
@@ -1534,11 +1534,11 @@
                     ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
 
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(half_scale, rect2, rect2, gfx::RRectF(), rect2,
-                               is_clipped, are_contents_opaque, opacity,
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(half_scale, rect2, rect2, gfx::MaskFilterInfo(),
+                               rect2, is_clipped, are_contents_opaque, opacity,
                                SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
@@ -1557,11 +1557,11 @@
   {
     quad2 = frame.render_pass_list.front()
                 ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(half_scale, rect3, rect3, gfx::RRectF(), rect3,
-                               is_clipped, are_contents_opaque, opacity,
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(half_scale, rect3, rect3, gfx::MaskFilterInfo(),
+                               rect3, is_clipped, are_contents_opaque, opacity,
                                SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
@@ -1580,12 +1580,12 @@
   {
     quad2 = frame.render_pass_list.front()
                 ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(half_scale, rect4, rect4, gfx::RRectF(), rect4,
-                               is_clipped, are_contents_opaque, opacity,
+    shared_quad_state2->SetAll(half_scale, rect4, rect4, gfx::MaskFilterInfo(),
+                               rect4, is_clipped, are_contents_opaque, opacity,
                                SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
@@ -1603,8 +1603,8 @@
   }
 
   {
-    shared_quad_state->SetAll(double_scale, rect1, rect1, gfx::RRectF(), rect1,
-                              is_clipped, are_contents_opaque, opacity,
+    shared_quad_state->SetAll(double_scale, rect1, rect1, gfx::MaskFilterInfo(),
+                              rect1, is_clipped, are_contents_opaque, opacity,
                               SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
@@ -1621,13 +1621,13 @@
   {
     quad2 = frame.render_pass_list.front()
                 ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(double_scale, rect5, rect5, gfx::RRectF(), rect5,
-                               is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        double_scale, rect5, rect5, gfx::MaskFilterInfo(), rect5, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect5, rect5, SK_ColorBLACK, false);
@@ -1649,13 +1649,13 @@
   }
 
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(double_scale, rect6, rect6, gfx::RRectF(), rect6,
-                               is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        double_scale, rect6, rect6, gfx::MaskFilterInfo(), rect6, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect6, rect6, SK_ColorBLACK, false);
@@ -1678,13 +1678,13 @@
   }
 
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(double_scale, rect7, rect7, gfx::RRectF(), rect7,
-                               is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        double_scale, rect7, rect7, gfx::MaskFilterInfo(), rect7, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect7, rect7, SK_ColorBLACK, false);
@@ -1706,13 +1706,13 @@
   }
 
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(double_scale, rect8, rect8, gfx::RRectF(), rect8,
-                               is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        double_scale, rect8, rect8, gfx::MaskFilterInfo(), rect8, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect8, rect8, SK_ColorBLACK, false);
@@ -1734,13 +1734,13 @@
   }
 
   {
-    shared_quad_state->SetAll(double_scale, rect10, rect10, gfx::RRectF(),
-                              rect10, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        double_scale, rect10, rect10, gfx::MaskFilterInfo(), rect10, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
-    shared_quad_state2->SetAll(double_scale, rect9, rect9, gfx::RRectF(), rect9,
-                               is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        double_scale, rect9, rect9, gfx::MaskFilterInfo(), rect9, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect10, rect10, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect9, rect9, SK_ColorBLACK, false);
@@ -1794,11 +1794,11 @@
   gfx::Transform inverted;
 
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
-                              is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(zero_scale, rect, rect, gfx::RRectF(), rect,
-                               is_clipped, are_contents_opaque, opacity,
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(zero_scale, rect, rect, gfx::MaskFilterInfo(),
+                               rect, is_clipped, are_contents_opaque, opacity,
                                SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
@@ -1818,11 +1818,11 @@
   }
 
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
-                              is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(epsilon_scale, rect, rect, gfx::RRectF(), rect,
-                               is_clipped, are_contents_opaque, opacity,
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(epsilon_scale, rect, rect, gfx::MaskFilterInfo(),
+                               rect, is_clipped, are_contents_opaque, opacity,
                                SkBlendMode::kSrcOver, 1);
 
     quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
@@ -1848,12 +1848,12 @@
   }
 
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
-                              is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(larger_epsilon_scale, rect, rect, gfx::RRectF(),
-                               rect, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        larger_epsilon_scale, rect, rect, gfx::MaskFilterInfo(), rect,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect, rect, SK_ColorBLACK, false);
@@ -1897,12 +1897,12 @@
 
   {
     negative_scale.Scale3d(-1, 1, 1);
-    shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
-                              is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(negative_scale, rect, rect, gfx::RRectF(), rect,
-                               is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        negative_scale, rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect, rect, SK_ColorBLACK, false);
@@ -1929,12 +1929,12 @@
   {
     negative_scale.MakeIdentity();
     negative_scale.Scale3d(1, -1, 1);
-    shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
-                              is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(negative_scale, rect, rect, gfx::RRectF(), rect,
-                               is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        negative_scale, rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect, rect, SK_ColorBLACK, false);
@@ -1961,12 +1961,12 @@
   {
     negative_scale.MakeIdentity();
     negative_scale.Scale3d(1, 1, -1);
-    shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
-                              is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(negative_scale, rect, rect, gfx::RRectF(), rect,
-                               is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        negative_scale, rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect, rect, SK_ColorBLACK, false);
@@ -2023,12 +2023,12 @@
                     ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
   {
     // Apply rotation transform on |rect1| only.
-    shared_quad_state->SetAll(rotate, rect1, rect1, gfx::RRectF(), rect1,
-                              is_clipped, are_contents_opaque, opacity,
+    shared_quad_state->SetAll(rotate, rect1, rect1, gfx::MaskFilterInfo(),
+                              rect1, is_clipped, are_contents_opaque, opacity,
                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2047,11 +2047,11 @@
 
   {
     // Apply rotation transform on |rect1| and |rect2|.
-    shared_quad_state->SetAll(rotate, rect1, rect1, gfx::RRectF(), rect1,
-                              is_clipped, are_contents_opaque, opacity,
+    shared_quad_state->SetAll(rotate, rect1, rect1, gfx::MaskFilterInfo(),
+                              rect1, is_clipped, are_contents_opaque, opacity,
                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(rotate, rect2, rect2, gfx::RRectF(), rect2,
-                               is_clipped, are_contents_opaque, opacity,
+    shared_quad_state2->SetAll(rotate, rect2, rect2, gfx::MaskFilterInfo(),
+                               rect2, is_clipped, are_contents_opaque, opacity,
                                SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
@@ -2069,12 +2069,12 @@
   {
     quad2 = frame.render_pass_list.front()
                 ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(rotate, rect1, rect1, gfx::RRectF(), rect1,
-                              is_clipped, are_contents_opaque, opacity,
+    shared_quad_state->SetAll(rotate, rect1, rect1, gfx::MaskFilterInfo(),
+                              rect1, is_clipped, are_contents_opaque, opacity,
                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
-                               rect3, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2095,11 +2095,11 @@
     // Since we only support updating |visible_rect| of DrawQuad with scale
     // or translation transform and rotation transform applies to quads,
     // |visible_rect| of |quad2| should not be changed.
-    shared_quad_state->SetAll(rotate, rect1, rect1, gfx::RRectF(), rect1,
-                              is_clipped, are_contents_opaque, opacity,
+    shared_quad_state->SetAll(rotate, rect1, rect1, gfx::MaskFilterInfo(),
+                              rect1, is_clipped, are_contents_opaque, opacity,
                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(rotate, rect3, rect3, gfx::RRectF(), rect3,
-                               is_clipped, are_contents_opaque, opacity,
+    shared_quad_state2->SetAll(rotate, rect3, rect3, gfx::MaskFilterInfo(),
+                               rect3, is_clipped, are_contents_opaque, opacity,
                                SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
@@ -2148,12 +2148,12 @@
   auto* quad2 = frame.render_pass_list.front()
                     ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
   {
-    shared_quad_state->SetAll(perspective, rect1, rect1, gfx::RRectF(), rect1,
-                              is_clipped, are_contents_opaque, opacity,
+    shared_quad_state->SetAll(perspective, rect1, rect1, gfx::MaskFilterInfo(),
+                              rect1, is_clipped, are_contents_opaque, opacity,
                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                               rect1, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect1, rect1, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2172,11 +2172,11 @@
   }
 
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(perspective, rect2, rect2, gfx::RRectF(), rect2,
-                               is_clipped, are_contents_opaque, opacity,
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(perspective, rect2, rect2, gfx::MaskFilterInfo(),
+                               rect2, is_clipped, are_contents_opaque, opacity,
                                SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
@@ -2218,12 +2218,13 @@
   auto* quad2 = frame.render_pass_list.front()
                     ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque,
-                              opacityLess1, SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, are_contents_opaque, opacity1,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1,
+                              gfx::MaskFilterInfo(), rect1, is_clipped,
+                              are_contents_opaque, opacityLess1,
+                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, are_contents_opaque, opacity1, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2240,12 +2241,12 @@
   }
 
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity1,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, are_contents_opaque, opacity1,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity1, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, are_contents_opaque, opacity1, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2282,12 +2283,12 @@
   auto* quad2 = frame.render_pass_list.front()
                     ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, transparent_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, transparent_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2304,12 +2305,12 @@
   }
 
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2353,12 +2354,12 @@
   //                         |     |
   //                         +-----+
   {
-    shared_quad_state->SetAll(translate_back, rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 1);
-    shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                               rect1, is_clipped, are_contents_opaque, opacity,
-                               SkBlendMode::kSrcOver, 1);
+    shared_quad_state->SetAll(
+        translate_back, rect1, rect1, gfx::MaskFilterInfo(), rect1, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 1);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 1);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect1, SK_ColorBLACK, false);
@@ -2411,12 +2412,12 @@
     //   +----+
     //           +-+
     //           +-+
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, transparent_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, transparent_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2440,12 +2441,12 @@
     //   +----+                       =>                              | +-+ |
     //           +-+                                                  | +-+ |
     //           +-+                                                  +-----+
-    shared_quad_state->SetAll(translate_up, rect1, rect1, gfx::RRectF(), rect1,
-                              is_clipped, opaque_content, opacity,
+    shared_quad_state->SetAll(translate_up, rect1, rect1, gfx::MaskFilterInfo(),
+                              rect1, is_clipped, opaque_content, opacity,
                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2470,12 +2471,12 @@
     //           +---+                                                 +----+
     quad2 = frame.render_pass_list.front()
                 ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(translate_up, rect1, rect1, gfx::RRectF(), rect1,
-                              is_clipped, opaque_content, opacity,
+    shared_quad_state->SetAll(translate_up, rect1, rect1, gfx::MaskFilterInfo(),
+                              rect1, is_clipped, opaque_content, opacity,
                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
-                               rect3, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2534,15 +2535,15 @@
     //   |    |----+             =>        |    |----+
     //   +----+                            +----+
     //
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state3->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
-                               rect3, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state3->SetAll(
+        gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     quad3->SetNew(shared_quad_state3, rect3, rect3, SK_ColorBLACK, false);
@@ -2569,9 +2570,9 @@
     //
     quad3 = frame.render_pass_list.front()
                 ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state3->SetAll(gfx::Transform(), rect4, rect4, gfx::RRectF(),
-                               rect4, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state3->SetAll(
+        gfx::Transform(), rect4, rect4, gfx::MaskFilterInfo(), rect4,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad3->SetNew(shared_quad_state3, rect4, rect4, SK_ColorBLACK, false);
     EXPECT_EQ(3u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
     display_->RemoveOverdrawQuads(&frame);
@@ -2598,9 +2599,9 @@
     //   |    |----+           =>          | |  |--|-+
     //   +----+                            +-|--+  |
     //                                       +-----+
-    shared_quad_state3->SetAll(gfx::Transform(), rect5, rect5, gfx::RRectF(),
-                               rect5, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state3->SetAll(
+        gfx::Transform(), rect5, rect5, gfx::MaskFilterInfo(), rect5,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad3->SetNew(shared_quad_state3, rect5, rect5, SK_ColorBLACK, false);
     EXPECT_EQ(3u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
     display_->RemoveOverdrawQuads(&frame);
@@ -2648,7 +2649,7 @@
     quads[i] =
         render_pass->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
     shared_quad_states[i]->SetAll(
-        gfx::Transform(), rects[i], rects[i], gfx::RRectF(), rects[i],
+        gfx::Transform(), rects[i], rects[i], gfx::MaskFilterInfo(), rects[i],
         false /*is_clipped*/, true /*are_contents_opaque*/, 1.f /*opacity*/,
         SkBlendMode::kSrcOver, 0 /*sorting_context_id*/);
     quads[i]->SetNew(shared_quad_states[i], rects[i], rects[i], SK_ColorBLACK,
@@ -2711,15 +2712,15 @@
     //   |    |----+             =>        |    |----+
     //   +----+                            +----+
     //
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state3->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
-                               rect3, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state3->SetAll(
+        gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     quad3->SetNew(shared_quad_state3, rect3, rect3, SK_ColorBLACK, false);
@@ -2784,12 +2785,12 @@
     //   +----+
     //
 
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                               rect1, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad1->SetNew(shared_quad_state2, rect1, rect1, render_pass_id,
                   mask_resource_id, gfx::RectF(), gfx::Size(),
@@ -2845,12 +2846,12 @@
     //   |   | ||
     //   +------+
     //
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, non_clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, non_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        non_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        non_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2872,12 +2873,12 @@
     //
     quad2 = frame.render_pass_list.front()
                 ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              clip_rect, clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, non_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), clip_rect,
+        clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        non_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2901,12 +2902,12 @@
     //   |   +-+|             =>                      +--+++
     //   +------+
     //
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              clip_rect, clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
-                               rect3, non_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), clip_rect,
+        clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        non_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
     EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2950,12 +2951,12 @@
   auto* quad2 = frame.render_pass_list.front()
                     ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     frame.render_pass_list.front()->copy_requests.push_back(
@@ -3020,18 +3021,18 @@
     // |       |   |        |
     // |   R1  |   |    R2  |
     // +-------+---+--------+
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                               rect2, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state3->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
-                               rect3, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state4->SetAll(gfx::Transform(), rect4, rect4, gfx::RRectF(),
-                               rect4, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state3->SetAll(
+        gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state4->SetAll(
+        gfx::Transform(), rect4, rect4, gfx::MaskFilterInfo(), rect4,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     R1->SetNew(shared_quad_state, rect1, rect1, render_pass_id,
                mask_resource_id, gfx::RectF(), gfx::Size(),
                gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
@@ -3068,18 +3069,18 @@
     // |       |           |
     // |   R2  |       R1  |
     // +-------+-----------+
-    shared_quad_state->SetAll(gfx::Transform(), rect5, rect5, gfx::RRectF(),
-                              rect5, is_clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                               rect1, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state3->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
-                               rect3, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state4->SetAll(gfx::Transform(), rect6, rect6, gfx::RRectF(),
-                               rect6, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect5, rect5, gfx::MaskFilterInfo(), rect5,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state3->SetAll(
+        gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state4->SetAll(
+        gfx::Transform(), rect6, rect6, gfx::MaskFilterInfo(), rect6,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     R1->SetNew(shared_quad_state, rect5, rect5, render_pass_id,
                mask_resource_id, gfx::RectF(), gfx::Size(),
                gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
@@ -3115,18 +3116,18 @@
     // |-----+     |       |
     // |   R2      |   R1  |
     // +-----------+-------+
-    shared_quad_state->SetAll(gfx::Transform(), rect5, rect5, gfx::RRectF(),
-                              rect5, is_clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                               rect1, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state3->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
-                               rect3, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
-    shared_quad_state4->SetAll(gfx::Transform(), rect7, rect7, gfx::RRectF(),
-                               rect7, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect5, rect5, gfx::MaskFilterInfo(), rect5,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state3->SetAll(
+        gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state4->SetAll(
+        gfx::Transform(), rect7, rect7, gfx::MaskFilterInfo(), rect7,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     R1->SetNew(shared_quad_state, rect5, rect5, render_pass_id,
                mask_resource_id, gfx::RectF(), gfx::Size(),
                gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
@@ -3204,11 +3205,11 @@
     // +--+--+
     // |  |  |
     // +--+--+
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     shared_quad_state2->SetAll(gfx::Transform(), rect_in_rect1, rect_in_rect1,
-                               gfx::RRectF(), rect_in_rect1, is_clipped,
+                               gfx::MaskFilterInfo(), rect_in_rect1, is_clipped,
                                opaque_content, opacity, SkBlendMode::kSrcOver,
                                0);
     quad1->SetNew(shared_quad_state, rect1_1, rect1_1, SK_ColorBLACK, false);
@@ -3248,8 +3249,8 @@
                 ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
     shared_quad_state2->SetAll(
         gfx::Transform(), rect_intersects_rect1, rect_intersects_rect1,
-        gfx::RRectF(), rect_intersects_rect1, is_clipped, opaque_content,
-        opacity, SkBlendMode::kSrcOver, 0);
+        gfx::MaskFilterInfo(), rect_intersects_rect1, is_clipped,
+        opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad5->SetNew(shared_quad_state2, rect_intersects_rect1,
                   rect_intersects_rect1, SK_ColorBLACK, false);
     EXPECT_EQ(5u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -3287,12 +3288,12 @@
 
     auto* quad6 = frame.render_pass_list.front()
                       ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
-    shared_quad_state->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
-                              rect2, is_clipped, opaque_content, opacity,
-                              SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
-                               rect3, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state2->SetAll(
+        gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad1->SetNew(shared_quad_state, rect2_1, rect2_1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state, rect2_2, rect2_2, SK_ColorBLACK, false);
     quad3->SetNew(shared_quad_state, rect2_3, rect2_3, SK_ColorBLACK, false);
@@ -3377,15 +3378,15 @@
     // |quad1| forms an occlusion rect; |quad2| follows a invertible transform
     // and is hiding behind quad1; |quad3| follows a non-invertible transform
     // and it is not covered by the occlusion rect.
-    shared_quad_state1->SetAll(invertible, rect1, rect1, gfx::RRectF(), rect1,
-                               is_clipped, opaque_content, opacity,
+    shared_quad_state1->SetAll(invertible, rect1, rect1, gfx::MaskFilterInfo(),
+                               rect1, is_clipped, opaque_content, opacity,
                                SkBlendMode::kSrcOver, 0);
-    shared_quad_state2->SetAll(invertible, rect2, rect2, gfx::RRectF(), rect2,
-                               is_clipped, opaque_content, opacity,
+    shared_quad_state2->SetAll(invertible, rect2, rect2, gfx::MaskFilterInfo(),
+                               rect2, is_clipped, opaque_content, opacity,
                                SkBlendMode::kSrcOver, 0);
-    shared_quad_state3->SetAll(non_invertible, rect3, rect3, gfx::RRectF(),
-                               rect3, is_clipped, opaque_content, opacity,
-                               SkBlendMode::kSrcOver, 0);
+    shared_quad_state3->SetAll(
+        non_invertible, rect3, rect3, gfx::MaskFilterInfo(), rect3, is_clipped,
+        opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad1->SetNew(shared_quad_state1, rect1, rect1, SK_ColorBLACK, false);
     quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
     quad3->SetNew(shared_quad_state3, rect3, rect3, SK_ColorBLACK, false);
@@ -3410,13 +3411,13 @@
     // |        |                 |        |
     // +--------+                 +--------+
     // Verify if draw occlusion can occlude quad with non-invertible
-    // transfrom.
-    shared_quad_state1->SetAll(invertible, rect1, rect1, gfx::RRectF(), rect1,
-                               is_clipped, opaque_content, opacity,
+    // transform.
+    shared_quad_state1->SetAll(invertible, rect1, rect1, gfx::MaskFilterInfo(),
+                               rect1, is_clipped, opaque_content, opacity,
                                SkBlendMode::kSrcOver, 0);
-    shared_quad_state3->SetAll(non_invertible_miss_z, rect3, rect3,
-                               gfx::RRectF(), rect3, is_clipped, opaque_content,
-                               opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state3->SetAll(
+        non_invertible_miss_z, rect3, rect3, gfx::MaskFilterInfo(), rect3,
+        is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
     quad1->SetNew(shared_quad_state1, rect1, rect1, SK_ColorBLACK, false);
     quad3->SetNew(shared_quad_state3, rect3, rect3, SK_ColorBLACK, false);
 
@@ -3455,9 +3456,9 @@
   // |    |
   // +----+
   {
-    shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
-                              rect1, is_clipped, are_contents_opaque, opacity,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
 
     quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
     EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -3522,7 +3523,7 @@
     shared_quad_state1->SetAll(
         gfx::Transform(), rect1 /* quad_layer_rect */,
         rect1 /* visible_quad_layer_rect */,
-        gfx::RRectF() /* rounded_corner_bounds*/, rect1 /*clip_rect */,
+        gfx::MaskFilterInfo() /* mask_filter_info */, rect1 /*clip_rect */,
         false /* is_clipped */, false /* are_contents_opaque */,
         0.5f /* opacity */, SkBlendMode::kSrcOver, 0 /* sorting_context_id */);
     auto* quad1 = pass->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
@@ -3535,7 +3536,7 @@
     shared_quad_state2->SetAll(
         gfx::Transform(), rect2 /* quad_layer_rect */,
         rect2 /* visible_quad_layer_rect */,
-        gfx::RRectF() /* rounded_corner_bounds */, rect2 /*clip_rect */,
+        gfx::MaskFilterInfo() /* mask_filter_info */, rect2 /*clip_rect */,
         false /* is_clipped */, true /* are_contents_opaque */,
         1.0f /* opacity */, SkBlendMode::kSrcOver, 0 /* sorting_context_id */);
     auto* quad2 = pass->quad_list.AllocateAndConstruct<SurfaceDrawQuad>();
@@ -3940,7 +3941,8 @@
   // The quad with rounded corner does not completely cover the quad below it.
   // The corners of the below quad are visiblg through the clipped corners.
   gfx::Rect quad_rect(10, 10, 100, 100);
-  gfx::RRectF rounded_corner_bounds(gfx::RectF(quad_rect), 10.f);
+  gfx::MaskFilterInfo mask_filter_info(
+      gfx::RRectF(gfx::RectF(quad_rect), 10.f));
 
   bool is_clipped = false;
   bool are_contents_opaque = true;
@@ -3958,16 +3960,16 @@
           ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
 
   {
-    shared_quad_state_occluded->SetAll(
-        gfx::Transform(), quad_rect, quad_rect, gfx::RRectF(), quad_rect,
-        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state_occluded->SetAll(gfx::Transform(), quad_rect, quad_rect,
+                                       gfx::MaskFilterInfo(), quad_rect,
+                                       is_clipped, are_contents_opaque, opacity,
+                                       SkBlendMode::kSrcOver, 0);
     occluded_quad->SetNew(shared_quad_state_occluded, quad_rect, quad_rect,
                           SK_ColorRED, false);
 
-    shared_quad_state_with_rrect->SetAll(gfx::Transform(), quad_rect, quad_rect,
-                                         rounded_corner_bounds, quad_rect,
-                                         is_clipped, are_contents_opaque,
-                                         opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state_with_rrect->SetAll(
+        gfx::Transform(), quad_rect, quad_rect, mask_filter_info, quad_rect,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     rounded_corner_quad->SetNew(shared_quad_state_with_rrect, quad_rect,
                                 quad_rect, SK_ColorBLUE, false);
 
@@ -3994,8 +3996,9 @@
   // The quad with rounded corner completely covers the quad below it.
   AggregatedFrame frame = MakeDefaultAggregatedFrame();
   gfx::Rect quad_rect(10, 10, 1000, 1000);
-  gfx::RRectF rounded_corner_bounds(gfx::RectF(quad_rect), 10.f);
   gfx::Rect occluded_quad_rect(13, 13, 994, 994);
+  gfx::MaskFilterInfo mask_filter_info(
+      gfx::RRectF(gfx::RectF(quad_rect), 10.f));
 
   bool is_clipped = false;
   bool are_contents_opaque = true;
@@ -4014,16 +4017,15 @@
 
   {
     shared_quad_state_occluded->SetAll(
-        gfx::Transform(), occluded_quad_rect, occluded_quad_rect, gfx::RRectF(),
-        occluded_quad_rect, is_clipped, are_contents_opaque, opacity,
-        SkBlendMode::kSrcOver, 0);
+        gfx::Transform(), occluded_quad_rect, occluded_quad_rect,
+        gfx::MaskFilterInfo(), occluded_quad_rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     occluded_quad->SetNew(shared_quad_state_occluded, occluded_quad_rect,
                           occluded_quad_rect, SK_ColorRED, false);
 
-    shared_quad_state_with_rrect->SetAll(gfx::Transform(), quad_rect, quad_rect,
-                                         rounded_corner_bounds, quad_rect,
-                                         is_clipped, are_contents_opaque,
-                                         opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state_with_rrect->SetAll(
+        gfx::Transform(), quad_rect, quad_rect, mask_filter_info, quad_rect,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     rounded_corner_quad->SetNew(shared_quad_state_with_rrect, quad_rect,
                                 quad_rect, SK_ColorBLUE, false);
 
@@ -4083,16 +4085,16 @@
 
   {
     shared_quad_state_occluder->SetAll(
-        gfx::Transform(), occluding_rect, occluding_rect, gfx::RRectF(),
+        gfx::Transform(), occluding_rect, occluding_rect, gfx::MaskFilterInfo(),
         occluding_rect, is_clipped, are_contents_opaque, opacity,
         SkBlendMode::kSrcOver, 0);
     quads[0]->SetNew(shared_quad_state_occluder, occluding_rect, occluding_rect,
                      SK_ColorRED, false);
 
     shared_quad_state_occluded->SetAll(
-        gfx::Transform(), occluded_sqs_rect, occluded_sqs_rect, gfx::RRectF(),
-        occluded_sqs_rect, is_clipped, are_contents_opaque, opacity,
-        SkBlendMode::kSrcOver, 0);
+        gfx::Transform(), occluded_sqs_rect, occluded_sqs_rect,
+        gfx::MaskFilterInfo(), occluded_sqs_rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     for (int i = 1; i < 4; i++) {
       quads[i]->SetNew(shared_quad_state_occluded, quad_rects[i - 1],
                        quad_rects[i - 1], SK_ColorRED, false);
@@ -4186,9 +4188,9 @@
   for (const auto& r : occluding_rects) {
     SharedQuadState* shared_quad_state_occluder =
         frame.render_pass_list.front()->CreateAndAppendSharedQuadState();
-    shared_quad_state_occluder->SetAll(gfx::Transform(), r, r, gfx::RRectF(), r,
-                                       is_clipped, are_contents_opaque, opacity,
-                                       SkBlendMode::kSrcOver, 0);
+    shared_quad_state_occluder->SetAll(
+        gfx::Transform(), r, r, gfx::MaskFilterInfo(), r, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     SolidColorDrawQuad* quad =
         frame.render_pass_list.front()
             ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
@@ -4200,7 +4202,7 @@
     SharedQuadState* shared_quad_state_occluded =
         frame.render_pass_list.front()->CreateAndAppendSharedQuadState();
     shared_quad_state_occluded->SetAll(
-        gfx::Transform(), occluded_rect, occluded_rect, gfx::RRectF(),
+        gfx::Transform(), occluded_rect, occluded_rect, gfx::MaskFilterInfo(),
         occluded_rect, is_clipped, are_contents_opaque, opacity,
         SkBlendMode::kSrcOver, 0);
     SolidColorDrawQuad* occluded_quad =
@@ -4268,7 +4270,7 @@
       frame.render_pass_list.front()
           ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
   shared_quad_state_occluding->SetAll(
-      gfx::Transform(), occluding_rect, occluding_rect, gfx::RRectF(),
+      gfx::Transform(), occluding_rect, occluding_rect, gfx::MaskFilterInfo(),
       occluding_rect, is_clipped, are_contents_opaque, opacity,
       SkBlendMode::kSrcOver, 0);
   occluding_quad->SetNew(shared_quad_state_occluding, occluding_rect,
@@ -4281,7 +4283,7 @@
       frame.render_pass_list.front()
           ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
   shared_quad_state_occluded->SetAll(
-      gfx::Transform(), occluded_rect, occluded_rect, gfx::RRectF(),
+      gfx::Transform(), occluded_rect, occluded_rect, gfx::MaskFilterInfo(),
       occluded_rect, is_clipped, are_contents_opaque, opacity,
       SkBlendMode::kSrcOver, 0);
   occluded_quad->SetNew(shared_quad_state_occluded, occluded_rect,
@@ -4317,7 +4319,8 @@
   //
   // * -> Visible rect for the quads.
   gfx::Rect quad_rect(10, 10, 1000, 1000);
-  gfx::RRectF rounded_corner_bounds(gfx::RectF(quad_rect), 10.f);
+  gfx::MaskFilterInfo mask_filter_info(
+      gfx::RRectF(gfx::RectF(quad_rect), 10.f));
   gfx::Rect occluded_quad_rect_1(0, 20, 600, 490);
   gfx::Rect occluded_quad_rect_2(600, 20, 600, 490);
   gfx::Rect occluded_quad_rect_3(0, 510, 600, 490);
@@ -4354,9 +4357,9 @@
 
   {
     shared_quad_state_occluded->SetAll(
-        gfx::Transform(), occluded_sqs_rect, occluded_sqs_rect, gfx::RRectF(),
-        occluded_sqs_rect, is_clipped, are_contents_opaque, opacity,
-        SkBlendMode::kSrcOver, 0);
+        gfx::Transform(), occluded_sqs_rect, occluded_sqs_rect,
+        gfx::MaskFilterInfo(), occluded_sqs_rect, is_clipped,
+        are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     occluded_quad_1->SetNew(shared_quad_state_occluded, occluded_quad_rect_1,
                             occluded_quad_rect_1, SK_ColorRED, false);
     occluded_quad_2->SetNew(shared_quad_state_occluded, occluded_quad_rect_2,
@@ -4366,10 +4369,9 @@
     occluded_quad_4->SetNew(shared_quad_state_occluded, occluded_quad_rect_4,
                             occluded_quad_rect_4, SK_ColorRED, false);
 
-    shared_quad_state_with_rrect->SetAll(gfx::Transform(), quad_rect, quad_rect,
-                                         rounded_corner_bounds, quad_rect,
-                                         is_clipped, are_contents_opaque,
-                                         opacity, SkBlendMode::kSrcOver, 0);
+    shared_quad_state_with_rrect->SetAll(
+        gfx::Transform(), quad_rect, quad_rect, mask_filter_info, quad_rect,
+        is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
     rounded_corner_quad->SetNew(shared_quad_state_with_rrect, quad_rect,
                                 quad_rect, SK_ColorBLUE, false);
 
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index fe0db90b..36b710f 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -1798,9 +1798,9 @@
 
   SetShaderOpacity(params->quad->shared_quad_state->opacity);
   if (current_program_->rounded_corner_rect_location() != -1) {
-    SetShaderRoundedCorner(
-        params->quad->shared_quad_state->rounded_corner_bounds,
-        params->window_matrix * params->projection_matrix);
+    SetShaderRoundedCorner(params->quad->shared_quad_state->mask_filter_info
+                               .rounded_corner_bounds(),
+                           params->window_matrix * params->projection_matrix);
   }
   SetShaderQuadF(params->surface_quad);
 }
@@ -2201,7 +2201,7 @@
     SetShaderColor(color, opacity);
     if (current_program_->rounded_corner_rect_location() != -1) {
       SetShaderRoundedCorner(
-          quad->shared_quad_state->rounded_corner_bounds,
+          quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
           current_frame()->window_matrix * current_frame()->projection_matrix);
     }
 
@@ -2388,7 +2388,7 @@
   SetShaderOpacity(quad->shared_quad_state->opacity);
   if (current_program_->rounded_corner_rect_location() != -1) {
     SetShaderRoundedCorner(
-        quad->shared_quad_state->rounded_corner_bounds,
+        quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
         current_frame()->window_matrix * current_frame()->projection_matrix);
   }
   DCHECK(CanApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode));
@@ -2488,7 +2488,7 @@
   SetShaderOpacity(quad->shared_quad_state->opacity);
   if (current_program_->rounded_corner_rect_location() != -1) {
     SetShaderRoundedCorner(
-        quad->shared_quad_state->rounded_corner_bounds,
+        quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
         current_frame()->window_matrix * current_frame()->projection_matrix);
   }
 
@@ -2628,7 +2628,7 @@
 
   if (current_program_->rounded_corner_rect_location() != -1) {
     SetShaderRoundedCorner(
-        quad->shared_quad_state->rounded_corner_bounds,
+        quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
         current_frame()->window_matrix * current_frame()->projection_matrix);
   }
 
@@ -2772,7 +2772,7 @@
   SetShaderOpacity(quad->shared_quad_state->opacity);
   if (current_program_->rounded_corner_rect_location() != -1) {
     SetShaderRoundedCorner(
-        quad->shared_quad_state->rounded_corner_bounds,
+        quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
         current_frame()->window_matrix * current_frame()->projection_matrix);
   }
   gfx::Size texture_size = lock.size();
@@ -2832,7 +2832,7 @@
 
   if (current_program_->rounded_corner_rect_location() != -1) {
     SetShaderRoundedCorner(
-        draw_cache_.rounded_corner_bounds,
+        draw_cache_.mask_filter_info.rounded_corner_bounds(),
         current_frame()->window_matrix * current_frame()->projection_matrix);
   }
 
@@ -2945,8 +2945,8 @@
       draw_cache_.needs_blending != quad->ShouldDrawWithBlending() ||
       draw_cache_.nearest_neighbor != quad->nearest_neighbor ||
       draw_cache_.background_color != quad->background_color ||
-      draw_cache_.rounded_corner_bounds !=
-          quad->shared_quad_state->rounded_corner_bounds ||
+      draw_cache_.mask_filter_info !=
+          quad->shared_quad_state->mask_filter_info ||
       draw_cache_.matrix_data.size() >= max_quads ||
       draw_cache_.is_video_frame != quad->is_video_frame) {
     FlushTextureQuadCache(SHARED_BINDING);
@@ -2956,8 +2956,7 @@
     draw_cache_.needs_blending = quad->ShouldDrawWithBlending();
     draw_cache_.nearest_neighbor = quad->nearest_neighbor;
     draw_cache_.background_color = quad->background_color;
-    draw_cache_.rounded_corner_bounds =
-        quad->shared_quad_state->rounded_corner_bounds;
+    draw_cache_.mask_filter_info = quad->shared_quad_state->mask_filter_info;
     draw_cache_.is_video_frame = quad->is_video_frame;
   }
 
@@ -4356,9 +4355,9 @@
   if (!use_fast_path_solid_color_quad_)
     return false;
 
-  // Rounded corners require blending with the background, which is not possible
+  // Mask filters require blending with the background, which is not possible
   // with the glClear draw method.
-  if (!sqs->rounded_corner_bounds.IsEmpty())
+  if (!sqs->mask_filter_info.IsEmpty())
     return false;
 
   // 3D transforms need vertex computation in 3D and cannot be handled using
diff --git a/components/viz/service/display/gl_renderer_draw_cache.h b/components/viz/service/display/gl_renderer_draw_cache.h
index a637154e..6abe06cc 100644
--- a/components/viz/service/display/gl_renderer_draw_cache.h
+++ b/components/viz/service/display/gl_renderer_draw_cache.h
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "components/viz/service/display/program_binding.h"
 #include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/rrect_f.h"
+#include "ui/gfx/mask_filter_info.h"
 
 namespace viz {
 
@@ -39,7 +39,7 @@
   bool needs_blending = false;
   bool nearest_neighbor = false;
   SkColor background_color = 0;
-  gfx::RRectF rounded_corner_bounds;
+  gfx::MaskFilterInfo mask_filter_info;
 
   // A cache for the coalesced quad data.
   std::vector<Float4> uv_xform_data;
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc
index 714398f..ca1df17 100644
--- a/components/viz/service/display/gl_renderer_unittest.cc
+++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -792,7 +792,7 @@
       root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
   SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
-                       gfx::Rect(1023, 1023), gfx::RRectF(),
+                       gfx::Rect(1023, 1023), gfx::MaskFilterInfo(),
                        gfx::Rect(1023, 1023), false, false, 1,
                        SkBlendMode::kSrcOver, 0);
   overlay_quad->SetNew(shared_state, gfx::Rect(1023, 1023),
@@ -855,7 +855,7 @@
       root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
   SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
-                       gfx::Rect(1025, 1025), gfx::RRectF(),
+                       gfx::Rect(1025, 1025), gfx::MaskFilterInfo(),
                        gfx::Rect(1025, 1025), false, false, 1,
                        SkBlendMode::kSrcOver, 0);
   overlay_quad->SetNew(shared_state, gfx::Rect(1025, 1025),
@@ -913,7 +913,7 @@
         root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
     SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
     shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
-                         gfx::Rect(kTextureSize), gfx::RRectF(),
+                         gfx::Rect(kTextureSize), gfx::MaskFilterInfo(),
                          gfx::Rect(kTextureSize), false, false, 1,
                          SkBlendMode::kSrcOver, 0);
     overlay_quad->SetNew(shared_state, gfx::Rect(kTextureSize),
@@ -1450,8 +1450,9 @@
   visible_rect.Inset(10, 20, 30, 40);
 
   SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(gfx::Transform(), gfx::Rect(), rect, gfx::RRectF(), rect,
-                       false, false, 1, SkBlendMode::kSrcOver, 0);
+  shared_state->SetAll(gfx::Transform(), gfx::Rect(), rect,
+                       gfx::MaskFilterInfo(), rect, false, false, 1,
+                       SkBlendMode::kSrcOver, 0);
 
   YUVVideoDrawQuad* quad =
       root_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
@@ -2003,8 +2004,8 @@
 
   // Add rounded corners to the solid color draw quad so that the fast path
   // of drawing using glClear is not used.
-  root_pass->shared_quad_state_list.front()->rounded_corner_bounds =
-      gfx::RRectF(gfx::RectF(quad_rect), 2.f);
+  root_pass->shared_quad_state_list.front()->mask_filter_info =
+      gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(quad_rect), 2.f));
 
   renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
   DrawFrame(renderer_.get(), viewport_size);
@@ -2031,8 +2032,8 @@
 
   // Add rounded corners to the solid color draw quad so that the fast path
   // of drawing using glClear is not used.
-  root_pass->shared_quad_state_list.front()->rounded_corner_bounds =
-      gfx::RRectF(gfx::RectF(quad_rect), 1.f);
+  root_pass->shared_quad_state_list.front()->mask_filter_info =
+      gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(quad_rect), 1.f));
 
   renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
   DrawFrame(renderer_.get(), viewport_size);
@@ -2911,7 +2912,7 @@
       root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
   SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
-                       gfx::Rect(viewport_size), gfx::RRectF(),
+                       gfx::Rect(viewport_size), gfx::MaskFilterInfo(),
                        gfx::Rect(viewport_size), false, false, 1,
                        SkBlendMode::kSrcOver, 0);
   overlay_quad->SetNew(shared_state, gfx::Rect(viewport_size),
@@ -3223,8 +3224,8 @@
   root_pass->damage_rect = root_pass_damage_rect;
   cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
 
-  root_pass->shared_quad_state_list.front()->rounded_corner_bounds =
-      gfx::RRectF(gfx::RectF(quad_rect), 5.f);
+  root_pass->shared_quad_state_list.front()->mask_filter_info =
+      gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(quad_rect), 5.f));
 
   // Fast Solid color draw quads should not be executed.
   AddExpectations(false /*use_fast_path*/, gfx::Rect());
@@ -3696,8 +3697,8 @@
       gfx::RectF tex_coord_rect(0, 0, 1, 1);
       SharedQuadState* shared_state =
           root_pass->CreateAndAppendSharedQuadState();
-      shared_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
-                           false, false, 1, SkBlendMode::kSrcOver, 0);
+      shared_state->SetAll(gfx::Transform(), rect, rect, gfx::MaskFilterInfo(),
+                           rect, false, false, 1, SkBlendMode::kSrcOver, 0);
       YUVVideoDrawQuad* quad =
           root_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
       quad->SetNew(shared_state, rect, rect, needs_blending, tex_coord_rect,
@@ -4111,8 +4112,8 @@
     sqs->is_clipped = true;
     sqs->clip_rect = gfx::Rect(2, 2, 6, 6);
     const float radius = 2;
-    sqs->rounded_corner_bounds =
-        gfx::RRectF(gfx::RectF(sqs->clip_rect), radius);
+    sqs->mask_filter_info =
+        gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(sqs->clip_rect), radius));
 
     switch (subtest) {
       case 0:
@@ -4132,8 +4133,11 @@
         break;
       case 2:
         // Subtest 2 has a non-simple rounded rect.
-        sqs->rounded_corner_bounds.SetCornerRadii(
-            gfx::RRectF::Corner::kUpperLeft, 1, 1);
+        gfx::RRectF rounded_corner_bounds =
+            sqs->mask_filter_info.rounded_corner_bounds();
+        rounded_corner_bounds.SetCornerRadii(gfx::RRectF::Corner::kUpperLeft, 1,
+                                             1);
+        sqs->mask_filter_info = gfx::MaskFilterInfo(rounded_corner_bounds);
         // Called 2 extra times in order to set up the rounded corner
         // parameters in the shader, because the CALayer is not handling
         // the rounded corners.
@@ -5095,7 +5099,7 @@
       root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
   SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
-                       gfx::Rect(50, 50), gfx::RRectF(),
+                       gfx::Rect(50, 50), gfx::MaskFilterInfo(),
                        gfx::Rect(viewport_size), false, false, 1,
                        SkBlendMode::kSrcOver, 0);
   overlay_quad->SetNew(
diff --git a/components/viz/service/display/overlay_candidate.cc b/components/viz/service/display/overlay_candidate.cc
index 925eefbb..d378382 100644
--- a/components/viz/service/display/overlay_candidate.cc
+++ b/components/viz/service/display/overlay_candidate.cc
@@ -157,8 +157,8 @@
   // We don't support an opacity value different than one for an overlay plane.
   if (quad->shared_quad_state->opacity != 1.f)
     return false;
-  // We can't support overlays with rounded corner clipping.
-  if (!quad->shared_quad_state->rounded_corner_bounds.IsEmpty())
+  // We can't support overlays with mask filter.
+  if (!quad->shared_quad_state->mask_filter_info.IsEmpty())
     return false;
   // We support only kSrc (no blending) and kSrcOver (blending with premul).
   if (!(quad->shared_quad_state->blend_mode == SkBlendMode::kSrc ||
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc
index f6dc6242..1497075 100644
--- a/components/viz/service/display/overlay_unittest.cc
+++ b/components/viz/service/display/overlay_unittest.cc
@@ -3326,7 +3326,7 @@
   quad_state->SetAll(
       /*quad_layer_rect=*/quad_to_target_transform, quad_rect,
       /*visible_quad_layer_rect=*/quad_rect,
-      /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/gfx::Rect(),
+      /*mask_filter_info=*/gfx::MaskFilterInfo(), /*clip_rect=*/gfx::Rect(),
       /*is_clipped=*/false,
       /*are contents opaque=*/true,
       /*opacity=*/1.f,
diff --git a/components/viz/service/display/renderer_perftest.cc b/components/viz/service/display/renderer_perftest.cc
index 00f6e3e..61b88cc 100644
--- a/components/viz/service/display/renderer_perftest.cc
+++ b/components/viz/service/display/renderer_perftest.cc
@@ -143,19 +143,18 @@
     gfx::Transform quad_to_target_transform,
     const gfx::Rect& rect,
     CompositorRenderPass* render_pass,
-    const gfx::RRectF& rrect) {
+    const gfx::MaskFilterInfo& mask_filter_info) {
   const gfx::Rect layer_rect = rect;
   const gfx::Rect visible_layer_rect = rect;
   const gfx::Rect clip_rect = rect;
   const bool is_clipped = false;
   const bool are_contents_opaque = false;
   const float opacity = 1.0f;
-  const gfx::RRectF rounded_corner_bounds = rrect;
   const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
   const int sorting_context_id = 0;
   SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
-                       rounded_corner_bounds, clip_rect, is_clipped,
+                       mask_filter_info, clip_rect, is_clipped,
                        are_contents_opaque, opacity, blend_mode,
                        sorting_context_id);
   return shared_state;
@@ -510,7 +509,7 @@
       std::unique_ptr<CompositorRenderPass> pass = CreateTestRootRenderPass();
 
       SharedQuadState* shared_state = CreateTestSharedQuadState(
-          gfx::Transform(), kSurfaceRect, pass.get(), gfx::RRectF());
+          gfx::Transform(), kSurfaceRect, pass.get(), gfx::MaskFilterInfo());
 
       CreateTestTextureDrawQuad(resource_list_.back().id, kSurfaceRect,
                                 /*background_color=*/SK_ColorTRANSPARENT,
@@ -545,7 +544,7 @@
     do {
       std::unique_ptr<CompositorRenderPass> pass = CreateTestRootRenderPass();
       SharedQuadState* shared_state = CreateTestSharedQuadState(
-          gfx::Transform(), kSurfaceRect, pass.get(), gfx::RRectF());
+          gfx::Transform(), kSurfaceRect, pass.get(), gfx::MaskFilterInfo());
 
       for (int i = 0; i < 5; i++) {
         for (int j = 0; j < 5; j++) {
@@ -582,7 +581,7 @@
     do {
       std::unique_ptr<CompositorRenderPass> pass = CreateTestRootRenderPass();
       SharedQuadState* shared_state = CreateTestSharedQuadState(
-          gfx::Transform(), kSurfaceRect, pass.get(), gfx::RRectF());
+          gfx::Transform(), kSurfaceRect, pass.get(), gfx::MaskFilterInfo());
 
       for (int i = 0; i < 5; i++) {
         for (int j = 0; j < 5; j++) {
@@ -641,7 +640,7 @@
         // SharedQuadState
         SharedQuadState* shared_state = CreateTestSharedQuadState(
             current_transform, gfx::Rect(kSurfaceSize), pass.get(),
-            gfx::RRectF());
+            gfx::MaskFilterInfo());
         ResourceId resource_id =
             share_resources ? resource_list_[0].id : resource_list_[i].id;
         CreateTestTileDrawQuad(resource_id, gfx::Rect(kTileSize), kTextureSize,
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc
index 3cf3b97e..0749e08 100644
--- a/components/viz/service/display/renderer_pixeltest.cc
+++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -151,12 +151,12 @@
   const bool is_clipped = false;
   const bool are_contents_opaque = false;
   const float opacity = 1.0f;
-  const gfx::RRectF rounded_corner_bounds = rrect;
+  const gfx::MaskFilterInfo mask_filter_info(rrect);
   const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
   int sorting_context_id = 0;
   SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
-                       rounded_corner_bounds, clip_rect, is_clipped,
+                       mask_filter_info, clip_rect, is_clipped,
                        are_contents_opaque, opacity, blend_mode,
                        sorting_context_id);
   return shared_state;
@@ -176,7 +176,7 @@
   int sorting_context_id = 0;
   SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
-                       /*rounded_corner_bounds=*/gfx::RRectF(), clip_rect,
+                       /*mask_filter_info=*/gfx::MaskFilterInfo(), clip_rect,
                        is_clipped, are_contents_opaque, opacity, blend_mode,
                        sorting_context_id);
   return shared_state;
diff --git a/components/viz/service/display/skia_readback_pixeltest.cc b/components/viz/service/display/skia_readback_pixeltest.cc
index 509179b4..64d15de 100644
--- a/components/viz/service/display/skia_readback_pixeltest.cc
+++ b/components/viz/service/display/skia_readback_pixeltest.cc
@@ -49,7 +49,7 @@
   const gfx::Rect clip_rect = rect;
   SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(gfx::Transform(), layer_rect, visible_layer_rect,
-                       gfx::RRectF(), clip_rect, /*is_clipped=*/false,
+                       gfx::MaskFilterInfo(), clip_rect, /*is_clipped=*/false,
                        /*are_contents_opaque=*/false, /*opacity=*/1.0f,
                        SkBlendMode::kSrcOver,
                        /*sorting_context_id=*/0);
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index a3ff43e5..9f944fd 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -1240,8 +1240,8 @@
   if (ShouldApplyRoundedCorner(quad)) {
     // Transform by the window and projection matrix to go from target to
     // device space, which should always be a scale+translate.
-    SkRRect corner_bounds =
-        SkRRect(quad->shared_quad_state->rounded_corner_bounds);
+    SkRRect corner_bounds = SkRRect(
+        quad->shared_quad_state->mask_filter_info.rounded_corner_bounds());
     SkMatrix to_device;
     gfx::TransformToFlattenedSkMatrix(target_to_device, &to_device);
 
diff --git a/components/viz/service/display/software_renderer.cc b/components/viz/service/display/software_renderer.cc
index 93ee9ca..6a8e248 100644
--- a/components/viz/service/display/software_renderer.cc
+++ b/components/viz/service/display/software_renderer.cc
@@ -259,7 +259,8 @@
   }
 
   if (should_apply_rounded_corner)
-    SetClipRRect(quad->shared_quad_state->rounded_corner_bounds);
+    SetClipRRect(
+        quad->shared_quad_state->mask_filter_info.rounded_corner_bounds());
 
   gfx::Transform quad_rect_matrix;
   QuadRectTransform(&quad_rect_matrix,
diff --git a/components/viz/service/display/software_renderer_unittest.cc b/components/viz/service/display/software_renderer_unittest.cc
index 83b8301f..202b3a7 100644
--- a/components/viz/service/display/software_renderer_unittest.cc
+++ b/components/viz/service/display/software_renderer_unittest.cc
@@ -153,7 +153,7 @@
   SharedQuadState* shared_quad_state =
       root_render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(gfx::Transform(), outer_rect, outer_rect,
-                            gfx::RRectF(), outer_rect, false, true, 1.0,
+                            gfx::MaskFilterInfo(), outer_rect, false, true, 1.0,
                             SkBlendMode::kSrcOver, 0);
   auto* inner_quad =
       root_render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -221,7 +221,7 @@
   SharedQuadState* shared_quad_state =
       root_render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(gfx::Transform(), outer_rect, outer_rect,
-                            gfx::RRectF(), outer_rect, false, true, 1.0,
+                            gfx::MaskFilterInfo(), outer_rect, false, true, 1.0,
                             SkBlendMode::kSrcOver, 0);
   auto* inner_quad = root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
   inner_quad->SetNew(shared_quad_state, inner_rect, inner_rect, needs_blending,
@@ -283,7 +283,7 @@
   SharedQuadState* shared_quad_state =
       root_render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(gfx::Transform(), tile_rect, tile_rect,
-                            gfx::RRectF(), tile_rect, false, true, 1.0,
+                            gfx::MaskFilterInfo(), tile_rect, false, true, 1.0,
                             SkBlendMode::kSrcOver, 0);
   auto* quad = root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
   quad->SetNew(shared_quad_state, tile_rect, tile_rect, needs_blending,
@@ -444,8 +444,8 @@
     SharedQuadState* shared_quad_state =
         root_pass->CreateAndAppendSharedQuadState();
     shared_quad_state->SetAll(gfx::Transform(), outer_rect, outer_rect,
-                              gfx::RRectF(), gfx::Rect(1, 1, 30, 30), true,
-                              true, 1.0, SkBlendMode::kSrcOver, 0);
+                              gfx::MaskFilterInfo(), gfx::Rect(1, 1, 30, 30),
+                              true, true, 1.0, SkBlendMode::kSrcOver, 0);
     auto* outer_quad = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
     outer_quad->SetNew(shared_quad_state, outer_rect, outer_rect, SK_ColorGREEN,
                        false);
@@ -458,10 +458,10 @@
 
     SharedQuadState* shared_quad_state =
         root_pass->CreateAndAppendSharedQuadState();
-    shared_quad_state->SetAll(gfx::Transform(), inner_rect, inner_rect,
-                              gfx::RRectF(gfx::RectF(5, 5, 10, 10), 2),
-                              inner_rect, false, true, 1.0,
-                              SkBlendMode::kSrcOver, 0);
+    shared_quad_state->SetAll(
+        gfx::Transform(), inner_rect, inner_rect,
+        gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(5, 5, 10, 10), 2)),
+        inner_rect, false, true, 1.0, SkBlendMode::kSrcOver, 0);
     auto* inner_quad = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
     inner_quad->SetNew(shared_quad_state, inner_rect, inner_rect, SK_ColorRED,
                        false);
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index 5a73163b..b269da2 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -113,22 +113,20 @@
   gfx::ContentColorUsage content_color_usage = gfx::ContentColorUsage::kSRGB;
 };
 
-struct SurfaceAggregator::RoundedCornerInfo {
-  RoundedCornerInfo() = default;
-
-  // |target_transform| is the transform that maps |bounds_arg| from its current
-  // space into the desired target space. It must be an axis aligned transform.
-  RoundedCornerInfo(const gfx::RRectF& bounds_arg,
-                    bool is_fast_rounded_corner,
+struct SurfaceAggregator::MaskFilterInfoExt {
+  MaskFilterInfoExt() = default;
+  MaskFilterInfoExt(const gfx::MaskFilterInfo& mask_filter_info_arg,
+                    bool is_fast_rounded_corner_arg,
                     const gfx::Transform target_transform)
-      : bounds(bounds_arg), is_fast_rounded_corner(is_fast_rounded_corner) {
-    if (bounds.IsEmpty())
+      : mask_filter_info(mask_filter_info_arg),
+        is_fast_rounded_corner(is_fast_rounded_corner_arg) {
+    if (mask_filter_info.IsEmpty())
       return;
-    bool success = target_transform.TransformRRectF(&bounds);
+    bool success = mask_filter_info.Transform(target_transform);
     DCHECK(success);
   }
 
-  gfx::RRectF bounds;
+  gfx::MaskFilterInfo mask_filter_info;
   bool is_fast_rounded_corner;
 };
 
@@ -427,7 +425,7 @@
     bool ignore_undamaged,
     gfx::Rect* damage_rect_in_quad_space,
     bool* damage_rect_in_quad_space_valid,
-    const RoundedCornerInfo& rounded_corner_info) {
+    const MaskFilterInfoExt& mask_filter_info) {
   SurfaceId primary_surface_id = surface_quad->surface_range.end();
   Surface* latest_surface =
       manager_->GetLatestInFlightSurface(surface_quad->surface_range);
@@ -450,7 +448,7 @@
   // can happen after a Viz process crash.
   if (!latest_surface || !latest_surface->HasActiveFrame()) {
     EmitDefaultBackgroundColorQuad(surface_quad, target_transform, clip_rect,
-                                   dest_pass, rounded_corner_info);
+                                   dest_pass, mask_filter_info);
     return;
   }
 
@@ -470,13 +468,13 @@
                                surface_quad->shared_quad_state,
                                target_transform, clip_rect,
                                fallback_frame.metadata.root_background_color,
-                               dest_pass, rounded_corner_info);
+                               dest_pass, mask_filter_info);
   }
 
   EmitSurfaceContent(latest_surface, parent_device_scale_factor, surface_quad,
                      target_transform, clip_rect, dest_pass, ignore_undamaged,
                      damage_rect_in_quad_space, damage_rect_in_quad_space_valid,
-                     rounded_corner_info);
+                     mask_filter_info);
 }
 
 void SurfaceAggregator::EmitSurfaceContent(
@@ -489,7 +487,7 @@
     bool ignore_undamaged,
     gfx::Rect* damage_rect_in_quad_space,
     bool* damage_rect_in_quad_space_valid,
-    const RoundedCornerInfo& rounded_corner_info) {
+    const MaskFilterInfoExt& mask_filter_info) {
   // If this surface's id is already in our referenced set then it creates
   // a cycle in the graph and should be dropped.
   SurfaceId surface_id = surface->surface_id();
@@ -578,7 +576,7 @@
   bool merge_pass =
       CanPotentiallyMergePass(*surface_quad) && !reflected_and_scaled &&
       copy_requests.empty() && combined_transform.Preserves2dAxisAlignment() &&
-      CanMergeRoundedCorner(rounded_corner_info, *render_pass_list.back());
+      CanMergeMaskFilterInfo(mask_filter_info, *render_pass_list.back());
 
   if (frame.metadata.delegated_ink_metadata) {
     // The metadata must be taken off of the surface, rather than a copy being
@@ -632,7 +630,7 @@
 
     CopyQuadsToPass(source, copy_pass.get(), frame.device_scale_factor(),
                     child_to_parent_map, gfx::Transform(), {}, surface_id,
-                    RoundedCornerInfo());
+                    MaskFilterInfoExt());
 
     // If the render pass has copy requests, or should be cached, or has
     // moving-pixel filters, or in a moving-pixel surface, we should damage the
@@ -678,7 +676,7 @@
 
     CopyQuadsToPass(last_pass, dest_pass, frame.device_scale_factor(),
                     child_to_parent_map, combined_transform, quads_clip,
-                    surface_id, rounded_corner_info);
+                    surface_id, mask_filter_info);
   } else {
     auto* shared_quad_state = CopyAndScaleSharedQuadState(
         source_sqs, scaled_quad_to_target_transform, target_transform,
@@ -688,7 +686,7 @@
         gfx::ScaleToEnclosingRect(source_sqs->visible_quad_layer_rect,
                                   inverse_extra_content_scale_x,
                                   inverse_extra_content_scale_y),
-        clip_rect, dest_pass, rounded_corner_info);
+        clip_rect, dest_pass, mask_filter_info);
 
     // At this point, we need to calculate three values in order to construct
     // the CompositorRenderPassDrawQuad:
@@ -748,14 +746,14 @@
     const gfx::Transform& target_transform,
     const ClipData& clip_rect,
     AggregatedRenderPass* dest_pass,
-    const RoundedCornerInfo& rounded_corner_info) {
+    const MaskFilterInfoExt& mask_filter_info) {
   // The primary surface is unavailable and there is no fallback
   // surface specified so create a SolidColorDrawQuad with the default
   // background color.
   SkColor background_color = surface_quad->default_background_color;
   auto* shared_quad_state =
       CopySharedQuadState(surface_quad->shared_quad_state, target_transform,
-                          clip_rect, dest_pass, rounded_corner_info);
+                          clip_rect, dest_pass, mask_filter_info);
 
   auto* solid_color_quad =
       dest_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -771,7 +769,7 @@
     const ClipData& clip_rect,
     SkColor background_color,
     AggregatedRenderPass* dest_pass,
-    const RoundedCornerInfo& rounded_corner_info) {
+    const MaskFilterInfoExt& mask_filter_info) {
   bool has_transparent_background = background_color == SK_ColorTRANSPARENT;
 
   // If the fallback Surface's active CompositorFrame has a non-transparent
@@ -789,7 +787,7 @@
         primary_shared_quad_state,
         primary_shared_quad_state->quad_to_target_transform, target_transform,
         right_gutter_rect, right_gutter_rect, clip_rect, dest_pass,
-        rounded_corner_info);
+        mask_filter_info);
 
     auto* right_gutter =
         dest_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -806,7 +804,7 @@
         primary_shared_quad_state,
         primary_shared_quad_state->quad_to_target_transform, target_transform,
         bottom_gutter_rect, bottom_gutter_rect, clip_rect, dest_pass,
-        rounded_corner_info);
+        mask_filter_info);
 
     auto* bottom_gutter =
         dest_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -858,7 +856,7 @@
       /*quad_to_target_transform=*/gfx::Transform(),
       /*quad_layer_rect=*/output_rect,
       /*visible_quad_layer_rect=*/output_rect,
-      /*rounded_corner_bounds=*/gfx::RRectF(),
+      /*mask_filter_info=*/gfx::MaskFilterInfo(),
       /*clip_rect=*/gfx::Rect(),
       /*is_clipped=*/false, /*are_contents_opaque=*/false, /*opacity=*/1.f,
       /*blend_mode=*/SkBlendMode::kSrc, /*sorting_context_id=*/0);
@@ -915,7 +913,7 @@
       /*quad_to_target_transform=*/root_surface_transform_,
       /*quad_layer_rect=*/output_rect,
       /*visible_quad_layer_rect=*/output_rect,
-      /*rounded_corner_bounds=*/gfx::RRectF(),
+      /*mask_filter_info=*/gfx::MaskFilterInfo(),
       /*clip_rect=*/gfx::Rect(),
       /*is_clipped=*/false, are_contents_opaque, /*opacity=*/1.f,
       /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
@@ -935,11 +933,11 @@
     const gfx::Transform& target_transform,
     const ClipData& clip_rect,
     AggregatedRenderPass* dest_render_pass,
-    const RoundedCornerInfo& rounded_corner_info) {
+    const MaskFilterInfoExt& mask_filter_info) {
   return CopyAndScaleSharedQuadState(
       source_sqs, source_sqs->quad_to_target_transform, target_transform,
       source_sqs->quad_layer_rect, source_sqs->visible_quad_layer_rect,
-      clip_rect, dest_render_pass, rounded_corner_info);
+      clip_rect, dest_render_pass, mask_filter_info);
 }
 
 SharedQuadState* SurfaceAggregator::CopyAndScaleSharedQuadState(
@@ -950,7 +948,7 @@
     const gfx::Rect& visible_quad_layer_rect,
     const ClipData& clip_rect,
     AggregatedRenderPass* dest_render_pass,
-    const RoundedCornerInfo& rounded_corner_info) {
+    const MaskFilterInfoExt& mask_filter_info_ext) {
   auto* shared_quad_state = dest_render_pass->CreateAndAppendSharedQuadState();
   ClipData new_clip_rect = CalculateClipRect(
       clip_rect, {source_sqs->is_clipped, source_sqs->clip_rect},
@@ -967,12 +965,12 @@
 
   shared_quad_state->SetAll(
       new_transform, quad_layer_rect, visible_quad_layer_rect,
-      rounded_corner_info.bounds, new_clip_rect.rect, new_clip_rect.is_clipped,
-      source_sqs->are_contents_opaque, source_sqs->opacity,
-      source_sqs->blend_mode, source_sqs->sorting_context_id);
+      mask_filter_info_ext.mask_filter_info, new_clip_rect.rect,
+      new_clip_rect.is_clipped, source_sqs->are_contents_opaque,
+      source_sqs->opacity, source_sqs->blend_mode,
+      source_sqs->sorting_context_id);
   shared_quad_state->is_fast_rounded_corner =
-      rounded_corner_info.is_fast_rounded_corner;
-
+      mask_filter_info_ext.is_fast_rounded_corner,
   shared_quad_state->de_jelly_delta_y = source_sqs->de_jelly_delta_y;
 
   return shared_quad_state;
@@ -986,7 +984,7 @@
     const gfx::Transform& target_transform,
     const ClipData& clip_rect,
     const SurfaceId& surface_id,
-    const RoundedCornerInfo& parent_rounded_corner_info) {
+    const MaskFilterInfoExt& parent_mask_filter_info_ext) {
   const QuadList& source_quad_list = source_pass.quad_list;
   const SharedQuadState* last_copied_source_shared_quad_state = nullptr;
 
@@ -1026,12 +1024,12 @@
       ProcessOverlayDamageList(source_pass, dest_pass, target_transform,
                                surface_id, clip_rect, &overlay_damage_index);
 
-  RoundedCornerInfo new_rounded_corner_info = parent_rounded_corner_info;
+  MaskFilterInfoExt new_mask_filter_info_ext = parent_mask_filter_info_ext;
   for (auto* quad : source_quad_list) {
     // Both cannot be set at once. If this happens then a surface is being
     // merged when it should not.
-    DCHECK(quad->shared_quad_state->rounded_corner_bounds.IsEmpty() ||
-           parent_rounded_corner_info.bounds.IsEmpty());
+    DCHECK(quad->shared_quad_state->mask_filter_info.IsEmpty() ||
+           parent_mask_filter_info_ext.mask_filter_info.IsEmpty());
 
     if (quad->material == DrawQuad::Material::kSurfaceContent) {
       const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
@@ -1042,27 +1040,27 @@
       if (!surface_quad->surface_range.end().is_valid())
         continue;
 
-      if (parent_rounded_corner_info.bounds.IsEmpty()) {
-        new_rounded_corner_info = RoundedCornerInfo(
-            quad->shared_quad_state->rounded_corner_bounds,
+      if (parent_mask_filter_info_ext.mask_filter_info.IsEmpty()) {
+        new_mask_filter_info_ext = MaskFilterInfoExt(
+            quad->shared_quad_state->mask_filter_info,
             quad->shared_quad_state->is_fast_rounded_corner, target_transform);
       }
 
       HandleSurfaceQuad(
           surface_quad, parent_device_scale_factor, target_transform, clip_rect,
           dest_pass, ignore_undamaged, &damage_rect_in_quad_space,
-          &damage_rect_in_quad_space_valid, new_rounded_corner_info);
+          &damage_rect_in_quad_space_valid, new_mask_filter_info_ext);
     } else {
       if (quad->shared_quad_state != last_copied_source_shared_quad_state) {
-        if (parent_rounded_corner_info.bounds.IsEmpty()) {
-          new_rounded_corner_info =
-              RoundedCornerInfo(quad->shared_quad_state->rounded_corner_bounds,
+        if (parent_mask_filter_info_ext.mask_filter_info.IsEmpty()) {
+          new_mask_filter_info_ext =
+              MaskFilterInfoExt(quad->shared_quad_state->mask_filter_info,
                                 quad->shared_quad_state->is_fast_rounded_corner,
                                 target_transform);
         }
         SharedQuadState* dest_shared_quad_state =
             CopySharedQuadState(quad->shared_quad_state, target_transform,
-                                clip_rect, dest_pass, new_rounded_corner_info);
+                                clip_rect, dest_pass, new_mask_filter_info_ext);
 
         if (quad == quad_with_overlay_damage_index)
           dest_shared_quad_state->overlay_damage_index = overlay_damage_index;
@@ -1220,7 +1218,7 @@
                     child_to_parent_map,
                     apply_surface_transform_to_root_pass ? surface_transform
                                                          : gfx::Transform(),
-                    {}, surface->surface_id(), RoundedCornerInfo());
+                    {}, surface->surface_id(), MaskFilterInfoExt());
 
     // If the render pass has copy requests, or should be cached, or has
     // moving-pixel filters, or in a moving-pixel surface, we should damage the
@@ -1698,23 +1696,24 @@
   }
 }
 
-bool SurfaceAggregator::CanMergeRoundedCorner(
-    const RoundedCornerInfo& rounded_corner_info,
+bool SurfaceAggregator::CanMergeMaskFilterInfo(
+    const MaskFilterInfoExt& mask_filter_info_ext,
     const CompositorRenderPass& root_render_pass) {
-  // If the quad has no rounded corner, then we do not have to block merging.
-  if (rounded_corner_info.bounds.IsEmpty())
+  // If the quad has no mask filter, then we do not have to block merging.
+  if (mask_filter_info_ext.mask_filter_info.IsEmpty())
     return true;
 
   // If the quad has rounded corner and it is not a fast rounded corner, we
   // cannot merge.
-  if (!rounded_corner_info.is_fast_rounded_corner)
+  if (mask_filter_info_ext.mask_filter_info.HasRoundedCorners() &&
+      !mask_filter_info_ext.is_fast_rounded_corner)
     return false;
 
-  // If any of the quads in the root render pass has a rounded corner of its
+  // If any of the quads in the root render pass has a mask filter of its
   // own, then we cannot merge.
   const SharedQuadStateList& sqs_list = root_render_pass.shared_quad_state_list;
   for (const auto* sqs : sqs_list) {
-    if (!sqs->rounded_corner_bounds.IsEmpty())
+    if (!sqs->mask_filter_info.IsEmpty())
       return false;
   }
   return true;
@@ -2212,8 +2211,8 @@
   auto* new_state = root_pass->CreateAndAppendSharedQuadState();
   gfx::Transform transform;
   new_state->SetAll(transform, render_pass->output_rect,
-                    render_pass->output_rect, gfx::RRectF(), jelly_clip, true,
-                    false, opacity, blend_mode, 0);
+                    render_pass->output_rect, gfx::MaskFilterInfo(), jelly_clip,
+                    true, false, opacity, blend_mode, 0);
   auto* quad =
       root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
   quad->SetNew(new_state, render_pass->output_rect, render_pass->output_rect,
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h
index 7f49924..abfe1b88 100644
--- a/components/viz/service/display/surface_aggregator.h
+++ b/components/viz/service/display/surface_aggregator.h
@@ -93,9 +93,9 @@
  private:
   struct ClipData;
   struct PrewalkResult;
-  struct RoundedCornerInfo;
   struct ChildSurfaceInfo;
   struct RenderPassMapEntry;
+  struct MaskFilterInfoExt;
 
   // Helper function that gets a list of render passes and returns a map from
   // render pass ids to render passes.
@@ -115,7 +115,7 @@
                          bool ignore_undamaged,
                          gfx::Rect* damage_rect_in_quad_space,
                          bool* damage_rect_in_quad_space_valid,
-                         const RoundedCornerInfo& rounded_corner_info);
+                         const MaskFilterInfoExt& mask_filter_info_pair);
 
   void EmitSurfaceContent(Surface* surface,
                           float parent_device_scale_factor,
@@ -126,14 +126,14 @@
                           bool ignore_undamaged,
                           gfx::Rect* damage_rect_in_quad_space,
                           bool* damage_rect_in_quad_space_valid,
-                          const RoundedCornerInfo& rounded_corner_info);
+                          const MaskFilterInfoExt& mask_filter_info_pair);
 
   void EmitDefaultBackgroundColorQuad(
       const SurfaceDrawQuad* surface_quad,
       const gfx::Transform& target_transform,
       const ClipData& clip_rect,
       AggregatedRenderPass* dest_pass,
-      const RoundedCornerInfo& rounded_corner_info);
+      const MaskFilterInfoExt& mask_filter_info_pair);
 
   void EmitGutterQuadsIfNecessary(
       const gfx::Rect& primary_rect,
@@ -143,14 +143,14 @@
       const ClipData& clip_rect,
       SkColor background_color,
       AggregatedRenderPass* dest_pass,
-      const RoundedCornerInfo& rounded_corner_info);
+      const MaskFilterInfoExt& mask_filter_info_pair);
 
   SharedQuadState* CopySharedQuadState(
       const SharedQuadState* source_sqs,
       const gfx::Transform& target_transform,
       const ClipData& clip_rect,
       AggregatedRenderPass* dest_render_pass,
-      const RoundedCornerInfo& rounded_corner_info);
+      const MaskFilterInfoExt& mask_filter_info_pair);
 
   SharedQuadState* CopyAndScaleSharedQuadState(
       const SharedQuadState* source_sqs,
@@ -160,7 +160,7 @@
       const gfx::Rect& visible_quad_layer_rect,
       const ClipData& clip_rect,
       AggregatedRenderPass* dest_render_pass,
-      const RoundedCornerInfo& rounded_corner_info);
+      const MaskFilterInfoExt& mask_filter_info_pair);
 
   void CopyQuadsToPass(
       const CompositorRenderPass& source_pass,
@@ -170,7 +170,7 @@
       const gfx::Transform& target_transform,
       const ClipData& clip_rect,
       const SurfaceId& surface_id,
-      const RoundedCornerInfo& rounded_corner_info);
+      const MaskFilterInfoExt& mask_filter_info_pair);
 
   // Recursively walks through the render pass and updates the
   // |can_use_backdrop_filter_cache| flag on all RenderPassDrawQuads(RPDQ).
@@ -235,9 +235,9 @@
   void PropagateCopyRequestPasses();
 
   // Returns true if the quad list from the render pass provided can be merged
-  // with its target render pass based on rounded corners.
-  bool CanMergeRoundedCorner(const RoundedCornerInfo& rounded_corner_info,
-                             const CompositorRenderPass& root_render_pass);
+  // with its target render pass based on mask filter info.
+  bool CanMergeMaskFilterInfo(const MaskFilterInfoExt& mask_filter_info_pair,
+                              const CompositorRenderPass& root_render_pass);
 
   int ChildIdForSurface(Surface* surface);
   bool IsSurfaceFrameIndexSameAsPrevious(const Surface* surface) const;
diff --git a/components/viz/service/display/surface_aggregator_pixeltest.cc b/components/viz/service/display/surface_aggregator_pixeltest.cc
index bc0ac6bb..96203ed4 100644
--- a/components/viz/service/display/surface_aggregator_pixeltest.cc
+++ b/components/viz/service/display/surface_aggregator_pixeltest.cc
@@ -72,7 +72,7 @@
     const gfx::Size& size) {
   const gfx::Rect layer_rect = gfx::Rect(size);
   const gfx::Rect visible_layer_rect = gfx::Rect(size);
-  const gfx::RRectF rounded_corner_bounds = gfx::RRectF();
+  const gfx::MaskFilterInfo mask_filter_info;
   const gfx::Rect clip_rect = gfx::Rect(size);
   bool is_clipped = false;
   bool are_contents_opaque = false;
@@ -80,7 +80,7 @@
   const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
   auto* shared_state = render_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(transform, layer_rect, visible_layer_rect,
-                       rounded_corner_bounds, clip_rect, is_clipped,
+                       mask_filter_info, clip_rect, is_clipped,
                        are_contents_opaque, opacity, blend_mode, 0);
   return shared_state;
 }
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index b3971e1..27e261f 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -183,7 +183,7 @@
                             float opacity,
                             const gfx::Transform& transform,
                             bool stretch_content_to_fill_bounds,
-                            const gfx::RRectF& rounded_corner_bounds,
+                            const gfx::MaskFilterInfo& mask_filter_info,
                             bool is_fast_rounded_corner) {
       Quad quad;
       quad.material = DrawQuad::Material::kSurfaceContent;
@@ -193,7 +193,7 @@
       quad.surface_range = surface_range;
       quad.default_background_color = default_background_color;
       quad.stretch_content_to_fill_bounds = stretch_content_to_fill_bounds;
-      quad.rounded_corner_bounds = rounded_corner_bounds;
+      quad.mask_filter_info = mask_filter_info;
       quad.is_fast_rounded_corner = is_fast_rounded_corner;
       return quad;
     }
@@ -218,8 +218,8 @@
     gfx::Rect primary_surface_rect;
     float opacity;
     gfx::Transform to_target_transform;
-    gfx::RRectF rounded_corner_bounds;
-    bool is_fast_rounded_corner;
+    gfx::MaskFilterInfo mask_filter_info;
+    bool is_fast_rounded_corner = false;
     bool allow_merge = true;
 
     // Set when material==DrawQuad::Material::kSolidColor.
@@ -279,7 +279,7 @@
                        desc.to_target_transform, desc.surface_range,
                        desc.default_background_color,
                        desc.stretch_content_to_fill_bounds,
-                       desc.rounded_corner_bounds, desc.is_fast_rounded_corner,
+                       desc.mask_filter_info, desc.is_fast_rounded_corner,
                        desc.allow_merge);
         break;
       case DrawQuad::Material::kCompositorRenderPass:
@@ -371,7 +371,7 @@
                              const SurfaceRange& surface_range,
                              SkColor default_background_color,
                              bool stretch_content_to_fill_bounds,
-                             const gfx::RRectF& rounded_corner_bounds,
+                             const gfx::MaskFilterInfo& mask_filter_info,
                              bool is_fast_rounded_corner,
                              bool allow_merge) {
     gfx::Transform layer_to_target_transform = transform;
@@ -384,9 +384,9 @@
 
     auto* shared_quad_state = pass->CreateAndAppendSharedQuadState();
     shared_quad_state->SetAll(layer_to_target_transform, layer_bounds,
-                              visible_layer_rect, rounded_corner_bounds,
-                              clip_rect, is_clipped, are_contents_opaque,
-                              opacity, blend_mode, 0);
+                              visible_layer_rect, mask_filter_info, clip_rect,
+                              is_clipped, are_contents_opaque, opacity,
+                              blend_mode, 0);
     shared_quad_state->is_fast_rounded_corner = is_fast_rounded_corner;
 
     SurfaceDrawQuad* surface_quad =
@@ -404,9 +404,9 @@
                                 bool can_use_backdrop_filter_cache) {
     gfx::Rect output_rect = gfx::Rect(0, 0, 5, 5);
     auto* shared_state = pass->CreateAndAppendSharedQuadState();
-    shared_state->SetAll(transform, output_rect, output_rect, gfx::RRectF(),
-                         output_rect, false, false, 1, SkBlendMode::kSrcOver,
-                         0);
+    shared_state->SetAll(transform, output_rect, output_rect,
+                         gfx::MaskFilterInfo(), output_rect, false, false, 1,
+                         SkBlendMode::kSrcOver, 0);
     auto* quad = pass->CreateAndAppendDrawQuad<CompositorRenderPassDrawQuad>();
     quad->SetAll(
         shared_state, output_rect, output_rect, /*needs_blending=*/true,
@@ -419,7 +419,7 @@
                               const gfx::Rect& output_rect) {
     auto* shared_state = pass->CreateAndAppendSharedQuadState();
     shared_state->SetAll(gfx::Transform(), output_rect, output_rect,
-                         gfx::RRectF(), output_rect, false, false, 1,
+                         gfx::MaskFilterInfo(), output_rect, false, false, 1,
                          SkBlendMode::kSrcOver, 0);
     auto* quad = pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
     quad->SetNew(shared_state, output_rect, output_rect, false,
@@ -553,8 +553,8 @@
     for (const SurfaceRange& range : ranges) {
       quads.push_back(Quad::SurfaceQuad(
           range, SK_ColorWHITE, gfx::Rect(5, 5), 1.f, gfx::Transform(),
-          /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
-          /*is_fast_border_radius*/ false));
+          /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+          /*is_fast_rounded_corner=*/false));
     }
     std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
     CompositorRenderPassList pass_list;
@@ -661,8 +661,8 @@
     std::vector<Quad> quads = {Quad::SurfaceQuad(
         SurfaceRange(base::nullopt, embedded_surface_id), SK_ColorWHITE,
         gfx::Rect(5, 5), .5f, gfx::Transform(),
-        /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
-        /*is_fast_border_radius*/ false)};
+        /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+        /*is_fast_rounded_corner=*/false)};
     std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
     SubmitCompositorFrame(root_sink_.get(), passes, root_local_surface_id_,
@@ -684,8 +684,8 @@
     std::vector<Quad> quads = {Quad::SurfaceQuad(
         SurfaceRange(base::nullopt, embedded_surface_id), SK_ColorWHITE,
         gfx::Rect(5, 5), .9999f, gfx::Transform(),
-        /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
-        /*is_fast_border_radius*/ false)};
+        /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+        /*is_fast_rounded_corner=*/false)};
     std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
     SubmitCompositorFrame(root_sink_.get(), passes, root_local_surface_id_,
@@ -720,11 +720,11 @@
                         embedded_local_surface_id, device_scale_factor);
   gfx::Transform rotate;
   rotate.Rotate(30);
-  std::vector<Quad> quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, embedded_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), 1.f, rotate,
-                        /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
-                        /*is_fast_border_radius*/ false)};
+  std::vector<Quad> quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, embedded_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), 1.f, rotate,
+      /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+      /*is_fast_rounded_corner=*/false)};
   std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
   SubmitCompositorFrame(root_sink_.get(), passes, root_local_surface_id_,
@@ -2204,14 +2204,14 @@
                 ->render_pass_id);
 }
 
-void AddSolidColorQuadWithBlendMode(const gfx::Size& size,
-                                    CompositorRenderPass* pass,
-                                    const SkBlendMode blend_mode,
-                                    const gfx::RRectF& corner_bounds) {
+void AddSolidColorQuadWithBlendMode(
+    const gfx::Size& size,
+    CompositorRenderPass* pass,
+    const SkBlendMode blend_mode,
+    const gfx::MaskFilterInfo& mask_filter_info) {
   const gfx::Transform layer_to_target_transform;
   const gfx::Rect layer_rect(size);
   const gfx::Rect visible_layer_rect(size);
-  const gfx::RRectF rounded_corner_bounds = corner_bounds;
   const gfx::Rect clip_rect(size);
 
   bool is_clipped = false;
@@ -2222,7 +2222,7 @@
   bool force_anti_aliasing_off = false;
   auto* sqs = pass->CreateAndAppendSharedQuadState();
   sqs->SetAll(layer_to_target_transform, layer_rect, visible_layer_rect,
-              rounded_corner_bounds, clip_rect, is_clipped, are_contents_opaque,
+              mask_filter_info, clip_rect, is_clipped, are_contents_opaque,
               opacity, blend_mode, 0);
 
   auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -2291,7 +2291,7 @@
   grandchild_pass->SetNew(pass_id, output_rect, damage_rect,
                           transform_to_root_target);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), grandchild_pass.get(),
-                                 blend_modes[2], gfx::RRectF());
+                                 blend_modes[2], gfx::MaskFilterInfo());
   QueuePassAsFrame(std::move(grandchild_pass), grandchild_local_surface_id,
                    device_scale_factor, grandchild_support.get());
 
@@ -2305,7 +2305,7 @@
   child_one_pass->SetNew(pass_id, output_rect, damage_rect,
                          transform_to_root_target);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), child_one_pass.get(),
-                                 blend_modes[1], gfx::RRectF());
+                                 blend_modes[1], gfx::MaskFilterInfo());
   auto* grandchild_surface_quad =
       child_one_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
   grandchild_surface_quad->SetNew(
@@ -2314,7 +2314,7 @@
       SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE,
       /*stretch_content_to_fill_bounds=*/false);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), child_one_pass.get(),
-                                 blend_modes[3], gfx::RRectF());
+                                 blend_modes[3], gfx::MaskFilterInfo());
   QueuePassAsFrame(std::move(child_one_pass), child_one_local_surface_id,
                    device_scale_factor, child_one_support.get());
 
@@ -2328,7 +2328,7 @@
   child_two_pass->SetNew(pass_id, output_rect, damage_rect,
                          transform_to_root_target);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), child_two_pass.get(),
-                                 blend_modes[5], gfx::RRectF());
+                                 blend_modes[5], gfx::MaskFilterInfo());
   QueuePassAsFrame(std::move(child_two_pass), child_two_local_surface_id,
                    device_scale_factor, child_two_support.get());
 
@@ -2337,7 +2337,7 @@
                     transform_to_root_target);
 
   AddSolidColorQuadWithBlendMode(SurfaceSize(), root_pass.get(), blend_modes[0],
-                                 gfx::RRectF());
+                                 gfx::MaskFilterInfo());
   auto* child_one_surface_quad =
       root_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
   child_one_surface_quad->SetNew(
@@ -2346,7 +2346,7 @@
       SurfaceRange(base::nullopt, child_one_surface_id), SK_ColorWHITE,
       /*stretch_content_to_fill_bounds=*/false);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), root_pass.get(), blend_modes[4],
-                                 gfx::RRectF());
+                                 gfx::MaskFilterInfo());
   auto* child_two_surface_quad =
       root_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
   child_two_surface_quad->SetNew(
@@ -2355,7 +2355,7 @@
       SurfaceRange(base::nullopt, child_two_surface_id), SK_ColorWHITE,
       /*stretch_content_to_fill_bounds=*/false);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), root_pass.get(), blend_modes[6],
-                                 gfx::RRectF());
+                                 gfx::MaskFilterInfo());
 
   QueuePassAsFrame(std::move(root_pass), root_local_surface_id_,
                    device_scale_factor, root_sink_.get());
@@ -2406,8 +2406,10 @@
 //  quad(d)           - rounded corner [2]
 TEST_F(SurfaceAggregatorValidSurfaceTest,
        AggregateSharedQuadStateRoundedCornerBounds) {
-  const gfx::RRectF kFastRoundedCornerBounds = gfx::RRectF(0, 0, 640, 480, 5);
-  const gfx::RRectF kRoundedCornerBounds = gfx::RRectF(0, 0, 100, 100, 2);
+  const gfx::MaskFilterInfo kMaskFilterInfoWithFastRoundedCorners(
+      gfx::RRectF(0, 0, 640, 480, 5));
+  const gfx::MaskFilterInfo kMaskFilterInfoWithRoundedCorners(
+      gfx::RRectF(0, 0, 100, 100, 2));
 
   ParentLocalSurfaceIdAllocator child_root_allocator;
   ParentLocalSurfaceIdAllocator child_one_allocator;
@@ -2439,7 +2441,7 @@
   child_three_pass->SetNew(pass_id, output_rect, damage_rect,
                            transform_to_root_target);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), child_three_pass.get(),
-                                 SkBlendMode::kSrcOver, gfx::RRectF());
+                                 SkBlendMode::kSrcOver, gfx::MaskFilterInfo());
   QueuePassAsFrame(std::move(child_three_pass), child_three_local_surface_id,
                    device_scale_factor, child_three_support.get());
 
@@ -2454,7 +2456,7 @@
   child_one_pass->SetNew(pass_id, output_rect, damage_rect,
                          transform_to_root_target);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), child_one_pass.get(),
-                                 SkBlendMode::kSrcOver, gfx::RRectF());
+                                 SkBlendMode::kSrcOver, gfx::MaskFilterInfo());
 
   // Add child three surface quad
   auto* child_three_surface_sqs =
@@ -2482,9 +2484,10 @@
   child_two_pass->SetNew(pass_id, output_rect, damage_rect,
                          transform_to_root_target);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), child_two_pass.get(),
-                                 SkBlendMode::kSrcOver, gfx::RRectF());
+                                 SkBlendMode::kSrcOver, gfx::MaskFilterInfo());
   AddSolidColorQuadWithBlendMode(SurfaceSize(), child_two_pass.get(),
-                                 SkBlendMode::kSrcOver, kRoundedCornerBounds);
+                                 SkBlendMode::kSrcOver,
+                                 kMaskFilterInfoWithRoundedCorners);
   QueuePassAsFrame(std::move(child_two_pass), child_two_local_surface_id,
                    device_scale_factor, child_two_support.get());
 
@@ -2523,7 +2526,7 @@
 
   // Add solid color quad
   AddSolidColorQuadWithBlendMode(SurfaceSize(), child_root_pass.get(),
-                                 SkBlendMode::kSrcOver, gfx::RRectF());
+                                 SkBlendMode::kSrcOver, gfx::MaskFilterInfo());
   QueuePassAsFrame(std::move(child_root_pass), child_root_local_surface_id,
                    device_scale_factor, child_root_support.get());
 
@@ -2535,7 +2538,8 @@
   auto* child_root_surface_quad =
       root_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
   child_root_surface_sqs->opacity = 1.f;
-  child_root_surface_sqs->rounded_corner_bounds = kFastRoundedCornerBounds;
+  child_root_surface_sqs->mask_filter_info =
+      kMaskFilterInfoWithFastRoundedCorners;
   child_root_surface_sqs->is_fast_rounded_corner = true;
   child_root_surface_quad->SetNew(
       child_root_surface_sqs, gfx::Rect(SurfaceSize()),
@@ -2561,17 +2565,17 @@
   const auto& aggregated_quad_list_of_surface =
       aggregated_pass_list[0]->quad_list;
   EXPECT_EQ(2u, aggregated_quad_list_of_surface.size());
-  EXPECT_EQ(kRoundedCornerBounds,
+  EXPECT_EQ(kMaskFilterInfoWithRoundedCorners,
             aggregated_quad_list_of_surface.back()
-                ->shared_quad_state->rounded_corner_bounds);
+                ->shared_quad_state->mask_filter_info);
 
   // The root render pass will have all the remaining quads with the rounded
   // corner set on them.
   const auto& aggregated_quad_list_of_root = aggregated_pass_list[1]->quad_list;
   EXPECT_EQ(4u, aggregated_quad_list_of_root.size());
   for (const auto* q : aggregated_quad_list_of_root) {
-    EXPECT_EQ(q->shared_quad_state->rounded_corner_bounds,
-              kFastRoundedCornerBounds);
+    EXPECT_EQ(q->shared_quad_state->mask_filter_info,
+              kMaskFilterInfoWithFastRoundedCorners);
   }
 }
 
@@ -6835,12 +6839,12 @@
   // root surface quads
   std::vector<Quad> root_surface_quads = {
       Quad::SolidColorQuad(SK_ColorRED, gfx::Rect(60, 0, 40, 40)),
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE,
-                        /*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100),
-                        /*opacity*/ 1.f, video_transform,
-                        /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
-                        /*is_fast_border_radius*/ false)};
+      Quad::SurfaceQuad(
+          SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+          /*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100),
+          /*opacity*/ 1.f, video_transform,
+          /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+          /*is_fast_rounded_corner=*/false)};
 
   std::vector<Pass> root_passes = {
       Pass(root_surface_quads,
@@ -6960,8 +6964,8 @@
         SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
         /*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100),
         /*opacity*/ 1.f, video_transform,
-        /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
-        /*is_fast_border_radius*/ false)};
+        /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+        /*is_fast_rounded_corner=*/false)};
 
     std::vector<Pass> root_passes = {
         Pass(root_surface_quads,
@@ -7058,8 +7062,8 @@
             SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
             /*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100),
             /*opacity*/ 1.f, video_transform,
-            /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
-            /*is_fast_border_radius*/ false)};
+            /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+            /*is_fast_rounded_corner=*/false)};
 
     std::vector<Pass> root_passes = {
         Pass(root_surface_quads,
@@ -7383,7 +7387,7 @@
 
     child_frame.render_pass_list[0]
         ->shared_quad_state_list.front()
-        ->rounded_corner_bounds = gfx::RRectF(0, 0, 100, 10, 5);
+        ->mask_filter_info = gfx::MaskFilterInfo(gfx::RRectF(0, 0, 100, 10, 5));
 
     child_sink_->SubmitCompositorFrame(child_local_surface_id,
                                        std::move(child_frame));
@@ -7412,8 +7416,9 @@
   auto* aggregated_first_pass_sqs =
       aggregated_frame.render_pass_list[0]->shared_quad_state_list.front();
 
-  EXPECT_EQ(gfx::RRectF(0, 7, 100, 10, 5),
-            aggregated_first_pass_sqs->rounded_corner_bounds);
+  EXPECT_EQ(
+      gfx::RRectF(0, 7, 100, 10, 5),
+      aggregated_first_pass_sqs->mask_filter_info.rounded_corner_bounds());
 }
 
 // Tests that the rounded corner bounds of a surface quad that gets transformed
@@ -7455,11 +7460,11 @@
                              child_local_surface_id);
   {
     // Set an opacity in order to prevent merging into the root render pass.
-    std::vector<Quad> child_quads = {
-        Quad::SurfaceQuad(SurfaceRange(base::nullopt, grandchild_surface_id),
-                          SK_ColorWHITE, gfx::Rect(5, 5), 0.5f,
-                          gfx::Transform(), false, gfx::RRectF(0, 0, 96, 10, 5),
-                          /*is_fast_border_radius*/ false)};
+    std::vector<Quad> child_quads = {Quad::SurfaceQuad(
+        SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE,
+        gfx::Rect(5, 5), 0.5f, gfx::Transform(), false,
+        gfx::MaskFilterInfo(gfx::RRectF(0, 0, 96, 10, 5)),
+        /*is_fast_rounded_corner=*/false)};
 
     std::vector<Pass> child_passes = {
         Pass(child_quads, CompositorRenderPassId{1}, SurfaceSize())};
@@ -7477,7 +7482,8 @@
   surface_transform.Translate(3, 4);
   std::vector<Quad> secondary_quads = {Quad::SurfaceQuad(
       SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
-      gfx::Rect(5, 5), 1.f, surface_transform, false, gfx::RRectF(), false)};
+      gfx::Rect(5, 5), 1.f, surface_transform, false, gfx::MaskFilterInfo(),
+      /*is_fast_rounded_corner=*/false)};
 
   std::vector<Pass> root_passes = {Pass(secondary_quads, SurfaceSize())};
 
@@ -7502,8 +7508,9 @@
   // Original rounded rect is (0, 0, 96, 10, 5). This then gets multiplied
   // by a device scale factor of 2 to (0, 0, 192, 20, 10), then moved
   // by a (3, 4) translation followed by a (0, 7) translation.
-  EXPECT_EQ(gfx::RRectF(3, 11, 192, 20, 10),
-            aggregated_first_pass_sqs->rounded_corner_bounds);
+  EXPECT_EQ(
+      gfx::RRectF(3, 11, 192, 20, 10),
+      aggregated_first_pass_sqs->mask_filter_info.rounded_corner_bounds());
 }
 
 // This is a variant of RoundedCornerTransformedSurfaceQuad that does not
@@ -7542,11 +7549,11 @@
   SurfaceId child_surface_id(child_sink_->frame_sink_id(),
                              child_local_surface_id);
   {
-    std::vector<Quad> child_quads = {
-        Quad::SurfaceQuad(SurfaceRange(base::nullopt, grandchild_surface_id),
-                          SK_ColorWHITE, gfx::Rect(5, 5), 1.f, gfx::Transform(),
-                          false, gfx::RRectF(0, 0, 96, 10, 5),
-                          /*is_fast_border_radius*/ false)};
+    std::vector<Quad> child_quads = {Quad::SurfaceQuad(
+        SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE,
+        gfx::Rect(5, 5), 1.f, gfx::Transform(), false,
+        gfx::MaskFilterInfo(gfx::RRectF(0, 0, 96, 10, 5)),
+        /*is_fast_rounded_corner=*/false)};
 
     std::vector<Pass> child_passes = {
         Pass(child_quads, CompositorRenderPassId{1}, SurfaceSize())};
@@ -7564,8 +7571,8 @@
   surface_transform.Translate(3, 4);
   std::vector<Quad> secondary_quads = {Quad::SurfaceQuad(
       SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
-      gfx::Rect(5, 5), 1.f, surface_transform, false, gfx::RRectF(),
-      /*is_fast_border_radius*/ false)};
+      gfx::Rect(5, 5), 1.f, surface_transform, false, gfx::MaskFilterInfo(),
+      /*is_fast_rounded_corner=*/false)};
 
   std::vector<Pass> root_passes = {Pass(secondary_quads, SurfaceSize())};
 
@@ -7590,8 +7597,9 @@
   // Original rounded rect is (0, 0, 96, 10, 5). This then gets multiplied
   // by a device scale factor of 2 to (0, 0, 192, 20, 10), then moved
   // by a (3, 4) translation followed by a (0, 7) translation.
-  EXPECT_EQ(gfx::RRectF(3, 11, 192, 20, 10),
-            aggregated_first_pass_sqs->rounded_corner_bounds);
+  EXPECT_EQ(
+      gfx::RRectF(3, 11, 192, 20, 10),
+      aggregated_first_pass_sqs->mask_filter_info.rounded_corner_bounds());
 }
 
 TEST_F(SurfaceAggregatorValidSurfaceTest, TransformedRoundedSurfaceQuad) {
@@ -7625,11 +7633,11 @@
   // Root surface.
   gfx::Transform surface_transform;
   surface_transform.Translate(3, 4);
-  std::vector<Quad> secondary_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), 1.f, surface_transform,
-                        false, gfx::RRectF(0, 0, 96, 10, 5),
-                        /* is_fast_border_radius */ true)};
+  std::vector<Quad> secondary_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), 1.f, surface_transform, false,
+      gfx::MaskFilterInfo(gfx::RRectF(0, 0, 96, 10, 5)),
+      /*is_fast_rounded_corner=*/true)};
 
   std::vector<Pass> root_passes = {Pass(secondary_quads, SurfaceSize())};
 
@@ -7656,8 +7664,9 @@
 
   // The rounded rect on the surface quad is already in the space of the root
   // surface, so the (3, 4) translation should not apply to it.
-  EXPECT_EQ(gfx::RRectF(0, 0, 96, 10, 5),
-            aggregated_first_pass_sqs->rounded_corner_bounds);
+  EXPECT_EQ(
+      gfx::RRectF(0, 0, 96, 10, 5),
+      aggregated_first_pass_sqs->mask_filter_info.rounded_corner_bounds());
 }
 
 // Verifies that if a child surface is embedded twice in the root surface,
diff --git a/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java b/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java
index d73e493..5848e9b2 100644
--- a/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java
+++ b/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java
@@ -364,6 +364,7 @@
      * @param manifestUrl The URL of the manifest that was used to generate the WebAPK.
      * @return The WebAPK's package name if installed, or null otherwise.
      */
+    @SuppressWarnings("QueryPermissionsNeeded")
     public static @Nullable String queryBoundWebApkForManifestUrl(
             Context context, String manifestUrl) {
         assert manifestUrl != null;
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 2c59fec..accfd31e 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -14153,9 +14153,8 @@
 
 // Verify that hidden tabs with a crashed subframe are not marked for reload
 // when the crashed subframe is hidden with "display:none".
-// TODO(crbug.com/1135595): Flaky.
 IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload,
-                       DISABLED_DoNotReloadHiddenTabWithHiddenCrashedSubframe) {
+                       DoNotReloadHiddenTabWithHiddenCrashedSubframe) {
   // Set WebContents to VISIBLE to avoid hitting the |!did_first_set_visible_|
   // case when we hide it later.
   web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE);
@@ -14165,7 +14164,15 @@
   EXPECT_TRUE(NavigateToURL(shell(), hidden_iframe_url));
   NavigateIframeToURL(web_contents(), "test_iframe",
                       embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // Ensure that the parent frame has propagated the OOPIF's hidden visibility
+  // to the browser process by forcing requestAnimationFrame and
+  // waiting for layout to finish.
   FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  EXPECT_EQ(true,
+            EvalJsAfterLifecycleUpdate(root->current_frame_host(), "", "true"));
+
+  // The OOPIF should be hidden at this point.
   RenderFrameProxyHost* proxy_to_parent =
       root->child_at(0)->render_manager()->GetProxyToParent();
   EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector()->IsHidden());
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 68125629..767a877 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -269,7 +269,9 @@
     {wf::EnableBackgroundFetch, features::kBackgroundFetch},
     {wf::EnableForcedColors, features::kForcedColors},
     {wf::EnableFractionalScrollOffsets, features::kFractionalScrollOffsets},
-    {wf::EnableGetDisplayMedia, blink::features::kRTCGetDisplayMedia},
+#if defined(OS_ANDROID)
+    {wf::EnableGetDisplayMedia, features::kUserMediaScreenCapturing},
+#endif
     {wf::EnableSignedExchangePrefetchCacheForNavigations,
      features::kSignedExchangePrefetchCacheForNavigations},
     {wf::EnableSignedExchangeSubresourcePrefetch,
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
index 9e6ebf0f..e2ac0b5 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
@@ -17,11 +17,11 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper;
 import org.chromium.content_shell_apk.ContentShellActivityTestRule;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/CriteriaHelperTest.java b/content/public/android/javatests/src/org/chromium/content/browser/CriteriaHelperTest.java
index da73ecf2..bb6d8745 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/CriteriaHelperTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/CriteriaHelperTest.java
@@ -22,9 +22,9 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.UiThreadTest;
 import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
index 498213e..57eaee9 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
@@ -14,13 +14,13 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
index 60e588e..14cd240 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
@@ -18,12 +18,12 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_shell_apk.ContentShellActivityTestRule;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VideoRotateToFullscreenTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VideoRotateToFullscreenTest.java
index 9cb900c..9178e6ae 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/VideoRotateToFullscreenTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/VideoRotateToFullscreenTest.java
@@ -19,12 +19,12 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeActivityTestRule.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeActivityTestRule.java
index 4764a9a8..3e2ad79 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeActivityTestRule.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeActivityTestRule.java
@@ -21,13 +21,13 @@
 import org.junit.Assert;
 
 import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content.browser.ViewEventSinkImpl;
 import org.chromium.content.browser.selection.SelectionPopupControllerImpl;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
 import org.chromium.content_public.browser.ImeAdapter;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
index be7213e..78639687 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -32,13 +32,13 @@
 
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/TextSuggestionMenuTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/TextSuggestionMenuTest.java
index b973d58..224fe4d 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/TextSuggestionMenuTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/TextSuggestionMenuTest.java
@@ -23,12 +23,12 @@
 
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content.R;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index a9c24f34..65f09bd 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -881,14 +881,18 @@
     "BackgroundMediaRendererHasModerateBinding",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Pre-warm up the network process on browser startup.
-const base::Feature kWarmUpNetworkProcess{"WarmUpNetworkProcess",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Force display to tick at ~60Hz refresh rate.
 const base::Feature kForce60HzRefreshRate{"Force60HzRefreshRate",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Screen Capture API support for Android
+const base::Feature kUserMediaScreenCapturing{
+    "UserMediaScreenCapturing", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Pre-warm up the network process on browser startup.
+const base::Feature kWarmUpNetworkProcess{"WarmUpNetworkProcess",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Kill switch for the WebNFC feature. This feature can be enabled for all sites
 // using the kEnableExperimentalWebPlatformFeatures flag or by a particular site
 // if it includes an Origin Trial key.  https://w3c.github.io/web-nfc/
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index e341a64e..94c8b4b 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -186,6 +186,7 @@
 CONTENT_EXPORT extern const base::Feature
     kBackgroundMediaRendererHasModerateBinding;
 CONTENT_EXPORT extern const base::Feature kForce60HzRefreshRate;
+CONTENT_EXPORT extern const base::Feature kUserMediaScreenCapturing;
 CONTENT_EXPORT extern const base::Feature kWarmUpNetworkProcess;
 CONTENT_EXPORT extern const base::Feature kWebNfc;
 #endif  // defined(OS_ANDROID)
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/Criteria.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/Criteria.java
index 7ddd3885..675a18d 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/Criteria.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/Criteria.java
@@ -10,6 +10,8 @@
 import org.hamcrest.Matcher;
 import org.hamcrest.StringDescription;
 
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
+
 /**
  * Provides a means for validating whether some condition/criteria has been met.
  * <p>
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/CriteriaHelper.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/CriteriaHelper.java
index cd36280..204c1990 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/CriteriaHelper.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/CriteriaHelper.java
@@ -10,6 +10,7 @@
 import org.hamcrest.Matchers;
 
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.TimeoutTimer;
 import org.chromium.content_public.browser.test.NestedSystemMessageHandler;
 
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/CriteriaNotSatisfiedException.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/CriteriaNotSatisfiedException.java
index 06f9d64..d28a43f 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/CriteriaNotSatisfiedException.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/CriteriaNotSatisfiedException.java
@@ -7,7 +7,8 @@
 /**
  * Exception indicating that a Criteria did not match expectations.
  */
-public class CriteriaNotSatisfiedException extends AssertionError {
+public class CriteriaNotSatisfiedException
+        extends org.chromium.base.test.util.CriteriaNotSatisfiedException {
     /**
      * @param msg The reason the criteria was not met.
      */
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/DOMUtils.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/DOMUtils.java
index e31fc92a3..cc7234ea 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/DOMUtils.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/DOMUtils.java
@@ -14,6 +14,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content.browser.RenderCoordinatesImpl;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
 import org.chromium.content_public.browser.WebContents;
diff --git a/content/renderer/media/batching_media_log.cc b/content/renderer/media/batching_media_log.cc
index aac0dee..26d330d 100644
--- a/content/renderer/media/batching_media_log.cc
+++ b/content/renderer/media/batching_media_log.cc
@@ -131,6 +131,10 @@
         queued_media_events_.push_back(*event);
     }
 
+    // TODO(crbug.com/1141985): This shouldn't exceed 1024 events within a
+    // single second. Crash to help us track down what's going wrong.
+    CHECK_LE(queued_media_events_.size(), 1024u);
+
     if (ipc_send_pending_)
       return;
 
diff --git a/content/test/data/browsing_data/site_data.html b/content/test/data/browsing_data/site_data.html
index 2539bfdf..dcbab53 100644
--- a/content/test/data/browsing_data/site_data.html
+++ b/content/test/data/browsing_data/site_data.html
@@ -111,6 +111,26 @@
     openFile_('foo.txt', { create: false }, success_, failure_);
   }
 
+  async function setFileSystemAccess() {
+    try {
+      let dir = await navigator.storage.getDirectory();
+      await dir.getFileHandle('foo.txt', {create: true});
+      success_();
+    } catch (e) {
+      failure_();
+    }
+  }
+
+  async function hasFileSystemAccess() {
+    try {
+      let dir = await navigator.storage.getDirectory();
+      await dir.getFileHandle('foo.txt', { create: false });
+      success_();
+    } catch (e) {
+      failure_();
+    }
+  }
+
   function setWebSql() {
     var db = openDatabase('testdb', '1.0', 'a test db', 1024);
     db.transaction(function (tx) {
diff --git a/content/test/data/gpu/webgpu-context-lost.html b/content/test/data/gpu/webgpu-context-lost.html
index d56dd640..ff9114e0e 100644
--- a/content/test/data/gpu/webgpu-context-lost.html
+++ b/content/test/data/gpu/webgpu-context-lost.html
@@ -1,4 +1,5 @@
 <html>
+
 <head>
   <script type='module'>
     let lostJustHappened = false;
@@ -19,21 +20,21 @@
     async function init(canvas, color) {
       let adapter = null;
 
-      // TODO: do this loop internally in the browser
-      while (!adapter) {
-       try {
-         adapter = await navigator.gpu.requestAdapter();
-       } catch (err) {
-         // TODO: remove try and catch here once we no longer expect rejections here.
-         // According to the spec, rejection should only happen when invalid stuff is passed in.
-         console.warn("request adapter failed:", err);
-       }
+      try {
+        adapter = await navigator.gpu.requestAdapter();
+      } catch (err) {
+        // TODO: remove try and catch here once we no longer expect rejections here.
+        // According to the spec, rejection should only happen when invalid stuff is passed in.
+        console.warn("request adapter failed:", err);
       }
-      const device = await adapter.requestDevice();
+
+      let device = await adapter.requestDevice();
       device.lost.then(async value => {
         // After device lost, re-initialize for new adapter and device.
         // We choose a different texture color from when we first
         // init to be sure that the texture is coming from here
+        device = null;
+        adapter = null;
         lostJustHappened = true;
         await init(canvas, reinitTextureColor);
       });
@@ -106,8 +107,13 @@
 
         device.defaultQueue.submit([commandEncoder.finish()]);
         if (lostJustHappened) {
-          // We want to check if it's been restored to the lost texture color.
-          checkTextureColor(texture, swapChainFormat, { x: 0, y: 0 }, reinitTextureColorArray );
+          // We don't want to check for the texture color until device and adapter have been reinitialized
+          // Checking prematurely was causing hangs in buffer.mapAync to never return (crbug.com/dawn/556)
+          if (device == null || adapter == null) {
+            return;
+          }
+          // We want to check if it's been restored to the reinit texture color.
+          checkTextureColor(texture, swapChainFormat, { x: 0, y: 0 }, reinitTextureColorArray);
           lostJustHappened = false;
         }
       }
@@ -141,7 +147,9 @@
     document.addEventListener('DOMContentLoaded', onLoad);
   </script>
 </head>
+
 <body>
   <div id='container'></div>
 </body>
+
 </html>
\ No newline at end of file
diff --git a/content/test/gpu/gpu_tests/context_lost_integration_test.py b/content/test/gpu/gpu_tests/context_lost_integration_test.py
index 5463b58e..c14233a 100644
--- a/content/test/gpu/gpu_tests/context_lost_integration_test.py
+++ b/content/test/gpu/gpu_tests/context_lost_integration_test.py
@@ -143,7 +143,10 @@
     cls.StartBrowser()
     cls.SetStaticServerDirs([data_path])
 
-  def _KillGPUProcess(self, number_of_gpu_process_kills, check_crash_count):
+  def _KillGPUProcess(self,
+                      number_of_gpu_process_kills,
+                      check_crash_count,
+                      timeout=wait_timeout):
     tab = self.tab
     # Doing the GPU process kill operation cooperatively -- in the
     # same page's context -- is much more stressful than restarting
@@ -158,7 +161,7 @@
       # to have fully reset before crashing the GPU process.
       if check_crash_count:
         tab.WaitForJavaScriptCondition(
-            'window.domAutomationController._finished', timeout=wait_timeout)
+            'window.domAutomationController._finished', timeout=timeout)
 
       # Crash the GPU process.
       #
@@ -170,7 +173,7 @@
       # process was chosen.
       tab.EvaluateJavaScript('chrome.gpuBenchmarking.crashGpuProcess()')
 
-      completed = _WaitForPageToFinish(tab)
+      completed = _WaitForPageToFinish(tab, timeout=timeout)
 
       if check_crash_count:
         self._CheckCrashCount(tab, expected_kills)
@@ -256,7 +259,9 @@
         '--enable-unsafe-webgpu',
     ])
     self._NavigateAndWaitForLoad(test_path)
-    self._KillGPUProcess(1, False)
+    # The gpu startup sometimes takes longer on the bots.
+    # Increasing the timeout for this test as it times out before completion
+    self._KillGPUProcess(1, False, timeout=180)
     self._RestartBrowser('must restart after tests that kill the GPU process')
 
   def _ContextLost_WebGLContextLostFromLoseContextExtension(self, test_path):
@@ -456,10 +461,10 @@
     ]
 
 
-def _WaitForPageToFinish(tab):
+def _WaitForPageToFinish(tab, timeout=wait_timeout):
   try:
     tab.WaitForJavaScriptCondition('window.domAutomationController._finished',
-                                   timeout=wait_timeout)
+                                   timeout=timeout)
     return True
   except exceptions.TimeoutException:
     return False
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
index b3eabe0..ebc45f80 100644
--- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -130,4 +130,7 @@
 [ linux ] ContextLost_WebGPUContextLostFromGPUProcessExit [ Skip ]
 [ fuchsia ] ContextLost_WebGPUContextLostFromGPUProcessExit [ Skip ]
 [ android ] ContextLost_WebGPUContextLostFromGPUProcessExit [ Skip ]
-[ chromeos ] ContextLost_WebGPUContextLostFromGPUProcessExit [ Skip ]
\ No newline at end of file
+[ chromeos ] ContextLost_WebGPUContextLostFromGPUProcessExit [ Skip ]
+
+# Flakily not getting WebGL blocked on context loss
+crbug.com/1143774 [ chromeos chromeos-board-kevin ] ContextLost_WebGLUnblockedAfterUserInitiatedReload [ RetryOnFailure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index a7b6d0ad..e684e89 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -114,10 +114,6 @@
 crbug.com/1108086 [ no-passthrough ] conformance2/renderbuffers/framebuffer-object-attachment.html [ Failure ]
 crbug.com/angleproject/4807 [ win angle-d3d11 passthrough ] conformance2/glsl3/switch-case.html [ Failure ]
 crbug.com/1081973 conformance/buffers/buffer-data-and-buffer-sub-data.html [ Failure ]
-crbug.com/1082455 [ win ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ]
-crbug.com/1082455 [ linux ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ]
-crbug.com/1082455 [ android ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ]
-crbug.com/1082455 [ mac no-passthrough ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ]
 crbug.com/1082533 [ mac intel ] conformance/textures/misc/texture-copying-and-deletion.html [ Failure ]
 crbug.com/1082533 [ win angle-vulkan passthrough ] conformance/textures/misc/texture-copying-and-deletion.html [ Failure ]
 crbug.com/1018028 [ win angle-vulkan ] conformance/rendering/bind-framebuffer-flush-bug.html [ Failure ]
@@ -632,6 +628,7 @@
 crbug.com/782317 [ mac intel ] conformance/rendering/rendering-stencil-large-viewport.html [ Failure ]
 crbug.com/1039465 [ mac intel ] conformance/textures/canvas/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ RetryOnFailure ]
 crbug.com/1018028 [ mac intel ] conformance/rendering/bind-framebuffer-flush-bug.html [ Failure ]
+crbug.com/1082455 [ mac intel ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ]
 
 # Mac Intel No-Passthrough
 crbug.com/1042011 [ mac intel-0xa2e no-passthrough ] conformance2/textures/canvas_sub_rectangle/tex-3d-r11f_g11f_b10f-rgb-half_float.html [ RetryOnFailure ]
@@ -639,7 +636,6 @@
 
 # Mac Passthrough
 crbug.com/angleproject/5223 [ mac passthrough ] conformance2/textures/misc/tex-mipmap-levels.html [ Failure ]
-crbug.com/angleproject/5227 [ mac passthrough ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ]
 
 # Mac Passthrough / AMD
 crbug.com/anglerpoject/5224 [ mac passthrough amd ] conformance2/rendering/instanced-arrays.html [ Failure ]
diff --git a/content/utility/utility_thread_impl.cc b/content/utility/utility_thread_impl.cc
index c70a7a7..3cefdc4 100644
--- a/content/utility/utility_thread_impl.cc
+++ b/content/utility/utility_thread_impl.cc
@@ -104,15 +104,18 @@
       return;
 
     // There are no more services running in this process. Time to terminate.
-    main_thread_task_runner_->PostTask(
+    //
+    // First ensure that shutdown also tears down |this|. This is necessary to
+    // support multiple tests in the same test suite using out-of-process
+    // services via the InProcessUtilityThreadHelper, and it must be done on the
+    // current thread to avoid data races.
+    auto main_thread_task_runner = main_thread_task_runner_;
+    GetInstanceStorage().reset();
+    main_thread_task_runner->PostTask(
         FROM_HERE, base::BindOnce(&ServiceBinderImpl::ShutDownProcess));
   }
 
   static void ShutDownProcess() {
-    // Ensure that shutdown also tears down |this|. This is necessary to support
-    // multiple tests in the same test suite using out-of-process services via
-    // the InProcessUtilityThreadHelper.
-    GetInstanceStorage().reset();
     UtilityThread::Get()->ReleaseProcess();
   }
 
diff --git a/device/fido/cable/v2_registration.cc b/device/fido/cable/v2_registration.cc
index 1c26b62..026f28f 100644
--- a/device/fido/cable/v2_registration.cc
+++ b/device/fido/cable/v2_registration.cc
@@ -5,6 +5,7 @@
 #include "device/fido/cable/v2_registration.h"
 
 #include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
 #include "components/cbor/reader.h"
 #include "components/cbor/values.h"
 #include "components/device_event_log/device_event_log.h"
@@ -31,15 +32,17 @@
       : event_callback_(std::move(event_callback)),
         instance_id_driver_(instance_id_driver),
         instance_id_(instance_id_driver->GetInstanceID(kFCMAppId)) {
+    // Registering with FCM on platforms other than Android could cause large
+    // number of new registrations with the FCM service. Thus this code does not
+    // compile on other platforms. Check with //components/gcm_driver owners
+    // before changing this.
+#if !defined(OS_ANDROID)
+    CHECK(false) << "Do not use outside of Android.";
+#endif
+
     gcm::GCMDriver* const gcm_driver = instance_id_->gcm_driver();
     CHECK(gcm_driver->GetAppHandler(kFCMAppId) == nullptr);
     instance_id_->gcm_driver()->AddAppHandler(kFCMAppId, this);
-
-    instance_id_->GetToken(
-        kFCMSenderId, instance_id::kGCMScope,
-        /*time_to_live=*/base::TimeDelta(), /*options=*/{},
-        /*flags=*/{},
-        base::BindOnce(&FCMHandler::GetTokenComplete, base::Unretained(this)));
   }
 
   ~FCMHandler() override {
@@ -49,6 +52,14 @@
 
   // Registration:
 
+  void PrepareContactID() override {
+    instance_id_->GetToken(
+        kFCMSenderId, instance_id::kGCMScope,
+        /*time_to_live=*/base::TimeDelta(), /*options=*/{},
+        /*flags=*/{},
+        base::BindOnce(&FCMHandler::GetTokenComplete, base::Unretained(this)));
+  }
+
   base::Optional<std::vector<uint8_t>> contact_id() const override {
     if (!registration_token_) {
       return base::nullopt;
diff --git a/device/fido/cable/v2_registration.h b/device/fido/cable/v2_registration.h
index 90461edc..1e5debb 100644
--- a/device/fido/cable/v2_registration.h
+++ b/device/fido/cable/v2_registration.h
@@ -42,6 +42,11 @@
 
   virtual ~Registration();
 
+  // PrepareContactID indicates that |contact_id| will soon be called. In order
+  // to save resources for the case when |contact_id| is never used,
+  // registration will be deferred until this is called.
+  virtual void PrepareContactID() = 0;
+
   // contact_id returns an opaque token that may be placed in pairing data for
   // desktops to later connect to. |nullopt| will be returned if the value is
   // not yet ready.
diff --git a/docs/commit_checklist.md b/docs/commit_checklist.md
index 6826a916..6ddeef9 100644
--- a/docs/commit_checklist.md
+++ b/docs/commit_checklist.md
@@ -78,6 +78,14 @@
 [Simple Chrome][simple-chrome] instructions to deploy your changes to a test
 device. Make sure you hit every code path you changed.
 
+Think about testing any edge cases that could break your code. Some common edge
+cases to consider:
+
+*   Guest mode
+*   Enterprise/EDU/Supervised users
+*   Accessibility
+*   Official Chrome-branded build (for Googlers)
+
 ## 6. Write unit or browser tests for any new code
 
 Consider automating any manual testing you did in the previous step.
diff --git a/docs/contributing.md b/docs/contributing.md
index a3c25050..2246188 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -353,6 +353,14 @@
   that future changes will be less likely to regress functionality. Protect
   your code with tests!
 
+- **Stick to the current set of supported languages as described in the
+  [styleguide][cr-styleguide].** While there is likely always a slightly better
+  tool for any particular job, maintainability of the codebase is paramount.
+  Reducing the number of languages eases toolchain and infrastructure
+  requirements, and minimizes the learning hurdles for developers to be
+  successful contributing across the codebase. Additions of new languages must
+  be approved by [//ENG_REVIEW_OWNERS](../ENG_REVIEW_OWNERS).
+
 ## Tips
 
 ### Review etiquette
diff --git a/docs/webui_explainer.md b/docs/webui_explainer.md
index 6d247540..f62e208 100644
--- a/docs/webui_explainer.md
+++ b/docs/webui_explainer.md
@@ -407,12 +407,12 @@
 ```
 
 <a name="SetupWebUIDataSource"></a>
-### webui::SetupWebUIDataSource() and webui::SetupBundledWebUIDataSource()
+### webui::SetupWebUIDataSource()
 
-These methods perform common configuration tasks on a data source for a Web UI
-that uses JS modules. When creating a Web UI that uses JS modules, use these
-utilities instead of duplicating the configuration steps they perform elsewhere.
-Specific setup steps performed by these utilities include:
+This method performs common configuration tasks on a data source for a Web UI
+that uses JS modules. When creating a Web UI that uses JS modules, use this
+utility instead of duplicating the configuration steps it performs elsewhere.
+Specific setup steps include:
 
 * Setting the content security policy to allow the data source to load only
   resources from its own host (e.g. chrome://history), chrome://resources, and
@@ -422,13 +422,7 @@
 * Adding the test loader files to the data source, so that test files can be
   loaded as JS modules.
 * Setting the resource to load for the empty path.
-
-The version for non-bundled UIs (<code>SetupWebUIDataSource()</code>) also adds
-all resources in a GritResourceMap.
-
-The version for bundled UIs (<code>SetupBundledWebUIDataSource()</code>) adds
-a single specified bundled resource. Note that this version is only defined when
-the optimize_webui build flag is enabled.
+* Adding all resources from a GritResourceMap.
 
 ## Browser (C++) &rarr; Renderer (JS)
 
diff --git a/extensions/browser/updater/safe_manifest_parser.h b/extensions/browser/updater/safe_manifest_parser.h
index 541faca..13852a1d 100644
--- a/extensions/browser/updater/safe_manifest_parser.h
+++ b/extensions/browser/updater/safe_manifest_parser.h
@@ -16,9 +16,15 @@
 
 namespace extensions {
 
-// Note: enum used for UMA. Do NOT reorder or remove entries. Don't forget to
-// update enums.xml (name: ManifestInvalidError) when adding new
-// entries. Some errors are common for the entire fetched update manifest which
+// Note: enum used for UMA. Do NOT reorder or remove entries.
+// 1) Don't forget to update enums.xml (name: ManifestInvalidError) when adding
+// new entries.
+// 2) Don't forget to update device_management_backend.proto (name:
+// ExtensionInstallReportLogEvent::ManifestInvalidError) when adding new
+// entries.
+// 3) Don't forget to update ConvertManifestInvalidErrorToProto method in
+// ExtensionInstallEventLogCollector.
+// Some errors are common for the entire fetched update manifest which
 // contains manifests of different extensions, while some errors are per
 // extension basis.
 enum class ManifestInvalidError {
diff --git a/extensions/common/manifest_handlers/background_info.h b/extensions/common/manifest_handlers/background_info.h
index b40f412..a5fd988 100644
--- a/extensions/common/manifest_handlers/background_info.h
+++ b/extensions/common/manifest_handlers/background_info.h
@@ -33,6 +33,9 @@
   static bool HasGeneratedBackgroundPage(const Extension* extension);
   static bool AllowJSAccess(const Extension* extension);
   static bool IsServiceWorkerBased(const Extension* extension);
+  static bool HasLazyContext(const Extension* extension) {
+    return HasLazyBackgroundPage(extension) || IsServiceWorkerBased(extension);
+  }
 
   bool has_background_page() const {
     return background_url_.is_valid() || !background_scripts_.empty();
diff --git a/fuchsia/cast_streaming/stream_consumer.cc b/fuchsia/cast_streaming/stream_consumer.cc
index ff2a53f..f83f4a0 100644
--- a/fuchsia/cast_streaming/stream_consumer.cc
+++ b/fuchsia/cast_streaming/stream_consumer.cc
@@ -12,8 +12,15 @@
 
 namespace {
 
-// Timeout to stop the Session when no data is received.
-constexpr base::TimeDelta kNoDataTimeout = base::TimeDelta::FromSeconds(10);
+// Timeout to stop the Session when no data is received. This is also used for
+// the frames duration because Senders may not send a new frame for ~10s.
+// When that happens, the Chromium media pipeline may end up deciding it does
+// not have enough data, resulting in the stream being stalled. Setting the
+// frame duration to this value prevents the media pipeline from considering the
+// stream as being stalled. As a result, we end up with overlapping frames but
+// this is fine since the media pipeline mostly considers the playout time when
+// deciding which frame to present or play.
+constexpr base::TimeDelta kNoDataTimeout = base::TimeDelta::FromSeconds(15);
 
 }  // namespace
 
@@ -159,8 +166,10 @@
            << "Received new frame. Timestamp: " << playout_time
            << ", is_key_frame: " << is_key_frame;
 
+  // See the |kNoDataTimeout| definition for why it is used for the frame
+  // duration here.
   frame_received_cb_.Run(media::mojom::DecoderBuffer::New(
-      playout_time /* timestamp */, base::TimeDelta() /* duration */,
+      playout_time /* timestamp */, kNoDataTimeout /* duration */,
       false /* is_end_of_stream */, buffer_size, is_key_frame,
       media::EmptyExtraData(), media::mojom::DecryptConfigPtr(),
       base::TimeDelta() /* front_discard */,
diff --git a/fuchsia/engine/browser/frame_impl.cc b/fuchsia/engine/browser/frame_impl.cc
index 46ab296..7a95d74 100644
--- a/fuchsia/engine/browser/frame_impl.cc
+++ b/fuchsia/engine/browser/frame_impl.cc
@@ -225,20 +225,23 @@
 }  // namespace
 
 // static
-FrameImpl* FrameImpl::FromRenderFrameHost(
-    content::RenderFrameHost* render_frame_host) {
-  content::WebContents* web_contents =
-      content::WebContents::FromRenderFrameHost(render_frame_host);
+FrameImpl* FrameImpl::FromWebContents(content::WebContents* web_contents) {
   if (!web_contents)
     return nullptr;
 
   auto& map = WebContentsToFrameImplMap();
   auto it = map.find(web_contents);
-  if (it == map.end())
-    return nullptr;
+  DCHECK(it != map.end()) << "WebContents not owned by a FrameImpl.";
   return it->second;
 }
 
+// static
+FrameImpl* FrameImpl::FromRenderFrameHost(
+    content::RenderFrameHost* render_frame_host) {
+  return FromWebContents(
+      content::WebContents::FromRenderFrameHost(render_frame_host));
+}
+
 FrameImpl::FrameImpl(std::unique_ptr<content::WebContents> web_contents,
                      ContextImpl* context,
                      fidl::InterfaceRequest<fuchsia::web::Frame> frame_request)
diff --git a/fuchsia/engine/browser/frame_impl.h b/fuchsia/engine/browser/frame_impl.h
index 7027e5e..e693482 100644
--- a/fuchsia/engine/browser/frame_impl.h
+++ b/fuchsia/engine/browser/frame_impl.h
@@ -47,8 +47,12 @@
                   public content::WebContentsObserver,
                   public content::WebContentsDelegate {
  public:
+  // Returns FrameImpl that owns the |web_contents| or nullptr if the
+  // |web_contents| is nullptr.
+  static FrameImpl* FromWebContents(content::WebContents* web_contents);
+
   // Returns FrameImpl that owns the |render_frame_host| or nullptr if the
-  // |render_frame_host| is not owned by a FrameImpl.
+  // |render_frame_host| is nullptr.
   static FrameImpl* FromRenderFrameHost(
       content::RenderFrameHost* render_frame_host);
 
@@ -66,6 +70,10 @@
     return &permission_controller_;
   }
 
+  UrlRequestRewriteRulesManager* url_request_rewrite_rules_manager() {
+    return &url_request_rewrite_rules_manager_;
+  }
+
   zx::unowned_channel GetBindingChannelForTest() const;
   content::WebContents* web_contents_for_test() const {
     return web_contents_.get();
diff --git a/fuchsia/engine/browser/url_request_rewrite_rules_manager.cc b/fuchsia/engine/browser/url_request_rewrite_rules_manager.cc
index ce0152b..9166a7f8 100644
--- a/fuchsia/engine/browser/url_request_rewrite_rules_manager.cc
+++ b/fuchsia/engine/browser/url_request_rewrite_rules_manager.cc
@@ -13,13 +13,6 @@
 
 namespace {
 
-using RoutingIdRewriterMap =
-    std::unordered_map<int, UrlRequestRewriteRulesManager*>;
-RoutingIdRewriterMap& GetRewriterMap() {
-  static base::NoDestructor<RoutingIdRewriterMap> rewriter_map;
-  return *rewriter_map;
-}
-
 bool IsValidUrlHost(base::StringPiece host) {
   return GURL(base::StrCat({url::kHttpScheme, "://", host})).is_valid();
 }
@@ -134,23 +127,6 @@
 
 }  // namespace
 
-UrlRequestRewriteRulesManager::ActiveFrame::ActiveFrame(
-    content::RenderFrameHost* rfh,
-    mojo::AssociatedRemote<mojom::UrlRequestRulesReceiver> ar)
-    : render_frame_host(rfh), associated_remote(std::move(ar)) {}
-UrlRequestRewriteRulesManager::ActiveFrame::ActiveFrame(
-    UrlRequestRewriteRulesManager::ActiveFrame&&) = default;
-UrlRequestRewriteRulesManager::ActiveFrame::~ActiveFrame() = default;
-
-// static
-UrlRequestRewriteRulesManager*
-UrlRequestRewriteRulesManager::ForFrameTreeNodeId(int frame_tree_node_id) {
-  auto iter = GetRewriterMap().find(frame_tree_node_id);
-  if (iter == GetRewriterMap().end())
-    return nullptr;
-  return iter->second;
-}
-
 // static
 std::unique_ptr<UrlRequestRewriteRulesManager>
 UrlRequestRewriteRulesManager::CreateForTesting() {
@@ -179,9 +155,8 @@
               std::move(rules)));
 
   // Send the updated rules to the receivers.
-  for (const auto& receiver_pair : active_frames_) {
-    receiver_pair.second.associated_remote->OnRulesUpdated(
-        mojo::Clone(cached_rules_->data));
+  for (const auto& receiver_pair : active_remotes_) {
+    receiver_pair.second->OnRulesUpdated(mojo::Clone(cached_rules_->data));
   }
 
   // TODO(crbug.com/976975): Only call the callback when there are pending
@@ -200,52 +175,24 @@
 
 void UrlRequestRewriteRulesManager::RenderFrameCreated(
     content::RenderFrameHost* render_frame_host) {
-  int frame_tree_node_id = render_frame_host->GetFrameTreeNodeId();
-
-  if (active_frames_.find(frame_tree_node_id) != active_frames_.end()) {
-    // This happens on cross-process navigations. It is not necessary to refresh
-    // the global map in this case as RenderFrameDeleted will not have been
-    // called for this RenderFrameHost.
-    size_t deleted = active_frames_.erase(frame_tree_node_id);
-    DCHECK(deleted == 1);
-  } else {
-    // Register this instance of UrlRequestRewriteRulesManager as the URL
-    // request rewriter handler for this RenderFrameHost ID.
-    auto iter =
-        GetRewriterMap().emplace(std::make_pair(frame_tree_node_id, this));
-    DCHECK(iter.second);
-  }
-
   // Register the frame rules receiver.
   mojo::AssociatedRemote<mojom::UrlRequestRulesReceiver> rules_receiver;
   render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
       &rules_receiver);
-  ActiveFrame active_frame(render_frame_host, std::move(rules_receiver));
-  auto iter =
-      active_frames_.emplace(frame_tree_node_id, std::move(active_frame));
+  auto iter = active_remotes_.emplace(
+      render_frame_host->GetGlobalFrameRoutingId(), std::move(rules_receiver));
   DCHECK(iter.second);
 
   base::AutoLock auto_lock(lock_);
   if (cached_rules_) {
     // Send an initial set of rules.
-    iter.first->second.associated_remote->OnRulesUpdated(
-        mojo::Clone(cached_rules_->data));
+    iter.first->second->OnRulesUpdated(mojo::Clone(cached_rules_->data));
   }
 }
 
 void UrlRequestRewriteRulesManager::RenderFrameDeleted(
     content::RenderFrameHost* render_frame_host) {
-  int frame_tree_node_id = render_frame_host->GetFrameTreeNodeId();
-  auto iter = active_frames_.find(frame_tree_node_id);
-  DCHECK(iter != active_frames_.end());
-
-  // On cross-process navigations, the new RenderFrameHost is created before
-  // the old one is deleted. When that happens, the map has already been
-  // updated, so it is safe to return here.
-  if (iter->second.render_frame_host != render_frame_host)
-    return;
-
-  active_frames_.erase(iter);
-  size_t deleted = GetRewriterMap().erase(frame_tree_node_id);
-  DCHECK(deleted == 1);
+  size_t removed =
+      active_remotes_.erase(render_frame_host->GetGlobalFrameRoutingId());
+  DCHECK_EQ(removed, 1u);
 }
diff --git a/fuchsia/engine/browser/url_request_rewrite_rules_manager.h b/fuchsia/engine/browser/url_request_rewrite_rules_manager.h
index e29a024..d41503e 100644
--- a/fuchsia/engine/browser/url_request_rewrite_rules_manager.h
+++ b/fuchsia/engine/browser/url_request_rewrite_rules_manager.h
@@ -8,6 +8,7 @@
 #include <fuchsia/web/cpp/fidl.h>
 
 #include "base/synchronization/lock.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "fuchsia/engine/common/web_engine_url_loader_throttle.h"
 #include "fuchsia/engine/url_request_rewrite.mojom.h"
@@ -25,9 +26,6 @@
     : public content::WebContentsObserver,
       public WebEngineURLLoaderThrottle::CachedRulesProvider {
  public:
-  static UrlRequestRewriteRulesManager* ForFrameTreeNodeId(
-      int frame_tree_node_id);
-
   static std::unique_ptr<UrlRequestRewriteRulesManager> CreateForTesting();
 
   explicit UrlRequestRewriteRulesManager(content::WebContents* web_contents);
@@ -45,21 +43,8 @@
   GetCachedRules() override;
 
  private:
-  // Helper struct containing a RenderFrameHost and its corresponding
-  // AssociatedRemote.
-  struct ActiveFrame {
-    ActiveFrame(content::RenderFrameHost* render_frame_host,
-                mojo::AssociatedRemote<mojom::UrlRequestRulesReceiver>
-                    associated_remote);
-    ActiveFrame(ActiveFrame&& other);
-    ~ActiveFrame();
-
-    content::RenderFrameHost* render_frame_host;
-    mojo::AssociatedRemote<mojom::UrlRequestRulesReceiver> associated_remote;
-  };
-
   // Test-only constructor.
-  explicit UrlRequestRewriteRulesManager();
+  UrlRequestRewriteRulesManager();
 
   // content::WebContentsObserver implementation.
   void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
@@ -69,8 +54,10 @@
   scoped_refptr<WebEngineURLLoaderThrottle::UrlRequestRewriteRules>
       cached_rules_ GUARDED_BY(lock_);
 
-  // Map of FrameTreeNode Ids to their current ActiveFrame.
-  std::map<int, ActiveFrame> active_frames_;
+  // Map of GlobalRoutingID to their current associated remote.
+  std::map<content::GlobalFrameRoutingId,
+           mojo::AssociatedRemote<mojom::UrlRequestRulesReceiver>>
+      active_remotes_;
 
   DISALLOW_COPY_AND_ASSIGN(UrlRequestRewriteRulesManager);
 };
diff --git a/fuchsia/engine/browser/web_engine_content_browser_client.cc b/fuchsia/engine/browser/web_engine_content_browser_client.cc
index b51ac76..e1720ed 100644
--- a/fuchsia/engine/browser/web_engine_content_browser_client.cc
+++ b/fuchsia/engine/browser/web_engine_content_browser_client.cc
@@ -16,6 +16,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/user_agent.h"
 #include "fuchsia/base/fuchsia_dir_scheme.h"
+#include "fuchsia/engine/browser/frame_impl.h"
 #include "fuchsia/engine/browser/url_request_rewrite_rules_manager.h"
 #include "fuchsia/engine/browser/web_engine_browser_context.h"
 #include "fuchsia/engine/browser/web_engine_browser_interface_binders.h"
@@ -194,16 +195,10 @@
     return {};
   }
 
-  UrlRequestRewriteRulesManager* adapter =
-      UrlRequestRewriteRulesManager::ForFrameTreeNodeId(frame_tree_node_id);
-  if (!adapter) {
-    // No popup support for rules rewriter.
-    return {};
-  }
-
   std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles;
   throttles.emplace_back(std::make_unique<WebEngineURLLoaderThrottle>(
-      UrlRequestRewriteRulesManager::ForFrameTreeNodeId(frame_tree_node_id)));
+      FrameImpl::FromWebContents(wc_getter.Run())
+          ->url_request_rewrite_rules_manager()));
   return throttles;
 }
 
diff --git a/fuchsia/engine/context_provider_impl.cc b/fuchsia/engine/context_provider_impl.cc
index f7a4151..dadf825a0 100644
--- a/fuchsia/engine/context_provider_impl.cc
+++ b/fuchsia/engine/context_provider_impl.cc
@@ -409,6 +409,9 @@
     AppendFeature(switches::kEnableFeatures,
                   features::kUseSkiaOutputDeviceBufferQueue.name,
                   &launch_command);
+    AppendFeature(switches::kEnableFeatures,
+                  features::kUseRealBuffersForPageFlipTest.name,
+                  &launch_command);
     launch_command.AppendSwitchASCII(switches::kEnableHardwareOverlays,
                                      "underlay");
     launch_command.AppendSwitch(switches::kUseOverlaysForVideo);
diff --git a/fuchsia/runners/cast/cast_runner.cc b/fuchsia/runners/cast/cast_runner.cc
index d10501e..6d76004 100644
--- a/fuchsia/runners/cast/cast_runner.cc
+++ b/fuchsia/runners/cast/cast_runner.cc
@@ -227,7 +227,7 @@
 
   // See http://b/141956135.
   params.set_user_agent_product("CrKey");
-  params.set_user_agent_version("1.43.000000");
+  params.set_user_agent_version("1.52.000000");
 
   // When tests require that VULKAN be disabled, DRM must also be disabled.
   if (disable_vulkan_for_test_) {
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm
index 6429849..2adfdc7 100644
--- a/ios/chrome/app/application_delegate/app_state.mm
+++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -200,7 +200,6 @@
 
 - (void)setMainSceneState:(SceneState*)mainSceneState {
   DCHECK(!_mainSceneState);
-
   _mainSceneState = mainSceneState;
   [self.observers appState:self sceneConnected:mainSceneState];
 }
@@ -577,7 +576,8 @@
       for (UIWindowScene* scene in connectedScenes) {
         if (![scene.delegate isKindOfClass:[SceneDelegate class]]) {
           // This might happen in tests.
-          // TODO(crbug.com/1113097): This shouldn't be needed.
+          // TODO(crbug.com/1113097): This shouldn't be needed. (It might also
+          // be the cause of crbug.com/1142782).
           [sceneStates addObject:[[SceneState alloc] initWithAppState:self]];
           continue;
         }
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 8b094e7..8f1c4ab2 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -2540,10 +2540,16 @@
   DCHECK(NTPHelper && NTPHelper->IsActive());
   // NTP is laid out only in the visible part of the screen.
   UIEdgeInsets viewportInsets = UIEdgeInsetsZero;
-  if (!IsRegularXRegularSizeClass(self))
+  if (!IsRegularXRegularSizeClass(self)) {
     viewportInsets.bottom = [self bottomToolbarHeight];
-  if (!IsSplitToolbarMode(self))
+  }
+
+  // Add toolbar margin to the frame for every scenario except compact-width
+  // non-otr, as that is the only case where there isn't a primary toolbar.
+  // (see crbug.com/1063173)
+  if (!IsSplitToolbarMode(self) || self.isOffTheRecord) {
     viewportInsets.top = [self expandedTopToolbarHeight];
+  }
   return UIEdgeInsetsInsetRect(self.contentArea.bounds, viewportInsets);
 }
 
@@ -2987,16 +2993,17 @@
   NewTabPageTabHelper* NTPHelper = NewTabPageTabHelper::FromWebState(webState);
   if (NTPHelper && NTPHelper->IsActive()) {
     // If the NTP is active, then it's used as the base view for snapshotting.
-    // When the tab strip is visible, the NTP is laid out below the toolbars, so
-    // it should not be inset while snapshotting.  When the tab strip is not
-    // used, the NTP is laid out fullscreen and the top portion of the view will
-    // be obstructed by the toolbars when the snapshot is displayed in the tab
-    // grid.  In that case, the NTP should be inset by the maximum viewport
-    /// insets.
-    // The NTP always sits above the bottom toolbar (when there is one) so the
-    // insets should not take into account the bottom toolbar.
+    // When the tab strip is visible, or for the incognito NTP, the NTP is laid
+    // out between the toolbars, so it should not be inset while snapshotting.
+    if ([self canShowTabStrip] || self.isOffTheRecord) {
+      return UIEdgeInsetsZero;
+    }
+
+    // For the regular NTP without tab strip, it sits above the bottom toolbar
+    // but, since it is displayed as full-screen at the top, it requires maximum
+    // viewport insets.
     maxViewportInsets.bottom = 0;
-    return [self canShowTabStrip] ? UIEdgeInsetsZero : maxViewportInsets;
+    return maxViewportInsets;
   } else {
     // If the NTP is inactive, the WebState's view is used as the base view for
     // snapshotting.  If fullscreen is implemented by resizing the scroll view,
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index 4cb0cda..033d5ec1 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -2390,9 +2390,14 @@
 
   NSMutableArray<SceneController*>* sceneControllers =
       [[NSMutableArray alloc] init];
-  for (SceneState* sceneState in self.sceneState.appState.connectedScenes) {
+  for (SceneState* sceneState in [self.sceneState.appState connectedScenes]) {
     SceneController* sceneController = sceneState.controller;
-    [sceneControllers addObject:sceneController];
+    // In some circumstances, the scene state may still exist while the
+    // corresponding scene controller has been deallocated.
+    // (see crbug.com/1142782).
+    if (sceneController) {
+      [sceneControllers addObject:sceneController];
+    }
   }
 
   for (SceneController* sceneController in sceneControllers) {
diff --git a/ios/chrome/browser/ui/ntp/incognito_view.mm b/ios/chrome/browser/ui/ntp/incognito_view.mm
index 7159248..50f1679 100644
--- a/ios/chrome/browser/ui/ntp/incognito_view.mm
+++ b/ios/chrome/browser/ui/ntp/incognito_view.mm
@@ -136,8 +136,7 @@
   UILayoutGuide* _bottomUnsafeAreaGuide;
   UILayoutGuide* _bottomUnsafeAreaGuideInSuperview;
 
-  // Height constraints for adding margins for the toolbars.
-  NSLayoutConstraint* _topToolbarMarginHeight;
+  // Height constraint for adding margins for the bottom toolbar.
   NSLayoutConstraint* _bottomToolbarMarginHeight;
 
   // Constraint ensuring that |containerView| is at least as high as the
@@ -207,38 +206,34 @@
     [_containerView addLayoutGuide:bottomGuide];
     [_containerView addLayoutGuide:_bottomUnsafeAreaGuide];
 
-    // Those layout guide are used to prevent the content from being displayed
-    // below the toolbars.
+    // This layout guide is used to prevent the content from being displayed
+    // below the bottom toolbar.
     UILayoutGuide* bottomToolbarMarginGuide = [[UILayoutGuide alloc] init];
-    UILayoutGuide* topToolbarMarginGuide = [[UILayoutGuide alloc] init];
     [_containerView addLayoutGuide:bottomToolbarMarginGuide];
-    [_containerView addLayoutGuide:topToolbarMarginGuide];
 
     _bottomToolbarMarginHeight =
         [bottomToolbarMarginGuide.heightAnchor constraintEqualToConstant:0];
-    _topToolbarMarginHeight =
-        [topToolbarMarginGuide.heightAnchor constraintEqualToConstant:0];
     // Updates the constraints to the correct value.
     [self updateToolbarMargins];
 
     [self addSubview:_containerView];
 
     [NSLayoutConstraint activateConstraints:@[
-      // Position the two toolbar margin guides between the two guides used to
-      // have the correct centering margin.
+      // Position the stack view's top at some margin under from the container
+      // top.
       [topGuide.topAnchor constraintEqualToAnchor:_containerView.topAnchor],
-      [topToolbarMarginGuide.topAnchor
-          constraintEqualToAnchor:topGuide.bottomAnchor
-                         constant:kLayoutGuideVerticalMargin],
+      [_stackView.topAnchor constraintEqualToAnchor:topGuide.bottomAnchor
+                                           constant:kLayoutGuideVerticalMargin],
+
+      // Position the stack view's bottom guide at some margin from the
+      // container bottom.
       [bottomGuide.topAnchor
           constraintEqualToAnchor:bottomToolbarMarginGuide.bottomAnchor
                          constant:kLayoutGuideVerticalMargin],
       [_containerView.bottomAnchor
           constraintEqualToAnchor:bottomGuide.bottomAnchor],
 
-      // Position the stack view between the two toolbar margin guides.
-      [topToolbarMarginGuide.bottomAnchor
-          constraintEqualToAnchor:_stackView.topAnchor],
+      // Position the stack view above the bottom toolbar margin guide.
       [bottomToolbarMarginGuide.topAnchor
           constraintEqualToAnchor:_stackView.bottomAnchor],
 
@@ -268,7 +263,6 @@
 
       // Activate the height constraints.
       _bottomToolbarMarginHeight,
-      _topToolbarMarginHeight,
 
       // Set a minimum top margin and make the bottom guide twice as tall as the
       // top guide.
@@ -364,15 +358,6 @@
 
 // Updates the height of the margins for the top and bottom toolbars.
 - (void)updateToolbarMargins {
-  if (IsRegularXRegularSizeClass(self)) {
-    _topToolbarMarginHeight.constant = 0;
-  } else {
-    CGFloat topInset = self.safeAreaInsets.top;
-    _topToolbarMarginHeight.constant =
-        topInset + ToolbarExpandedHeight(
-                       self.traitCollection.preferredContentSizeCategory);
-  }
-
   if (IsSplitToolbarMode(self)) {
     _bottomToolbarMarginHeight.constant = kSecondaryToolbarHeight;
   } else {
diff --git a/media/base/audio_buffer.cc b/media/base/audio_buffer.cc
index 622c915..9798522 100644
--- a/media/base/audio_buffer.cc
+++ b/media/base/audio_buffer.cc
@@ -228,12 +228,6 @@
                       nullptr, 0, kNoTimestamp, nullptr));
 }
 
-// Convert int16_t values in the range [INT16_MIN, INT16_MAX] to [-1.0, 1.0].
-inline float ConvertSample(int16_t value) {
-  return value * (value < 0 ? -1.0f / std::numeric_limits<int16_t>::min()
-                            : 1.0f / std::numeric_limits<int16_t>::max());
-}
-
 void AudioBuffer::AdjustSampleRate(int sample_rate) {
   DCHECK(!end_of_stream_);
   sample_rate_ = sample_rate;
@@ -281,14 +275,16 @@
     return;
   }
 
+  // Note: The conversion steps below will clip values to [1.0, -1.0f].
+
   if (sample_format_ == kSampleFormatPlanarF32) {
-    // Format is planar float32. Copy the data from each channel as a block.
     for (int ch = 0; ch < channel_count_; ++ch) {
+      float* dest_data = dest->channel(ch) + dest_frame_offset;
       const float* source_data =
           reinterpret_cast<const float*>(channel_data_[ch]) +
           source_frame_offset;
-      memcpy(dest->channel(ch) + dest_frame_offset, source_data,
-             sizeof(float) * frames_to_copy);
+      for (int i = 0; i < frames_to_copy; ++i)
+        dest_data[i] = Float32SampleTypeTraits::FromFloat(source_data[i]);
     }
     return;
   }
@@ -301,37 +297,35 @@
           reinterpret_cast<const int16_t*>(channel_data_[ch]) +
           source_frame_offset;
       float* dest_data = dest->channel(ch) + dest_frame_offset;
-      for (int i = 0; i < frames_to_copy; ++i) {
-        dest_data[i] = ConvertSample(source_data[i]);
-      }
+      for (int i = 0; i < frames_to_copy; ++i)
+        dest_data[i] = SignedInt16SampleTypeTraits::ToFloat(source_data[i]);
     }
     return;
   }
 
+  const int bytes_per_channel = SampleFormatToBytesPerChannel(sample_format_);
+  const int frame_size = channel_count_ * bytes_per_channel;
+  const uint8_t* source_data = data_.get() + source_frame_offset * frame_size;
+
   if (sample_format_ == kSampleFormatF32) {
-    // Format is interleaved float32. Copy the data into each channel.
-    const float* source_data = reinterpret_cast<const float*>(data_.get()) +
-                               source_frame_offset * channel_count_;
-    for (int ch = 0; ch < channel_count_; ++ch) {
-      float* dest_data = dest->channel(ch) + dest_frame_offset;
-      for (int i = 0, offset = ch; i < frames_to_copy;
-           ++i, offset += channel_count_) {
-        dest_data[i] = source_data[offset];
-      }
-    }
-    return;
+    dest->FromInterleavedPartial<Float32SampleTypeTraits>(
+        reinterpret_cast<const float*>(source_data), dest_frame_offset,
+        frames_to_copy);
+  } else if (sample_format_ == kSampleFormatU8) {
+    dest->FromInterleavedPartial<UnsignedInt8SampleTypeTraits>(
+        source_data, dest_frame_offset, frames_to_copy);
+  } else if (sample_format_ == kSampleFormatS16) {
+    dest->FromInterleavedPartial<SignedInt16SampleTypeTraits>(
+        reinterpret_cast<const int16_t*>(source_data), dest_frame_offset,
+        frames_to_copy);
+  } else if (sample_format_ == kSampleFormatS24 ||
+             sample_format_ == kSampleFormatS32) {
+    dest->FromInterleavedPartial<SignedInt32SampleTypeTraits>(
+        reinterpret_cast<const int32_t*>(source_data), dest_frame_offset,
+        frames_to_copy);
+  } else {
+    NOTREACHED() << "Unsupported audio sample type: " << sample_format_;
   }
-
-  // Remaining formats are integer interleaved data. Use the deinterleaving code
-  // in AudioBus to copy the data.
-  DCHECK(
-      sample_format_ == kSampleFormatU8 || sample_format_ == kSampleFormatS16 ||
-      sample_format_ == kSampleFormatS24 || sample_format_ == kSampleFormatS32);
-  int bytes_per_channel = SampleFormatToBytesPerChannel(sample_format_);
-  int frame_size = channel_count_ * bytes_per_channel;
-  const uint8_t* source_data = data_.get() + source_frame_offset * frame_size;
-  dest->FromInterleavedPartial(source_data, dest_frame_offset, frames_to_copy,
-                               bytes_per_channel);
 }
 
 void AudioBuffer::TrimStart(int frames_to_trim) {
diff --git a/media/base/audio_buffer.h b/media/base/audio_buffer.h
index 71f5c87..55adc828 100644
--- a/media/base/audio_buffer.h
+++ b/media/base/audio_buffer.h
@@ -124,8 +124,8 @@
   // Copy frames into |dest|. |frames_to_copy| is the number of frames to copy.
   // |source_frame_offset| specifies how many frames in the buffer to skip
   // first. |dest_frame_offset| is the frame offset in |dest|. The frames are
-  // converted from their source format into planar float32 data (which is all
-  // that AudioBus handles).
+  // converted and clipped from their source format into planar float32 data
+  // (which is all that AudioBus handles).
   void ReadFrames(int frames_to_copy,
                   int source_frame_offset,
                   int dest_frame_offset,
diff --git a/media/base/audio_buffer_queue_unittest.cc b/media/base/audio_buffer_queue_unittest.cc
index 3cf5e12..94e20d5 100644
--- a/media/base/audio_buffer_queue_unittest.cc
+++ b/media/base/audio_buffer_queue_unittest.cc
@@ -18,18 +18,24 @@
 
 namespace media {
 
-const int kSampleRate = 44100;
+constexpr int kSampleRate = 44100;
 
+enum class ValueType { kNormal, kFloat };
 static void VerifyBus(AudioBus* bus,
                       int offset,
                       int frames,
                       int buffer_size,
                       float start,
-                      float increment) {
+                      float increment,
+                      ValueType type = ValueType::kNormal) {
   for (int ch = 0; ch < bus->channels(); ++ch) {
     const float v = start + ch * buffer_size * increment;
     for (int i = offset; i < offset + frames; ++i) {
-      ASSERT_FLOAT_EQ(v + (i - offset) * increment, bus->channel(ch)[i])
+      float expected_value = v + (i - offset) * increment;
+      if (type == ValueType::kFloat)
+        expected_value /= std::numeric_limits<uint16_t>::max();
+
+      ASSERT_FLOAT_EQ(expected_value, bus->channel(ch)[i])
           << "i=" << i << ", ch=" << ch;
     }
   }
@@ -94,7 +100,7 @@
 
   EXPECT_EQ(4, buffer.ReadFrames(4, 0, bus.get()));
   EXPECT_EQ(4, buffer.frames());
-  VerifyBus(bus.get(), 0, 4, bus->frames(), 10, 1);
+  VerifyBus(bus.get(), 0, 4, bus->frames(), 10, 1, ValueType::kFloat);
 
   buffer.Append(MakeTestBuffer<float>(
       kSampleFormatF32, channel_layout, 20.0f, 1.0f, 8));
@@ -106,7 +112,7 @@
   buffer.SeekFrames(16);
   EXPECT_EQ(4, buffer.ReadFrames(4, 0, bus.get()));
   EXPECT_EQ(0, buffer.frames());
-  VerifyBus(bus.get(), 0, 4, bus->frames(), 34, 1);
+  VerifyBus(bus.get(), 0, 4, bus->frames(), 34, 1, ValueType::kFloat);
 
   buffer.Append(MakeTestBuffer<float>(
       kSampleFormatF32, channel_layout, 40.0f, 1.0f, 8));
@@ -116,13 +122,13 @@
   EXPECT_EQ(16, buffer.frames());
 
   EXPECT_EQ(4, buffer.ReadFrames(4, 0, bus.get()));
-  VerifyBus(bus.get(), 0, 4, bus->frames(), 40, 1);
+  VerifyBus(bus.get(), 0, 4, bus->frames(), 40, 1, ValueType::kFloat);
 
   // Read off the end of the buffer.
   EXPECT_EQ(12, buffer.frames());
   buffer.SeekFrames(8);
   EXPECT_EQ(4, buffer.ReadFrames(100, 0, bus.get()));
-  VerifyBus(bus.get(), 0, 4, bus->frames(), 54, 1);
+  VerifyBus(bus.get(), 0, 4, bus->frames(), 54, 1, ValueType::kFloat);
 }
 
 TEST(AudioBufferQueueTest, Seek) {
@@ -188,13 +194,13 @@
   std::unique_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
   EXPECT_EQ(3, buffer.ReadFrames(3, 0, bus.get()));
   EXPECT_EQ(73, buffer.frames());
-  VerifyBus(bus.get(), 0, 3, 6, 1, 1);
+  VerifyBus(bus.get(), 0, 3, 6, 1, 1, ValueType::kFloat);
 
   // Now read 5 frames, which will span buffers. Append the data into AudioBus.
   EXPECT_EQ(5, buffer.ReadFrames(5, 3, bus.get()));
   EXPECT_EQ(68, buffer.frames());
-  VerifyBus(bus.get(), 0, 6, 6, 1, 1);
-  VerifyBus(bus.get(), 6, 2, 10, 13, 1);
+  VerifyBus(bus.get(), 0, 6, 6, 1, 1, ValueType::kFloat);
+  VerifyBus(bus.get(), 6, 2, 10, 13, 1, ValueType::kFloat);
 
   // Now skip into the third buffer.
   buffer.SeekFrames(20);
@@ -202,7 +208,7 @@
 
   // Now read 2 frames, which are in the third buffer.
   EXPECT_EQ(2, buffer.ReadFrames(2, 0, bus.get()));
-  VerifyBus(bus.get(), 0, 2, 60, 45, 1);
+  VerifyBus(bus.get(), 0, 2, 60, 45, 1, ValueType::kFloat);
 }
 
 TEST(AudioBufferQueueTest, ReadU8) {
@@ -289,8 +295,8 @@
   std::unique_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
   EXPECT_EQ(6, buffer.ReadFrames(6, 0, bus.get()));
   EXPECT_EQ(8, buffer.frames());
-  VerifyBus(bus.get(), 0, 4, 4, 1, 1);
-  VerifyBus(bus.get(), 4, 2, 10, 50, 1);
+  VerifyBus(bus.get(), 0, 4, 4, 1, 1, ValueType::kFloat);
+  VerifyBus(bus.get(), 4, 2, 10, 50, 1, ValueType::kFloat);
 }
 
 TEST(AudioBufferQueueTest, ReadS16Planar) {
@@ -333,9 +339,9 @@
   std::unique_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
   EXPECT_EQ(30, buffer.ReadFrames(30, 0, bus.get()));
   EXPECT_EQ(46, buffer.frames());
-  VerifyBus(bus.get(), 0, 6, 6, 0, 1);
-  VerifyBus(bus.get(), 6, 10, 10, 6 * channels, 1);
-  VerifyBus(bus.get(), 16, 14, 60, 16 * channels, 1);
+  VerifyBus(bus.get(), 0, 6, 6, 0, 1, ValueType::kFloat);
+  VerifyBus(bus.get(), 6, 10, 10, 6 * channels, 1, ValueType::kFloat);
+  VerifyBus(bus.get(), 16, 14, 60, 16 * channels, 1, ValueType::kFloat);
 }
 
 TEST(AudioBufferQueueTest, Peek) {
@@ -355,17 +361,17 @@
   EXPECT_EQ(frames, buffer.PeekFrames(60, 0, 0, bus1.get()));
   EXPECT_EQ(30, buffer.PeekFrames(30, 0, 0, bus1.get()));
   EXPECT_EQ(frames, buffer.frames());
-  VerifyBus(bus1.get(), 0, 30, bus1->frames(), 0, 1);
+  VerifyBus(bus1.get(), 0, 30, bus1->frames(), 0, 1, ValueType::kFloat);
 
   // Now read the next 30 frames (which should be the same as those peeked at).
   std::unique_ptr<AudioBus> bus2 = AudioBus::Create(channels, frames);
   EXPECT_EQ(30, buffer.ReadFrames(30, 0, bus2.get()));
-  VerifyBus(bus2.get(), 0, 30, bus2->frames(), 0, 1);
+  VerifyBus(bus2.get(), 0, 30, bus2->frames(), 0, 1, ValueType::kFloat);
 
   // Peek 10 frames forward
   bus1->Zero();
   EXPECT_EQ(5, buffer.PeekFrames(5, 10, 0, bus1.get()));
-  VerifyBus(bus1.get(), 0, 5, bus1->frames(), 40, 1);
+  VerifyBus(bus1.get(), 0, 5, bus1->frames(), 40, 1, ValueType::kFloat);
 
   // Peek to the end of the buffer.
   EXPECT_EQ(30, buffer.frames());
diff --git a/media/base/audio_buffer_unittest.cc b/media/base/audio_buffer_unittest.cc
index 31b5f4d0..c769bd5a 100644
--- a/media/base/audio_buffer_unittest.cc
+++ b/media/base/audio_buffer_unittest.cc
@@ -14,25 +14,34 @@
 
 namespace media {
 
-static const int kSampleRate = 4800;
+constexpr int kSampleRate = 4800;
 
+enum class ValueType { kNormal, kFloat };
 static void VerifyBusWithOffset(AudioBus* bus,
                                 int offset,
                                 int frames,
                                 float start,
                                 float start_offset,
-                                float increment) {
+                                float increment,
+                                ValueType type = ValueType::kNormal) {
   for (int ch = 0; ch < bus->channels(); ++ch) {
     const float v = start_offset + start + ch * bus->frames() * increment;
     for (int i = offset; i < offset + frames; ++i) {
-      ASSERT_FLOAT_EQ(v + i * increment, bus->channel(ch)[i]) << "i=" << i
-                                                              << ", ch=" << ch;
+      float expected_value = v + i * increment;
+      if (type == ValueType::kFloat)
+        expected_value /= std::numeric_limits<uint16_t>::max();
+      ASSERT_FLOAT_EQ(expected_value, bus->channel(ch)[i])
+          << "i=" << i << ", ch=" << ch;
     }
   }
 }
 
-static void VerifyBus(AudioBus* bus, int frames, float start, float increment) {
-  VerifyBusWithOffset(bus, 0, frames, start, 0, increment);
+static void VerifyBus(AudioBus* bus,
+                      int frames,
+                      float start,
+                      float increment,
+                      ValueType type = ValueType::kNormal) {
+  VerifyBusWithOffset(bus, 0, frames, start, 0, increment, type);
 }
 
 static void TrimRangeTest(SampleFormat sample_format) {
@@ -57,7 +66,7 @@
 
   // Verify all frames before trimming.
   buffer->ReadFrames(frames, 0, 0, bus.get());
-  VerifyBus(bus.get(), frames, 0, 1);
+  VerifyBus(bus.get(), frames, 0, 1, ValueType::kFloat);
 
   // Trim 10ms of frames from the middle of the buffer.
   int trim_start = frames / 2;
@@ -69,13 +78,9 @@
   EXPECT_EQ(duration - trim_duration, buffer->duration());
   bus->Zero();
   buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get());
-  VerifyBus(bus.get(), trim_start, 0, 1);
-  VerifyBusWithOffset(bus.get(),
-                      trim_start,
-                      buffer->frame_count() - trim_start,
-                      0,
-                      trim_length,
-                      1);
+  VerifyBus(bus.get(), trim_start, 0, 1, ValueType::kFloat);
+  VerifyBusWithOffset(bus.get(), trim_start, buffer->frame_count() - trim_start,
+                      0, trim_length, 1, ValueType::kFloat);
 
   // Trim 10ms of frames from the start, which just adjusts the buffer's
   // internal start offset.
@@ -86,13 +91,9 @@
   EXPECT_EQ(duration - 2 * trim_duration, buffer->duration());
   bus->Zero();
   buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get());
-  VerifyBus(bus.get(), trim_start, trim_length, 1);
-  VerifyBusWithOffset(bus.get(),
-                      trim_start,
-                      buffer->frame_count() - trim_start,
-                      trim_length,
-                      trim_length,
-                      1);
+  VerifyBus(bus.get(), trim_start, trim_length, 1, ValueType::kFloat);
+  VerifyBusWithOffset(bus.get(), trim_start, buffer->frame_count() - trim_start,
+                      trim_length, trim_length, 1, ValueType::kFloat);
 
   // Trim 10ms of frames from the end, which just adjusts the buffer's frame
   // count.
@@ -102,13 +103,9 @@
   EXPECT_EQ(duration - 3 * trim_duration, buffer->duration());
   bus->Zero();
   buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get());
-  VerifyBus(bus.get(), trim_start, trim_length, 1);
-  VerifyBusWithOffset(bus.get(),
-                      trim_start,
-                      buffer->frame_count() - trim_start,
-                      trim_length,
-                      trim_length,
-                      1);
+  VerifyBus(bus.get(), trim_start, trim_length, 1, ValueType::kFloat);
+  VerifyBusWithOffset(bus.get(), trim_start, buffer->frame_count() - trim_start,
+                      trim_length, trim_length, 1, ValueType::kFloat);
 
   // Trim another 10ms from the inner portion of the buffer.
   buffer->TrimRange(trim_start, trim_start + trim_length);
@@ -117,13 +114,9 @@
   EXPECT_EQ(duration - 4 * trim_duration, buffer->duration());
   bus->Zero();
   buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get());
-  VerifyBus(bus.get(), trim_start, trim_length, 1);
-  VerifyBusWithOffset(bus.get(),
-                      trim_start,
-                      buffer->frame_count() - trim_start,
-                      trim_length,
-                      trim_length * 2,
-                      1);
+  VerifyBus(bus.get(), trim_start, trim_length, 1, ValueType::kFloat);
+  VerifyBusWithOffset(bus.get(), trim_start, buffer->frame_count() - trim_start,
+                      trim_length, trim_length * 2, 1, ValueType::kFloat);
 
   // Trim off the end using TrimRange() to ensure end index is exclusive.
   buffer->TrimRange(buffer->frame_count() - trim_length, buffer->frame_count());
@@ -132,13 +125,9 @@
   EXPECT_EQ(duration - 5 * trim_duration, buffer->duration());
   bus->Zero();
   buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get());
-  VerifyBus(bus.get(), trim_start, trim_length, 1);
-  VerifyBusWithOffset(bus.get(),
-                      trim_start,
-                      buffer->frame_count() - trim_start,
-                      trim_length,
-                      trim_length * 2,
-                      1);
+  VerifyBus(bus.get(), trim_start, trim_length, 1, ValueType::kFloat);
+  VerifyBusWithOffset(bus.get(), trim_start, buffer->frame_count() - trim_start,
+                      trim_length, trim_length * 2, 1, ValueType::kFloat);
 
   // Trim off the start using TrimRange() to ensure start index is inclusive.
   buffer->TrimRange(0, trim_length);
@@ -148,13 +137,9 @@
   EXPECT_EQ(duration - 6 * trim_duration, buffer->duration());
   bus->Zero();
   buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get());
-  VerifyBus(bus.get(), trim_start, 2 * trim_length, 1);
-  VerifyBusWithOffset(bus.get(),
-                      trim_start,
-                      buffer->frame_count() - trim_start,
-                      trim_length * 2,
-                      trim_length * 2,
-                      1);
+  VerifyBus(bus.get(), trim_start, 2 * trim_length, 1, ValueType::kFloat);
+  VerifyBusWithOffset(bus.get(), trim_start, buffer->frame_count() - trim_start,
+                      trim_length * 2, trim_length * 2, 1, ValueType::kFloat);
 }
 
 TEST(AudioBufferTest, CopyFrom) {
@@ -345,12 +330,12 @@
                                                              start_time);
   std::unique_ptr<AudioBus> bus = AudioBus::Create(channels, frames);
   buffer->ReadFrames(10, 0, 0, bus.get());
-  VerifyBus(bus.get(), 10, 1, 1);
+  VerifyBus(bus.get(), 10, 1, 1, ValueType::kFloat);
 
   // Read second 10 frames.
   bus->Zero();
   buffer->ReadFrames(10, 10, 0, bus.get());
-  VerifyBus(bus.get(), 10, 11, 1);
+  VerifyBus(bus.get(), 10, 11, 1, ValueType::kFloat);
 }
 
 TEST(AudioBufferTest, ReadS16Planar) {
@@ -406,12 +391,12 @@
   // channels.
   std::unique_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
   buffer->ReadFrames(frames, 0, 0, bus.get());
-  VerifyBus(bus.get(), frames, 1, 1);
+  VerifyBus(bus.get(), frames, 1, 1, ValueType::kFloat);
 
   // Now read 20 frames from the middle of the buffer.
   bus->Zero();
   buffer->ReadFrames(20, 50, 0, bus.get());
-  VerifyBus(bus.get(), 20, 51, 1);
+  VerifyBus(bus.get(), 20, 51, 1, ValueType::kFloat);
 }
 
 TEST(AudioBufferTest, EmptyBuffer) {
@@ -487,7 +472,7 @@
 
   std::unique_ptr<AudioBus> bus = AudioBus::Create(channels, frames);
   buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get());
-  VerifyBus(bus.get(), buffer->frame_count(), 0.0f, 1.0f);
+  VerifyBus(bus.get(), buffer->frame_count(), 0.0f, 1.0f, ValueType::kFloat);
 
   // Trim off 10ms of frames from the start.
   buffer->TrimStart(ten_ms_of_frames);
@@ -495,7 +480,8 @@
   EXPECT_EQ(frames - ten_ms_of_frames, buffer->frame_count());
   EXPECT_EQ(duration - ten_ms, buffer->duration());
   buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get());
-  VerifyBus(bus.get(), buffer->frame_count(), ten_ms_of_frames, 1.0f);
+  VerifyBus(bus.get(), buffer->frame_count(), ten_ms_of_frames, 1.0f,
+            ValueType::kFloat);
 
   // Trim off 10ms of frames from the end.
   buffer->TrimEnd(ten_ms_of_frames);
@@ -503,7 +489,8 @@
   EXPECT_EQ(frames - 2 * ten_ms_of_frames, buffer->frame_count());
   EXPECT_EQ(duration - 2 * ten_ms, buffer->duration());
   buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get());
-  VerifyBus(bus.get(), buffer->frame_count(), ten_ms_of_frames, 1.0f);
+  VerifyBus(bus.get(), buffer->frame_count(), ten_ms_of_frames, 1.0f,
+            ValueType::kFloat);
 
   // Trim off 40ms more from the start.
   buffer->TrimStart(4 * ten_ms_of_frames);
@@ -511,7 +498,8 @@
   EXPECT_EQ(frames - 6 * ten_ms_of_frames, buffer->frame_count());
   EXPECT_EQ(duration - 6 * ten_ms, buffer->duration());
   buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get());
-  VerifyBus(bus.get(), buffer->frame_count(), 5 * ten_ms_of_frames, 1.0f);
+  VerifyBus(bus.get(), buffer->frame_count(), 5 * ten_ms_of_frames, 1.0f,
+            ValueType::kFloat);
 
   // Trim off the final 40ms from the end.
   buffer->TrimEnd(4 * ten_ms_of_frames);
diff --git a/media/base/audio_discard_helper_unittest.cc b/media/base/audio_discard_helper_unittest.cc
index 324439d5..9300fea 100644
--- a/media/base/audio_discard_helper_unittest.cc
+++ b/media/base/audio_discard_helper_unittest.cc
@@ -40,7 +40,7 @@
   std::unique_ptr<AudioBus> temp_bus =
       AudioBus::Create(buffer.channel_count(), 1);
   buffer.ReadFrames(1, index, 0, temp_bus.get());
-  return temp_bus->channel(0)[0];
+  return temp_bus->channel(0)[0] * std::numeric_limits<uint16_t>::max();
 }
 
 TEST(AudioDiscardHelperTest, TimeDeltaToFrames) {
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc
index 9056c8b8..81046464 100644
--- a/media/base/pipeline_impl.cc
+++ b/media/base/pipeline_impl.cc
@@ -470,7 +470,7 @@
   DCHECK(media_task_runner_->BelongsToCurrentThread());
 
   volume_ = volume;
-  if (state_ == kPlaying)
+  if (shared_state_.renderer)
     shared_state_.renderer->SetVolume(volume_);
 }
 
diff --git a/media/base/pipeline_impl_unittest.cc b/media/base/pipeline_impl_unittest.cc
index a19dcac..cb31db0 100644
--- a/media/base/pipeline_impl_unittest.cc
+++ b/media/base/pipeline_impl_unittest.cc
@@ -639,6 +639,30 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(PipelineImplTest, SetVolumeDuringStartup) {
+  CreateAudioStream();
+  SetDemuxerExpectations();
+
+  // The audio renderer should receive two calls to SetVolume().
+  float expected = 0.5f;
+  EXPECT_CALL(*renderer_, SetVolume(expected)).Times(2);
+  EXPECT_CALL(callbacks_, OnStart(PIPELINE_OK));
+  EXPECT_CALL(callbacks_, OnMetadata(_))
+      .WillOnce(RunOnceClosure(base::BindOnce(&PipelineImpl::SetVolume,
+                                              base::Unretained(pipeline_.get()),
+                                              expected)));
+  ExpectRendererInitialization();
+  EXPECT_CALL(*renderer_, SetPlaybackRate(0.0));
+  EXPECT_CALL(*renderer_, StartPlayingFrom(start_time_))
+      .WillOnce(SetBufferingState(&renderer_client_, BUFFERING_HAVE_ENOUGH,
+                                  BUFFERING_CHANGE_REASON_UNKNOWN));
+  EXPECT_CALL(callbacks_,
+              OnBufferingStateChange(BUFFERING_HAVE_ENOUGH,
+                                     BUFFERING_CHANGE_REASON_UNKNOWN));
+  StartPipeline();
+  base::RunLoop().RunUntilIdle();
+}
+
 TEST_F(PipelineImplTest, SetPreservesPitch) {
   CreateAudioStream();
   SetDemuxerExpectations();
diff --git a/media/base/test_helpers.cc b/media/base/test_helpers.cc
index 73ac060..84f8a204 100644
--- a/media/base/test_helpers.cc
+++ b/media/base/test_helpers.cc
@@ -350,6 +350,45 @@
   return output;
 }
 
+template <>
+scoped_refptr<AudioBuffer> MakeAudioBuffer<float>(SampleFormat format,
+                                                  ChannelLayout channel_layout,
+                                                  size_t channel_count,
+                                                  int sample_rate,
+                                                  float start,
+                                                  float increment,
+                                                  size_t frames,
+                                                  base::TimeDelta timestamp) {
+  const size_t channels = ChannelLayoutToChannelCount(channel_layout);
+  scoped_refptr<AudioBuffer> output = AudioBuffer::CreateBuffer(
+      format, channel_layout, static_cast<int>(channel_count), sample_rate,
+      static_cast<int>(frames));
+  output->set_timestamp(timestamp);
+
+  const bool is_planar =
+      format == kSampleFormatPlanarS16 || format == kSampleFormatPlanarF32;
+
+  // Values in channel 0 will be:
+  //   (start) / max_value
+  //   (start + increment) / max_value
+  //   (start + 2 * increment) / max_value, ...
+  // While, values in channel 1 will be:
+  //   (start + frames * increment) / max_value
+  //   (start + (frames + 1) * increment) / max_value
+  //   (start + (frames + 2) * increment) / max_value, ...
+  for (size_t ch = 0; ch < channels; ++ch) {
+    float* buffer =
+        reinterpret_cast<float*>(output->channel_data()[is_planar ? ch : 0]);
+    const float v = static_cast<float>(start + ch * frames * increment);
+    for (size_t i = 0; i < frames; ++i) {
+      buffer[is_planar ? i : ch + i * channels] =
+          static_cast<float>(v + i * increment) /
+          std::numeric_limits<uint16_t>::max();
+    }
+  }
+  return output;
+}
+
 scoped_refptr<AudioBuffer> MakeBitstreamAudioBuffer(
     SampleFormat format,
     ChannelLayout channel_layout,
@@ -408,7 +447,6 @@
 DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(uint8_t);
 DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(int16_t);
 DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(int32_t);
-DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(float);
 
 static const char kFakeVideoBufferHeader[] = "FakeVideoBufferForTest";
 
diff --git a/media/base/test_helpers.h b/media/base/test_helpers.h
index 3a0df8e..d7bcf89c 100644
--- a/media/base/test_helpers.h
+++ b/media/base/test_helpers.h
@@ -177,6 +177,18 @@
                                            size_t frames,
                                            base::TimeDelta timestamp);
 
+// Similar to above, but for float types where the maximum range is limited to
+// [-1.0f, 1.0f]. Here the stored values will be divided by 65536.
+template <>
+scoped_refptr<AudioBuffer> MakeAudioBuffer<float>(SampleFormat format,
+                                                  ChannelLayout channel_layout,
+                                                  size_t channel_count,
+                                                  int sample_rate,
+                                                  float start,
+                                                  float increment,
+                                                  size_t frames,
+                                                  base::TimeDelta timestamp);
+
 // Create an AudioBuffer containing bitstream data. |start| and |increment| are
 // used to specify the values for the data. The value is determined by:
 //   start + frames * increment
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index db89028..4475980 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -2919,8 +2919,9 @@
       // base::Unretained is safe because |this| owns memory_pressure_listener_.
       memory_pressure_listener_ =
           std::make_unique<base::MemoryPressureListener>(
-              FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnMemoryPressure,
-                                    base::Unretained(this)));
+              FROM_HERE,
+              base::BindRepeating(&WebMediaPlayerImpl::OnMemoryPressure,
+                                  base::Unretained(this)));
     }
   }
 
@@ -3638,8 +3639,8 @@
     } else if (update_background_status_cb_.IsCancelled()) {
       // Only trigger updates when we don't have one already scheduled.
       update_background_status_cb_.Reset(
-          base::Bind(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
-                     base::Unretained(this)));
+          base::BindOnce(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
+                         base::Unretained(this)));
 
       // Defer disable track until we're sure the clip will be backgrounded for
       // some time. Resuming may take half a second, so frequent tab switches
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index c8ed323..9cafe63 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -999,7 +999,7 @@
 
   OverlayInfo overlay_info_;
 
-  base::CancelableClosure update_background_status_cb_;
+  base::CancelableOnceClosure update_background_status_cb_;
 
   mojo::Remote<mojom::MediaMetricsProvider> media_metrics_provider_;
   mojo::Remote<mojom::PlaybackEventsRecorder> playback_events_recorder_;
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc
index f2b32bb..49a298e 100644
--- a/media/cdm/aes_decryptor_unittest.cc
+++ b/media/cdm/aes_decryptor_unittest.cc
@@ -252,14 +252,15 @@
   void SetUp() override {
     if (GetParam() == TestType::kAesDecryptor) {
       OnCdmCreated(
-          new AesDecryptor(base::Bind(&MockCdmClient::OnSessionMessage,
-                                      base::Unretained(&cdm_client_)),
-                           base::Bind(&MockCdmClient::OnSessionClosed,
-                                      base::Unretained(&cdm_client_)),
-                           base::Bind(&MockCdmClient::OnSessionKeysChange,
-                                      base::Unretained(&cdm_client_)),
-                           base::Bind(&MockCdmClient::OnSessionExpirationUpdate,
-                                      base::Unretained(&cdm_client_))),
+          new AesDecryptor(
+              base::BindRepeating(&MockCdmClient::OnSessionMessage,
+                                  base::Unretained(&cdm_client_)),
+              base::BindRepeating(&MockCdmClient::OnSessionClosed,
+                                  base::Unretained(&cdm_client_)),
+              base::BindRepeating(&MockCdmClient::OnSessionKeysChange,
+                                  base::Unretained(&cdm_client_)),
+              base::BindRepeating(&MockCdmClient::OnSessionExpirationUpdate,
+                                  base::Unretained(&cdm_client_))),
           std::string());
     } else if (GetParam() == TestType::kCdmAdapter) {
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
@@ -283,18 +284,19 @@
       std::unique_ptr<CdmAllocator> allocator(new SimpleCdmAllocator());
       std::unique_ptr<CdmAuxiliaryHelper> cdm_helper(
           new MockCdmAuxiliaryHelper(std::move(allocator)));
-      CdmAdapter::Create(helper_->KeySystemName(),
-                         cdm_config, create_cdm_func, std::move(cdm_helper),
-                         base::Bind(&MockCdmClient::OnSessionMessage,
-                                    base::Unretained(&cdm_client_)),
-                         base::Bind(&MockCdmClient::OnSessionClosed,
-                                    base::Unretained(&cdm_client_)),
-                         base::Bind(&MockCdmClient::OnSessionKeysChange,
-                                    base::Unretained(&cdm_client_)),
-                         base::Bind(&MockCdmClient::OnSessionExpirationUpdate,
-                                    base::Unretained(&cdm_client_)),
-                         base::BindOnce(&AesDecryptorTest::OnCdmCreated,
-                                        base::Unretained(this)));
+      CdmAdapter::Create(
+          helper_->KeySystemName(), cdm_config, create_cdm_func,
+          std::move(cdm_helper),
+          base::BindRepeating(&MockCdmClient::OnSessionMessage,
+                              base::Unretained(&cdm_client_)),
+          base::BindRepeating(&MockCdmClient::OnSessionClosed,
+                              base::Unretained(&cdm_client_)),
+          base::BindRepeating(&MockCdmClient::OnSessionKeysChange,
+                              base::Unretained(&cdm_client_)),
+          base::BindRepeating(&MockCdmClient::OnSessionExpirationUpdate,
+                              base::Unretained(&cdm_client_)),
+          base::BindOnce(&AesDecryptorTest::OnCdmCreated,
+                         base::Unretained(this)));
 
       base::RunLoop().RunUntilIdle();
 #else
diff --git a/media/cdm/cdm_adapter.cc b/media/cdm/cdm_adapter.cc
index af83941..e62c8404 100644
--- a/media/cdm/cdm_adapter.cc
+++ b/media/cdm/cdm_adapter.cc
@@ -226,7 +226,7 @@
   DCHECK(session_expiration_update_cb_);
 
   helper_->SetFileReadCB(
-      base::Bind(&CdmAdapter::OnFileRead, weak_factory_.GetWeakPtr()));
+      base::BindRepeating(&CdmAdapter::OnFileRead, weak_factory_.GetWeakPtr()));
 }
 
 CdmAdapter::~CdmAdapter() {
diff --git a/media/cdm/cdm_adapter_unittest.cc b/media/cdm/cdm_adapter_unittest.cc
index 3b8cc935..6e27a40 100644
--- a/media/cdm/cdm_adapter_unittest.cc
+++ b/media/cdm/cdm_adapter_unittest.cc
@@ -140,18 +140,19 @@
     std::unique_ptr<StrictMock<MockCdmAuxiliaryHelper>> cdm_helper(
         new StrictMock<MockCdmAuxiliaryHelper>(std::move(allocator)));
     cdm_helper_ = cdm_helper.get();
-    CdmAdapter::Create(GetKeySystemName(), cdm_config, GetCreateCdmFunc(),
-                       std::move(cdm_helper),
-                       base::Bind(&MockCdmClient::OnSessionMessage,
-                                  base::Unretained(&cdm_client_)),
-                       base::Bind(&MockCdmClient::OnSessionClosed,
-                                  base::Unretained(&cdm_client_)),
-                       base::Bind(&MockCdmClient::OnSessionKeysChange,
-                                  base::Unretained(&cdm_client_)),
-                       base::Bind(&MockCdmClient::OnSessionExpirationUpdate,
-                                  base::Unretained(&cdm_client_)),
-                       base::BindOnce(&CdmAdapterTestBase::OnCdmCreated,
-                                      base::Unretained(this), expected_result));
+    CdmAdapter::Create(
+        GetKeySystemName(), cdm_config, GetCreateCdmFunc(),
+        std::move(cdm_helper),
+        base::BindRepeating(&MockCdmClient::OnSessionMessage,
+                            base::Unretained(&cdm_client_)),
+        base::BindRepeating(&MockCdmClient::OnSessionClosed,
+                            base::Unretained(&cdm_client_)),
+        base::BindRepeating(&MockCdmClient::OnSessionKeysChange,
+                            base::Unretained(&cdm_client_)),
+        base::BindRepeating(&MockCdmClient::OnSessionExpirationUpdate,
+                            base::Unretained(&cdm_client_)),
+        base::BindOnce(&CdmAdapterTestBase::OnCdmCreated,
+                       base::Unretained(this), expected_result));
     RunUntilIdle();
     ASSERT_EQ(expected_result == SUCCESS, !!cdm_);
   }
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
index 5ad5056e..1211f1b 100644
--- a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
+++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
@@ -327,11 +327,14 @@
       cdm_host_proxy_(new CdmHostProxyImpl<HostInterface>(host)),
       cdm_(new ClearKeyPersistentSessionCdm(
           cdm_host_proxy_.get(),
-          base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)),
-          base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this)),
-          base::Bind(&ClearKeyCdm::OnSessionKeysChange, base::Unretained(this)),
-          base::Bind(&ClearKeyCdm::OnSessionExpirationUpdate,
-                     base::Unretained(this)))),
+          base::BindRepeating(&ClearKeyCdm::OnSessionMessage,
+                              base::Unretained(this)),
+          base::BindRepeating(&ClearKeyCdm::OnSessionClosed,
+                              base::Unretained(this)),
+          base::BindRepeating(&ClearKeyCdm::OnSessionKeysChange,
+                              base::Unretained(this)),
+          base::BindRepeating(&ClearKeyCdm::OnSessionExpirationUpdate,
+                              base::Unretained(this)))),
       key_system_(key_system) {
   DCHECK(g_is_cdm_module_initialized);
 }
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc b/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc
index 6e2dcba4..c342812 100644
--- a/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc
+++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc
@@ -99,10 +99,10 @@
       session_message_cb_(session_message_cb),
       session_closed_cb_(session_closed_cb) {
   cdm_ = base::MakeRefCounted<AesDecryptor>(
-      base::Bind(&ClearKeyPersistentSessionCdm::OnSessionMessage,
-                 weak_factory_.GetWeakPtr()),
-      base::Bind(&ClearKeyPersistentSessionCdm::OnSessionClosed,
-                 weak_factory_.GetWeakPtr()),
+      base::BindRepeating(&ClearKeyPersistentSessionCdm::OnSessionMessage,
+                          weak_factory_.GetWeakPtr()),
+      base::BindRepeating(&ClearKeyPersistentSessionCdm::OnSessionClosed,
+                          weak_factory_.GetWeakPtr()),
       session_keys_change_cb, session_expiration_update_cb);
 }
 
@@ -129,8 +129,8 @@
     // Since it's a persistent session, we need to save the session ID after
     // it's been created.
     new_promise = std::make_unique<NewPersistentSessionCdmPromise>(
-        base::Bind(&ClearKeyPersistentSessionCdm::AddPersistentSession,
-                   weak_factory_.GetWeakPtr()),
+        base::BindOnce(&ClearKeyPersistentSessionCdm::AddPersistentSession,
+                       weak_factory_.GetWeakPtr()),
         std::move(promise));
   }
   cdm_->CreateSessionAndGenerateRequest(session_type, init_data_type, init_data,
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc
index da01bca..558f840 100644
--- a/media/renderers/video_resource_updater.cc
+++ b/media/renderers/video_resource_updater.cc
@@ -528,23 +528,24 @@
   frame_resources_.clear();
 }
 
-void VideoResourceUpdater::AppendQuads(viz::CompositorRenderPass* render_pass,
-                                       scoped_refptr<VideoFrame> frame,
-                                       gfx::Transform transform,
-                                       gfx::Rect quad_rect,
-                                       gfx::Rect visible_quad_rect,
-                                       const gfx::RRectF& rounded_corner_bounds,
-                                       gfx::Rect clip_rect,
-                                       bool is_clipped,
-                                       bool contents_opaque,
-                                       float draw_opacity,
-                                       int sorting_context_id) {
+void VideoResourceUpdater::AppendQuads(
+    viz::CompositorRenderPass* render_pass,
+    scoped_refptr<VideoFrame> frame,
+    gfx::Transform transform,
+    gfx::Rect quad_rect,
+    gfx::Rect visible_quad_rect,
+    const gfx::MaskFilterInfo& mask_filter_info,
+    gfx::Rect clip_rect,
+    bool is_clipped,
+    bool contents_opaque,
+    float draw_opacity,
+    int sorting_context_id) {
   DCHECK(frame.get());
 
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(transform, quad_rect, visible_quad_rect,
-                            rounded_corner_bounds, clip_rect, is_clipped,
+                            mask_filter_info, clip_rect, is_clipped,
                             contents_opaque, draw_opacity,
                             SkBlendMode::kSrcOver, sorting_context_id);
 
diff --git a/media/renderers/video_resource_updater.h b/media/renderers/video_resource_updater.h
index ec732002..ab49f3c2 100644
--- a/media/renderers/video_resource_updater.h
+++ b/media/renderers/video_resource_updater.h
@@ -29,7 +29,6 @@
 
 namespace gfx {
 class Rect;
-class RRectF;
 class Transform;
 }  // namespace gfx
 
@@ -45,6 +44,10 @@
 class SharedBitmapReporter;
 }  // namespace viz
 
+namespace gfx {
+class MaskFilterInfo;
+}
+
 namespace media {
 class PaintCanvasVideoRenderer;
 class VideoFrame;
@@ -120,7 +123,7 @@
                    gfx::Transform transform,
                    gfx::Rect quad_rect,
                    gfx::Rect visible_quad_rect,
-                   const gfx::RRectF& rounded_corner_bounds,
+                   const gfx::MaskFilterInfo& mask_filter_info,
                    gfx::Rect clip_rect,
                    bool is_clipped,
                    bool context_opaque,
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index fb725f7..a219fea 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -2,13 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//base/trace_event/tracing.gni")
 import("//build/buildflag_header.gni")
 import("//build/config/compiler/compiler.gni")
 import("//build/config/nacl/config.gni")
 import("//tools/ipc_fuzzer/ipc_fuzzer.gni")
 
 declare_args() {
-  enable_mojo_tracing = false
+  enable_mojo_tracing = extended_tracing_enabled
 
   # enable_random_mojo_delays starts a task runner that periodically pauses
   # random Mojo bindings and later resumes them, in order to test whether parts
diff --git a/net/BUILD.gn b/net/BUILD.gn
index af9b6c2..46693b3c 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -157,6 +157,8 @@
     "base/rand_callback.h",
     "base/registry_controlled_domains/registry_controlled_domain.cc",
     "base/registry_controlled_domains/registry_controlled_domain.h",
+    "base/schemeful_site.cc",
+    "base/schemeful_site.h",
     "base/sockaddr_storage.cc",
     "base/sockaddr_storage.h",
     "base/sys_addrinfo.h",
@@ -4152,6 +4154,7 @@
     "base/registry_controlled_domains/registry_controlled_domain_unittest.cc",
     "base/scheme_host_port_matcher_rule_unittest.cc",
     "base/scheme_host_port_matcher_unittest.cc",
+    "base/schemeful_site_unittest.cc",
     "base/test_completion_callback_unittest.cc",
     "base/test_proxy_delegate.cc",
     "base/test_proxy_delegate.h",
diff --git a/net/base/registry_controlled_domains/effective_tld_names.dat b/net/base/registry_controlled_domains/effective_tld_names.dat
index 75bc095..24171a8 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.dat
+++ b/net/base/registry_controlled_domains/effective_tld_names.dat
@@ -911,16 +911,18 @@
 sld.do
 web.do
 
-// dz : https://en.wikipedia.org/wiki/.dz
+// dz : http://www.nic.dz/images/pdf_nic/charte.pdf
 dz
+art.dz
+asso.dz
 com.dz
+edu.dz
+gov.dz
 org.dz
 net.dz
-gov.dz
-edu.dz
-asso.dz
 pol.dz
-art.dz
+soc.dz
+tm.dz
 
 // ec : http://www.nic.ec/reg/paso1.asp
 // Submitted by registry <vabboud@nic.ec>
@@ -1154,7 +1156,7 @@
 // gs : https://en.wikipedia.org/wiki/.gs
 gs
 
-// gt : http://www.gt/politicas_de_registro.html
+// gt : https://www.gt/sitio/registration_policy.php?lang=en
 gt
 com.gt
 edu.gt
@@ -4701,13 +4703,12 @@
 //      ccTLD for the Netherlands
 nl
 
-// no : http://www.norid.no/regelverk/index.en.html
-// The Norwegian registry has declined to notify us of updates. The web pages
-// referenced below are the official source of the data. There is also an
-// announce mailing list:
-// https://postlister.uninett.no/sympa/info/norid-diskusjon
+// no : https://www.norid.no/en/om-domenenavn/regelverk-for-no/
+// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/
+// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/
+// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/
 no
-// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html
+// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/
 fhs.no
 vgs.no
 fylkesbibl.no
@@ -4715,13 +4716,13 @@
 museum.no
 idrett.no
 priv.no
-// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html
+// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/
 mil.no
 stat.no
 dep.no
 kommune.no
 herad.no
-// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html
+// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/
 // counties
 aa.no
 ah.no
@@ -7113,7 +7114,7 @@
 
 // newGTLDs
 
-// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2020-08-07T17:16:50Z
+// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2020-10-28T17:55:28Z
 // This list is auto-generated, don't edit it manually.
 // aaa : 2015-02-26 American Automobile Association, Inc.
 aaa
@@ -7331,7 +7332,7 @@
 // auto : 2014-11-13 XYZ.COM LLC
 auto
 
-// autos : 2014-01-09 DERAutos, LLC
+// autos : 2014-01-09 XYZ.COM LLC
 autos
 
 // avianca : 2015-01-08 Avianca Holdings S.A.
@@ -7481,7 +7482,7 @@
 // bnpparibas : 2014-05-29 BNP Paribas
 bnpparibas
 
-// boats : 2014-12-04 DERBoats, LLC
+// boats : 2014-12-04 XYZ.COM LLC
 boats
 
 // boehringer : 2015-07-09 Boehringer Ingelheim International GmbH
@@ -7520,7 +7521,7 @@
 // boutique : 2013-11-14 Binky Moon, LLC
 boutique
 
-// box : 2015-11-12 .BOX INC.
+// box : 2015-11-12 Intercap Registry Inc.
 box
 
 // bradesco : 2014-12-18 Banco Bradesco S.A.
@@ -8504,7 +8505,7 @@
 // homegoods : 2015-07-16 The TJX Companies, Inc.
 homegoods
 
-// homes : 2014-01-09 DERHomes, LLC
+// homes : 2014-01-09 XYZ.COM LLC
 homes
 
 // homesense : 2015-07-16 The TJX Companies, Inc.
@@ -8612,9 +8613,6 @@
 // insure : 2014-03-20 Binky Moon, LLC
 insure
 
-// intel : 2015-08-06 Intel Corporation
-intel
-
 // international : 2013-11-07 Binky Moon, LLC
 international
 
@@ -9020,9 +9018,6 @@
 // merckmsd : 2016-07-14 MSD Registry Holdings, Inc.
 merckmsd
 
-// metlife : 2015-05-07 MetLife Services and Solutions, LLC
-metlife
-
 // miami : 2013-12-19 Minds + Machines Group Limited
 miami
 
@@ -9086,7 +9081,7 @@
 // moto : 2015-06-04 Motorola Trademark Holdings, LLC
 moto
 
-// motorcycles : 2014-01-09 DERMotorcycles, LLC
+// motorcycles : 2014-01-09 XYZ.COM LLC
 motorcycles
 
 // mov : 2014-01-30 Charleston Road Registry Inc.
@@ -9191,7 +9186,7 @@
 // northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC
 northwesternmutual
 
-// norton : 2014-12-04 Symantec Corporation
+// norton : 2014-12-04 NortonLifeLock Inc.
 norton
 
 // now : 2015-06-25 Amazon Registry Services, Inc.
@@ -9251,7 +9246,7 @@
 // ong : 2014-03-06 Public Interest Registry
 ong
 
-// onl : 2013-09-16 I-Registry Ltd.
+// onl : 2013-09-16 iRegistry GmbH
 onl
 
 // online : 2015-01-15 DotOnline Inc.
@@ -9548,7 +9543,7 @@
 // rexroth : 2015-06-18 Robert Bosch GMBH
 rexroth
 
-// rich : 2013-11-21 I-Registry Ltd.
+// rich : 2013-11-21 iRegistry GmbH
 rich
 
 // richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited
@@ -10247,9 +10242,6 @@
 // website : 2014-04-03 DotWebsite Inc.
 website
 
-// wed : 2013-10-01 Atgron, Inc.
-wed
-
 // wedding : 2014-04-24 Minds + Machines Group Limited
 wedding
 
@@ -10460,7 +10452,7 @@
 // xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited
 電訊盈科
 
-// xn--g2xx48c : 2015-01-30 Minds + Machines Group Limited
+// xn--g2xx48c : 2015-01-30 Nawang Heli(Xiamen) Network Service Co., LTD.
 购物
 
 // xn--gckr3f0f : 2015-02-26 Amazon Registry Services, Inc.
@@ -10607,7 +10599,7 @@
 // xyz : 2013-12-05 XYZ.COM LLC
 xyz
 
-// yachts : 2014-01-09 DERYachts, LLC
+// yachts : 2014-01-09 XYZ.COM LLC
 yachts
 
 // yahoo : 2015-04-02 Yahoo! Domain Services Inc.
@@ -10692,12 +10684,6 @@
 // Submitted by Werner Kaltofen <wk@all-inkl.com>
 kasserver.com
 
-// Algorithmia, Inc. : algorithmia.com
-// Submitted by Eli Perelman <eperelman@algorithmia.io>
-*.algorithmia.com
-!teams.algorithmia.com
-!test.algorithmia.com
-
 // Altervista: https://www.altervista.org
 // Submitted by Carlo Cannas <tech_staff@altervista.it>
 altervista.org
@@ -11043,7 +11029,8 @@
 cloudera.site
 
 // Cloudflare, Inc. : https://www.cloudflare.com/
-// Submitted by Jake Riesterer <publicsuffixlist@cloudflare.com>
+// Submitted by Cloudflare Team <publicsuffixlist@cloudflare.com>
+pages.dev
 trycloudflare.com
 workers.dev
 
@@ -11238,6 +11225,10 @@
 // Submitted by Richard Harper <richard@duckdns.org>
 duckdns.org
 
+// Bip : https://bip.sh
+// Submitted by Joel Kennedy <joel@bip.sh>
+bip.sh
+
 // bitbridge.net : Submitted by Craig Welch, abeliidev@gmail.com
 bitbridge.net
 
@@ -11589,6 +11580,10 @@
 onred.one
 staging.onred.one
 
+// One.com: https://www.one.com/
+// Submitted by Jacob Bunk Nielsen <jbn@one.com>
+service.one
+
 // Enonic : http://enonic.com/
 // Submitted by Erik Kaareng-Sunde <esu@enonic.com>
 enonic.io
@@ -11875,6 +11870,7 @@
 gentapps.com
 gentlentapis.com
 lab.ms
+cdn-edges.net
 
 // GitHub, Inc.
 // Submitted by Patrick Toomey <security@github.com>
@@ -11887,6 +11883,7 @@
 
 // Gitplac.si - https://gitplac.si
 // Submitted by Aljaž Starc <me@aljaxus.eu>
+gitapp.si
 gitpage.si
 
 // Glitch, Inc : https://glitch.com
@@ -11926,6 +11923,18 @@
 *.0emm.com
 appspot.com
 *.r.appspot.com
+codespot.com
+googleapis.com
+googlecode.com
+pagespeedmobilizer.com
+publishproxy.com
+withgoogle.com
+withyoutube.com
+*.gateway.dev
+cloud.goog
+translate.goog
+cloudfunctions.net
+
 blogspot.ae
 blogspot.al
 blogspot.am
@@ -12000,15 +12009,6 @@
 blogspot.tw
 blogspot.ug
 blogspot.vn
-cloudfunctions.net
-cloud.goog
-codespot.com
-googleapis.com
-googlecode.com
-pagespeedmobilizer.com
-publishproxy.com
-withgoogle.com
-withyoutube.com
 
 // Aaron Marais' Gitlab pages: https://lab.aaronleem.co.za
 // Submitted by Aaron Marais <its_me@aaronleem.co.za>
@@ -12146,6 +12146,10 @@
 // Submited by Vasiliy Sheredeko <piphon@gmail.com>
 na4u.ru
 
+// iopsys software solutions AB : https://iopsys.eu/
+// Submitted by Roman Azarenko <roman.azarenko@iopsys.eu>
+iopsys.se
+
 // IPiFony Systems, Inc. : https://www.ipifony.com/
 // Submitted by Matthew Hardeman <mhardeman@ipifony.com>
 ipifony.net
@@ -12163,29 +12167,92 @@
 
 //Jelastic, Inc. : https://jelastic.com/
 // Submited by Ihor Kolodyuk <ik@jelastic.com>
+mel.cloudlets.com.au
+cloud.interhostsolutions.be
+users.scale.virtualcloud.com.br
+mycloud.by
+alp1.ae.flow.ch
 appengine.flow.ch
+es-1.axarnet.cloud
+diadem.cloud
 vip.jelastic.cloud
 jele.cloud
+it1.eur.aruba.jenv-aruba.cloud
+it1.jenv-aruba.cloud
+it1-eur.jenv-arubabiz.cloud
+primetel.cloud
+uk.primetel.cloud
+ca.reclaim.cloud
+uk.reclaim.cloud
+us.reclaim.cloud
+ch.trendhosting.cloud
+de.trendhosting.cloud
 jele.club
+clicketcloud.com
+ams.cloudswitches.com
+au.cloudswitches.com
+sg.cloudswitches.com
 dopaas.com
+elastyco.com
+nv.elastyco.com
 hidora.com
+paas.hosted-by-previder.com
+rag-cloud.hosteur.com
+rag-cloud-ch.hosteur.com
 jcloud.ik-server.com
+jcloud-ver-jpc.ik-server.com
 demo.jelastic.com
+kilatiron.com
 paas.massivegrid.com
+jed.wafaicloud.com
+lon.wafaicloud.com
+ryd.wafaicloud.com
 j.scaleforce.com.cy
 jelastic.dogado.eu
+paas.leviracloud.eu
 fi.cloudplatform.fi
+demo.datacenter.fi
 paas.datacenter.fi
 jele.host
 mircloud.host
 jele.io
+ocs.opusinteractive.io
+cloud.unispace.io
+cloud-de.unispace.io
+cloud-fr1.unispace.io
+jc.neen.it
+cloud.jelastic.open.tim.it
+jcloud.kz
+upaas.kazteleport.kz
+jl.serv.net.mx
 cloudjiffy.net
+fra1-de.cloudjiffy.net
+west1-us.cloudjiffy.net
+ams1.jls.docktera.net
 jls-sto1.elastx.net
+jls-sto2.elastx.net
+jls-sto3.elastx.net
+fr-1.paas.massivegrid.net
+lon-1.paas.massivegrid.net
+lon-2.paas.massivegrid.net
+ny-1.paas.massivegrid.net
+ny-2.paas.massivegrid.net
+sg-1.paas.massivegrid.net
 jelastic.saveincloud.net
+nordeste-idc.saveincloud.net
+j.scaleforce.net
+jelastic.tsukaeru.net
+atl.jelastic.vps-host.net
+njs.jelastic.vps-host.net
+unicloud.pl
+mircloud.ru
 jelastic.regruhosting.ru
+enscaled.sg
 jele.site
 jelastic.team
 j.layershift.co.uk
+phx.enscaled.us
+mircloud.us
 
 // Jino : https://www.jino.ru
 // Submitted by Sergey Ulyashin <ulyashin@jino.ru>
@@ -12279,6 +12346,10 @@
 // Submitted by Victor Velchev <admin@liquidnetlimited.com>
 we.bs
 
+// localzone.xyz
+// Submitted by Kenny Niehage <hello@yahe.sh>
+localzone.xyz
+
 // Log'in Line : https://www.loginline.com/
 // Submitted by Rémi Mach <remi.mach@loginline.com>
 loginline.app
@@ -12375,11 +12446,17 @@
 co.pl
 
 // Microsoft Corporation : http://microsoft.com
-// Submitted by Mostafa Elzeiny <moelzein@microsoft.com>
+// Submitted by Mitch Webster <miwebst@microsoft.com>
 *.azurecontainer.io
 azurewebsites.net
 azure-mobile.net
 cloudapp.net
+azurestaticapps.net
+centralus.azurestaticapps.net
+eastasia.azurestaticapps.net
+eastus2.azurestaticapps.net
+westeurope.azurestaticapps.net
+westus2.azurestaticapps.net
 
 // minion.systems : http://minion.systems
 // Submitted by Robert Böttinger <r@minion.systems>
@@ -13115,6 +13192,7 @@
 // Submitted by Mark Staarink <mark@tlon.io>
 arvo.network
 azimuth.network
+tlon.network
 
 // TownNews.com : http://www.townnews.com
 // Submitted by Dustin Ward <dward@townnews.com>
@@ -13268,6 +13346,15 @@
 // Submitted by Masayuki Note <masa@blade.wafflecell.com>
 wafflecell.com
 
+// WapBlog.ID : https://www.wapblog.id
+// Submitted by Fajar Sodik <official@wapblog.id>
+idnblogger.com
+indowapblog.com
+bloghp.id
+wblog.id
+wbq.me
+fastblog.net
+
 // WebHare bv: https://www.webhare.com/
 // Submitted by Arnold Hendriks <info@webhare.com>
 *.webhare.dev
@@ -13373,12 +13460,22 @@
 // Submitted by Ben Aubin <security@mintere.com>
 mintere.site
 
+// Cityhost LLC  : https://cityhost.ua
+// Submitted by Maksym Rivtin <support@cityhost.net.ua>
+cx.ua
+
 // WP Engine : https://wpengine.com/
 // Submitted by Michael Smith <michael.smith@wpengine.com>
+// Submitted by Brandon DuRette <brandon.durette@wpengine.com>
 wpenginepowered.com
+js.wpenginepowered.com
 
 // Impertrix Solutions : <https://impertrixcdn.com>
 // Submitted by Zhixiang Zhao <csuite@impertrix.com>
 impertrixcdn.com
 impertrix.com
+
+// GignoSystemJapan: http://gsj.bz
+// Submitted by GignoSystemJapan <kakutou-ec@gsj.bz>
+gsj.bz
 // ===END PRIVATE DOMAINS===
diff --git a/net/base/registry_controlled_domains/effective_tld_names.gperf b/net/base/registry_controlled_domains/effective_tld_names.gperf
index 8dc7800..9a2e2e3 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.gperf
+++ b/net/base/registry_controlled_domains/effective_tld_names.gperf
@@ -247,12 +247,12 @@
 alesund.no, 0
 alfaromeo, 0
 algard.no, 0
-algorithmia.com, 6
 alibaba, 0
 alipay, 0
 allfinanz, 0
 allstate, 0
 ally, 0
+alp1.ae.flow.ch, 4
 alpha-myqnapcloud.com, 4
 alpha.bounty-full.com, 4
 alsace, 0
@@ -290,6 +290,8 @@
 amica, 0
 amli.no, 0
 amot.no, 0
+ams.cloudswitches.com, 4
+ams1.jls.docktera.net, 4
 amsterdam, 0
 amsterdam.museum, 0
 amsw.nl, 4
@@ -486,6 +488,7 @@
 atami.shizuoka.jp, 0
 ath.cx, 4
 athleta, 0
+atl.jelastic.vps-host.net, 4
 atlanta.museum, 0
 atm.pl, 0
 ato.br, 0
@@ -493,6 +496,7 @@
 atsuma.hokkaido.jp, 0
 attorney, 0
 au, 0
+au.cloudswitches.com, 4
 au.eu.org, 4
 auction, 0
 audi, 0
@@ -545,6 +549,7 @@
 azure, 0
 azure-mobile.net, 4
 azurecontainer.io, 6
+azurestaticapps.net, 4
 azurewebsites.net, 4
 b-data.io, 4
 b.bg, 0
@@ -728,6 +733,7 @@
 bingo, 0
 bio, 0
 bio.br, 0
+bip.sh, 4
 bir.ru, 4
 biratori.hokkaido.jp, 0
 birdart.museum, 0
@@ -780,6 +786,7 @@
 blogdns.com, 4
 blogdns.net, 4
 blogdns.org, 4
+bloghp.id, 4
 blogsite.org, 4
 blogsite.xyz, 4
 blogspot.ae, 4
@@ -999,6 +1006,7 @@
 ca.eu.org, 4
 ca.it, 0
 ca.na, 0
+ca.reclaim.cloud, 4
 ca.us, 0
 caa.aero, 0
 caa.li, 4
@@ -1138,6 +1146,7 @@
 cci.fr, 0
 cd, 0
 cd.eu.org, 4
+cdn-edges.net, 4
 cdn77-ssl.net, 4
 ce.gov.br, 0
 ce.it, 0
@@ -1147,6 +1156,7 @@
 celtic.museum, 0
 center, 0
 center.museum, 0
+centralus.azurestaticapps.net, 4
 ceo, 0
 cern, 0
 certification.aero, 0
@@ -1161,6 +1171,7 @@
 ch.eu.org, 4
 ch.it, 0
 ch.tc, 4
+ch.trendhosting.cloud, 4
 chambagri.fr, 0
 championship.aero, 0
 chanel, 0
@@ -1269,15 +1280,21 @@
 cleverapps.io, 4
 clic2000.net, 4
 click, 0
+clicketcloud.com, 4
 clinic, 0
 clinique, 0
 clinton.museum, 0
 clock.museum, 0
 clothing, 0
 cloud, 0
+cloud-de.unispace.io, 4
+cloud-fr1.unispace.io, 4
 cloud.fedoraproject.org, 4
 cloud.goog, 4
+cloud.interhostsolutions.be, 4
+cloud.jelastic.open.tim.it, 4
 cloud.metacentrum.cz, 6
+cloud.unispace.io, 4
 cloud66.ws, 4
 cloud66.zone, 4
 cloudaccess.host, 4
@@ -1676,6 +1693,7 @@
 cv.ua, 0
 cw, 0
 cx, 0
+cx.ua, 4
 cy, 0
 cy.eu.org, 4
 cya.gg, 4
@@ -1745,6 +1763,7 @@
 de.gt, 4
 de.ls, 4
 de.md, 4
+de.trendhosting.cloud, 4
 de.us, 0
 deal, 0
 dealer, 0
@@ -1766,6 +1785,7 @@
 delmenhorst.museum, 0
 deloitte, 0
 delta, 0
+demo.datacenter.fi, 4
 demo.jelastic.com, 4
 democracia.bo, 0
 democrat, 0
@@ -1797,6 +1817,7 @@
 dgca.aero, 0
 dh.bytemark.co.uk, 4
 dhl, 0
+diadem.cloud, 4
 diamonds, 0
 dielddanuorri.no, 0
 diet, 0
@@ -1949,7 +1970,9 @@
 earth, 0
 east-kazakhstan.su, 4
 eastafrica.museum, 0
+eastasia.azurestaticapps.net, 4
 eastcoast.museum, 0
+eastus2.azurestaticapps.net, 4
 eat, 0
 eating-organic.net, 4
 eaton.mi.us, 0
@@ -2122,6 +2145,7 @@
 eisenbahn.museum, 0
 ekloges.cy, 0
 elasticbeanstalk.com, 4
+elastyco.com, 4
 elb.amazonaws.com, 6
 elb.amazonaws.com.cn, 6
 elblag.pl, 0
@@ -2163,6 +2187,7 @@
 enna.it, 0
 enonic.io, 4
 ens.tn, 0
+enscaled.sg, 4
 ent.platform.sh, 4
 enterprisecloud.nu, 4
 enterprises, 0
@@ -2181,6 +2206,7 @@
 erotica.hu, 0
 erotika.hu, 0
 es, 0
+es-1.axarnet.cloud, 4
 es.ax, 4
 es.eu.org, 4
 es.gov.br, 0
@@ -2266,6 +2292,7 @@
 farsund.no, 0
 fashion, 0
 fast, 0
+fastblog.net, 4
 fastly-terrarium.com, 4
 fastlylb.net, 4
 fastvps-server.com, 4
@@ -2427,8 +2454,10 @@
 fox, 0
 foz.br, 0
 fr, 0
+fr-1.paas.massivegrid.net, 4
 fr.eu.org, 4
 fr.it, 0
+fra1-de.cloudjiffy.net, 4
 frana.no, 0
 francaise.museum, 0
 frankfurt.museum, 0
@@ -2623,6 +2652,7 @@
 gap, 0
 garden, 0
 garden.museum, 0
+gateway.dev, 6
 gateway.museum, 0
 gaular.no, 0
 gausdal.no, 0
@@ -2688,6 +2718,7 @@
 giske.no, 0
 git-pages.rit.edu, 4
 git-repos.de, 4
+gitapp.si, 4
 github.io, 4
 githubusercontent.com, 4
 gitlab.io, 4
@@ -2991,6 +3022,7 @@
 gs.tr.no, 0
 gs.va.no, 0
 gs.vf.no, 0
+gsj.bz, 4
 gsm.pl, 0
 gt, 0
 gu, 0
@@ -3365,6 +3397,7 @@
 id.us, 0
 ide.kyoto.jp, 0
 idf.il, 0
+idnblogger.com, 4
 idrett.no, 0
 idv.hk, 0
 idv.tw, 0
@@ -3466,6 +3499,7 @@
 indianmarket.museum, 0
 indie.porn, 4
 indigena.bo, 0
+indowapblog.com, 4
 industria.bo, 0
 industries, 0
 ine.kyoto.jp, 0
@@ -3538,7 +3572,6 @@
 int.tt, 0
 int.ve, 0
 int.vn, 0
-intel, 0
 intelligence.museum, 0
 interactive.museum, 0
 international, 0
@@ -3551,6 +3584,7 @@
 io, 0
 io.kg, 4
 iobb.net, 4
+iopsys.se, 4
 ip6.arpa, 0
 ipifony.net, 4
 ipiranga, 0
@@ -3672,6 +3706,9 @@
 it, 0
 it.ao, 0
 it.eu.org, 4
+it1-eur.jenv-arubabiz.cloud, 4
+it1.eur.aruba.jenv-aruba.cloud, 4
+it1.jenv-aruba.cloud, 4
 itabashi.tokyo.jp, 0
 itako.ibaraki.jp, 0
 itakura.gunma.jp, 0
@@ -3719,6 +3756,7 @@
 j.bg, 0
 j.layershift.co.uk, 4
 j.scaleforce.com.cy, 4
+j.scaleforce.net, 4
 jab.br, 0
 jaguar, 0
 jambyl.su, 4
@@ -3727,12 +3765,16 @@
 jan-mayen.no, 0
 java, 0
 jaworzno.pl, 0
+jc.neen.it, 4
 jcb, 0
+jcloud-ver-jpc.ik-server.com, 4
 jcloud.ik-server.com, 4
+jcloud.kz, 4
 jcp, 0
 jdevcloud.com, 4
 jdf.br, 0
 je, 0
+jed.wafaicloud.com, 4
 jeep, 0
 jefferson.museum, 0
 jeju.kr, 0
@@ -3740,6 +3782,7 @@
 jelastic.regruhosting.ru, 4
 jelastic.saveincloud.net, 4
 jelastic.team, 4
+jelastic.tsukaeru.net, 4
 jele.cloud, 4
 jele.club, 4
 jele.host, 4
@@ -3761,8 +3804,11 @@
 jinsekikogen.hiroshima.jp, 0
 jio, 0
 jl.cn, 0
+jl.serv.net.mx, 4
 jll, 0
 jls-sto1.elastx.net, 4
+jls-sto2.elastx.net, 4
+jls-sto3.elastx.net, 4
 jm, 2
 jmp, 0
 jnj, 0
@@ -3797,6 +3843,7 @@
 jprs, 0
 js.cn, 0
 js.org, 4
+js.wpenginepowered.com, 4
 judaica.museum, 0
 judygarland.museum, 0
 juedisches.museum, 0
@@ -4055,6 +4102,7 @@
 kikonai.hokkaido.jp, 0
 kikuchi.kumamoto.jp, 0
 kikugawa.shizuoka.jp, 0
+kilatiron.com, 4
 kim, 0
 kimino.wakayama.jp, 0
 kimitsu.chiba.jp, 0
@@ -4479,6 +4527,7 @@
 loans, 0
 localhistory.museum, 0
 localhost.daplie.me, 4
+localzone.xyz, 4
 locker, 0
 locus, 0
 lodi.it, 0
@@ -4501,6 +4550,9 @@
 lombardia.it, 0
 lombardy.it, 0
 lomza.pl, 0
+lon-1.paas.massivegrid.net, 4
+lon-2.paas.massivegrid.net, 4
+lon.wafaicloud.com, 4
 london, 0
 london.cloudapps.digital, 4
 london.museum, 0
@@ -4725,6 +4777,7 @@
 meinforum.net, 4
 meiwa.gunma.jp, 0
 meiwa.mie.jp, 0
+mel.cloudlets.com.au, 4
 meland.no, 0
 melbourne, 0
 meldal.no, 0
@@ -4743,7 +4796,6 @@
 mesaverde.museum, 0
 messina.it, 0
 meteorapp.com, 4
-metlife, 0
 mex.com, 4
 mg, 0
 mg.gov.br, 0
@@ -4886,6 +4938,8 @@
 mint, 0
 mintere.site, 4
 mircloud.host, 4
+mircloud.ru, 4
+mircloud.us, 4
 misaki.okayama.jp, 0
 misaki.osaka.jp, 0
 misasa.tottori.jp, 0
@@ -5104,6 +5158,7 @@
 myactivedirectory.com, 4
 myasustor.com, 4
 mycd.eu, 4
+mycloud.by, 4
 mydatto.com, 4
 mydatto.net, 4
 myddns.rocks, 4
@@ -5544,6 +5599,7 @@
 nittedal.no, 0
 niyodogawa.kochi.jp, 0
 nj.us, 0
+njs.jelastic.vps-host.net, 4
 nl, 0
 nl.ca, 0
 nl.ci, 4
@@ -5628,6 +5684,7 @@
 nord-fron.no, 0
 nord-odal.no, 0
 norddal.no, 0
+nordeste-idc.saveincloud.net, 4
 nordkapp.no, 0
 nordre-land.no, 0
 nordreisa.no, 0
@@ -5685,8 +5742,11 @@
 numata.hokkaido.jp, 0
 numazu.shizuoka.jp, 0
 nuoro.it, 0
+nv.elastyco.com, 4
 nv.us, 0
 nx.cn, 0
+ny-1.paas.massivegrid.net, 4
+ny-2.paas.massivegrid.net, 4
 ny.us, 0
 nyaa.am, 4
 nyan.to, 4
@@ -5744,6 +5804,7 @@
 oci.customer-oci.com, 6
 ocp.customer-oci.com, 6
 ocs.customer-oci.com, 6
+ocs.opusinteractive.io, 4
 od.ua, 0
 odate.akita.jp, 0
 odawara.kanagawa.jp, 0
@@ -6161,6 +6222,8 @@
 pa.leg.br, 4
 pa.us, 0
 paas.datacenter.fi, 4
+paas.hosted-by-previder.com, 4
+paas.leviracloud.eu, 4
 paas.massivegrid.com, 4
 pacific.museum, 0
 paderborn.museum, 0
@@ -6168,6 +6231,7 @@
 padua.it, 0
 page, 0
 pagefrontapp.com, 4
+pages.dev, 4
 pages.wiardweb.com, 4
 pagespeedmobilizer.com, 4
 pagexl.com, 4
@@ -6250,6 +6314,7 @@
 photography, 0
 photography.museum, 0
 photos, 0
+phx.enscaled.us, 4
 physio, 0
 pi.gov.br, 0
 pi.it, 0
@@ -6379,6 +6444,7 @@
 presse.ml, 0
 pri.ee, 0
 prime, 0
+primetel.cloud, 4
 principe.st, 0
 priv.at, 4
 priv.hu, 0
@@ -6486,6 +6552,8 @@
 radio.fm, 4
 radom.pl, 0
 radoy.no, 0
+rag-cloud-ch.hosteur.com, 4
+rag-cloud.hosteur.com, 4
 ragusa.it, 0
 rahkkeravju.no, 0
 raholt.no, 0
@@ -6668,6 +6736,7 @@
 rw, 0
 rwe, 0
 rybnik.pl, 0
+ryd.wafaicloud.com, 4
 rygge.no, 0
 ryokami.saitama.jp, 0
 ryugasaki.ibaraki.jp, 0
@@ -6996,6 +7065,7 @@
 servequake.com, 4
 servesarcasm.com, 4
 service.gov.uk, 4
+service.one, 4
 services, 0
 services.aero, 0
 ses, 0
@@ -7015,6 +7085,8 @@
 sf.no, 0
 sfr, 0
 sg, 0
+sg-1.paas.massivegrid.net, 4
+sg.cloudswitches.com, 4
 sh, 0
 sh.cn, 0
 shacknet.nu, 4
@@ -7212,6 +7284,7 @@
 so.gov.pl, 0
 so.it, 0
 sobetsu.hokkaido.jp, 0
+soc.dz, 0
 soc.lk, 0
 soc.srcf.net, 4
 soccer, 0
@@ -7563,7 +7636,6 @@
 te.ua, 0
 teaches-yoga.com, 4
 team, 0
-teams.algorithmia.com, 5
 tec.br, 0
 tec.mi.us, 0
 tec.ve, 0
@@ -7595,7 +7667,6 @@
 ternopil.ua, 0
 teshikaga.hokkaido.jp, 0
 test-iserv.de, 4
-test.algorithmia.com, 5
 test.ru, 4
 test.tj, 0
 teva, 0
@@ -7635,8 +7706,10 @@
 tkmaxx, 0
 tksat.bo, 0
 tl, 0
+tlon.network, 4
 tm, 0
 tm.cy, 0
+tm.dz, 0
 tm.fr, 0
 tm.hu, 0
 tm.km, 0
@@ -7783,6 +7856,7 @@
 traniandriabarletta.it, 0
 tranibarlettaandria.it, 0
 tranoy.no, 0
+translate.goog, 4
 transport.museum, 0
 transporte.bo, 0
 transurl.be, 6
@@ -7954,6 +8028,8 @@
 uk.eu.org, 4
 uk.kg, 4
 uk.net, 4
+uk.primetel.cloud, 4
+uk.reclaim.cloud, 4
 uk0.bigv.io, 4
 ukco.me, 4
 uki.kumamoto.jp, 0
@@ -7973,6 +8049,7 @@
 unazuki.toyama.jp, 0
 undersea.museum, 0
 uni5.net, 4
+unicloud.pl, 4
 unicom, 0
 union.aero, 0
 univ.sn, 0
@@ -7986,6 +8063,7 @@
 uol, 0
 uonuma.niigata.jp, 0
 uozu.toyama.jp, 0
+upaas.kazteleport.kz, 4
 upow.gov.pl, 0
 uppo.gov.pl, 0
 ups, 0
@@ -8022,6 +8100,7 @@
 us.na, 0
 us.org, 4
 us.platform.sh, 4
+us.reclaim.cloud, 4
 usa.museum, 0
 usa.oita.jp, 0
 usantiques.museum, 0
@@ -8033,6 +8112,7 @@
 user.party.eus, 4
 user.srcf.net, 4
 usercontent.jp, 4
+users.scale.virtualcloud.com.br, 4
 usgarden.museum, 0
 ushiku.ibaraki.jp, 0
 ushistory.museum, 0
@@ -8264,6 +8344,8 @@
 watches, 0
 waw.pl, 0
 wazuka.kyoto.jp, 0
+wblog.id, 4
+wbq.me, 4
 we.bs, 4
 we.tc, 4
 weather, 0
@@ -8296,7 +8378,6 @@
 website, 0
 website.yandexcloud.net, 4
 webspace.rocks, 4
-wed, 0
 wedding, 0
 wedeploy.io, 4
 wedeploy.me, 4
@@ -8306,8 +8387,11 @@
 weir, 0
 wellbeingzone.co.uk, 4
 wellbeingzone.eu, 4
+west1-us.cloudjiffy.net, 4
 western.museum, 0
+westeurope.azurestaticapps.net, 4
 westfalen.museum, 0
+westus2.azurestaticapps.net, 4
 wf, 0
 whaling.museum, 0
 whoswho, 0
diff --git a/net/base/schemeful_site.cc b/net/base/schemeful_site.cc
new file mode 100644
index 0000000..0edb7ac
--- /dev/null
+++ b/net/base/schemeful_site.cc
@@ -0,0 +1,125 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/schemeful_site.h"
+
+#include "base/check.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "url/gurl.h"
+#include "url/url_canon.h"
+#include "url/url_constants.h"
+
+namespace net {
+
+namespace {
+
+// Return a new origin using the registerable domain of `origin` if possible and
+// a port of 0. Otherwise, returns the passed in origin. Follows steps specified
+// in https://html.spec.whatwg.org/multipage/origin.html#obtain-a-site
+url::Origin SwitchToRegistrableDomainAndRemovePort(const url::Origin& origin) {
+  // There is currently no reason for getting the schemeful site of a web
+  // socket, so disallow passing in websocket origins.
+  DCHECK_NE(origin.scheme(), url::kWsScheme);
+  DCHECK_NE(origin.scheme(), url::kWssScheme);
+
+  // 1. If origin is an opaque origin, then return origin.
+  if (origin.opaque())
+    return origin;
+
+  std::string registerable_domain;
+
+  // Non-normative step.
+  // We only lookup the registerable domain for HTTP/HTTPS schemes, this is
+  // non-normative. Other schemes for non-opaque origins like "file" do not
+  // meaningfully have a registerable domain for their host, so they are
+  // skipped.
+  if (origin.scheme() == url::kHttpsScheme ||
+      origin.scheme() == url::kHttpScheme) {
+    registerable_domain = GetDomainAndRegistry(
+        origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+  }
+
+  // If origin's host's registrable domain is null, then return (origin's
+  // scheme, origin's host).
+  //
+  // `GetDomainAndRegistry()` returns an empty string for IP literals and
+  // effective TLDs.
+  if (registerable_domain.empty())
+    registerable_domain = origin.host();
+
+  DCHECK(!registerable_domain.empty());
+
+  int port = url::DefaultPortForScheme(origin.scheme().c_str(),
+                                       origin.scheme().length());
+
+  // Provide a default port of 0 for non-standard schemes.
+  if (port == url::PORT_UNSPECIFIED)
+    port = 0;
+
+  // We tack on a port of 0, as a port is not included in the result of running
+  // the above algorithm.
+  return url::Origin::CreateFromNormalizedTuple(origin.scheme(),
+                                                registerable_domain, port);
+}
+
+}  // namespace
+
+SchemefulSite::SchemefulSite(const url::Origin& origin)
+    : origin_(SwitchToRegistrableDomainAndRemovePort(origin)) {}
+
+SchemefulSite::SchemefulSite(const GURL& url)
+    : origin_(
+          SwitchToRegistrableDomainAndRemovePort(url::Origin::Create(url))) {}
+
+SchemefulSite::SchemefulSite(const SchemefulSite& other) = default;
+SchemefulSite::SchemefulSite(SchemefulSite&& other) = default;
+
+SchemefulSite& SchemefulSite::operator=(const SchemefulSite& other) = default;
+SchemefulSite& SchemefulSite::operator=(SchemefulSite&& other) = default;
+
+// static
+SchemefulSite SchemefulSite::Deserialize(const std::string& value) {
+  return SchemefulSite(GURL(value));
+}
+
+std::string SchemefulSite::Serialize() const {
+  return origin_.Serialize();
+}
+
+std::string SchemefulSite::GetDebugString() const {
+  return origin_.GetDebugString();
+}
+
+const url::Origin& SchemefulSite::GetInternalOriginForTesting() const {
+  return origin_;
+}
+
+bool SchemefulSite::operator==(const SchemefulSite& other) const {
+  return origin_ == other.origin_;
+}
+
+bool SchemefulSite::operator!=(const SchemefulSite& other) const {
+  return !(*this == other);
+}
+
+// Allows SchemefulSite to be used as a key in STL containers (for example, a
+// std::set or std::map).
+bool SchemefulSite::operator<(const SchemefulSite& other) const {
+  return origin_ < other.origin_;
+}
+
+// static
+base::Optional<SchemefulSite> SchemefulSite::DeserializeWithNonce(
+    const std::string& value) {
+  base::Optional<url::Origin> result = url::Origin::Deserialize(value);
+  if (!result)
+    return base::nullopt;
+  return SchemefulSite(result.value());
+}
+
+base::Optional<std::string> SchemefulSite::SerializeWithNonce() {
+  return origin_.SerializeWithNonceAndInitIfNeeded();
+}
+
+}  // namespace net
diff --git a/net/base/schemeful_site.h b/net/base/schemeful_site.h
new file mode 100644
index 0000000..b936801b
--- /dev/null
+++ b/net/base/schemeful_site.h
@@ -0,0 +1,80 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_SCHEMEFUL_SITE_H_
+#define NET_BASE_SCHEMEFUL_SITE_H_
+
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/optional.h"
+#include "net/base/net_export.h"
+#include "url/origin.h"
+
+class GURL;
+
+namespace net {
+
+// Class which represents a scheme and etld+1 for an origin, as specified by
+// https://html.spec.whatwg.org/multipage/origin.html#obtain-a-site.
+class NET_EXPORT SchemefulSite {
+ public:
+  SchemefulSite() = default;
+  explicit SchemefulSite(const url::Origin& origin);
+
+  // Using the origin constructor is preferred as this is less efficient.
+  // Should only be used if the origin for a given GURL is not readily
+  // available.
+  explicit SchemefulSite(const GURL& url);
+
+  SchemefulSite(const SchemefulSite& other);
+  SchemefulSite(SchemefulSite&& other);
+
+  SchemefulSite& operator=(const SchemefulSite& other);
+  SchemefulSite& operator=(SchemefulSite&& other);
+
+  // Deserializes a string obtained from `Serialize()` to a `SchemefulSite`.
+  // Returns an opaque `SchemefulSite` if the value was invalid in any way.
+  static SchemefulSite Deserialize(const std::string& value);
+
+  // Returns a serialized version of `origin_`. If the underlying origin is
+  // invalid, returns an empty string. If serialization of opaque origins with
+  // their associated nonce is necessary, see `SerializeWithNonce()`.
+  std::string Serialize() const;
+
+  std::string GetDebugString() const;
+
+  bool opaque() const { return origin_.opaque(); }
+
+  // Testing only function which allows tests to access the underlying `origin_`
+  // in order to verify behavior.
+  const url::Origin& GetInternalOriginForTesting() const;
+
+  bool operator==(const SchemefulSite& other) const;
+
+  bool operator!=(const SchemefulSite& other) const;
+
+  bool operator<(const SchemefulSite& other) const;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(SchemefulSiteTest, OpaqueSerialization);
+
+  // Deserializes a string obtained from `SerializeWithNonce()` to a
+  // `SchemefulSite`. Returns nullopt if the value was invalid in any way.
+  static base::Optional<SchemefulSite> DeserializeWithNonce(
+      const std::string& value);
+
+  // Returns a serialized version of `origin_`. For an opaque `origin_`, this
+  // serializes with the nonce.  See `url::origin::SerializeWithNonce()` for
+  // usage information.
+  base::Optional<std::string> SerializeWithNonce();
+
+  // Origin which stores the result of running the steps documented at
+  // https://html.spec.whatwg.org/multipage/origin.html#obtain-a-site.
+  url::Origin origin_;
+};
+
+}  // namespace net
+
+#endif  // NET_BASE_SCHEMEFUL_SITE_H_
diff --git a/net/base/schemeful_site_unittest.cc b/net/base/schemeful_site_unittest.cc
new file mode 100644
index 0000000..9b28f1d1d
--- /dev/null
+++ b/net/base/schemeful_site_unittest.cc
@@ -0,0 +1,181 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/schemeful_site.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+#include "url/url_util.h"
+
+namespace net {
+
+TEST(SchemefulSiteTest, DifferentOriginSameRegisterableDomain) {
+  // List of origins which should all share a schemeful site.
+  url::Origin kTestOrigins[] = {
+      url::Origin::Create(GURL("http://a.foo.test")),
+      url::Origin::Create(GURL("http://b.foo.test")),
+      url::Origin::Create(GURL("http://foo.test")),
+      url::Origin::Create(GURL("http://a.b.foo.test"))};
+
+  for (const auto& origin_a : kTestOrigins) {
+    for (const auto& origin_b : kTestOrigins) {
+      EXPECT_EQ(SchemefulSite(origin_a), SchemefulSite(origin_b));
+    }
+  }
+}
+
+TEST(SchemefulSiteTest, Operators) {
+  // Create a list of origins that should all have different schemeful sites.
+  // These are in ascending order.
+  url::Origin kTestOrigins[] = {
+      url::Origin::Create(GURL("data:text/html,<body>Hello World</body>")),
+      url::Origin::Create(GURL("file://foo")),
+      url::Origin::Create(GURL("http://a.bar.test")),
+      url::Origin::Create(GURL("http://c.test")),
+      url::Origin::Create(GURL("http://d.test")),
+      url::Origin::Create(GURL("http://a.foo.test")),
+      url::Origin::Create(GURL("https://a.bar.test")),
+      url::Origin::Create(GURL("https://c.test")),
+      url::Origin::Create(GURL("https://d.test")),
+      url::Origin::Create(GURL("https://a.foo.test"))};
+
+  // Compare each origin to every other origin and ensure the operators work as
+  // expected.
+  for (size_t first = 0; first < base::size(kTestOrigins); ++first) {
+    SchemefulSite site1 = SchemefulSite(kTestOrigins[first]);
+    SCOPED_TRACE(site1.GetDebugString());
+
+    EXPECT_EQ(site1, site1);
+    EXPECT_FALSE(site1 < site1);
+
+    // Check the operators work on copies.
+    SchemefulSite site1_copy = site1;
+    EXPECT_EQ(site1, site1_copy);
+    EXPECT_FALSE(site1 < site1_copy);
+
+    for (size_t second = first + 1; second < base::size(kTestOrigins);
+         ++second) {
+      SchemefulSite site2 = SchemefulSite(kTestOrigins[second]);
+      SCOPED_TRACE(site2.GetDebugString());
+
+      EXPECT_TRUE(site1 < site2);
+      EXPECT_FALSE(site2 < site1);
+      EXPECT_FALSE(site1 == site2);
+      EXPECT_FALSE(site2 == site1);
+    }
+  }
+}
+
+TEST(SchemefulSiteTest, SchemeUsed) {
+  url::Origin origin_a = url::Origin::Create(GURL("https://foo.test"));
+  url::Origin origin_b = url::Origin::Create(GURL("http://foo.test"));
+  EXPECT_NE(SchemefulSite(origin_a), SchemefulSite(origin_b));
+}
+
+TEST(SchemefulSiteTest, PortIgnored) {
+  // Both origins are non-opaque.
+  url::Origin origin_a = url::Origin::Create(GURL("https://foo.test:80"));
+  url::Origin origin_b = url::Origin::Create(GURL("https://foo.test:2395"));
+
+  EXPECT_EQ(SchemefulSite(origin_a), SchemefulSite(origin_b));
+}
+
+TEST(SchemefulSiteTest, TopLevelDomainsNotModified) {
+  url::Origin origin_tld = url::Origin::Create(GURL("https://com"));
+  EXPECT_EQ(url::Origin::Create(GURL("https://com")),
+            SchemefulSite(origin_tld).GetInternalOriginForTesting());
+
+  // Unknown TLD's should not be modified.
+  url::Origin origin_tld_unknown =
+      url::Origin::Create(GURL("https://bar:1234"));
+  EXPECT_EQ(url::Origin::Create(GURL("https://bar")),
+            SchemefulSite(origin_tld_unknown).GetInternalOriginForTesting());
+
+  // Check for two-part TLDs.
+  url::Origin origin_two_part_tld = url::Origin::Create(GURL("http://a.co.uk"));
+  EXPECT_EQ(url::Origin::Create(GURL("http://a.co.uk")),
+            SchemefulSite(origin_two_part_tld).GetInternalOriginForTesting());
+}
+
+TEST(SchemefulSiteTest, NonStandardScheme) {
+  url::ScopedSchemeRegistryForTests scoped_registry;
+  url::AddStandardScheme("foo", url::SCHEME_WITH_HOST);
+  url::Origin origin = url::Origin::Create(GURL("foo://a.b.test"));
+  EXPECT_FALSE(origin.opaque());
+
+  // We should not use registerable domains for non-standard schemes, even if
+  // one exists for the host.
+  EXPECT_EQ(url::Origin::Create(GURL("foo://a.b.test")),
+            SchemefulSite(origin).GetInternalOriginForTesting());
+}
+
+TEST(SchemefulSiteTest, IPBasedOriginsRemovePort) {
+  // IPv4 and IPv6 origins should not be modified, except for removing their
+  // ports.
+  url::Origin origin_ipv4_a =
+      url::Origin::Create(GURL("http://127.0.0.1:1234"));
+  url::Origin origin_ipv4_b = url::Origin::Create(GURL("http://127.0.0.1"));
+  EXPECT_EQ(url::Origin::Create(GURL("http://127.0.0.1")),
+            SchemefulSite(origin_ipv4_a).GetInternalOriginForTesting());
+  EXPECT_EQ(SchemefulSite(origin_ipv4_a), SchemefulSite(origin_ipv4_b));
+
+  url::Origin origin_ipv6 = url::Origin::Create(GURL("https://[::1]"));
+  EXPECT_EQ(url::Origin::Create(GURL("https://[::1]")),
+            SchemefulSite(origin_ipv6).GetInternalOriginForTesting());
+}
+
+TEST(SchemefulSiteTest, OpaqueOrigins) {
+  url::Origin opaque_origin_a =
+      url::Origin::Create(GURL("data:text/html,<body>Hello World</body>"));
+
+  // The schemeful site of an opaque origin should always equal other schemeful
+  // site instances of the same origin.
+  EXPECT_EQ(SchemefulSite(opaque_origin_a), SchemefulSite(opaque_origin_a));
+
+  url::Origin opaque_origin_b =
+      url::Origin::Create(GURL("data:text/html,<body>Hello World</body>"));
+
+  // Two different opaque origins should never have the same SchemefulSite.
+  EXPECT_NE(SchemefulSite(opaque_origin_a), SchemefulSite(opaque_origin_b));
+}
+
+TEST(SchemefulSiteTest, SerializationConsistent) {
+  url::ScopedSchemeRegistryForTests scoped_registry;
+  url::AddStandardScheme("chrome", url::SCHEME_WITH_HOST);
+
+  // List of origins which should all share a schemeful site.
+  SchemefulSite kTestSites[] = {
+      SchemefulSite(url::Origin::Create(GURL("http://a.foo.test"))),
+      SchemefulSite(url::Origin::Create(GURL("https://b.foo.test"))),
+      SchemefulSite(url::Origin::Create(GURL("http://b.foo.test"))),
+      SchemefulSite(url::Origin::Create(GURL("http://a.b.foo.test"))),
+      SchemefulSite(url::Origin::Create(GURL("chrome://a.b.test")))};
+
+  for (const auto& site : kTestSites) {
+    SCOPED_TRACE(site.GetDebugString());
+    EXPECT_FALSE(site.GetInternalOriginForTesting().opaque());
+
+    base::Optional<SchemefulSite> deserialized_site =
+        SchemefulSite::Deserialize(site.Serialize());
+    EXPECT_TRUE(deserialized_site);
+    EXPECT_EQ(site, deserialized_site);
+  }
+}
+
+TEST(SchemefulSiteTest, OpaqueSerialization) {
+  // List of origins which should all share a schemeful site.
+  SchemefulSite kTestSites[] = {
+      SchemefulSite(), SchemefulSite(url::Origin()),
+      SchemefulSite(GURL("data:text/html,<body>Hello World</body>"))};
+
+  for (auto& site : kTestSites) {
+    base::Optional<SchemefulSite> deserialized_site =
+        SchemefulSite::DeserializeWithNonce(*site.SerializeWithNonce());
+    EXPECT_TRUE(deserialized_site);
+    EXPECT_EQ(site, *deserialized_site);
+  }
+}
+
+}  // namespace net
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc
index 18b36ab..b8e84314 100644
--- a/net/http/transport_security_state.cc
+++ b/net/http/transport_security_state.cc
@@ -454,6 +454,7 @@
     const X509Certificate* served_certificate_chain,
     const X509Certificate* validated_certificate_chain,
     const PublicKeyPinReportStatus report_status,
+    const NetworkIsolationKey& network_isolation_key,
     std::string* pinning_failure_log) {
   // Perform pin validation only if the server actually has public key pins.
   if (!HasPublicKeyPins(host_port_pair.host())) {
@@ -463,7 +464,7 @@
   PKPStatus pin_validity = CheckPublicKeyPinsImpl(
       host_port_pair, is_issued_by_known_root, public_key_hashes,
       served_certificate_chain, validated_certificate_chain, report_status,
-      pinning_failure_log);
+      network_isolation_key, pinning_failure_log);
 
   // Don't track statistics when a local trust anchor would override the pinning
   // anyway.
@@ -745,6 +746,7 @@
     const X509Certificate* served_certificate_chain,
     const X509Certificate* validated_certificate_chain,
     const TransportSecurityState::PublicKeyPinReportStatus report_status,
+    const net::NetworkIsolationKey& network_isolation_key,
     std::string* failure_log) {
   if (pkp_state.CheckPublicKeyPins(hashes, failure_log))
     return PKPStatus::OK;
@@ -786,7 +788,8 @@
           base::TimeDelta::FromMinutes(kTimeToRememberReportsMins));
 
   report_sender_->Send(pkp_state.report_uri, "application/json; charset=utf-8",
-                       serialized_report, base::OnceCallback<void()>(),
+                       serialized_report, network_isolation_key,
+                       base::OnceCallback<void()>(),
                        base::BindOnce(RecordUMAForHPKPReportFailure));
   return PKPStatus::VIOLATED;
 }
@@ -1114,6 +1117,7 @@
     const X509Certificate* served_certificate_chain,
     const X509Certificate* validated_certificate_chain,
     const PublicKeyPinReportStatus report_status,
+    const NetworkIsolationKey& network_isolation_key,
     std::string* failure_log) {
   PKPState pkp_state;
   bool found_state = GetPKPState(host_port_pair.host(), &pkp_state);
@@ -1124,7 +1128,7 @@
   return CheckPinsAndMaybeSendReport(
       host_port_pair, is_issued_by_known_root, pkp_state, hashes,
       served_certificate_chain, validated_certificate_chain, report_status,
-      failure_log);
+      network_isolation_key, failure_log);
 }
 
 bool TransportSecurityState::GetStaticDomainState(const std::string& host,
diff --git a/net/http/transport_security_state.h b/net/http/transport_security_state.h
index da59832..ed34c788 100644
--- a/net/http/transport_security_state.h
+++ b/net/http/transport_security_state.h
@@ -303,6 +303,7 @@
     virtual void Send(const GURL& report_uri,
                       base::StringPiece content_type,
                       base::StringPiece report,
+                      const NetworkIsolationKey& network_isolation_key,
                       base::OnceCallback<void()> success_callback,
                       base::OnceCallback<void(const GURL&,
                                               int /* net_error */,
@@ -385,6 +386,7 @@
       const X509Certificate* served_certificate_chain,
       const X509Certificate* validated_certificate_chain,
       const PublicKeyPinReportStatus report_status,
+      const NetworkIsolationKey& network_isolation_key,
       std::string* failure_log);
   bool HasPublicKeyPins(const std::string& host);
 
@@ -606,6 +608,7 @@
       const X509Certificate* served_certificate_chain,
       const X509Certificate* validated_certificate_chain,
       const PublicKeyPinReportStatus report_status,
+      const NetworkIsolationKey& network_isolation_key,
       std::string* failure_log);
 
   // If a Delegate is present, notify it that the internal state has
@@ -648,6 +651,7 @@
       const X509Certificate* served_certificate_chain,
       const X509Certificate* validated_certificate_chain,
       const TransportSecurityState::PublicKeyPinReportStatus report_status,
+      const net::NetworkIsolationKey& network_isolation_key,
       std::string* failure_log);
 
   // Returns true and updates |*expect_ct_result| iff there is a static
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index 4b90996..8ffeb1cf 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -121,27 +121,34 @@
       const GURL& report_uri,
       base::StringPiece content_type,
       base::StringPiece report,
+      const NetworkIsolationKey& network_isolation_key,
       base::OnceCallback<void()> success_callback,
       base::OnceCallback<void(const GURL&, int, int)> error_callback) override {
     latest_report_uri_ = report_uri;
     latest_report_.assign(report.data(), report.size());
     latest_content_type_.assign(content_type.data(), content_type.size());
+    latest_network_isolation_key_ = network_isolation_key;
   }
 
   void Clear() {
     latest_report_uri_ = GURL();
     latest_report_ = std::string();
     latest_content_type_ = std::string();
+    latest_network_isolation_key_ = NetworkIsolationKey();
   }
 
   const GURL& latest_report_uri() { return latest_report_uri_; }
   const std::string& latest_report() { return latest_report_; }
   const std::string& latest_content_type() { return latest_content_type_; }
+  const NetworkIsolationKey& latest_network_isolation_key() {
+    return latest_network_isolation_key_;
+  }
 
  private:
   GURL latest_report_uri_;
   std::string latest_report_;
   std::string latest_content_type_;
+  NetworkIsolationKey latest_network_isolation_key_;
 };
 
 // A mock ReportSenderInterface that simulates a net error on every report sent.
@@ -158,6 +165,7 @@
       const GURL& report_uri,
       base::StringPiece content_type,
       base::StringPiece report,
+      const NetworkIsolationKey& network_isolation_key,
       base::OnceCallback<void()> success_callback,
       base::OnceCallback<void(const GURL&, int, int)> error_callback) override {
     ASSERT_FALSE(error_callback.is_null());
@@ -328,7 +336,7 @@
 }
 
 // As with CreateUniqueHostName(), returns a unique NetworkIsolationKey for use
-// with Expect-CT prunung tests.
+// with Expect-CT pruning tests.
 NetworkIsolationKey CreateUniqueNetworkIsolationKey(bool is_transient) {
   if (is_transient)
     return NetworkIsolationKey::CreateTransient();
@@ -914,6 +922,8 @@
   const char kPreloadedPinDomain[] = "with-report-uri-pkp.preloaded.test";
   const uint16_t kPort = 443;
   HostPortPair host_port_pair(kPreloadedPinDomain, kPort);
+  net::NetworkIsolationKey network_isolation_key =
+      NetworkIsolationKey::CreateTransient();
 
   TransportSecurityState state;
   MockCertificateReportSender mock_report_sender;
@@ -948,9 +958,10 @@
   // Trigger a violation and check that it sends a report.
   std::string failure_log;
   EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
-            state.CheckPublicKeyPins(
-                host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
-                TransportSecurityState::ENABLE_PIN_REPORTS, &failure_log));
+            state.CheckPublicKeyPins(host_port_pair, true, bad_hashes,
+                                     cert1.get(), cert2.get(),
+                                     TransportSecurityState::ENABLE_PIN_REPORTS,
+                                     network_isolation_key, &failure_log));
 
   EXPECT_EQ(report_uri, mock_report_sender.latest_report_uri());
 
@@ -961,6 +972,8 @@
   ASSERT_NO_FATAL_FAILURE(CheckHPKPReport(
       report, host_port_pair, pkp_state.include_subdomains, pkp_state.domain,
       cert1.get(), cert2.get(), pkp_state.spki_hashes));
+  EXPECT_EQ(network_isolation_key,
+            mock_report_sender.latest_network_isolation_key());
 }
 
 // Tests that report URIs are thrown out if they point to the same host,
@@ -969,6 +982,8 @@
   HostPortPair host_port_pair(kHost, kPort);
   GURL https_report_uri("https://example.test/report");
   GURL http_report_uri("http://example.test/report");
+  NetworkIsolationKey network_isolation_key =
+      NetworkIsolationKey::CreateTransient();
   TransportSecurityState state;
   MockCertificateReportSender mock_report_sender;
   state.SetReportSender(&mock_report_sender);
@@ -998,20 +1013,24 @@
   // because the report-uri is HTTPS and same-host as the pins.
   std::string failure_log;
   EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
-            state.CheckPublicKeyPins(
-                host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
-                TransportSecurityState::ENABLE_PIN_REPORTS, &failure_log));
+            state.CheckPublicKeyPins(host_port_pair, true, bad_hashes,
+                                     cert1.get(), cert2.get(),
+                                     TransportSecurityState::ENABLE_PIN_REPORTS,
+                                     network_isolation_key, &failure_log));
 
   EXPECT_TRUE(mock_report_sender.latest_report_uri().is_empty());
 
   // An HTTP report uri to the same host should be okay.
   state.AddHPKP("example.test", expiry, true, good_hashes, http_report_uri);
   EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
-            state.CheckPublicKeyPins(
-                host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
-                TransportSecurityState::ENABLE_PIN_REPORTS, &failure_log));
+            state.CheckPublicKeyPins(host_port_pair, true, bad_hashes,
+                                     cert1.get(), cert2.get(),
+                                     TransportSecurityState::ENABLE_PIN_REPORTS,
+                                     network_isolation_key, &failure_log));
 
   EXPECT_EQ(http_report_uri, mock_report_sender.latest_report_uri());
+  EXPECT_EQ(network_isolation_key,
+            mock_report_sender.latest_network_isolation_key());
 }
 
 // Tests that static (preloaded) expect CT state is read correctly.
@@ -3165,6 +3184,8 @@
   HostPortPair host_port_pair(kHost, kPort);
   HostPortPair subdomain_host_port_pair(kSubdomain, kPort);
   GURL report_uri(kReportUri);
+  NetworkIsolationKey network_isolation_key =
+      NetworkIsolationKey::CreateTransient();
   // Two dummy certs to use as the server-sent and validated chains. The
   // contents don't matter.
   scoped_refptr<X509Certificate> cert1 =
@@ -3191,9 +3212,10 @@
 
   std::string failure_log;
   EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
-            state.CheckPublicKeyPins(
-                host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
-                TransportSecurityState::ENABLE_PIN_REPORTS, &failure_log));
+            state.CheckPublicKeyPins(host_port_pair, true, bad_hashes,
+                                     cert1.get(), cert2.get(),
+                                     TransportSecurityState::ENABLE_PIN_REPORTS,
+                                     network_isolation_key, &failure_log));
 
   // A report should have been sent. Check that it contains the
   // right information.
@@ -3203,22 +3225,29 @@
   ASSERT_NO_FATAL_FAILURE(CheckHPKPReport(report, host_port_pair, true, kHost,
                                           cert1.get(), cert2.get(),
                                           good_hashes));
+  EXPECT_EQ(network_isolation_key,
+            mock_report_sender.latest_network_isolation_key());
   mock_report_sender.Clear();
 
   // Now trigger the same violation; a duplicative report should not be
   // sent.
   EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
-            state.CheckPublicKeyPins(
-                host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
-                TransportSecurityState::ENABLE_PIN_REPORTS, &failure_log));
+            state.CheckPublicKeyPins(host_port_pair, true, bad_hashes,
+                                     cert1.get(), cert2.get(),
+                                     TransportSecurityState::ENABLE_PIN_REPORTS,
+                                     network_isolation_key, &failure_log));
   EXPECT_EQ(GURL(), mock_report_sender.latest_report_uri());
   EXPECT_EQ(std::string(), mock_report_sender.latest_report());
+  EXPECT_EQ(NetworkIsolationKey(),
+            mock_report_sender.latest_network_isolation_key());
 }
 
 TEST_F(TransportSecurityStateStaticTest, HPKPReporting) {
   HostPortPair host_port_pair(kHost, kPort);
   HostPortPair subdomain_host_port_pair(kSubdomain, kPort);
   GURL report_uri(kReportUri);
+  NetworkIsolationKey network_isolation_key =
+      NetworkIsolationKey::CreateTransient();
   // Two dummy certs to use as the server-sent and validated chains. The
   // contents don't matter.
   scoped_refptr<X509Certificate> cert1 =
@@ -3247,7 +3276,8 @@
   EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
             state.CheckPublicKeyPins(
                 host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
-                TransportSecurityState::DISABLE_PIN_REPORTS, &failure_log));
+                TransportSecurityState::DISABLE_PIN_REPORTS,
+                network_isolation_key, &failure_log));
 
   // No report should have been sent because of the DISABLE_PIN_REPORTS
   // argument.
@@ -3255,18 +3285,20 @@
   EXPECT_EQ(std::string(), mock_report_sender.latest_report());
 
   EXPECT_EQ(TransportSecurityState::PKPStatus::OK,
-            state.CheckPublicKeyPins(
-                host_port_pair, true, good_hashes, cert1.get(), cert2.get(),
-                TransportSecurityState::ENABLE_PIN_REPORTS, &failure_log));
+            state.CheckPublicKeyPins(host_port_pair, true, good_hashes,
+                                     cert1.get(), cert2.get(),
+                                     TransportSecurityState::ENABLE_PIN_REPORTS,
+                                     network_isolation_key, &failure_log));
 
   // No report should have been sent because there was no violation.
   EXPECT_EQ(GURL(), mock_report_sender.latest_report_uri());
   EXPECT_EQ(std::string(), mock_report_sender.latest_report());
 
   EXPECT_EQ(TransportSecurityState::PKPStatus::BYPASSED,
-            state.CheckPublicKeyPins(
-                host_port_pair, false, bad_hashes, cert1.get(), cert2.get(),
-                TransportSecurityState::ENABLE_PIN_REPORTS, &failure_log));
+            state.CheckPublicKeyPins(host_port_pair, false, bad_hashes,
+                                     cert1.get(), cert2.get(),
+                                     TransportSecurityState::ENABLE_PIN_REPORTS,
+                                     network_isolation_key, &failure_log));
 
   // No report should have been sent because the certificate chained to a
   // non-public root.
@@ -3274,9 +3306,10 @@
   EXPECT_EQ(std::string(), mock_report_sender.latest_report());
 
   EXPECT_EQ(TransportSecurityState::PKPStatus::OK,
-            state.CheckPublicKeyPins(
-                host_port_pair, false, good_hashes, cert1.get(), cert2.get(),
-                TransportSecurityState::ENABLE_PIN_REPORTS, &failure_log));
+            state.CheckPublicKeyPins(host_port_pair, false, good_hashes,
+                                     cert1.get(), cert2.get(),
+                                     TransportSecurityState::ENABLE_PIN_REPORTS,
+                                     network_isolation_key, &failure_log));
 
   // No report should have been sent because there was no violation, even though
   // the certificate chained to a local trust anchor.
@@ -3284,9 +3317,10 @@
   EXPECT_EQ(std::string(), mock_report_sender.latest_report());
 
   EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
-            state.CheckPublicKeyPins(
-                host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
-                TransportSecurityState::ENABLE_PIN_REPORTS, &failure_log));
+            state.CheckPublicKeyPins(host_port_pair, true, bad_hashes,
+                                     cert1.get(), cert2.get(),
+                                     TransportSecurityState::ENABLE_PIN_REPORTS,
+                                     network_isolation_key, &failure_log));
 
   // Now a report should have been sent. Check that it contains the
   // right information.
@@ -3303,7 +3337,7 @@
             state.CheckPublicKeyPins(subdomain_host_port_pair, true, bad_hashes,
                                      cert1.get(), cert2.get(),
                                      TransportSecurityState::ENABLE_PIN_REPORTS,
-                                     &failure_log));
+                                     network_isolation_key, &failure_log));
 
   // Now a report should have been sent for the subdomain. Check that it
   // contains the right information.
@@ -3315,6 +3349,8 @@
   ASSERT_NO_FATAL_FAILURE(CheckHPKPReport(report, subdomain_host_port_pair,
                                           true, kHost, cert1.get(), cert2.get(),
                                           good_hashes));
+  EXPECT_EQ(network_isolation_key,
+            mock_report_sender.latest_network_isolation_key());
 }
 
 // Tests that a histogram entry is recorded when TransportSecurityState
@@ -3352,7 +3388,8 @@
   EXPECT_EQ(TransportSecurityState::PKPStatus::VIOLATED,
             state.CheckPublicKeyPins(
                 host_port_pair, true, bad_hashes, cert1.get(), cert2.get(),
-                TransportSecurityState::ENABLE_PIN_REPORTS, &failure_log));
+                TransportSecurityState::ENABLE_PIN_REPORTS,
+                NetworkIsolationKey::CreateTransient(), &failure_log));
 
   // Check that the UMA histogram was updated when the report failed to
   // send.
diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc
index 6c7c05d..e67bcb29 100644
--- a/net/quic/crypto/proof_verifier_chromium.cc
+++ b/net/quic/crypto/proof_verifier_chromium.cc
@@ -496,7 +496,6 @@
         // possible values of CheckCTRequirements() are handled.
         break;
     }
-
     TransportSecurityState::PKPStatus pin_validity =
         transport_security_state_->CheckPublicKeyPins(
             HostPortPair(hostname_, port_),
@@ -504,6 +503,7 @@
             cert_verify_result.public_key_hashes, cert_.get(),
             cert_verify_result.verified_cert.get(),
             TransportSecurityState::ENABLE_PIN_REPORTS,
+            proof_verifier_->network_isolation_key_,
             &verify_details_->pinning_failure_log);
     switch (pin_validity) {
       case TransportSecurityState::PKPStatus::VIOLATED:
diff --git a/net/quic/crypto/proof_verifier_chromium_test.cc b/net/quic/crypto/proof_verifier_chromium_test.cc
index 312ae5f..315bb87 100644
--- a/net/quic/crypto/proof_verifier_chromium_test.cc
+++ b/net/quic/crypto/proof_verifier_chromium_test.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "net/base/completion_once_callback.h"
 #include "net/base/net_errors.h"
@@ -133,6 +134,35 @@
 
 }  // namespace
 
+// A mock ReportSenderInterface that just remembers the latest report
+// URI and its NetworkIsolationKey.
+class MockCertificateReportSender
+    : public TransportSecurityState::ReportSenderInterface {
+ public:
+  MockCertificateReportSender() = default;
+  ~MockCertificateReportSender() override = default;
+
+  void Send(
+      const GURL& report_uri,
+      base::StringPiece content_type,
+      base::StringPiece report,
+      const NetworkIsolationKey& network_isolation_key,
+      base::OnceCallback<void()> success_callback,
+      base::OnceCallback<void(const GURL&, int, int)> error_callback) override {
+    latest_report_uri_ = report_uri;
+    latest_network_isolation_key_ = network_isolation_key;
+  }
+
+  const GURL& latest_report_uri() { return latest_report_uri_; }
+  const NetworkIsolationKey& latest_network_isolation_key() {
+    return latest_network_isolation_key_;
+  }
+
+ private:
+  GURL latest_report_uri_;
+  NetworkIsolationKey latest_network_isolation_key_;
+};
+
 class ProofVerifierChromiumTest : public ::testing::Test {
  public:
   ProofVerifierChromiumTest()
@@ -708,6 +738,69 @@
   EXPECT_TRUE(verify_details->pkp_bypassed);
 }
 
+// Test that PKP errors result in sending reports.
+TEST_F(ProofVerifierChromiumTest, PKPReport) {
+  NetworkIsolationKey network_isolation_key =
+      NetworkIsolationKey::CreateTransient();
+
+  MockCertificateReportSender report_sender;
+  transport_security_state_.SetReportSender(&report_sender);
+
+  HashValueVector spki_hashes;
+  HashValue hash(HASH_VALUE_SHA256);
+  memset(hash.data(), 0, hash.size());
+  spki_hashes.push_back(hash);
+
+  GURL report_uri("https://foo.test/");
+  transport_security_state_.AddHPKP(
+      kCTAndPKPHost, base::Time::Now() + base::TimeDelta::FromDays(1),
+      false /* include_subdomains */, spki_hashes, report_uri);
+  ScopedTransportSecurityStateSource scoped_security_state_source;
+
+  dummy_result_.is_issued_by_known_root = true;
+  dummy_result_.public_key_hashes = MakeHashValueVector(0x01);
+
+  MockCertVerifier dummy_verifier;
+  dummy_verifier.AddResultForCert(test_cert_.get(), dummy_result_, OK);
+
+  ProofVerifierChromium proof_verifier(
+      &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_,
+      ct_verifier_.get(), nullptr, {}, network_isolation_key);
+
+  std::unique_ptr<DummyProofVerifierCallback> callback(
+      new DummyProofVerifierCallback);
+  quic::QuicAsyncStatus status = proof_verifier.VerifyProof(
+      kCTAndPKPHost, kTestPort, kTestConfig, kTestTransportVersion,
+      kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(),
+      verify_context_.get(), &error_details_, &details_, std::move(callback));
+  ASSERT_EQ(quic::QUIC_FAILURE, status);
+
+  ASSERT_TRUE(details_.get());
+  ProofVerifyDetailsChromium* verify_details =
+      static_cast<ProofVerifyDetailsChromium*>(details_.get());
+  EXPECT_TRUE(verify_details->cert_verify_result.cert_status &
+              CERT_STATUS_PINNED_KEY_MISSING);
+  EXPECT_FALSE(verify_details->pkp_bypassed);
+  EXPECT_NE("", verify_details->pinning_failure_log);
+
+  callback = std::make_unique<DummyProofVerifierCallback>();
+  status = proof_verifier.VerifyCertChain(
+      kCTAndPKPHost, kTestPort, certs_, kTestEmptyOCSPResponse, kTestEmptySCT,
+      verify_context_.get(), &error_details_, &details_, std::move(callback));
+  ASSERT_EQ(quic::QUIC_FAILURE, status);
+
+  ASSERT_TRUE(details_.get());
+  verify_details = static_cast<ProofVerifyDetailsChromium*>(details_.get());
+  EXPECT_TRUE(verify_details->cert_verify_result.cert_status &
+              CERT_STATUS_PINNED_KEY_MISSING);
+  EXPECT_FALSE(verify_details->pkp_bypassed);
+  EXPECT_NE("", verify_details->pinning_failure_log);
+
+  EXPECT_EQ(report_uri, report_sender.latest_report_uri());
+  EXPECT_EQ(network_isolation_key,
+            report_sender.latest_network_isolation_key());
+}
+
 // Test that when CT is required (in this case, by the delegate), the
 // absence of CT information is a socket error.
 TEST_F(ProofVerifierChromiumTest, CTIsRequired) {
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 103bafb2..d29204c 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -1203,7 +1203,8 @@
             host_and_port_, server_cert_verify_result_.is_issued_by_known_root,
             server_cert_verify_result_.public_key_hashes, server_cert_.get(),
             server_cert_verify_result_.verified_cert.get(),
-            TransportSecurityState::ENABLE_PIN_REPORTS, &pinning_failure_log_);
+            TransportSecurityState::ENABLE_PIN_REPORTS,
+            ssl_config_.network_isolation_key, &pinning_failure_log_);
     switch (pin_validity) {
       case TransportSecurityState::PKPStatus::VIOLATED:
         server_cert_verify_result_.cert_status |=
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 9556041..6eb6fcb3 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -885,7 +885,7 @@
           HostPortPair(new_hostname, 0), ssl_info.is_issued_by_known_root,
           ssl_info.public_key_hashes, ssl_info.unverified_cert.get(),
           ssl_info.cert.get(), TransportSecurityState::DISABLE_PIN_REPORTS,
-          &pinning_failure_log) ==
+          network_isolation_key, &pinning_failure_log) ==
       TransportSecurityState::PKPStatus::VIOLATED) {
     return false;
   }
diff --git a/net/url_request/report_sender.cc b/net/url_request/report_sender.cc
index 1a04006..269658b 100644
--- a/net/url_request/report_sender.cc
+++ b/net/url_request/report_sender.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "net/base/elements_upload_data_stream.h"
+#include "net/base/isolation_info.h"
 #include "net/base/load_flags.h"
 #include "net/base/request_priority.h"
 #include "net/base/upload_bytes_element_reader.h"
@@ -58,6 +59,7 @@
 void ReportSender::Send(const GURL& report_uri,
                         base::StringPiece content_type,
                         base::StringPiece report,
+                        const NetworkIsolationKey& network_isolation_key,
                         SuccessCallback success_callback,
                         ErrorCallback error_callback) {
   DCHECK(!content_type.empty());
@@ -66,9 +68,10 @@
   url_request->SetUserData(
       &kUserDataKey, std::make_unique<CallbackInfo>(std::move(success_callback),
                                                     std::move(error_callback)));
-
   url_request->SetLoadFlags(kLoadFlags);
   url_request->set_allow_credentials(false);
+  url_request->set_isolation_info(IsolationInfo::CreatePartial(
+      IsolationInfo::RequestType::kOther, network_isolation_key));
 
   HttpRequestHeaders extra_headers;
   extra_headers.SetHeader(HttpRequestHeaders::kContentType, content_type);
diff --git a/net/url_request/report_sender.h b/net/url_request/report_sender.h
index 1e40236..7e2f57c 100644
--- a/net/url_request/report_sender.h
+++ b/net/url_request/report_sender.h
@@ -20,6 +20,7 @@
 
 namespace net {
 
+class NetworkIsolationKey;
 class URLRequestContext;
 
 // ReportSender asynchronously sends serialized reports to a URI.
@@ -27,6 +28,9 @@
 // the format of the report being sent (JSON, protobuf, etc.) and the particular
 // data that it contains. Multiple reports can be in-flight at once. This class
 // owns inflight requests and cleans them up when necessary.
+//
+// Despite this class's name, it has nothing to do with the Reporting API,
+// which is implemented in net/reporting.
 class NET_EXPORT ReportSender
     : public URLRequest::Delegate,
       public TransportSecurityState::ReportSenderInterface {
@@ -49,6 +53,7 @@
   void Send(const GURL& report_uri,
             base::StringPiece content_type,
             base::StringPiece report,
+            const NetworkIsolationKey& network_isolation_key,
             SuccessCallback success_callback,
             ErrorCallback error_callback) override;
 
diff --git a/net/url_request/report_sender_unittest.cc b/net/url_request/report_sender_unittest.cc
index c921c6cc..da2bda3 100644
--- a/net/url_request/report_sender_unittest.cc
+++ b/net/url_request/report_sender_unittest.cc
@@ -143,6 +143,11 @@
     expected_content_type_ = content_type;
   }
 
+  void set_expected_network_isolation_key(
+      const NetworkIsolationKey& expected_network_isolation_key) {
+    expected_network_isolation_key_ = expected_network_isolation_key;
+  }
+
   // NetworkDelegateImpl implementation.
   int OnBeforeURLRequest(URLRequest* request,
                          CompletionOnceCallback callback,
@@ -153,6 +158,12 @@
     EXPECT_FALSE(request->allow_credentials());
     EXPECT_TRUE(request->load_flags() & LOAD_DO_NOT_SAVE_COOKIES);
 
+    EXPECT_EQ(expected_network_isolation_key_,
+              request->isolation_info().network_isolation_key());
+    EXPECT_EQ(IsolationInfo::RequestType::kOther,
+              request->isolation_info().request_type());
+    EXPECT_TRUE(request->site_for_cookies().IsNull());
+
     const HttpRequestHeaders& extra_headers = request->extra_request_headers();
     std::string content_type;
     EXPECT_TRUE(extra_headers.GetHeader(HttpRequestHeaders::kContentType,
@@ -179,6 +190,7 @@
   GURL expect_url_;
   std::set<std::string> expect_reports_;
   std::string expected_content_type_;
+  NetworkIsolationKey expected_network_isolation_key_;
 
   DISALLOW_COPY_AND_ASSIGN(TestReportSenderNetworkDelegate);
 };
@@ -211,6 +223,9 @@
       size_t request_sequence_number,
       base::OnceCallback<void()> success_callback,
       base::OnceCallback<void(const GURL&, int, int)> error_callback) {
+    NetworkIsolationKey network_isolation_key =
+        NetworkIsolationKey::CreateTransient();
+
     base::RunLoop run_loop;
     network_delegate_.set_url_request_destroyed_callback(
         run_loop.QuitClosure());
@@ -218,10 +233,11 @@
     network_delegate_.set_expect_url(url);
     network_delegate_.ExpectReport(report);
     network_delegate_.set_expected_content_type("application/foobar");
+    network_delegate_.set_expected_network_isolation_key(network_isolation_key);
 
     EXPECT_EQ(request_sequence_number, network_delegate_.num_requests());
 
-    reporter->Send(url, "application/foobar", report,
+    reporter->Send(url, "application/foobar", report, network_isolation_key,
                    std::move(success_callback), std::move(error_callback));
 
     // The report is sent asynchronously, so wait for the report's
@@ -277,11 +293,11 @@
 
   EXPECT_EQ(0u, network_delegate_.num_requests());
 
-  reporter.Send(url, "application/foobar", kDummyReport,
+  reporter.Send(url, "application/foobar", kDummyReport, NetworkIsolationKey(),
                 base::OnceCallback<void()>(),
                 base::OnceCallback<void(const GURL&, int, int)>());
   reporter.Send(url, "application/foobar", kSecondDummyReport,
-                base::OnceCallback<void()>(),
+                NetworkIsolationKey(), base::OnceCallback<void()>(),
                 base::OnceCallback<void(const GURL&, int, int)>());
 
   run_loop.Run();
@@ -306,7 +322,7 @@
 
   std::unique_ptr<ReportSender> reporter(
       new ReportSender(context(), TRAFFIC_ANNOTATION_FOR_TESTS));
-  reporter->Send(url, "application/foobar", kDummyReport,
+  reporter->Send(url, "application/foobar", kDummyReport, NetworkIsolationKey(),
                  base::OnceCallback<void()>(),
                  base::OnceCallback<void(const GURL&, int, int)>());
   reporter.reset();
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 67e2b492..16df2a1 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -640,20 +640,26 @@
       const GURL& report_uri,
       base::StringPiece content_type,
       base::StringPiece report,
+      const NetworkIsolationKey& network_isolation_key,
       base::OnceCallback<void()> success_callback,
       base::OnceCallback<void(const GURL&, int, int)> error_callback) override {
     latest_report_uri_ = report_uri;
     latest_report_.assign(report.data(), report.size());
     latest_content_type_.assign(content_type.data(), content_type.size());
+    latest_network_isolation_key_ = network_isolation_key;
   }
   const GURL& latest_report_uri() { return latest_report_uri_; }
   const std::string& latest_report() { return latest_report_; }
   const std::string& latest_content_type() { return latest_content_type_; }
+  const NetworkIsolationKey& latest_network_isolation_key() {
+    return latest_network_isolation_key_;
+  }
 
  private:
   GURL latest_report_uri_;
   std::string latest_report_;
   std::string latest_content_type_;
+  NetworkIsolationKey latest_network_isolation_key_;
 };
 
 // OCSPErrorTestDelegate caches the SSLInfo passed to OnSSLCertificateError.
@@ -2873,7 +2879,12 @@
         origin2_(url::Origin::Create(GURL("https://bar.test/"))),
         isolation_info1_(IsolationInfo::CreateForInternalRequest(origin1_)),
         isolation_info2_(IsolationInfo::CreateForInternalRequest(origin2_)),
-        test_server_(base::FilePath(kTestFilePath)) {}
+        test_server_(base::FilePath(kTestFilePath)) {
+    // Needed for NetworkIsolationKey to make it down to the socket layer, for
+    // the PKP violation report test.
+    feature_list_.InitAndEnableFeature(
+        net::features::kPartitionConnectionsByNetworkIsolationKey);
+  }
 
  protected:
   // ProtocolHandler for the scheme that's unsafe to redirect to.
@@ -3036,6 +3047,8 @@
   HttpTestServer* http_test_server() { return &test_server_; }
 
  private:
+  base::test::ScopedFeatureList feature_list_;
+
   HttpTestServer test_server_;
 };
 
@@ -5196,11 +5209,14 @@
   context.set_cert_verifier(&cert_verifier);
   context.Init();
 
+  IsolationInfo isolation_info = IsolationInfo::CreateTransient();
+
   // Now send a request to trigger the violation.
   TestDelegate d;
   std::unique_ptr<URLRequest> violating_request(context.CreateRequest(
       https_test_server.GetURL(test_server_hostname, "/simple.html"),
       DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
+  violating_request->set_isolation_info(isolation_info);
   violating_request->Start();
   d.RunUntilComplete();
 
@@ -5218,6 +5234,8 @@
   std::string report_hostname;
   EXPECT_TRUE(report_dict->GetString("hostname", &report_hostname));
   EXPECT_EQ(test_server_hostname, report_hostname);
+  EXPECT_EQ(isolation_info.network_isolation_key(),
+            mock_report_sender.latest_network_isolation_key());
 }
 
 // Tests that reports do not get sent on requests to static pkp hosts that
@@ -5263,6 +5281,7 @@
   std::unique_ptr<URLRequest> request(context.CreateRequest(
       https_test_server.GetURL(test_server_hostname, "/simple.html"),
       DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
+  request->set_isolation_info(IsolationInfo::CreateTransient());
   request->Start();
   d.RunUntilComplete();
 
@@ -5271,6 +5290,8 @@
   EXPECT_EQ(OK, d.request_status());
   EXPECT_EQ(GURL(), mock_report_sender.latest_report_uri());
   EXPECT_EQ(std::string(), mock_report_sender.latest_report());
+  EXPECT_EQ(NetworkIsolationKey(),
+            mock_report_sender.latest_network_isolation_key());
   TransportSecurityState::STSState sts_state;
   TransportSecurityState::PKPState pkp_state;
   EXPECT_TRUE(security_state.GetStaticDomainState(test_server_hostname,
@@ -5321,6 +5342,7 @@
   std::unique_ptr<URLRequest> request(context.CreateRequest(
       https_test_server.GetURL(test_server_hostname, "/simple.html"),
       DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
+  request->set_isolation_info(IsolationInfo::CreateTransient());
   request->Start();
   d.RunUntilComplete();
 
@@ -5329,6 +5351,8 @@
   EXPECT_EQ(OK, d.request_status());
   EXPECT_EQ(GURL(), mock_report_sender.latest_report_uri());
   EXPECT_EQ(std::string(), mock_report_sender.latest_report());
+  EXPECT_EQ(NetworkIsolationKey(),
+            mock_report_sender.latest_network_isolation_key());
   TransportSecurityState::STSState sts_state;
   TransportSecurityState::PKPState pkp_state;
   EXPECT_TRUE(security_state.GetStaticDomainState(test_server_hostname,
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index 0be7a67..794b235 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -2199,6 +2199,10 @@
   pp::PDF::SetLinkUnderCursor(this, link_under_cursor.c_str());
 }
 
+bool OutOfProcessInstance::IsValidLink(const std::string& url) {
+  return pp::Var(url).is_string();
+}
+
 void OutOfProcessInstance::ProcessPreviewPageInfo(const std::string& url,
                                                   int dest_page_index) {
   DCHECK(IsPrintPreview());
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h
index 86a7487..65dd58c 100644
--- a/pdf/out_of_process_instance.h
+++ b/pdf/out_of_process_instance.h
@@ -165,6 +165,7 @@
   void DocumentFocusChanged(bool document_has_focus) override;
   void SetSelectedText(const std::string& selected_text) override;
   void SetLinkUnderCursor(const std::string& link_under_cursor) override;
+  bool IsValidLink(const std::string& url) override;
 
   // PreviewModeClient::Client:
   void PreviewDocumentLoadComplete() override;
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h
index 3f60282..e738797f 100644
--- a/pdf/pdf_engine.h
+++ b/pdf/pdf_engine.h
@@ -279,6 +279,12 @@
 
     // Sets the link under cursor.
     virtual void SetLinkUnderCursor(const std::string& link_under_cursor) = 0;
+
+    // If the link cannot be converted to JS payload struct, then it is not
+    // possible to pass it to JS. In this case, ignore the link like other PDF
+    // viewers.
+    // See https://crbug.com/312882 for an example.
+    virtual bool IsValidLink(const std::string& url) = 0;
   };
 
   struct AccessibilityLinkInfo {
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc
index 3fb0629..ce2e95f 100644
--- a/pdf/pdf_view_web_plugin.cc
+++ b/pdf/pdf_view_web_plugin.cc
@@ -293,6 +293,10 @@
   NOTIMPLEMENTED();
 }
 
+bool PdfViewWebPlugin::IsValidLink(const std::string& url) {
+  return base::Value(url).is_string();
+}
+
 bool PdfViewWebPlugin::IsValid() const {
   return container_ && container_->GetDocument().GetFrame();
 }
diff --git a/pdf/pdf_view_web_plugin.h b/pdf/pdf_view_web_plugin.h
index ce2e99c..3622c41 100644
--- a/pdf/pdf_view_web_plugin.h
+++ b/pdf/pdf_view_web_plugin.h
@@ -102,6 +102,7 @@
   void DocumentFocusChanged(bool document_has_focus) override;
   void SetSelectedText(const std::string& selected_text) override;
   void SetLinkUnderCursor(const std::string& link_under_cursor) override;
+  bool IsValidLink(const std::string& url) override;
 
   // BlinkUrlLoader::Client:
   bool IsValid() const override;
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 37e3931..c460e41 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -811,6 +811,10 @@
   return document_ ? document_->form() : nullptr;
 }
 
+bool PDFiumEngine::IsValidLink(const std::string& url) {
+  return client_->IsValidLink(url);
+}
+
 void PDFiumEngine::ContinueFind(int32_t result) {
   StartFind(current_find_text_, result != 0);
 }
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index 3ec53b9..0a59d55 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -186,6 +186,8 @@
   FPDF_DOCUMENT doc() const;
   FPDF_FORMHANDLE form() const;
 
+  bool IsValidLink(const std::string& url);
+
  private:
   // This helper class is used to detect the difference in selection between
   // construction and destruction.  At destruction, it invalidates all the
diff --git a/pdf/pdfium/pdfium_page.cc b/pdf/pdfium/pdfium_page.cc
index c547696..81b89a8c 100644
--- a/pdf/pdfium/pdfium_page.cc
+++ b/pdf/pdfium/pdfium_page.cc
@@ -55,17 +55,6 @@
 constexpr float k270DegreesInRadians = 3 * base::kPiFloat / 2;
 constexpr float k360DegreesInRadians = 2 * base::kPiFloat;
 
-PDFiumPage::IsValidLinkFunction g_is_valid_link_func_for_testing = nullptr;
-
-// If the link cannot be converted to a pp::Var, then it is not possible to
-// pass it to JS. In this case, ignore the link like other PDF viewers.
-// See https://crbug.com/312882 for an example.
-// TODO(crbug.com/702993): Get rid of the PPAPI usage here, as well as
-// SetIsValidLinkFunctionForTesting() and related code.
-bool IsValidLink(const std::string& url) {
-  return pp::Var(url).is_string();
-}
-
 gfx::RectF FloatPageRectToPixelRect(FPDF_PAGE page, const gfx::RectF& input) {
   int output_width = FPDF_GetPageWidthF(page);
   int output_height = FPDF_GetPageHeightF(page);
@@ -283,12 +272,6 @@
   DCHECK_EQ(0, preventing_unload_count_);
 }
 
-// static
-void PDFiumPage::SetIsValidLinkFunctionForTesting(
-    IsValidLinkFunction function) {
-  g_is_valid_link_func_for_testing = function;
-}
-
 void PDFiumPage::Unload() {
   // Do not unload while in the middle of a load.
   if (preventing_unload_count_)
@@ -985,10 +968,7 @@
     Link link;
     link.target.url = base::UTF16ToUTF8(url);
 
-    IsValidLinkFunction is_valid_link_func =
-        g_is_valid_link_func_for_testing ? g_is_valid_link_func_for_testing
-                                         : &IsValidLink;
-    if (!is_valid_link_func(link.target.url))
+    if (!engine_->IsValidLink(link.target.url))
       continue;
 
     // Make sure all the characters in the URL are valid per RFC 1738.
diff --git a/pdf/pdfium/pdfium_page.h b/pdf/pdfium/pdfium_page.h
index ce29a0b..2564f8d2 100644
--- a/pdf/pdfium/pdfium_page.h
+++ b/pdf/pdfium/pdfium_page.h
@@ -44,9 +44,6 @@
   PDFiumPage(PDFiumPage&& that);
   ~PDFiumPage();
 
-  using IsValidLinkFunction = bool (*)(const std::string& url);
-  static void SetIsValidLinkFunctionForTesting(IsValidLinkFunction function);
-
   // Unloads the PDFium data for this page from memory.
   void Unload();
   // Gets the FPDF_PAGE for this page, loading and parsing it if necessary.
diff --git a/pdf/pdfium/pdfium_test_base.cc b/pdf/pdfium/pdfium_test_base.cc
index 4eca65b..300f9f56 100644
--- a/pdf/pdfium/pdfium_test_base.cc
+++ b/pdf/pdfium/pdfium_test_base.cc
@@ -35,10 +35,6 @@
 }
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
-bool IsValidLinkForTesting(const std::string& url) {
-  return !url.empty();
-}
-
 }  // namespace
 
 PDFiumTestBase::PDFiumTestBase() = default;
@@ -56,11 +52,9 @@
 
 void PDFiumTestBase::SetUp() {
   InitializePDFium();
-  PDFiumPage::SetIsValidLinkFunctionForTesting(&IsValidLinkForTesting);
 }
 
 void PDFiumTestBase::TearDown() {
-  PDFiumPage::SetIsValidLinkFunctionForTesting(nullptr);
   FPDF_DestroyLibrary();
 }
 
diff --git a/pdf/preview_mode_client.cc b/pdf/preview_mode_client.cc
index 0d99f77..bdafe060 100644
--- a/pdf/preview_mode_client.cc
+++ b/pdf/preview_mode_client.cc
@@ -173,4 +173,9 @@
   NOTREACHED();
 }
 
+bool PreviewModeClient::IsValidLink(const std::string& url) {
+  NOTREACHED();
+  return false;
+}
+
 }  // namespace chrome_pdf
diff --git a/pdf/preview_mode_client.h b/pdf/preview_mode_client.h
index f388cb5..a5250c4 100644
--- a/pdf/preview_mode_client.h
+++ b/pdf/preview_mode_client.h
@@ -77,6 +77,7 @@
   uint32_t GetBackgroundColor() override;
   void SetSelectedText(const std::string& selected_text) override;
   void SetLinkUnderCursor(const std::string& link_under_cursor) override;
+  bool IsValidLink(const std::string& url) override;
 
  private:
   Client* const client_;
diff --git a/pdf/test/test_client.cc b/pdf/test/test_client.cc
index 6f7dfc4..2fd87a42 100644
--- a/pdf/test/test_client.cc
+++ b/pdf/test/test_client.cc
@@ -67,4 +67,8 @@
 
 void TestClient::SetLinkUnderCursor(const std::string& link_under_cursor) {}
 
+bool TestClient::IsValidLink(const std::string& url) {
+  return !url.empty();
+}
+
 }  // namespace chrome_pdf
diff --git a/pdf/test/test_client.h b/pdf/test/test_client.h
index 66d6223a05..6f62f17d 100644
--- a/pdf/test/test_client.h
+++ b/pdf/test/test_client.h
@@ -40,6 +40,7 @@
   float GetToolbarHeightInScreenCoords() override;
   void SetSelectedText(const std::string& selected_text) override;
   void SetLinkUnderCursor(const std::string& link_under_cursor) override;
+  bool IsValidLink(const std::string& url) override;
 
  private:
   // Not owned. Expected to dangle briefly, as the engine usually is destroyed
diff --git a/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java b/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java
index 9bb6b07..2175c6ae 100644
--- a/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java
+++ b/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java
@@ -82,6 +82,7 @@
      * @param intent The (implicit) intent to launch.
      * @return True if the intent was resolved.
      */
+    @SuppressWarnings("QueryPermissionsNeeded")
     public static boolean startActivitySafely(Context context, Intent intent) {
         if (intent.resolveActivity(context.getPackageManager()) == null) {
             Log.w(TAG, "Unable to resolve activity for: %s", intent);
diff --git a/services/network/cookie_access_delegate_impl.cc b/services/network/cookie_access_delegate_impl.cc
index b9900b8..44478b2 100644
--- a/services/network/cookie_access_delegate_impl.cc
+++ b/services/network/cookie_access_delegate_impl.cc
@@ -5,13 +5,16 @@
 #include "services/network/cookie_access_delegate_impl.h"
 
 #include "net/cookies/cookie_util.h"
+#include "services/network/first_party_sets/preloaded_first_party_sets.h"
 
 namespace network {
 
 CookieAccessDelegateImpl::CookieAccessDelegateImpl(
     mojom::CookieAccessDelegateType type,
+    const PreloadedFirstPartySets* preloaded_first_party_sets,
     const CookieSettings* cookie_settings)
     : type_(type), cookie_settings_(cookie_settings) {
+  // TODO(crbug.com/1143756): Save and use the PreloadedFirstPartySets.
   if (type == mojom::CookieAccessDelegateType::USE_CONTENT_SETTINGS) {
     DCHECK(cookie_settings);
   }
diff --git a/services/network/cookie_access_delegate_impl.h b/services/network/cookie_access_delegate_impl.h
index 88a2bc9..c5eb00a 100644
--- a/services/network/cookie_access_delegate_impl.h
+++ b/services/network/cookie_access_delegate_impl.h
@@ -13,6 +13,8 @@
 
 namespace network {
 
+class PreloadedFirstPartySets;
+
 // This class acts as a delegate for the CookieStore to query the
 // CookieManager's CookieSettings for instructions on how to handle a given
 // cookie with respect to SameSite.
@@ -22,9 +24,12 @@
   // If |type| is USE_CONTENT_SETTINGS, a non-null |cookie_settings| is
   // expected. |cookie_settings| contains the set of content settings that
   // describes which cookies should be subject to legacy access rules.
-  // If non-null, |cookie_settings| is expected to outlive this class.
-  CookieAccessDelegateImpl(mojom::CookieAccessDelegateType type,
-                           const CookieSettings* cookie_settings = nullptr);
+  // If non-null, |cookie_settings| is expected to outlive this class. If
+  // non-null, `preloaded_first_party_sets` must outlive `this`.
+  CookieAccessDelegateImpl(
+      mojom::CookieAccessDelegateType type,
+      const PreloadedFirstPartySets* preloaded_first_party_sets,
+      const CookieSettings* cookie_settings = nullptr);
 
   ~CookieAccessDelegateImpl() override;
 
diff --git a/services/network/cookie_manager.cc b/services/network/cookie_manager.cc
index c3b7148..595993a 100644
--- a/services/network/cookie_manager.cc
+++ b/services/network/cookie_manager.cc
@@ -45,6 +45,7 @@
 
 CookieManager::CookieManager(
     net::URLRequestContext* url_request_context,
+    const PreloadedFirstPartySets* preloaded_first_party_sets,
     scoped_refptr<SessionCleanupCookieStore> session_cleanup_cookie_store,
     mojom::CookieManagerParamsPtr params)
     : cookie_store_(url_request_context->cookie_store()),
@@ -60,6 +61,7 @@
   }
   cookie_store_->SetCookieAccessDelegate(
       std::make_unique<CookieAccessDelegateImpl>(cookie_access_delegate_type,
+                                                 preloaded_first_party_sets,
                                                  &cookie_settings_));
 }
 
diff --git a/services/network/cookie_manager.h b/services/network/cookie_manager.h
index 85566e9..bffe9be 100644
--- a/services/network/cookie_manager.h
+++ b/services/network/cookie_manager.h
@@ -22,11 +22,12 @@
 namespace net {
 class CookieStore;
 class URLRequestContext;
-}
+}  // namespace net
 
 class GURL;
 
 namespace network {
+class PreloadedFirstPartySets;
 class SessionCleanupCookieStore;
 
 // Wrap a cookie store in an implementation of the mojo cookie interface.
@@ -35,9 +36,11 @@
  public:
   // Construct a CookieService that can serve mojo requests for the underlying
   // cookie store.  |url_request_context->cookie_store()| must outlive this
-  // object.
+  // object. `*preloaded_first_party_sets` must outlive
+  // `url_request_context->cookie_store()`.
   CookieManager(
       net::URLRequestContext* url_request_context,
+      const PreloadedFirstPartySets* preloaded_first_party_sets,
       scoped_refptr<SessionCleanupCookieStore> session_cleanup_cookie_store,
       mojom::CookieManagerParamsPtr params);
 
diff --git a/services/network/cookie_manager_unittest.cc b/services/network/cookie_manager_unittest.cc
index bc3cc725..e28625c 100644
--- a/services/network/cookie_manager_unittest.cc
+++ b/services/network/cookie_manager_unittest.cc
@@ -343,7 +343,8 @@
     url_request_context_ = std::make_unique<net::URLRequestContext>();
     url_request_context_->set_cookie_store(cookie_monster_.get());
     cookie_service_ = std::make_unique<CookieManager>(
-        url_request_context_.get(), std::move(cleanup_store), nullptr);
+        url_request_context_.get(), nullptr /* preloaded_first_party_sets */,
+        std::move(cleanup_store), nullptr);
     cookie_service_->AddReceiver(
         cookie_service_remote_.BindNewPipeAndPassReceiver());
     service_wrapper_ = std::make_unique<SynchronousCookieManager>(
diff --git a/services/network/expect_ct_reporter.cc b/services/network/expect_ct_reporter.cc
index ff6bbf0d..5055242 100644
--- a/services/network/expect_ct_reporter.cc
+++ b/services/network/expect_ct_reporter.cc
@@ -230,11 +230,10 @@
     return;
   }
 
-  // TODO(https://crbug.com/993805):  Pass in preflight->network_isolation_key,
-  // once reporting API accepts NetworkIsolationKeys.
   report_sender_->Send(preflight->report_uri,
                        "application/expect-ct-report+json; charset=utf-8",
-                       preflight->serialized_report, success_callback_,
+                       preflight->serialized_report,
+                       preflight->network_isolation_key, success_callback_,
                        // Since |this| owns the |report_sender_|, it's safe to
                        // use base::Unretained here: |report_sender_| will be
                        // destroyed before |this|.
diff --git a/services/network/expect_ct_reporter_unittest.cc b/services/network/expect_ct_reporter_unittest.cc
index e2fc979..4eed0b4 100644
--- a/services/network/expect_ct_reporter_unittest.cc
+++ b/services/network/expect_ct_reporter_unittest.cc
@@ -52,6 +52,7 @@
       const GURL& report_uri,
       base::StringPiece content_type,
       base::StringPiece serialized_report,
+      const net::NetworkIsolationKey& network_isolation_key,
       base::OnceCallback<void()> success_callback,
       base::OnceCallback<void(const GURL&, int, int)> error_callback) override {
     sent_report_count_++;
@@ -59,6 +60,7 @@
     latest_serialized_report_.assign(serialized_report.data(),
                                      serialized_report.size());
     latest_content_type_.assign(content_type.data(), content_type.size());
+    latest_network_isolation_key_ = network_isolation_key;
     if (!report_callback_.is_null()) {
       EXPECT_EQ(expected_report_uri_, latest_report_uri_);
       std::move(report_callback_).Run();
@@ -77,6 +79,10 @@
     return latest_serialized_report_;
   }
 
+  const net::NetworkIsolationKey latest_network_isolation_key() const {
+    return latest_network_isolation_key_;
+  }
+
   // Can be called to wait for a single report, which is expected to be sent to
   // |report_uri|. Returns immediately if a report has already been sent in the
   // past.
@@ -96,6 +102,7 @@
   GURL latest_report_uri_;
   std::string latest_content_type_;
   std::string latest_serialized_report_;
+  net::NetworkIsolationKey latest_network_isolation_key_;
   base::OnceClosure report_callback_;
   GURL expected_report_uri_;
 };
@@ -440,11 +447,13 @@
 
     const GURL fail_report_uri = test_server().GetURL(fail_path);
     const GURL successful_report_uri = test_server().GetURL(successful_path);
+    const net::NetworkIsolationKey network_isolation_key =
+        net::NetworkIsolationKey::CreateTransient();
 
     reporter->OnExpectCTFailed(
         host_port, fail_report_uri, base::Time(), ssl_info.cert.get(),
         ssl_info.unverified_cert.get(), ssl_info.signed_certificate_timestamps,
-        net::NetworkIsolationKey());
+        network_isolation_key);
     bad_cors_run_loop.Run();
     // The CORS preflight response may not even have been received yet, so
     // these expectations are mostly aspirational.
@@ -459,9 +468,10 @@
     reporter->OnExpectCTFailed(
         host_port, successful_report_uri, base::Time(), ssl_info.cert.get(),
         ssl_info.unverified_cert.get(), ssl_info.signed_certificate_timestamps,
-        net::NetworkIsolationKey());
+        network_isolation_key);
     sender->WaitForReport(successful_report_uri);
     EXPECT_EQ(successful_report_uri, sender->latest_report_uri());
+    EXPECT_EQ(network_isolation_key, sender->latest_network_isolation_key());
     EXPECT_EQ(1, sender->sent_report_count());
   }
 
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index cc6cffc7..e56e718 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -408,7 +408,8 @@
                             session_cleanup_cookie_store);
   url_request_context_ = url_request_context_owner_.url_request_context.get();
   cookie_manager_ = std::make_unique<CookieManager>(
-      url_request_context_, std::move(session_cleanup_cookie_store),
+      url_request_context_, network_service_->preloaded_first_party_sets(),
+      std::move(session_cleanup_cookie_store),
       std::move(params_->cookie_manager_params));
 
   network_service_->RegisterNetworkContext(this);
@@ -464,9 +465,11 @@
           std::make_unique<NetworkContextApplicationStatusListener>()),
 #endif
       receiver_(this, std::move(receiver)),
-      cookie_manager_(std::make_unique<CookieManager>(url_request_context,
-                                                      nullptr,
-                                                      nullptr)),
+      cookie_manager_(std::make_unique<CookieManager>(
+          url_request_context,
+          nullptr,
+          nullptr /* preloaded_first_party_sets */,
+          nullptr)),
       socket_factory_(
           std::make_unique<SocketFactory>(url_request_context_->net_log(),
                                           url_request_context)),
diff --git a/services/network/network_service.h b/services/network/network_service.h
index f95a842..239319f 100644
--- a/services/network/network_service.h
+++ b/services/network/network_service.h
@@ -279,6 +279,10 @@
     return legacy_tls_config_distributor_.get();
   }
 
+  const PreloadedFirstPartySets* preloaded_first_party_sets() const {
+    return preloaded_first_party_sets_.get();
+  }
+
   bool os_crypt_config_set() const { return os_crypt_config_set_; }
 
   void set_host_resolver_factory_for_testing(
diff --git a/services/viz/public/cpp/compositing/mojom_traits_perftest.cc b/services/viz/public/cpp/compositing/mojom_traits_perftest.cc
index ec6e512..a740cc7 100644
--- a/services/viz/public/cpp/compositing/mojom_traits_perftest.cc
+++ b/services/viz/public/cpp/compositing/mojom_traits_perftest.cc
@@ -217,8 +217,9 @@
           pass_in->CreateAndAppendSharedQuadState();
       shared_state1_in->SetAll(
           arbitrary_matrix1, arbitrary_rect1, arbitrary_rect1,
-          arbitrary_rrectf1, arbitrary_rect2, arbitrary_bool1, arbitrary_bool1,
-          arbitrary_float1, arbitrary_blend_mode1, arbitrary_context_id1);
+          gfx::MaskFilterInfo(arbitrary_rrectf1), arbitrary_rect2,
+          arbitrary_bool1, arbitrary_bool1, arbitrary_float1,
+          arbitrary_blend_mode1, arbitrary_context_id1);
 
       auto* texture_in = pass_in->CreateAndAppendDrawQuad<TextureDrawQuad>();
       texture_in->SetAll(
@@ -259,8 +260,9 @@
           pass_in->CreateAndAppendSharedQuadState();
       shared_state2_in->SetAll(
           arbitrary_matrix2, arbitrary_rect2, arbitrary_rect2,
-          arbitrary_rrectf2, arbitrary_rect3, arbitrary_bool1, arbitrary_bool1,
-          arbitrary_float2, arbitrary_blend_mode2, arbitrary_context_id2);
+          gfx::MaskFilterInfo(arbitrary_rrectf2), arbitrary_rect3,
+          arbitrary_bool1, arbitrary_bool1, arbitrary_float2,
+          arbitrary_blend_mode2, arbitrary_context_id2);
       for (uint32_t j = 0; j < 6; ++j) {
         auto* tile_in = pass_in->CreateAndAppendDrawQuad<TileDrawQuad>();
         tile_in->SetAll(
@@ -276,8 +278,9 @@
           pass_in->CreateAndAppendSharedQuadState();
       shared_state3_in->SetAll(
           arbitrary_matrix1, arbitrary_rect3, arbitrary_rect3,
-          arbitrary_rrectf3, arbitrary_rect1, arbitrary_bool1, arbitrary_bool1,
-          arbitrary_float3, arbitrary_blend_mode3, arbitrary_context_id3);
+          gfx::MaskFilterInfo(arbitrary_rrectf3), arbitrary_rect1,
+          arbitrary_bool1, arbitrary_bool1, arbitrary_float3,
+          arbitrary_blend_mode3, arbitrary_context_id3);
       for (uint32_t j = 0; j < 5; ++j) {
         auto* solidcolor_in =
             pass_in->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
diff --git a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
index 90e3b112..1e01871 100644
--- a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
@@ -416,7 +416,8 @@
                                                 13.f, 14.f, 15.f, 16.f);
   const gfx::Rect layer_rect(1234, 5678);
   const gfx::Rect visible_layer_rect(12, 34, 56, 78);
-  const gfx::RRectF rounded_corner_bounds(gfx::RectF(1.f, 2.f, 30.f, 40.f), 5);
+  const gfx::MaskFilterInfo mask_filter_info(
+      gfx::RRectF(gfx::RectF(1.f, 2.f, 30.f, 40.f), 5));
   const gfx::Rect clip_rect(123, 456, 789, 101112);
   const bool is_clipped = true;
   bool are_contents_opaque = true;
@@ -426,9 +427,8 @@
   bool is_fast_rounded_corner = true;
   SharedQuadState input_sqs;
   input_sqs.SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
-                   rounded_corner_bounds, clip_rect, is_clipped,
-                   are_contents_opaque, opacity, blend_mode,
-                   sorting_context_id);
+                   mask_filter_info, clip_rect, is_clipped, are_contents_opaque,
+                   opacity, blend_mode, sorting_context_id);
   input_sqs.is_fast_rounded_corner = is_fast_rounded_corner;
   SharedQuadState output_sqs;
   mojo::test::SerializeAndDeserialize<mojom::SharedQuadState>(&input_sqs,
@@ -436,7 +436,8 @@
   EXPECT_EQ(quad_to_target_transform, output_sqs.quad_to_target_transform);
   EXPECT_EQ(layer_rect, output_sqs.quad_layer_rect);
   EXPECT_EQ(visible_layer_rect, output_sqs.visible_quad_layer_rect);
-  EXPECT_EQ(rounded_corner_bounds, output_sqs.rounded_corner_bounds);
+  EXPECT_EQ(mask_filter_info.rounded_corner_bounds(),
+            output_sqs.mask_filter_info.rounded_corner_bounds());
   EXPECT_EQ(clip_rect, output_sqs.clip_rect);
   EXPECT_EQ(is_clipped, output_sqs.is_clipped);
   EXPECT_EQ(opacity, output_sqs.opacity);
@@ -459,8 +460,8 @@
       15.f, 16.f);
   const gfx::Rect sqs_layer_rect(1234, 5678);
   const gfx::Rect sqs_visible_layer_rect(12, 34, 56, 78);
-  const gfx::RRectF sqs_rounded_corner_bounds(gfx::RectF(3.f, 4.f, 50.f, 15.f),
-                                              3);
+  const gfx::MaskFilterInfo sqs_mask_filter_info(
+      gfx::RRectF(gfx::RectF(3.f, 4.f, 50.f, 15.f), 3));
   const gfx::Rect sqs_clip_rect(123, 456, 789, 101112);
   const bool sqs_is_clipped = true;
   bool sqs_are_contents_opaque = false;
@@ -469,7 +470,7 @@
   const int sqs_sorting_context_id = 1337;
   SharedQuadState* sqs = render_pass->CreateAndAppendSharedQuadState();
   sqs->SetAll(sqs_quad_to_target_transform, sqs_layer_rect,
-              sqs_visible_layer_rect, sqs_rounded_corner_bounds, sqs_clip_rect,
+              sqs_visible_layer_rect, sqs_mask_filter_info, sqs_clip_rect,
               sqs_is_clipped, sqs_are_contents_opaque, sqs_opacity,
               sqs_blend_mode, sqs_sorting_context_id);
 
@@ -544,7 +545,7 @@
   EXPECT_EQ(sqs_quad_to_target_transform, out_sqs->quad_to_target_transform);
   EXPECT_EQ(sqs_layer_rect, out_sqs->quad_layer_rect);
   EXPECT_EQ(sqs_visible_layer_rect, out_sqs->visible_quad_layer_rect);
-  EXPECT_EQ(sqs_rounded_corner_bounds, out_sqs->rounded_corner_bounds);
+  EXPECT_EQ(sqs_mask_filter_info, out_sqs->mask_filter_info);
   EXPECT_EQ(sqs_clip_rect, out_sqs->clip_rect);
   EXPECT_EQ(sqs_is_clipped, out_sqs->is_clipped);
   EXPECT_EQ(sqs_are_contents_opaque, out_sqs->are_contents_opaque);
@@ -723,7 +724,7 @@
       gfx::Transform(16.1f, 15.3f, 14.3f, 13.7f, 12.2f, 11.4f, 10.4f, 9.8f,
                      8.1f, 7.3f, 6.3f, 5.7f, 4.8f, 3.4f, 2.4f, 1.2f),
       gfx::Rect(1, 2), gfx::Rect(1337, 5679, 9101112, 131415),
-      gfx::RRectF(gfx::RectF(5.f, 6.f, 70.f, 89.f), 10.f),
+      gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(5.f, 6.f, 70.f, 89.f), 10.f)),
       gfx::Rect(1357, 2468, 121314, 1337), true, true, 2, SkBlendMode::kSrcOver,
       1);
 
@@ -732,7 +733,7 @@
       gfx::Transform(1.1f, 2.3f, 3.3f, 4.7f, 5.2f, 6.4f, 7.4f, 8.8f, 9.1f,
                      10.3f, 11.3f, 12.7f, 13.8f, 14.4f, 15.4f, 16.2f),
       gfx::Rect(1337, 1234), gfx::Rect(1234, 5678, 9101112, 13141516),
-      gfx::RRectF(gfx::RectF(23.f, 45.f, 60.f, 70.f), 8.f),
+      gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(23.f, 45.f, 60.f, 70.f), 8.f)),
       gfx::Rect(1357, 2468, 121314, 1337), true, true, 2, SkBlendMode::kSrcOver,
       1);
 
@@ -792,8 +793,7 @@
   EXPECT_EQ(shared_state_1->quad_layer_rect, out_sqs1->quad_layer_rect);
   EXPECT_EQ(shared_state_1->visible_quad_layer_rect,
             out_sqs1->visible_quad_layer_rect);
-  EXPECT_EQ(shared_state_1->rounded_corner_bounds,
-            out_sqs1->rounded_corner_bounds);
+  EXPECT_EQ(shared_state_1->mask_filter_info, out_sqs1->mask_filter_info);
   EXPECT_EQ(shared_state_1->clip_rect, out_sqs1->clip_rect);
   EXPECT_EQ(shared_state_1->is_clipped, out_sqs1->is_clipped);
   EXPECT_EQ(shared_state_1->opacity, out_sqs1->opacity);
@@ -806,8 +806,7 @@
   EXPECT_EQ(shared_state_2->quad_layer_rect, out_sqs2->quad_layer_rect);
   EXPECT_EQ(shared_state_2->visible_quad_layer_rect,
             out_sqs2->visible_quad_layer_rect);
-  EXPECT_EQ(shared_state_2->rounded_corner_bounds,
-            out_sqs2->rounded_corner_bounds);
+  EXPECT_EQ(shared_state_2->mask_filter_info, out_sqs2->mask_filter_info);
   EXPECT_EQ(shared_state_2->clip_rect, out_sqs2->clip_rect);
   EXPECT_EQ(shared_state_2->is_clipped, out_sqs2->is_clipped);
   EXPECT_EQ(shared_state_2->opacity, out_sqs2->opacity);
diff --git a/services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h b/services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h
index 830191111..5bbe76a 100644
--- a/services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h
+++ b/services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h
@@ -7,6 +7,7 @@
 
 #include "components/viz/common/quads/shared_quad_state.h"
 #include "services/viz/public/mojom/compositing/shared_quad_state.mojom-shared.h"
+#include "ui/gfx/mojom/mask_filter_info_mojom_traits.h"
 #include "ui/gfx/mojom/rrect_f_mojom_traits.h"
 
 namespace mojo {
@@ -35,9 +36,9 @@
     return input.sqs->visible_quad_layer_rect;
   }
 
-  static const gfx::RRectF& rounded_corner_bounds(
+  static const gfx::MaskFilterInfo& mask_filter_info(
       const OptSharedQuadState& input) {
-    return input.sqs->rounded_corner_bounds;
+    return input.sqs->mask_filter_info;
   }
 
   static const gfx::Rect& clip_rect(const OptSharedQuadState& input) {
@@ -93,9 +94,9 @@
     return sqs.visible_quad_layer_rect;
   }
 
-  static const gfx::RRectF& rounded_corner_bounds(
+  static const gfx::MaskFilterInfo& mask_filter_info(
       const viz::SharedQuadState& sqs) {
-    return sqs.rounded_corner_bounds;
+    return sqs.mask_filter_info;
   }
 
   static const gfx::Rect& clip_rect(const viz::SharedQuadState& sqs) {
@@ -137,7 +138,7 @@
     if (!data.ReadQuadToTargetTransform(&out->quad_to_target_transform) ||
         !data.ReadQuadLayerRect(&out->quad_layer_rect) ||
         !data.ReadVisibleQuadLayerRect(&out->visible_quad_layer_rect) ||
-        !data.ReadRoundedCornerBounds(&out->rounded_corner_bounds) ||
+        !data.ReadMaskFilterInfo(&out->mask_filter_info) ||
         !data.ReadClipRect(&out->clip_rect)) {
       return false;
     }
diff --git a/services/viz/public/mojom/compositing/shared_quad_state.mojom b/services/viz/public/mojom/compositing/shared_quad_state.mojom
index 214f508b..98ba301 100644
--- a/services/viz/public/mojom/compositing/shared_quad_state.mojom
+++ b/services/viz/public/mojom/compositing/shared_quad_state.mojom
@@ -7,6 +7,7 @@
 import "ui/gfx/geometry/mojom/geometry.mojom";
 import "ui/gfx/mojom/rrect_f.mojom";
 import "ui/gfx/mojom/transform.mojom";
+import "ui/gfx/mojom/mask_filter_info.mojom";
 
 // See viz::SharedQuadState.
 struct SharedQuadState {
@@ -20,9 +21,10 @@
   // of the quad rects.
   gfx.mojom.Rect visible_quad_layer_rect;
 
-  // This rect lives in the target content space. It defines the corner radius
-  // to clip the quads with.
-  gfx.mojom.RRectF rounded_corner_bounds;
+  // This rect lives in the target content space. It defines the mask filter
+  // info applied to the quad, and also defines rounded corner rects to clip the
+  // quads with.
+  gfx.mojom.MaskFilterInfo mask_filter_info;
 
   // This rect lives in the target content space.
   gfx.mojom.Rect clip_rect;
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index 88aceba..4065c097 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -5342,30 +5342,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04",
-              "pool": "chrome.tests",
-              "ssd": "0"
-            }
-          ],
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5518,29 +5494,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04",
-              "pool": "chrome.tests",
-              "ssd": "0"
-            }
-          ],
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5735,31 +5688,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--gtest_filter=-SadTabViewInteractiveUITest.ReloadMultipleSadTabs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04",
-              "pool": "chrome.tests",
-              "ssd": "0"
-            }
-          ],
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 83ccf5d..cf265b401 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -1819,28 +1819,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -1977,27 +1955,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -2169,28 +2126,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -3484,29 +3419,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -3651,28 +3563,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -3854,29 +3744,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -5104,25 +4971,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--gtest_filter=-OutOfProcessPPAPITest.TrueTypeFont:All/AccessibilityHitTestingBrowserTest.CachingAsyncHitTest_WithPinchZoom*:All/SitePerProcessInternalsHitTestBrowserTest.ScrollNestedLocalNonFastScrollableDiv*:BackForwardCacheBrowserTest.WindowOpen"
-        ],
-        "experiment_percentage": 100,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5211,23 +5059,6 @@
       },
       {
         "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--gtest_filter=-BluetoothShellApiTest.ApiSanityCheck:BluetoothSocketApiTest.Listen:BluetoothSocketApiTest.PermissionDenied"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "args": [
           "--gtest_filter=-NativeExtensionBindingsSystemUnittest*:BluetoothSocketApiUnittest.CreateThenClose:FeatureProviderTest.PermissionFeatureAvailability"
         ],
         "merge": {
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 0e35ca06..8427bd0 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -12054,28 +12054,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -12246,27 +12224,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -12455,28 +12412,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -13759,29 +13694,6 @@
       },
       {
         "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "merge": {
@@ -13982,28 +13894,6 @@
       },
       {
         "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "merge": {
@@ -14205,29 +14095,6 @@
       },
       {
         "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "merge": {
@@ -15580,28 +15447,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -15772,27 +15617,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -15981,28 +15805,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -17194,28 +16996,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -17386,27 +17166,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -17595,28 +17354,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18807,28 +18544,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18982,27 +18697,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -19191,28 +18885,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -20423,28 +20095,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -20615,27 +20265,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -20824,28 +20453,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -22054,28 +21661,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -22246,27 +21831,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -22455,28 +22019,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -43641,28 +43183,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -43833,27 +43353,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -44042,28 +43541,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 0b988b1..6114bb0 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -50714,29 +50714,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -50881,28 +50858,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -51084,29 +51039,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -52401,28 +52333,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -52593,27 +52503,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -52802,28 +52691,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -54472,29 +54339,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -54675,28 +54519,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -54896,29 +54718,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -56660,28 +56459,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -56852,27 +56629,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -57061,28 +56817,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -58297,29 +58031,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04",
-              "ssd": "0"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -58446,28 +58157,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04",
-              "ssd": "0"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -58631,29 +58320,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04",
-              "ssd": "0"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 67306946..894c602 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -5586,29 +5586,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -5789,28 +5766,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -6010,29 +5965,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -7727,28 +7659,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -7919,27 +7829,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -8128,28 +8017,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -9836,28 +9703,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -10028,27 +9873,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -10237,28 +10061,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 2252e4f..5d9c6d2 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -7172,29 +7172,6 @@
       },
       {
         "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "merge": {
@@ -7355,28 +7332,6 @@
       },
       {
         "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "merge": {
@@ -7558,29 +7513,6 @@
       },
       {
         "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "merge": {
@@ -9129,30 +9061,6 @@
       },
       {
         "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "merge": {
@@ -9322,29 +9230,6 @@
       },
       {
         "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "merge": {
@@ -9535,30 +9420,6 @@
       },
       {
         "args": [
-          "--enable-features=StorageServiceOutOfProcess",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "merge": {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index f1826f0c..94e8fff 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -2145,30 +2145,6 @@
         "test_id_prefix": "ninja://content/test:content_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-18363"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -2397,29 +2373,6 @@
         "test_id_prefix": "ninja://extensions:extensions_browsertests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-18363"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -2688,30 +2641,6 @@
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
       },
       {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-18363"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
         "isolate_profile_data": true,
         "merge": {
           "args": [],
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index b7fc8698..efa7aaca0 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2490,53 +2490,6 @@
       }
     }
   },
-  'storage_service_content_browsertests': {
-    'modifications': {
-      'Linux Tests (dbg)(1)': {
-        'swarming': {
-          'shards': 4,
-        },
-      },
-      'linux-chromeos-dbg': {
-        'swarming': {
-          'shards': 6,
-        },
-      },
-      # https://crbug.com/1111979,
-      'linux-lacros-tester-rel': {
-        'experiment_percentage': 100,
-        'args': [
-          '--gtest_filter=-OutOfProcessPPAPITest.TrueTypeFont:'
-          'All/AccessibilityHitTestingBrowserTest.CachingAsyncHitTest_WithPinchZoom*:'
-          'All/SitePerProcessInternalsHitTestBrowserTest.ScrollNestedLocalNonFastScrollableDiv*:'
-          'BackForwardCacheBrowserTest.WindowOpen',
-        ],
-      },
-    },
-  },
-  'storage_service_extensions_browsertests': {
-    'modifications': {
-      # https://crbug.com/1111979,
-      'linux-lacros-tester-rel': {
-        'args': [
-          '--gtest_filter=-BluetoothShellApiTest.ApiSanityCheck:BluetoothSocketApiTest.Listen:BluetoothSocketApiTest.PermissionDenied',
-        ],
-      },
-    },
-  },
-  'storage_service_interactive_ui_tests': {
-    'remove_from': [
-      'linux-lacros-tester-rel', # https://crbug.com/1111979
-    ],
-    'modifications': {
-      'linux-chromeos-chrome': {
-        # TODO(crbug.com/970649): Remove this filter.
-        'args': [
-          '--gtest_filter=-SadTabViewInteractiveUITest.ReloadMultipleSadTabs',
-        ],
-      },
-    }
-  },
   'swiftshader_unittests': {
     'remove_from': [
       # Save capacity on the hardware where we have only a few machines.
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 30e664a..77a2fd18 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -4054,34 +4054,6 @@
         'results_handler': 'layout tests',
       },
     },
-    # TODO(https://crbug.com/1057802): Remove these tests once Out-of-Process
-    # Storage is on by default.
-    'storage_service_gtests': {
-      'storage_service_content_browsertests': {
-        'args': [
-          '--enable-features=StorageServiceOutOfProcess',
-        ],
-        'swarming': {
-          'shards': 2,
-        },
-        'test': 'content_browsertests',
-      },
-      'storage_service_extensions_browsertests': {
-        'args': [
-          '--enable-features=StorageServiceOutOfProcess',
-        ],
-        'test': 'extensions_browsertests',
-      },
-      'storage_service_interactive_ui_tests': {
-        'args': [
-          '--enable-features=StorageServiceOutOfProcess'
-        ],
-        'swarming': {
-          'shards': 3,
-        },
-        'test': 'interactive_ui_tests',
-      },
-    },
 
     'swangle_gtests': {
       'angle_deqp_egl_tests': {
@@ -4874,7 +4846,6 @@
       'linux_specific_xr_gtests',
       'non_android_and_cast_and_chromeos_chromium_gtests',
       'non_android_chromium_gtests',
-      'storage_service_gtests',
       'vr_platform_specific_chromium_gtests',
       'weblayer_gtests',
     ],
@@ -4938,7 +4909,6 @@
       'non_android_chromium_gtests_skia_gold',
       'non_skia_renderer_gtests',
       'pixel_browser_tests_gtests',
-      'storage_service_gtests',
       'vr_platform_specific_chromium_gtests',
       'weblayer_gtests',
       'win_specific_chromium_gtests',
@@ -5586,7 +5556,6 @@
       'linux_chromeos_specific_gtests',
       'linux_flavor_specific_chromium_gtests',
       'non_android_chromium_gtests',
-      'storage_service_gtests',
     ],
 
     'linux_chromeos_gtests_oobe': [
@@ -5599,7 +5568,6 @@
       'linux_chromeos_specific_gtests',
       'linux_flavor_specific_chromium_gtests',
       'non_android_chromium_gtests',
-      'storage_service_gtests',
     ],
 
     'linux_lacros_gtests': [
@@ -5615,7 +5583,6 @@
       'linux_flavor_specific_chromium_gtests',
       'linux_lacros_specific_gtests',
       'non_android_chromium_gtests',
-      'storage_service_gtests',
     ],
 
     'linux_viz_gtests': [
diff --git a/testing/scripts/run_wpt_tests.py b/testing/scripts/run_wpt_tests.py
index 41802641..d04e0de 100755
--- a/testing/scripts/run_wpt_tests.py
+++ b/testing/scripts/run_wpt_tests.py
@@ -36,6 +36,7 @@
 CHROME_BINARY = "../../out/{}/chrome"
 CHROMEDRIVER_BINARY = "../../out/{}/chromedriver"
 
+DEFAULT_ISOLATED_SCRIPT_TEST_OUTPUT = "../../out/{}/results.json"
 MOJO_JS_PATH = "../../out/{}/gen/"
 
 class WPTTestAdapter(wpt_common.BaseWptScriptAdapter):
@@ -43,8 +44,11 @@
     @property
     def rest_args(self):
         rest_args = super(WPTTestAdapter, self).rest_args
+
+        # Update the output directory to the default if it's not set.
+        self.maybe_set_default_isolated_script_test_output()
+
         # Here we add all of the arguments required to run WPT tests on Chrome.
-        target_dir = self.options.target
         rest_args.extend([
             "../../third_party/blink/web_tests/external/wpt/wpt",
             "--venv=../../",
@@ -52,13 +56,14 @@
             "run",
             "chrome"
         ] + self.options.test_list + [
-            "--binary=" + CHROME_BINARY.format(target_dir),
+            "--binary=" + CHROME_BINARY.format(self.options.target),
             "--binary-arg=--host-resolver-rules="
                 "MAP nonexistent.*.test ~NOTFOUND, MAP *.test 127.0.0.1",
             "--binary-arg=--enable-experimental-web-platform-features",
             "--binary-arg=--enable-blink-test-features",
             "--binary-arg=--enable-blink-features=MojoJS,MojoJSTest",
-            "--webdriver-binary=" + CHROMEDRIVER_BINARY.format(target_dir),
+            "--webdriver-binary=" + CHROMEDRIVER_BINARY.format(
+                self.options.target),
             "--webdriver-arg=--enable-chrome-logs",
             "--headless",
             "--no-capture-stdio",
@@ -72,7 +77,7 @@
             # it uses the exit code to determine which shards to retry (ie:
             # those that had non-zero exit codes).
             #"--no-fail-on-unexpected",
-            "--metadata", WPT_METADATA_OUTPUT_DIR.format(target_dir),
+            "--metadata", WPT_METADATA_OUTPUT_DIR.format(self.options.target),
             # By specifying metadata above, WPT will try to find manifest in the
             # metadata directory. So here we point it back to the correct path
             # for the manifest.
@@ -82,7 +87,7 @@
             # a lengthy import/export cycle to refresh. So we allow WPT to
             # update the manifest in cast it's stale.
             #"--no-manifest-update",
-            "--manifest", WPT_WORKING_COPY_MANIFEST.format(target_dir),
+            "--manifest", WPT_WORKING_COPY_MANIFEST.format(self.options.target),
             # (crbug.com/1023835) The flags below are temporary to aid debugging
             "--log-mach=-",
             "--log-mach-verbose",
@@ -90,7 +95,7 @@
             # TODO(lpz): Consider removing --processes and compute automatically
             # from multiprocessing.cpu_count()
             #"--processes=5",
-            "--mojojs-path=" + MOJO_JS_PATH.format(target_dir),
+            "--mojojs-path=" + MOJO_JS_PATH.format(self.options.target),
         ])
         return rest_args
 
@@ -101,6 +106,15 @@
         parser.add_argument("test_list", nargs="*",
                             help="List of tests or test directories to run")
 
+    def maybe_set_default_isolated_script_test_output(self):
+        if self.options.isolated_script_test_output:
+            return
+        default_value = DEFAULT_ISOLATED_SCRIPT_TEST_OUTPUT.format(
+            self.options.target)
+        print("--isolated-script-test-output not set, defaulting to %s" %
+              default_value)
+        self.options.isolated_script_test_output = default_value
+
     def do_pre_test_run_tasks(self):
         # Copy the checked-in manifest to the temporary working directory
         shutil.copy(WPT_CHECKED_IN_MANIFEST,
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 592ade06..ecf6ce8 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1788,6 +1788,23 @@
             ]
         }
     ],
+    "ContentCaptureConstantStreaming": [
+        {
+            "platforms": [
+                "android",
+                "android_weblayer",
+                "android_webview"
+            ],
+            "experiments": [
+                {
+                    "name": "ContentCaptureConstantStreaming",
+                    "enable_features": [
+                        "ContentCaptureConstantStreaming"
+                    ]
+                }
+            ]
+        }
+    ],
     "ContentCaptureExperiment": [
         {
             "platforms": [
@@ -2762,6 +2779,25 @@
             ]
         }
     ],
+    "EnhancedProtectionPromoCard": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "params": {
+                        "EnhancedProtectionPromoMaxImpressionsAndroid": "13",
+                        "SigninPromoMaxImpressionsAndroid": "13"
+                    },
+                    "enable_features": [
+                        "EnhancedProtectionPromoCard"
+                    ]
+                }
+            ]
+        }
+    ],
     "EnterpriseReportingInChromeOS": [
         {
             "platforms": [
@@ -4101,25 +4137,6 @@
             ]
         }
     ],
-    "LookalikeInterstitialForPunycode": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "LookalikeInterstitialForPunycode"
-                    ]
-                }
-            ]
-        }
-    ],
     "LowPriorityAdProcesses": [
         {
             "platforms": [
@@ -4323,6 +4340,26 @@
             ]
         }
     ],
+    "MetricsDownsampleConsistently": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "ios",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "MetricsDownsampleConsistently"
+                    ]
+                }
+            ]
+        }
+    ],
     "MixedFormWarnings": [
         {
             "platforms": [
diff --git a/third_party/android_sdk/README.chromium b/third_party/android_sdk/README.chromium
index 7d15c68..ab66ba5 100644
--- a/third_party/android_sdk/README.chromium
+++ b/third_party/android_sdk/README.chromium
@@ -2,7 +2,7 @@
 URL: http://developer.android.com/sdk/index.html
 Version: 30
   Android SDK Build-tools 30.0.1
-  Android SDK Command-line Tools 2.1
+  Android SDK Command-line Tools 3.0
   Android SDK Emulator 30.0.12
   Android SDK Platform-tools 30.0.3
   Android SDK Platform API 30
diff --git a/third_party/androidx/fetch_all_androidx.py b/third_party/androidx/fetch_all_androidx.py
index 8bd85453..b409861 100755
--- a/third_party/androidx/fetch_all_androidx.py
+++ b/third_party/androidx/fetch_all_androidx.py
@@ -163,6 +163,7 @@
     data_files = ['BUILD.gn', 'additional_readme_paths.json']
     for lib_dir in lib_dirs:
         abs_lib_dir = os.path.join(libs_dir, lib_dir)
+        androidx_rel_lib_dir = os.path.relpath(abs_lib_dir, _ANDROIDX_PATH)
         if not os.path.isdir(abs_lib_dir):
             continue
         lib_files = os.listdir(abs_lib_dir)
@@ -173,13 +174,15 @@
             raise Exception('README.chromium not in {}'.format(abs_lib_dir))
         if not 'LICENSE' in lib_files:
             raise Exception('LICENSE not in {}'.format(abs_lib_dir))
-        data_files.append(os.path.join(abs_lib_dir, 'README.chromium'))
-        data_files.append(os.path.join(abs_lib_dir, 'LICENSE'))
+        data_files.append(os.path.join(androidx_rel_lib_dir,
+                                       'README.chromium'))
+        data_files.append(os.path.join(androidx_rel_lib_dir, 'LICENSE'))
 
         _rel_extracted_files = _extract_files_from_yaml(
             os.path.join(abs_lib_dir, 'cipd.yaml'))
         data_files.extend(
-            os.path.join(abs_lib_dir, f) for f in _rel_extracted_files)
+            os.path.join(androidx_rel_lib_dir, f)
+            for f in _rel_extracted_files)
 
     contents = [
         '# Copyright 2020 The Chromium Authors. All rights reserved.',
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index bf9f239..123c76d 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -176,11 +176,6 @@
 const base::Feature kRawClipboard{"RawClipboard",
                                   base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables usage of getDisplayMedia() that allows capture of web content, see
-// https://crbug.com/865060.
-const base::Feature kRTCGetDisplayMedia{"RTCGetDisplayMedia",
-                                        base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Changes the default RTCPeerConnection constructor behavior to use Unified
 // Plan as the SDP semantics. When the feature is enabled, Unified Plan is used
 // unless the default is overridden (by passing {sdpSemantics:'plan-b'} as the
@@ -749,6 +744,10 @@
 const base::Feature kReducedReferrerGranularity{
     "ReducedReferrerGranularity", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables the constant streaming in the ContentCapture task.
+const base::Feature kContentCaptureConstantStreaming = {
+    "ContentCaptureConstantStreaming", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables the user activated exponential delay in the ContentCapture task.
 const base::Feature kContentCaptureUserActivatedDelay = {
     "ContentCaptureUserActivatedDelay", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/third_party/blink/perf_tests/layout/nested-grid-lots-of-tracks.html b/third_party/blink/perf_tests/layout/nested-grid-lots-of-tracks.html
new file mode 100644
index 0000000..e09d3574
--- /dev/null
+++ b/third_party/blink/perf_tests/layout/nested-grid-lots-of-tracks.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<style>
+.grid {
+  display: grid;
+}
+.grid > div {
+  grid-area: 1 / 1 / -1 / -1;
+}
+.auto {
+  grid-template: repeat(100, auto) / repeat(100, auto);
+}
+.min-content {
+  grid-template: repeat(100, min-content) / repeat(100, min-content);
+}
+.max-content {
+  grid-template: repeat(100, max-content) / repeat(100, max-content);
+}
+.flex {
+  grid-template: repeat(100, 1fr) / repeat(100, 1fr);
+}
+.percent {
+  grid-template: repeat(100, 1%) / repeat(100, 1%);
+}
+.length {
+  grid-template: repeat(100, 1px) / repeat(100, 1px);
+}
+</style>
+<template id="template">
+  <div class="grid auto">
+    <div class="grid min-content">
+      <div class="grid max-content">
+        <div class="grid flex">
+          <div class="grid percent">
+            <div class="grid length">
+              <div class="grid auto">
+                <div class="grid min-content">
+                  <div class="grid max-content">
+                    <div class="grid flex">
+                      <div class="grid percent">
+                        <div class="grid length">
+                          <div>Inner content</div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script src="../resources/runner.js"></script>
+<script>
+'use strict';
+function startTest() {
+  let prototype = document.getElementById("template").content.firstElementChild;
+  let testcase;
+  PerfTestRunner.measureRunsPerSecond({
+    description: "Measures performance of layout on a page using nested grids with lots of tracks.",
+    setup() {
+      testcase = prototype.cloneNode(true);
+      document.body.appendChild(testcase);
+    },
+    run() {
+      testcase.style.display = "none";
+      PerfTestRunner.forceLayout();
+      testcase.style.display = "";
+      PerfTestRunner.forceLayout();
+    },
+  });
+}
+</script>
+<body onload="startTest()"></body>
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 764f8f5b9..80c7329 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -49,7 +49,6 @@
 BLINK_COMMON_EXPORT extern const base::Feature
     kPurgeRendererMemoryWhenBackgrounded;
 BLINK_COMMON_EXPORT extern const base::Feature kRawClipboard;
-BLINK_COMMON_EXPORT extern const base::Feature kRTCGetDisplayMedia;
 BLINK_COMMON_EXPORT extern const base::Feature kRTCUnifiedPlanByDefault;
 BLINK_COMMON_EXPORT extern const base::Feature kRTCOfferExtmapAllowMixed;
 BLINK_COMMON_EXPORT extern const base::Feature kRTCGpuCodecSupportWaiter;
@@ -300,6 +299,8 @@
 
 BLINK_COMMON_EXPORT extern const base::Feature kReducedReferrerGranularity;
 
+BLINK_COMMON_EXPORT extern const base::Feature kContentCaptureConstantStreaming;
+
 BLINK_COMMON_EXPORT extern const base::Feature
     kContentCaptureUserActivatedDelay;
 
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
index 9f666b41..d36cb64 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
@@ -49,7 +49,6 @@
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
 #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
-#include "third_party/blink/renderer/platform/heap/unified_heap_controller.h"
 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
diff --git a/third_party/blink/renderer/core/content_capture/content_capture_test.cc b/third_party/blink/renderer/core/content_capture/content_capture_test.cc
index 0f80905..5b052134 100644
--- a/third_party/blink/renderer/core/content_capture/content_capture_test.cc
+++ b/third_party/blink/renderer/core/content_capture/content_capture_test.cc
@@ -23,13 +23,57 @@
 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
 
 namespace blink {
 
 namespace {
+
 gfx::Rect GetRect(LayoutObject* layout_object) {
   return gfx::Rect(EnclosingIntRect(layout_object->VisualRectInDocument()));
 }
+
+void FindNodeVectorsDiff(const Vector<Persistent<Node>>& a,
+                         const Vector<Persistent<Node>>& b,
+                         Vector<Persistent<Node>>& a_diff_b) {
+  for (auto& i : a) {
+    if (!b.Contains(i))
+      a_diff_b.push_back(i);
+  }
+}
+
+void FindNodeVectorsDiff(const Vector<Persistent<Node>>& a,
+                         const Vector<Persistent<Node>>& b,
+                         Vector<Persistent<Node>>& a_diff_b,
+                         Vector<Persistent<Node>>& b_diff_a) {
+  FindNodeVectorsDiff(a, b, a_diff_b);
+  FindNodeVectorsDiff(b, a, b_diff_a);
+}
+
+void FindNodeVectorsUnion(const Vector<Persistent<Node>>& a,
+                          const Vector<Persistent<Node>>& b,
+                          HashSet<Persistent<Node>>& a_and_b) {
+  for (auto& n : a) {
+    a_and_b.insert(n);
+  }
+  for (auto& n : b) {
+    a_and_b.insert(n);
+  }
+}
+
+void ToNodeIds(const Vector<Persistent<Node>>& nodes,
+               Vector<int64_t>& node_ids) {
+  for (auto& v : nodes) {
+    node_ids.push_back(reinterpret_cast<int64_t>(static_cast<Node*>(v)));
+  }
+}
+
+void ToNodeTexts(const Vector<Persistent<Node>>& nodes,
+                 Vector<std::string>& texts) {
+  for (auto& n : nodes)
+    texts.push_back(n->nodeValue().Utf8());
+}
+
 }  // namespace
 
 class WebContentCaptureClientTestHelper : public WebContentCaptureClient {
@@ -54,8 +98,11 @@
                          bool first_data) override {
     data_ = data;
     first_data_ = first_data;
-    for (auto& d : data)
-      all_text_.push_back(d.GetValue().Utf8());
+    for (auto& d : data) {
+      auto text = d.GetValue().Utf8();
+      all_text_.push_back(text);
+      captured_text_.push_back(text);
+    }
   }
 
   void DidUpdateContent(const WebVector<WebContentHolder>& data) override {
@@ -78,6 +125,8 @@
 
   const Vector<std::string>& AllText() const { return all_text_; }
 
+  const Vector<std::string>& CapturedText() const { return captured_text_; }
+
   const Vector<std::string>& UpdatedText() const { return updated_text_; }
 
   const WebVector<int64_t>& RemovedData() const { return removed_data_; }
@@ -87,6 +136,7 @@
     data_.Clear();
     updated_data_.Clear();
     removed_data_.Clear();
+    captured_text_.clear();
   }
 
  private:
@@ -96,6 +146,7 @@
   WebVector<int64_t> removed_data_;
   Vector<std::string> all_text_;
   Vector<std::string> updated_text_;
+  Vector<std::string> captured_text_;
 };
 
 class ContentCaptureTaskTestHelper : public ContentCaptureTask {
@@ -163,18 +214,14 @@
   WebContentCaptureClient& client_;
 };
 
-class ContentCaptureTest : public PageTestBase,
-                           public ::testing::WithParamInterface<bool> {
+class ContentCaptureTest
+    : public PageTestBase,
+      public ::testing::WithParamInterface<std::vector<base::Feature>> {
  public:
   ContentCaptureTest() {
     EnablePlatform();
-    if (GetParam()) {
-      feature_list_.InitAndEnableFeature(
-          features::kContentCaptureUserActivatedDelay);
-    } else {
-      feature_list_.InitAndDisableFeature(
-          features::kContentCaptureUserActivatedDelay);
-    }
+    feature_list_.InitWithFeatures(
+        GetParam(), /*disabled_features=*/std::vector<base::Feature>());
   }
 
   void SetUp() override {
@@ -207,6 +254,14 @@
     // ContentCaptureManager is created by LocalFrame.
     content_capture_manager_->GetContentCaptureTask()
         ->SetCapturedContentForTesting(node_ids_);
+    InitScrollingTestData();
+  }
+
+  void SimulateScrolling(size_t step) {
+    CHECK_LT(step, 4u);
+    content_capture_manager_->GetContentCaptureTask()
+        ->SetCapturedContentForTesting(scrolling_node_ids_[step]);
+    content_capture_manager_->OnScrollPositionChanged();
   }
 
   void CreateTextNodeAndNotifyManager() {
@@ -282,32 +337,86 @@
 
   Node& invisible_node() const { return *invisible_node_; }
 
+  const Vector<Vector<std::string>>& scrolling_expected_captured_nodes() {
+    return scrolling_expected_captured_nodes_;
+  }
+
+  const Vector<Vector<int64_t>>& scrolling_expected_removed_nodes() {
+    return scrolling_expected_removed_nodes_;
+  }
+
  private:
   void ResetResult() {
     GetWebContentCaptureClient()->ResetResults();
   }
 
-  // TODO(michaelbai): Remove this once integrate with LayoutText.
-  void InitNodeHolders() {
-    Vector<std::string> ids{"p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8"};
+  void BuildNodesInfo(const Vector<std::string>& ids,
+                      Vector<Persistent<Node>>& nodes,
+                      Vector<cc::NodeInfo>& node_ids) {
     for (auto id : ids) {
       Node* node = GetElementById(id.c_str())->firstChild();
       CHECK(node);
       LayoutObject* layout_object = node->GetLayoutObject();
       CHECK(layout_object);
       CHECK(layout_object->IsText());
-      nodes_.push_back(node);
+      nodes.push_back(node);
       GetContentCaptureManager()->ScheduleTaskIfNeeded(*node);
-      node_ids_.push_back(
+      node_ids.push_back(
           cc::NodeInfo(DOMNodeIds::IdForNode(node), GetRect(layout_object)));
     }
+  }
+
+  // TODO(michaelbai): Remove this once integrate with LayoutText.
+  void InitNodeHolders() {
+    BuildNodesInfo(
+        Vector<std::string>{"p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8"},
+        nodes_, node_ids_);
     invisible_node_ = GetElementById("invisible")->firstChild();
     DCHECK(invisible_node_.Get());
   }
 
+  void InitScrollingTestData() {
+    Vector<Vector<Persistent<Node>>> nodes{4};
+    BuildNodesInfo(Vector<std::string>{"p1", "p2", "p3"}, nodes[0],
+                   scrolling_node_ids_[0]);
+    BuildNodesInfo(Vector<std::string>{"p3", "p4", "p5"}, nodes[1],
+                   scrolling_node_ids_[1]);
+    BuildNodesInfo(Vector<std::string>{"p6", "p7", "p8"}, nodes[2],
+                   scrolling_node_ids_[2]);
+    BuildNodesInfo(Vector<std::string>{"p2", "p3"}, nodes[3],
+                   scrolling_node_ids_[3]);
+    // Build expected result.
+    if (base::FeatureList::IsEnabled(
+            features::kContentCaptureConstantStreaming)) {
+      for (int i = 0; i < 4; ++i) {
+        Vector<Persistent<Node>> a_diff_b;
+        Vector<Persistent<Node>> b_diff_a;
+        FindNodeVectorsDiff(nodes[i],
+                            i == 0 ? Vector<Persistent<Node>>() : nodes[i - 1],
+                            a_diff_b, b_diff_a);
+        ToNodeTexts(a_diff_b, scrolling_expected_captured_nodes_[i]);
+        ToNodeIds(b_diff_a, scrolling_expected_removed_nodes_[i]);
+      }
+    } else {
+      HashSet<Persistent<Node>> sent;
+      for (int i = 0; i < 4; ++i) {
+        Vector<Persistent<Node>> a_diff_b;
+        Vector<Persistent<Node>> b;
+        CopyToVector(sent, b);
+        FindNodeVectorsDiff(nodes[i], b, a_diff_b);
+        ToNodeTexts(a_diff_b, scrolling_expected_captured_nodes_[i]);
+        sent.clear();
+        FindNodeVectorsUnion(b, nodes[i], sent);
+      }
+    }
+  }
+
   Vector<Persistent<Node>> nodes_;
   Vector<cc::NodeInfo> node_ids_;
   Persistent<Node> invisible_node_;
+  Vector<Vector<std::string>> scrolling_expected_captured_nodes_{4};
+  Vector<Vector<int64_t>> scrolling_expected_removed_nodes_{4};
+  Vector<Vector<cc::NodeInfo>> scrolling_node_ids_{4};
   std::unique_ptr<WebContentCaptureClientTestHelper> content_capture_client_;
   Persistent<ContentCaptureManagerTestHelper> content_capture_manager_;
   Persistent<ContentCaptureLocalFrameClientHelper> local_frame_client_;
@@ -315,7 +424,16 @@
   base::test::ScopedFeatureList feature_list_;
 };
 
-INSTANTIATE_TEST_SUITE_P(, ContentCaptureTest, testing::Values(true, false));
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    ContentCaptureTest,
+    testing::Values(
+        std::vector<base::Feature>{},
+        std::vector<base::Feature>{features::kContentCaptureUserActivatedDelay},
+        std::vector<base::Feature>{features::kContentCaptureConstantStreaming},
+        std::vector<base::Feature>{
+            features::kContentCaptureUserActivatedDelay,
+            features::kContentCaptureConstantStreaming}));
 
 TEST_P(ContentCaptureTest, Basic) {
   RunContentCaptureTask();
@@ -326,6 +444,23 @@
             GetWebContentCaptureClient()->Data().size());
 }
 
+TEST_P(ContentCaptureTest, Scrolling) {
+  for (size_t step = 0; step < 4; ++step) {
+    SimulateScrolling(step);
+    RunContentCaptureTask();
+    EXPECT_EQ(ContentCaptureTask::TaskState::kStop,
+              GetContentCaptureTask()->GetTaskStateForTesting());
+    EXPECT_THAT(GetWebContentCaptureClient()->CapturedText(),
+                testing::UnorderedElementsAreArray(
+                    scrolling_expected_captured_nodes()[step]))
+        << "at step " << step;
+    EXPECT_THAT(GetWebContentCaptureClient()->RemovedData(),
+                testing::UnorderedElementsAreArray(
+                    scrolling_expected_removed_nodes()[step]))
+        << "at step " << step;
+  }
+}
+
 TEST_P(ContentCaptureTest, PauseAndResume) {
   // The task stops before captures content.
   GetContentCaptureTask()->SetTaskStopState(
@@ -605,7 +740,8 @@
   task->Schedule(ContentCaptureTask::ScheduleReason::kScrolling);
   base::TimeDelta interval2 = task->GetTaskNextFireIntervalForTesting();
   auto test_running_time = base::TimeTicks::Now() - begin;
-  if (GetParam()) {
+  if (base::FeatureList::IsEnabled(
+          features::kContentCaptureUserActivatedDelay)) {
     // The first scheduled task is always shortest even though caused by
     // NonUserTriggered.
     EXPECT_LE(interval1, GetWebContentCaptureClient()->GetTaskShortDelay());
diff --git a/third_party/blink/renderer/core/content_capture/task_session.cc b/third_party/blink/renderer/core/content_capture/task_session.cc
index 1c63b13b..cd95473a 100644
--- a/third_party/blink/renderer/core/content_capture/task_session.cc
+++ b/third_party/blink/renderer/core/content_capture/task_session.cc
@@ -6,11 +6,20 @@
 
 #include <utility>
 
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
 
 namespace blink {
 
+namespace {
+bool IsConstantStreamingEnabled() {
+  return base::FeatureList::IsEnabled(
+      features::kContentCaptureConstantStreaming);
+}
+
+}  // namespace
+
 TaskSession::DocumentSession::DocumentSession(const Document& document,
                                               SentNodeCountCallback& callback)
     : document_(&document), callback_(callback) {}
@@ -21,7 +30,9 @@
 }
 
 bool TaskSession::DocumentSession::AddDetachedNode(const Node& node) {
-  if (sent_nodes_.Contains(&node)) {
+  // Take the node out of |sent_nodes|, otherwise, the |node| would be found
+  // invisible in next capturing and be reported as the removed node again.
+  if (sent_nodes_.Take(&node)) {
     detached_nodes_.emplace_back(reinterpret_cast<int64_t>(&node));
     return true;
   }
@@ -72,9 +83,34 @@
     const gfx::Rect& visual_rect) {
   if (changed_nodes_.Take(&node)) {
     changed_content_.Set(WeakMember<Node>(&node), visual_rect);
-  } else if (!sent_nodes_.Contains(&node)) {
-    captured_content_.Set(WeakMember<Node>(&node), visual_rect);
-  }  // else |node| has been sent and unchanged.
+  } else {
+    if (IsConstantStreamingEnabled()) {
+      if (auto value = sent_nodes_.Take(&node))
+        visible_sent_nodes_.insert(value);
+      else
+        captured_content_.Set(WeakMember<Node>(&node), visual_rect);
+    } else {
+      if (!sent_nodes_.Contains(&node))
+        captured_content_.Set(WeakMember<Node>(&node), visual_rect);
+      // else |node| has been sent and unchanged.
+    }
+  }
+}
+
+void TaskSession::DocumentSession::OnGroupingComplete() {
+  if (!IsConstantStreamingEnabled())
+    return;
+
+  // All nodes in |sent_nodes_| aren't visible any more, remove them.
+  for (auto weak_node : sent_nodes_) {
+    if (auto* node = weak_node.Get())
+      detached_nodes_.emplace_back(reinterpret_cast<int64_t>(node));
+  }
+  // |visible_sent_nodes_| are still visible and moved to |sent_nodes_|.
+  sent_nodes_.swap(visible_sent_nodes_);
+  visible_sent_nodes_.clear();
+  // Any node in |changed_nodes_| isn't visible any more and shall be clear.
+  changed_nodes_.clear();
 }
 
 void TaskSession::DocumentSession::Trace(Visitor* visitor) const {
@@ -82,6 +118,7 @@
   visitor->Trace(changed_content_);
   visitor->Trace(document_);
   visitor->Trace(sent_nodes_);
+  visitor->Trace(visible_sent_nodes_);
   visitor->Trace(changed_nodes_);
 }
 
@@ -90,6 +127,7 @@
   captured_content_.clear();
   detached_nodes_.Clear();
   sent_nodes_.clear();
+  visible_sent_nodes_.clear();
   changed_nodes_.clear();
 }
 
@@ -124,6 +162,9 @@
           .OnContentCaptured(*node, i.visual_rect);
     }
   }
+  for (auto doc_session : to_document_session_.Values()) {
+    doc_session->OnGroupingComplete();
+  }
 }
 
 void TaskSession::OnNodeDetached(const Node& node) {
diff --git a/third_party/blink/renderer/core/content_capture/task_session.h b/third_party/blink/renderer/core/content_capture/task_session.h
index 38da3c45..427bcec 100644
--- a/third_party/blink/renderer/core/content_capture/task_session.h
+++ b/third_party/blink/renderer/core/content_capture/task_session.h
@@ -60,6 +60,8 @@
     bool AddDetachedNode(const Node& node);
     // Invoked on the content of this document is captured.
     void OnContentCaptured(Node& node, const gfx::Rect& visual_rect);
+    // Invoked after TaskSession grouped all captured content.
+    void OnGroupingComplete();
     bool HasUnsentData() const {
       return HasUnsentCapturedContent() || HasUnsentChangedContent() ||
              HasUnsentDetachedNodes();
@@ -98,6 +100,11 @@
     WeakMember<const Document> document_;
     // A set of weak reference of the node that has been sent.
     HeapHashSet<WeakMember<const Node>> sent_nodes_;
+    // A set of node that has been sent in previous capturing and still visible
+    // now, it is only valid while TaskSession is groupping the captured
+    // content, the nodes are moved and replace the |sent_nodes_| in
+    // OnGroupingComplete().
+    HeapHashSet<WeakMember<const Node>> visible_sent_nodes_;
     // A set of node whose value has been changed since last capture.
     HeapHashSet<WeakMember<Node>> changed_nodes_;
 
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 eeb56ef63..c923814 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
@@ -121,11 +121,6 @@
   transform_uses_reference_box_ =
       TransformHelper::DependsOnReferenceBox(StyleRef());
 
-  // Since layout depends on the bounds of the filter, we need to force layout
-  // when the filter changes.
-  if (diff.FilterChanged())
-    SetNeedsLayout(layout_invalidation_reason::kStyleChange);
-
   if (diff.NeedsFullLayout()) {
     SetNeedsBoundariesUpdate();
     if (diff.TransformChanged())
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 a1cdc81..5272c6e 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
@@ -189,10 +189,7 @@
 
 bool LayoutSVGContainer::UpdateCachedBoundaries() {
   NOT_DESTROYED();
-  auto old_object_bounding_box = object_bounding_box_;
-  content_.ComputeBoundingBoxes(
-      object_bounding_box_, object_bounding_box_valid_, stroke_bounding_box_);
-  return old_object_bounding_box != object_bounding_box_;
+  return content_.UpdateBoundingBoxes(object_bounding_box_valid_);
 }
 
 bool LayoutSVGContainer::NodeAtPoint(HitTestResult& result,
@@ -205,7 +202,7 @@
                                             LocalToSVGParentTransform());
   if (!local_location)
     return false;
-  if (!SVGLayoutSupport::IntersectsClipPath(*this, object_bounding_box_,
+  if (!SVGLayoutSupport::IntersectsClipPath(*this, content_.ObjectBoundingBox(),
                                             *local_location))
     return false;
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
index 8f845cf..cecb654 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
@@ -76,7 +76,7 @@
 
   FloatRect ObjectBoundingBox() const final {
     NOT_DESTROYED();
-    return object_bounding_box_;
+    return content_.ObjectBoundingBox();
   }
 
  protected:
@@ -103,7 +103,7 @@
 
   FloatRect StrokeBoundingBox() const final {
     NOT_DESTROYED();
-    return stroke_bounding_box_;
+    return content_.StrokeBoundingBox();
   }
 
   bool NodeAtPoint(HitTestResult&,
@@ -120,9 +120,6 @@
 
  private:
   SVGContentContainer content_;
-  // TODO(fs): Some of this state can move to the "child list" object.
-  FloatRect object_bounding_box_;
-  FloatRect stroke_bounding_box_;
   bool object_bounding_box_valid_;
   bool needs_boundaries_update_ : 1;
   bool did_screen_scale_factor_change_ : 1;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
index d257a3c..7477ea0 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
@@ -126,11 +126,6 @@
 void LayoutSVGInline::StyleDidChange(StyleDifference diff,
                                      const ComputedStyle* old_style) {
   NOT_DESTROYED();
-  // Since layout depends on the bounds of the filter, we need to force layout
-  // when the filter changes.
-  if (diff.FilterChanged())
-    SetNeedsLayout(layout_invalidation_reason::kStyleChange);
-
   if (diff.NeedsFullLayout())
     SetNeedsBoundariesUpdate();
 
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 88975df..8b3cd488 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
@@ -139,15 +139,6 @@
 void LayoutSVGModelObject::StyleDidChange(StyleDifference diff,
                                           const ComputedStyle* old_style) {
   NOT_DESTROYED();
-  // Since layout depends on the bounds of the filter, we need to force layout
-  // when the filter changes. We also need to make sure paint will be
-  // performed, since if the filter changed we will not have cached result from
-  // before and thus will not flag paint in ClientLayoutChanged.
-  if (diff.FilterChanged()) {
-    SetNeedsLayoutAndFullPaintInvalidation(
-        layout_invalidation_reason::kStyleChange);
-  }
-
   if (diff.NeedsFullLayout()) {
     SetNeedsBoundariesUpdate();
     if (diff.TransformChanged())
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 969e019..0d7cc14 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
@@ -535,9 +535,7 @@
 void LayoutSVGRoot::UpdateCachedBoundaries() {
   NOT_DESTROYED();
   bool ignore;
-  content_.ComputeBoundingBoxes(object_bounding_box_,
-                                /* object_bounding_box_valid */ ignore,
-                                stroke_bounding_box_);
+  content_.UpdateBoundingBoxes(/* object_bounding_box_valid */ ignore);
 }
 
 bool LayoutSVGRoot::NodeAtPoint(HitTestResult& result,
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.h b/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
index 4c6f7c1..833cbe4 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
@@ -161,15 +161,15 @@
 
   FloatRect ObjectBoundingBox() const override {
     NOT_DESTROYED();
-    return object_bounding_box_;
+    return content_.ObjectBoundingBox();
   }
   FloatRect StrokeBoundingBox() const override {
     NOT_DESTROYED();
-    return stroke_bounding_box_;
+    return content_.StrokeBoundingBox();
   }
   FloatRect VisualRectInLocalSVGCoordinates() const override {
     NOT_DESTROYED();
-    return stroke_bounding_box_;
+    return content_.StrokeBoundingBox();
   }
 
   bool NodeAtPoint(HitTestResult&,
@@ -213,9 +213,6 @@
 
   SVGContentContainer content_;
   LayoutSize container_size_;
-  // TODO(fs): Some of this state can move to the "child list" object.
-  FloatRect object_bounding_box_;
-  FloatRect stroke_bounding_box_;
   AffineTransform local_to_border_box_transform_;
   bool is_layout_size_changed_ : 1;
   bool did_screen_scale_factor_change_ : 1;
diff --git a/third_party/blink/renderer/core/layout/svg/svg_content_container.cc b/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
index 8a5ca1f7..850e279 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
@@ -135,13 +135,8 @@
   return true;
 }
 
-void SVGContentContainer::ComputeBoundingBoxes(
-    FloatRect& object_bounding_box,
-    bool& object_bounding_box_valid,
-    FloatRect& stroke_bounding_box) const {
-  object_bounding_box = FloatRect();
+bool SVGContentContainer::UpdateBoundingBoxes(bool& object_bounding_box_valid) {
   object_bounding_box_valid = false;
-  stroke_bounding_box = FloatRect();
 
   // When computing the strokeBoundingBox, we use the visualRects of
   // the container's children so that the container's stroke includes the
@@ -149,6 +144,8 @@
   // filters applied to containers to correctly bound the children, and also
   // improves inlining of SVG content, as the stroke bound is used in that
   // situation also.
+  FloatRect object_bounding_box;
+  FloatRect stroke_bounding_box;
   for (LayoutObject* current = children_.FirstChild(); current;
        current = current->NextSibling()) {
     // Don't include elements that are not rendered in the union.
@@ -162,6 +159,13 @@
     stroke_bounding_box.Unite(
         transform.MapRect(current->VisualRectInLocalSVGCoordinates()));
   }
+
+  bool changed = false;
+  changed |= object_bounding_box_ != object_bounding_box;
+  object_bounding_box_ = object_bounding_box;
+  changed |= stroke_bounding_box_ != stroke_bounding_box;
+  stroke_bounding_box_ = stroke_bounding_box;
+  return changed;
 }
 
 bool SVGContentContainer::ComputeHasNonIsolatedBlendingDescendants() const {
diff --git a/third_party/blink/renderer/core/layout/svg/svg_content_container.h b/third_party/blink/renderer/core/layout/svg/svg_content_container.h
index 8f0fed4e..0a75ad5 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_content_container.h
+++ b/third_party/blink/renderer/core/layout/svg/svg_content_container.h
@@ -7,10 +7,10 @@
 
 #include "third_party/blink/renderer/core/layout/api/hit_test_action.h"
 #include "third_party/blink/renderer/core/layout/layout_object_child_list.h"
+#include "third_party/blink/renderer/platform/geometry/float_rect.h"
 
 namespace blink {
 
-class FloatRect;
 class HitTestLocation;
 class HitTestResult;
 
@@ -28,9 +28,10 @@
   void Layout(const SVGContainerLayoutInfo&);
   bool HitTest(HitTestResult&, const HitTestLocation&, HitTestAction) const;
 
-  void ComputeBoundingBoxes(FloatRect& object_bounding_box,
-                            bool& object_bounding_box_valid,
-                            FloatRect& stroke_bounding_box) const;
+  bool UpdateBoundingBoxes(bool& object_bounding_box_valid);
+  const FloatRect& ObjectBoundingBox() const { return object_bounding_box_; }
+  const FloatRect& StrokeBoundingBox() const { return stroke_bounding_box_; }
+
   bool ComputeHasNonIsolatedBlendingDescendants() const;
 
   LayoutObjectChildList& Children() { return children_; }
@@ -38,6 +39,9 @@
 
  private:
   LayoutObjectChildList children_;
+
+  FloatRect object_bounding_box_;
+  FloatRect stroke_bounding_box_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
index 381a9b34..1a0aab59 100644
--- a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
+++ b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
@@ -20,7 +20,6 @@
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/heap/trace_traits.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "v8/include/v8.h"
diff --git a/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.cc b/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.cc
index 39de3ac..0b925ca8 100644
--- a/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.cc
+++ b/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.cc
@@ -11,13 +11,19 @@
 #include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/mojom/file_system_access/native_file_system_manager.mojom-blink.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/security_context.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
 #include "third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h"
 #include "third_party/blink/renderer/modules/file_system_access/native_file_system_error.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
@@ -26,29 +32,20 @@
 // The name to use for the root directory of a sandboxed file system.
 constexpr const char kSandboxRootDirectoryName[] = "";
 
-}  // namespace
+void GetDirectoryImpl(ScriptPromiseResolver* resolver, bool allow_access) {
+  ExecutionContext* context = resolver->GetExecutionContext();
+  if (!resolver->GetScriptState()->ContextIsValid())
+    return;
 
-// static
-ScriptPromise StorageManagerNativeFileSystem::getDirectory(
-    ScriptState* script_state,
-    const StorageManager& storage,
-    ExceptionState& exception_state) {
-  ExecutionContext* context = ExecutionContext::From(script_state);
-  if (!context->GetSecurityOrigin()->CanAccessNativeFileSystem()) {
-    if (context->IsSandboxed(network::mojom::blink::WebSandboxFlags::kOrigin)) {
-      exception_state.ThrowSecurityError(
-          "Storage directory access is denied because the context is "
-          "sandboxed and lacks the 'allow-same-origin' flag.");
-      return ScriptPromise();
-    } else {
-      exception_state.ThrowSecurityError("Storage directory access is denied.");
-      return ScriptPromise();
-    }
+  if (!allow_access) {
+    auto* const isolate = resolver->GetScriptState()->GetIsolate();
+    ScriptState::Scope scope(resolver->GetScriptState());
+    resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
+        isolate, DOMExceptionCode::kSecurityError,
+        "Storage directory access is denied."));
+    return;
   }
 
-  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-  ScriptPromise result = resolver->Promise();
-
   mojo::Remote<mojom::blink::NativeFileSystemManager> manager;
   context->GetBrowserInterfaceBroker().GetInterface(
       manager.BindNewPipeAndPassReceiver());
@@ -71,6 +68,53 @@
             context, kSandboxRootDirectoryName, std::move(handle)));
       },
       WrapPersistent(resolver), std::move(manager)));
+}
+
+}  // namespace
+
+// static
+ScriptPromise StorageManagerNativeFileSystem::getDirectory(
+    ScriptState* script_state,
+    const StorageManager& storage,
+    ExceptionState& exception_state) {
+  ExecutionContext* context = ExecutionContext::From(script_state);
+
+  if (!context->GetSecurityOrigin()->CanAccessNativeFileSystem()) {
+    if (context->IsSandboxed(network::mojom::blink::WebSandboxFlags::kOrigin)) {
+      exception_state.ThrowSecurityError(
+          "Storage directory access is denied because the context is "
+          "sandboxed and lacks the 'allow-same-origin' flag.");
+      return ScriptPromise();
+    } else {
+      exception_state.ThrowSecurityError("Storage directory access is denied.");
+      return ScriptPromise();
+    }
+  }
+
+  SECURITY_DCHECK(context->IsWindow() || context->IsWorkerGlobalScope());
+  WebContentSettingsClient* content_settings_client = nullptr;
+  if (auto* window = DynamicTo<LocalDOMWindow>(context)) {
+    LocalFrame* frame = window->GetFrame();
+    if (!frame) {
+      exception_state.ThrowSecurityError("Storage directory access is denied.");
+      return ScriptPromise();
+    }
+    content_settings_client = frame->GetContentSettingsClient();
+  } else {
+    content_settings_client =
+        To<WorkerGlobalScope>(context)->ContentSettingsClient();
+  }
+
+  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  ScriptPromise result = resolver->Promise();
+
+  if (content_settings_client) {
+    content_settings_client->AllowStorageAccess(
+        WebContentSettingsClient::StorageType::kFileSystem,
+        WTF::Bind(&GetDirectoryImpl, WrapPersistent(resolver)));
+  } else {
+    GetDirectoryImpl(resolver, true);
+  }
 
   return result;
 }
diff --git a/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.cc b/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.cc
index 263e52f..4072870 100644
--- a/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.cc
@@ -33,12 +33,6 @@
                           estimated_capture_time));
 }
 
-void PushableMediaStreamVideoSource::Stop() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DoStopSource();
-  running_ = false;
-}
-
 void PushableMediaStreamVideoSource::StartSourceImpl(
     VideoCaptureDeliverFrameCB frame_callback,
     EncodedVideoFrameCB encoded_frame_callback) {
diff --git a/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h b/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h
index 3d99fc4..8accdc2 100644
--- a/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h
+++ b/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h
@@ -26,9 +26,7 @@
   // media::VideoFrame::timestamp().
   void PushFrame(scoped_refptr<media::VideoFrame> video_frame,
                  base::TimeTicks estimated_capture_time);
-  // TODO(crbug.com/1142955): Remove this method. StopSource() should be used
-  // instead.
-  void Stop();
+  bool running() const { return running_; }
 
   // MediaStreamVideoSource
   void StartSourceImpl(VideoCaptureDeliverFrameCB frame_callback,
diff --git a/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source_test.cc b/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source_test.cc
index 8a9df2a..4cd633b 100644
--- a/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source_test.cc
@@ -91,15 +91,18 @@
 TEST_F(PushableMediaStreamVideoSourceTest, StartAndStop) {
   EXPECT_EQ(MediaStreamSource::kReadyStateLive,
             stream_source_->GetReadyState());
+  EXPECT_FALSE(pushable_video_source_->running());
 
   WebMediaStreamTrack track = StartSource();
   EXPECT_EQ(MediaStreamSource::kReadyStateLive,
             stream_source_->GetReadyState());
+  EXPECT_TRUE(pushable_video_source_->running());
 
   // If the pushable source stops, the MediaStreamSource should stop.
   pushable_video_source_->StopSource();
   EXPECT_EQ(MediaStreamSource::kReadyStateEnded,
             stream_source_->GetReadyState());
+  EXPECT_FALSE(pushable_video_source_->running());
 }
 
 TEST_F(PushableMediaStreamVideoSourceTest, FramesPropagateToSink) {
diff --git a/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc b/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc
index 99ffdaa..ca73526b 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc
@@ -65,13 +65,13 @@
   ScriptPromise abort(ScriptState* script_state,
                       ScriptValue reason,
                       ExceptionState& exception_state) override {
-    source_->Stop();
+    source_->StopSource();
     return ScriptPromise::CastUndefined(script_state);
   }
 
   ScriptPromise close(ScriptState* script_state,
                       ExceptionState& exception_state) override {
-    source_->Stop();
+    source_->StopSource();
     return ScriptPromise::CastUndefined(script_state);
   }
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
index 85d4229..9a90b7a 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -928,8 +928,8 @@
     case GL_DEPTH_STENCIL:
       // To be WebGL 1 backward compatible.
       if (samples > 0) {
-        SynthesizeGLError(GL_INVALID_ENUM, function_name,
-                          "invalid internalformat");
+        SynthesizeGLError(GL_INVALID_OPERATION, function_name,
+                          "internalformat invalid for samples > 0");
         return;
       }
       RenderbufferStorageHelper(target, 0, GL_DEPTH24_STENCIL8, width, height,
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 7ce365c..40589b2 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -1535,8 +1535,7 @@
   if (buffers_needing_clearing == 0 || (mask && framebuffer_binding_))
     return kSkipped;
 
-  WebGLContextAttributes* context_attributes = getContextAttributes();
-  if (!context_attributes) {
+  if (isContextLost()) {
     // Unlikely, but context was lost.
     return kSkipped;
   }
@@ -1558,14 +1557,19 @@
       true, true, true,
       !GetDrawingBuffer()->RequiresAlphaChannelToBePreserved());
   GLbitfield clear_mask = GL_COLOR_BUFFER_BIT;
-  if (context_attributes->depth()) {
+
+  const bool has_depth =
+      CreationAttributes().depth && GetDrawingBuffer()->HasDepthBuffer();
+  const bool has_stencil =
+      CreationAttributes().stencil && GetDrawingBuffer()->HasStencilBuffer();
+
+  if (has_depth) {
     if (!combined_clear || !depth_mask_ || !(mask & GL_DEPTH_BUFFER_BIT))
       ContextGL()->ClearDepthf(1.0f);
     clear_mask |= GL_DEPTH_BUFFER_BIT;
     ContextGL()->DepthMask(true);
   }
-  if (context_attributes->stencil() ||
-      GetDrawingBuffer()->HasImplicitStencilBuffer()) {
+  if (has_stencil || GetDrawingBuffer()->HasImplicitStencilBuffer()) {
     if (combined_clear && (mask & GL_STENCIL_BUFFER_BIT))
       ContextGL()->ClearStencil(clear_stencil_ & stencil_mask_);
     else
@@ -8528,8 +8532,8 @@
   if (framebuffer_binding_) {
     have_stencil_buffer = framebuffer_binding_->HasStencilBuffer();
   } else {
-    WebGLContextAttributes* attributes = getContextAttributes();
-    have_stencil_buffer = attributes && attributes->stencil();
+    have_stencil_buffer = !isContextLost() && CreationAttributes().stencil &&
+                          GetDrawingBuffer()->HasStencilBuffer();
   }
   EnableOrDisable(GL_STENCIL_TEST, stencil_enabled_ && have_stencil_buffer);
 }
diff --git a/third_party/blink/renderer/platform/exported/platform.cc b/third_party/blink/renderer/platform/exported/platform.cc
index 8790c00..ff270b6 100644
--- a/third_party/blink/renderer/platform/exported/platform.cc
+++ b/third_party/blink/renderer/platform/exported/platform.cc
@@ -49,6 +49,7 @@
 #include "third_party/blink/renderer/platform/fonts/font_cache_memory_dump_provider.h"
 #include "third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h"
 #include "third_party/blink/renderer/platform/heap/gc_task_runner.h"
+#include "third_party/blink/renderer/platform/heap/process_heap.h"
 #include "third_party/blink/renderer/platform/instrumentation/canvas_memory_dump_provider.h"
 #include "third_party/blink/renderer/platform/instrumentation/instance_counters_memory_dump_provider.h"
 #include "third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h"
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
index b784445b..8828439 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
@@ -237,7 +237,7 @@
                gfx::Transform());
 
   viz::SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
-  sqs->SetAll(gfx::Transform(), bounds, bounds, gfx::RRectF(), bounds,
+  sqs->SetAll(gfx::Transform(), bounds, bounds, gfx::MaskFilterInfo(), bounds,
               is_clipped, is_opaque, 1.f, SkBlendMode::kSrcOver, 0);
 
   viz::TransferableResource resource;
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index 5188b066..b0e1c6d 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -1383,7 +1383,8 @@
   // of antialiasing issues on the rounded corner edges.
   // is_fast_rounded_corner means to intentionally prefer faster compositing
   // and less memory over highest quality.
-  if (!effect.rounded_corner_bounds.IsEmpty() && !effect.is_fast_rounded_corner)
+  if (effect.mask_filter_info.HasRoundedCorners() &&
+      !effect.is_fast_rounded_corner)
     return cc::RenderSurfaceReason::kRoundedCorner;
   return cc::RenderSurfaceReason::kNone;
 }
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index c38add2..5afe918d 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -3050,7 +3050,7 @@
   EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
   EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_0.rounded_corner_bounds);
+            mask_isolation_0.mask_filter_info.rounded_corner_bounds());
   EXPECT_FALSE(mask_isolation_0.HasRenderSurface());
 }
 
@@ -3149,7 +3149,7 @@
   EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
   EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_0.rounded_corner_bounds);
+            mask_isolation_0.mask_filter_info.rounded_corner_bounds());
   EXPECT_FALSE(mask_isolation_0.HasRenderSurface());
 }
 
@@ -3304,7 +3304,7 @@
   EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
   EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_0.rounded_corner_bounds);
+            mask_isolation_0.mask_filter_info.rounded_corner_bounds());
   EXPECT_FALSE(mask_isolation_0.HasRenderSurface());
 
   ASSERT_EQ(e1_id, cc_filter.parent_id);
@@ -3316,13 +3316,13 @@
   EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_1.blend_mode);
   EXPECT_TRUE(mask_isolation_1.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_1.rounded_corner_bounds);
+            mask_isolation_1.mask_filter_info.rounded_corner_bounds());
   EXPECT_TRUE(mask_isolation_1.HasRenderSurface());
 
   EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_2.blend_mode);
   EXPECT_TRUE(mask_isolation_2.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_2.rounded_corner_bounds);
+            mask_isolation_2.mask_filter_info.rounded_corner_bounds());
   EXPECT_FALSE(mask_isolation_2.HasRenderSurface());
 }
 
@@ -3509,7 +3509,7 @@
 
   EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_0.rounded_corner_bounds);
+            mask_isolation_0.mask_filter_info.rounded_corner_bounds());
   EXPECT_FALSE(mask_isolation_0.HasRenderSurface());
 }
 
@@ -3562,7 +3562,7 @@
   EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
   EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_0.rounded_corner_bounds);
+            mask_isolation_0.mask_filter_info.rounded_corner_bounds());
   EXPECT_FALSE(mask_isolation_0.HasRenderSurface());
 
   int t1_id = content1->transform_tree_index();
@@ -3582,7 +3582,7 @@
   EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_1.blend_mode);
   EXPECT_TRUE(mask_isolation_1.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_1.rounded_corner_bounds);
+            mask_isolation_1.mask_filter_info.rounded_corner_bounds());
   EXPECT_FALSE(mask_isolation_1.HasRenderSurface());
 }
 
@@ -3643,7 +3643,7 @@
   const cc::EffectNode& cc_e2 = *GetPropertyTrees().effect_tree.Node(e2_id);
   EXPECT_TRUE(cc_e2.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_0.rounded_corner_bounds);
+            mask_isolation_0.mask_filter_info.rounded_corner_bounds());
 }
 
 TEST_P(PaintArtifactCompositorTest, SynthesizedClipRespectOutputClip) {
@@ -3698,7 +3698,7 @@
   EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
   EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_0.rounded_corner_bounds);
+            mask_isolation_0.mask_filter_info.rounded_corner_bounds());
   EXPECT_FALSE(mask_isolation_0.HasRenderSurface());
 
   EXPECT_EQ(c1_id, content1->clip_tree_index());
@@ -3712,7 +3712,7 @@
   ASSERT_EQ(e0_id, cc_e1.parent_id);
   EXPECT_TRUE(mask_isolation_1.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_1.rounded_corner_bounds);
+            mask_isolation_1.mask_filter_info.rounded_corner_bounds());
   EXPECT_FALSE(mask_isolation_1.HasRenderSurface());
 
   EXPECT_EQ(c1_id, content2->clip_tree_index());
@@ -3725,7 +3725,7 @@
   EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_2.blend_mode);
   EXPECT_TRUE(mask_isolation_2.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_2.rounded_corner_bounds);
+            mask_isolation_2.mask_filter_info.rounded_corner_bounds());
   EXPECT_FALSE(mask_isolation_2.HasRenderSurface());
 }
 
@@ -3783,7 +3783,7 @@
   EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
   EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_0.rounded_corner_bounds);
+            mask_isolation_0.mask_filter_info.rounded_corner_bounds());
 
   EXPECT_EQ(c1_id, content1->clip_tree_index());
   int e1_id = content1->effect_tree_index();
@@ -3797,7 +3797,7 @@
   EXPECT_EQ(SkBlendMode::kMultiply, mask_isolation_1.blend_mode);
   EXPECT_TRUE(mask_isolation_1.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_1.rounded_corner_bounds);
+            mask_isolation_1.mask_filter_info.rounded_corner_bounds());
 
   EXPECT_EQ(c1_id, content2->clip_tree_index());
   int mask_isolation_2_id = content2->effect_tree_index();
@@ -3809,7 +3809,7 @@
   EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
   EXPECT_TRUE(mask_isolation_2.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_2.rounded_corner_bounds);
+            mask_isolation_2.mask_filter_info.rounded_corner_bounds());
 }
 
 TEST_P(PaintArtifactCompositorTest, SynthesizedClipDelegateBackdropFilter) {
@@ -3881,7 +3881,7 @@
   EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
   EXPECT_EQ(1.0f, mask_isolation_0.opacity);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_0.rounded_corner_bounds);
+            mask_isolation_0.mask_filter_info.rounded_corner_bounds());
 
   EXPECT_EQ(t1_id, content1->transform_tree_index());
   int c2_id = content1->clip_tree_index();
@@ -3908,7 +3908,8 @@
   EXPECT_FALSE(mask_isolation_1.is_fast_rounded_corner);
   // Opacity should also be moved to mask_isolation_1.
   EXPECT_EQ(0.5f, mask_isolation_1.opacity);
-  EXPECT_EQ(gfx::RRectF(), mask_isolation_1.rounded_corner_bounds);
+  EXPECT_EQ(gfx::RRectF(),
+            mask_isolation_1.mask_filter_info.rounded_corner_bounds());
 
   EXPECT_EQ(t0_id, clip_mask1->transform_tree_index());
   EXPECT_EQ(c2_id, clip_mask1->clip_tree_index());
@@ -3936,7 +3937,7 @@
   EXPECT_TRUE(mask_isolation_2.is_fast_rounded_corner);
   EXPECT_EQ(1.0f, mask_isolation_2.opacity);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation_2.rounded_corner_bounds);
+            mask_isolation_2.mask_filter_info.rounded_corner_bounds());
 }
 
 TEST_P(PaintArtifactCompositorTest, SynthesizedClipMultipleNonBackdropEffects) {
@@ -4004,7 +4005,7 @@
   EXPECT_EQ(c1_id, mask_isolation.clip_id);
   EXPECT_TRUE(mask_isolation.is_fast_rounded_corner);
   EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
-            mask_isolation.rounded_corner_bounds);
+            mask_isolation.mask_filter_info.rounded_corner_bounds());
 
   EXPECT_EQ(c0_id, content2->clip_tree_index());
   EXPECT_EQ(e0_id, content2->effect_tree_index());
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index bb9b299..e7b42b4 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -639,7 +639,7 @@
   DCHECK(mask_isolation);
   bool needs_layer =
       !pending_synthetic_mask_layers_.Contains(mask_isolation->id) &&
-      mask_isolation->rounded_corner_bounds.IsEmpty();
+      mask_isolation->mask_filter_info.IsEmpty();
 
   CompositorElementId mask_isolation_id, mask_effect_id;
   SynthesizedClip& clip = client_.CreateOrReuseSynthesizedClipLayer(
@@ -984,8 +984,8 @@
       // is used. See PropertyTreeManager::EmitClipMaskLayer().
       if (SupportsShaderBasedRoundedCorner(*pending_clip.clip,
                                            pending_clip.type, next_effect)) {
-        synthetic_effect.rounded_corner_bounds =
-            gfx::RRectF(pending_clip.clip->PixelSnappedClipRect());
+        synthetic_effect.mask_filter_info = gfx::MaskFilterInfo(
+            gfx::RRectF(pending_clip.clip->PixelSnappedClipRect()));
         synthetic_effect.is_fast_rounded_corner = true;
 
         // Nested rounded corner clips need to force render surfaces for
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_resource_provider.cc b/third_party/blink/renderer/platform/graphics/video_frame_resource_provider.cc
index b902879..4d090c9 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_resource_provider.cc
@@ -110,15 +110,15 @@
 
   gfx::Rect visible_quad_rect = quad_rect;
   gfx::Rect clip_rect;
-  gfx::RRectF rounded_corner_bounds;
+  gfx::MaskFilterInfo mask_filter_info;
   bool is_clipped = false;
   float draw_opacity = 1.0f;
   int sorting_context_id = 0;
 
   resource_updater_->AppendQuads(render_pass, std::move(frame), transform,
-                                 quad_rect, visible_quad_rect,
-                                 rounded_corner_bounds, clip_rect, is_clipped,
-                                 is_opaque, draw_opacity, sorting_context_id);
+                                 quad_rect, visible_quad_rect, mask_filter_info,
+                                 clip_rect, is_clipped, is_opaque, draw_opacity,
+                                 sorting_context_id);
 }
 
 void VideoFrameResourceProvider::ReleaseFrameResources() {
diff --git a/third_party/blink/renderer/platform/heap/BUILD.gn b/third_party/blink/renderer/platform/heap/BUILD.gn
index 8f0ca03..1ed52cf 100644
--- a/third_party/blink/renderer/platform/heap/BUILD.gn
+++ b/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -34,10 +34,14 @@
     configs -= [ "//build/config/compiler:afdo_optimize_size" ]
   }
 
-  sources = [
-    "unsanitized_atomic.cc",
-    "unsanitized_atomic.h",
-  ]
+  if (!enable_blink_heap_use_v8_oilpan) {
+    sources = [
+      "impl/unsanitized_atomic.cc",
+      "impl/unsanitized_atomic.h",
+    ]
+  } else {
+    sources = []
+  }
 
   deps = [
     "//base",
@@ -50,66 +54,107 @@
   configs += [ "//build/config/compiler:noshadowing" ]
 
   sources = [
-    "atomic_entry_flag.h",
-    "blink_gc.cc",
-    "blink_gc.h",
-    "blink_gc_memory_dump_provider.cc",
     "blink_gc_memory_dump_provider.h",
     "collection_support/heap_hash_table_backing.h",
     "collection_support/heap_linked_stack.h",
     "collection_support/heap_vector_backing.h",
     "disallow_new_wrapper.h",
-    "finalizer_traits.h",
     "garbage_collected.h",
-    "gc_info.cc",
-    "gc_info.h",
     "gc_task_runner.h",
     "handle.h",
-    "heap.cc",
     "heap.h",
-    "heap_allocator.cc",
     "heap_allocator.h",
-    "heap_compact.cc",
-    "heap_compact.h",
-    "heap_page.cc",
-    "heap_page.h",
-    "heap_stats_collector.cc",
     "heap_stats_collector.h",
     "heap_traits.h",
-    "marking_scheduling_oracle.cc",
-    "marking_scheduling_oracle.h",
-    "marking_verifier.cc",
-    "marking_verifier.h",
-    "marking_visitor.cc",
-    "marking_visitor.h",
     "member.h",
-    "name_traits.h",
-    "page_bloom_filter.h",
-    "page_memory.cc",
-    "page_memory.h",
-    "page_pool.cc",
-    "page_pool.h",
     "persistent.h",
-    "persistent_node.cc",
-    "persistent_node.h",
-    "process_heap.cc",
     "process_heap.h",
     "self_keep_alive.h",
-    "thread_state.cc",
     "thread_state.h",
     "thread_state_scopes.h",
-    "thread_state_statistics.cc",
-    "thread_state_statistics.h",
-    "threading_traits.h",
-    "trace_traits.h",
-    "unified_heap_controller.cc",
     "unified_heap_controller.h",
-    "unified_heap_marking_visitor.cc",
     "unified_heap_marking_visitor.h",
     "visitor.h",
-    "worklist.h",
   ]
 
+  if (enable_blink_heap_use_v8_oilpan) {
+    sources += [
+      "v8_wrapper/blink_gc.h",
+      "v8_wrapper/blink_gc_memory_dump_provider.h",
+      "v8_wrapper/disallow_new_wrapper.h",
+      "v8_wrapper/garbage_collected.h",
+      "v8_wrapper/gc_task_runner.h",
+      "v8_wrapper/heap.h",
+      "v8_wrapper/heap_allocator.h",
+      "v8_wrapper/heap_stats_collector.h",
+      "v8_wrapper/heap_traits.h",
+      "v8_wrapper/member.h",
+      "v8_wrapper/persistent.h",
+      "v8_wrapper/process_heap.h",
+      "v8_wrapper/thread_state.h",
+      "v8_wrapper/thread_state_scopes.h",
+      "v8_wrapper/unified_heap_controller.h",
+      "v8_wrapper/unified_heap_marking_visitor.h",
+      "v8_wrapper/visitor.h",
+    ]
+  } else {
+    sources += [
+      "impl/atomic_entry_flag.h",
+      "impl/blink_gc.cc",
+      "impl/blink_gc.h",
+      "impl/blink_gc_memory_dump_provider.cc",
+      "impl/blink_gc_memory_dump_provider.h",
+      "impl/disallow_new_wrapper.h",
+      "impl/finalizer_traits.h",
+      "impl/garbage_collected.h",
+      "impl/gc_info.cc",
+      "impl/gc_info.h",
+      "impl/gc_task_runner.h",
+      "impl/heap.cc",
+      "impl/heap.h",
+      "impl/heap_allocator.cc",
+      "impl/heap_allocator.h",
+      "impl/heap_compact.cc",
+      "impl/heap_compact.h",
+      "impl/heap_page.cc",
+      "impl/heap_page.h",
+      "impl/heap_stats_collector.cc",
+      "impl/heap_stats_collector.h",
+      "impl/heap_traits.h",
+      "impl/marking_scheduling_oracle.cc",
+      "impl/marking_scheduling_oracle.h",
+      "impl/marking_verifier.cc",
+      "impl/marking_verifier.h",
+      "impl/marking_visitor.cc",
+      "impl/marking_visitor.h",
+      "impl/member.h",
+      "impl/name_traits.h",
+      "impl/page_bloom_filter.h",
+      "impl/page_memory.cc",
+      "impl/page_memory.h",
+      "impl/page_pool.cc",
+      "impl/page_pool.h",
+      "impl/persistent.h",
+      "impl/persistent_node.cc",
+      "impl/persistent_node.h",
+      "impl/process_heap.cc",
+      "impl/process_heap.h",
+      "impl/thread_state.cc",
+      "impl/thread_state.h",
+      "impl/thread_state_scopes.h",
+      "impl/thread_state_statistics.cc",
+      "impl/thread_state_statistics.h",
+      "impl/threading_traits.h",
+      "impl/trace_traits.h",
+      "impl/unified_heap_controller.cc",
+      "impl/unified_heap_controller.h",
+      "impl/unified_heap_marking_visitor.cc",
+      "impl/unified_heap_marking_visitor.h",
+      "impl/visitor.h",
+      "impl/worklist.h",
+    ]
+  }
+
   deps = [
     ":blink_heap_buildflags",
     "//base",
diff --git a/third_party/blink/renderer/platform/heap/blink_gc.h b/third_party/blink/renderer/platform/heap/blink_gc.h
index e6a47ee..bba5216 100644
--- a/third_party/blink/renderer/platform/heap/blink_gc.h
+++ b/third_party/blink/renderer/platform/heap/blink_gc.h
@@ -1,126 +1,16 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_
 
-// BlinkGC.h is a file that defines common things used by Blink GC.
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-#define PRINT_HEAP_STATS 0  // Enable this macro to print heap stats to stderr.
-
-namespace blink {
-
-class LivenessBroker;
-class MarkingVisitor;
-class Visitor;
-
-using Address = uint8_t*;
-using ConstAddress = const uint8_t*;
-
-using VisitorCallback = void (*)(Visitor*, const void*);
-using MarkingVisitorCallback = void (*)(MarkingVisitor*, const void*);
-using TraceCallback = VisitorCallback;
-using WeakCallback = void (*)(const LivenessBroker&, const void*);
-using EphemeronCallback = VisitorCallback;
-
-// Simple alias to avoid heap compaction type signatures turning into
-// a sea of generic |void*|s.
-using MovableReference = const void*;
-
-// List of all arenas. Includes typed arenas as well.
-#define FOR_EACH_ARENA(H) \
-  H(NormalPage1)          \
-  H(NormalPage2)          \
-  H(NormalPage3)          \
-  H(NormalPage4)          \
-  H(Vector)               \
-  H(HashTable)            \
-  H(Node)                 \
-  H(CSSValue)             \
-  H(LargeObject)
-
-class PLATFORM_EXPORT WorklistTaskId {
- public:
-  static constexpr int MutatorThread = 0;
-  static constexpr int ConcurrentThreadBase = 1;
-};
-
-class PLATFORM_EXPORT BlinkGC final {
-  STATIC_ONLY(BlinkGC);
-
- public:
-  // CollectionType represents generational collection. kMinor collects objects
-  // in the young generation (i.e. allocated since the previous collection
-  // cycle, since we use sticky bits), kMajor collects the entire heap.
-  enum class CollectionType { kMinor, kMajor };
-
-  // When garbage collecting we need to know whether or not there
-  // can be pointers to Blink GC managed objects on the stack for
-  // each thread. When threads reach a safe point they record
-  // whether or not they have pointers on the stack.
-  enum StackState { kNoHeapPointersOnStack, kHeapPointersOnStack };
-
-  enum MarkingType {
-    // The marking completes synchronously.
-    kAtomicMarking,
-    // The marking task is split and executed in chunks (either on the mutator
-    // thread or concurrently).
-    kIncrementalAndConcurrentMarking
-  };
-
-  enum SweepingType {
-    // The sweeping task is split into chunks and scheduled lazily and
-    // concurrently.
-    kConcurrentAndLazySweeping,
-    // The sweeping task executes synchronously right after marking.
-    kEagerSweeping,
-  };
-
-  // Commented out reasons have been used in the past but are not used any
-  // longer. We keep them here as the corresponding UMA histograms cannot be
-  // changed.
-  enum class GCReason {
-    // kIdleGC = 0
-    // kPreciseGC = 1
-    // kConservativeGC = 2
-    kForcedGCForTesting = 3,
-    // kMemoryPressureGC = 4
-    // kPageNavigationGC = 5
-    kThreadTerminationGC = 6,
-    // kTesting = 7
-    // kIncrementalIdleGC = 8
-    // kIncrementalV8FollowupGC = 9
-    kUnifiedHeapGC = 10,
-    kUnifiedHeapForMemoryReductionGC = 11,
-    kUnifiedHeapForcedForTestingGC = 12,
-    // Used by UMA_HISTOGRAM_ENUMERATION macro.
-    kMaxValue = kUnifiedHeapForcedForTestingGC,
-  };
-
-#define DeclareArenaIndex(name) k##name##ArenaIndex,
-  enum ArenaIndices {
-    FOR_EACH_ARENA(DeclareArenaIndex)
-    // Values used for iteration of heap segments.
-    kNumberOfArenas,
-  };
-#undef DeclareArenaIndex
-
-  enum V8GCType {
-    kV8MinorGC,
-    kV8MajorGC,
-  };
-
-  static const char* ToString(GCReason);
-  static const char* ToString(MarkingType);
-  static const char* ToString(StackState);
-  static const char* ToString(SweepingType);
-  static const char* ToString(ArenaIndices);
-};
-
-}  // namespace blink
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/blink_gc.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_
diff --git a/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h b/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h
index 42be708..e3216e1 100644
--- a/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h
+++ b/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h
@@ -1,47 +1,16 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
 
-#include "base/trace_event/memory_dump_provider.h"
-#include "third_party/blink/renderer/platform/heap/blink_gc.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}  // namespace base
-
-namespace blink {
-
-class ThreadState;
-
-class PLATFORM_EXPORT BlinkGCMemoryDumpProvider final
-    : public base::trace_event::MemoryDumpProvider {
-  USING_FAST_MALLOC(BlinkGCMemoryDumpProvider);
-
- public:
-  enum class HeapType { kBlinkMainThread, kBlinkWorkerThread };
-
-  ~BlinkGCMemoryDumpProvider() final;
-  BlinkGCMemoryDumpProvider(
-      ThreadState* thread_state,
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-      HeapType heap_type);
-
-  // MemoryDumpProvider implementation.
-  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&,
-                    base::trace_event::ProcessMemoryDump*) final;
-
- private:
-  ThreadState* const thread_state_;
-  const HeapType heap_type_;
-  const std::string dump_base_name_;
-};
-
-}  // namespace blink
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
diff --git a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
index 0d4a826..d29ba0e2 100644
--- a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
+++ b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
@@ -5,9 +5,9 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
 
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
-#include "third_party/blink/renderer/platform/heap/threading_traits.h"
-#include "third_party/blink/renderer/platform/heap/trace_traits.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/threading_traits.h"
+#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
 
diff --git a/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h b/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
index 07c97e2..12b72b7 100644
--- a/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
+++ b/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
@@ -6,13 +6,13 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
 
 #include "base/check_op.h"
-#include "third_party/blink/renderer/platform/heap/finalizer_traits.h"
-#include "third_party/blink/renderer/platform/heap/gc_info.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/impl/finalizer_traits.h"
+#include "third_party/blink/renderer/platform/heap/impl/gc_info.h"
+#include "third_party/blink/renderer/platform/heap/impl/threading_traits.h"
+#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/heap/threading_traits.h"
-#include "third_party/blink/renderer/platform/heap/trace_traits.h"
 #include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
diff --git a/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h b/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h
index 1d3b1f3..9d60caf 100644
--- a/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h
+++ b/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h
@@ -1,53 +1,16 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_DISALLOW_NEW_WRAPPER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_DISALLOW_NEW_WRAPPER_H_
 
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-namespace blink {
-
-// DisallowNewWrapper wraps a disallow new type in a GarbageCollected class.
-template <typename T>
-class DisallowNewWrapper final
-    : public GarbageCollected<DisallowNewWrapper<T>> {
- public:
-  explicit DisallowNewWrapper(const T& value) : value_(value) {
-    static_assert(WTF::IsDisallowNew<T>::value,
-                  "T needs to be a disallow new type");
-    static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable");
-  }
-  explicit DisallowNewWrapper(T&& value) : value_(std::forward<T>(value)) {
-    static_assert(WTF::IsDisallowNew<T>::value,
-                  "T needs to be a disallow new type");
-    static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable");
-  }
-
-  const T& Value() const { return value_; }
-  T&& TakeValue() { return std::move(value_); }
-
-  void Trace(Visitor* visitor) const { visitor->Trace(value_); }
-
- private:
-  T value_;
-};
-
-// Wraps a disallow new type in a GarbageCollected class, making it possible to
-// be referenced off heap from a Persistent.
-template <typename T>
-DisallowNewWrapper<T>* WrapDisallowNew(const T& value) {
-  return MakeGarbageCollected<DisallowNewWrapper<T>>(value);
-}
-
-template <typename T>
-DisallowNewWrapper<T>* WrapDisallowNew(T&& value) {
-  return MakeGarbageCollected<DisallowNewWrapper<T>>(std::forward<T>(value));
-}
-
-}  // namespace blink
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_DISALLOW_NEW_WRAPPER_H_
diff --git a/third_party/blink/renderer/platform/heap/garbage_collected.h b/third_party/blink/renderer/platform/heap/garbage_collected.h
index dfd6a12c..9371593 100644
--- a/third_party/blink/renderer/platform/heap/garbage_collected.h
+++ b/third_party/blink/renderer/platform/heap/garbage_collected.h
@@ -1,117 +1,16 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_
 
-#include "base/macros.h"
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-namespace blink {
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/garbage_collected.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
-template <typename T>
-class GarbageCollected;
-
-// GC_PLUGIN_IGNORE is used to make the plugin ignore a particular class or
-// field when checking for proper usage.  When using GC_PLUGIN_IGNORE
-// a bug-number should be provided as an argument where the bug describes
-// what needs to happen to remove the GC_PLUGIN_IGNORE again.
-#if defined(__clang__)
-#define GC_PLUGIN_IGNORE(bug) \
-  __attribute__((annotate("blink_gc_plugin_ignore")))
-#else
-#define GC_PLUGIN_IGNORE(bug)
-#endif
-
-// Template to determine if a class is a GarbageCollectedMixin by checking if it
-// has IsGarbageCollectedMixinMarker
-template <typename T>
-struct IsGarbageCollectedMixin {
- private:
-  typedef char YesType;
-  struct NoType {
-    char padding[8];
-  };
-
-  template <typename U>
-  static YesType CheckMarker(typename U::IsGarbageCollectedMixinMarker*);
-  template <typename U>
-  static NoType CheckMarker(...);
-
- public:
-  static const bool value = sizeof(CheckMarker<T>(nullptr)) == sizeof(YesType);
-};
-
-// TraceDescriptor is used to describe how to trace an object.
-struct TraceDescriptor {
-  STACK_ALLOCATED();
-
- public:
-  // The adjusted base pointer of the object that should be traced.
-  const void* base_object_payload;
-  // A callback for tracing the object.
-  TraceCallback callback;
-};
-
-// The GarbageCollectedMixin interface can be used to automatically define
-// TraceTrait/ObjectAliveTrait on non-leftmost deriving classes which need
-// to be garbage collected.
-class PLATFORM_EXPORT GarbageCollectedMixin {
- public:
-  typedef int IsGarbageCollectedMixinMarker;
-  virtual void Trace(Visitor*) const {}
-};
-
-// Base class for objects allocated in the Blink garbage-collected heap.
-//
-// Instances of GarbageCollected will be finalized if they are non-trivially
-// destructible.
-template <typename T>
-class GarbageCollected;
-
-template <typename T,
-          bool = WTF::IsSubclassOfTemplate<typename std::remove_const<T>::type,
-                                           GarbageCollected>::value>
-class NeedsAdjustPointer;
-
-template <typename T>
-class NeedsAdjustPointer<T, true> {
-  static_assert(sizeof(T), "T must be fully defined");
-
- public:
-  static const bool value = false;
-};
-
-template <typename T>
-class NeedsAdjustPointer<T, false> {
-  static_assert(sizeof(T), "T must be fully defined");
-
- public:
-  static const bool value =
-      IsGarbageCollectedMixin<typename std::remove_const<T>::type>::value;
-};
-
-// TODO(sof): migrate to wtf/TypeTraits.h
-template <typename T>
-class IsFullyDefined {
-  using TrueType = char;
-  struct FalseType {
-    char dummy[2];
-  };
-
-  template <typename U, size_t sz = sizeof(U)>
-  static TrueType IsSizeofKnown(U*);
-  static FalseType IsSizeofKnown(...);
-  static T& t_;
-
- public:
-  static const bool value = sizeof(TrueType) == sizeof(IsSizeofKnown(&t_));
-};
-
-}  // namespace blink
-
-#endif
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_
diff --git a/third_party/blink/renderer/platform/heap/gc_task_runner.h b/third_party/blink/renderer/platform/heap/gc_task_runner.h
index b00f3b2..758506b7 100644
--- a/third_party/blink/renderer/platform/heap/gc_task_runner.h
+++ b/third_party/blink/renderer/platform/heap/gc_task_runner.h
@@ -1,90 +1,16 @@
-/*
- * Copyright (C) 2014 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 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_TASK_RUNNER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_TASK_RUNNER_H_
 
-#include <memory>
-#include "base/location.h"
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-namespace blink {
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/gc_task_runner.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
-class GCTaskObserver final : public Thread::TaskObserver {
-  USING_FAST_MALLOC(GCTaskObserver);
-
- public:
-  GCTaskObserver() : nesting_(0) {}
-
-  ~GCTaskObserver() override {
-    // m_nesting can be 1 if this was unregistered in a task and
-    // didProcessTask was not called.
-    DCHECK(!nesting_ || nesting_ == 1);
-  }
-
-  void WillProcessTask(const base::PendingTask&, bool) override { nesting_++; }
-
-  void DidProcessTask(const base::PendingTask&) override {
-    // In the production code WebKit::initialize is called from inside the
-    // message loop so we can get didProcessTask() without corresponding
-    // willProcessTask once. This is benign.
-    if (nesting_)
-      nesting_--;
-
-    ThreadState::Current()->SafePoint(nesting_
-                                          ? BlinkGC::kHeapPointersOnStack
-                                          : BlinkGC::kNoHeapPointersOnStack);
-  }
-
- private:
-  int nesting_;
-};
-
-class GCTaskRunner final {
-  USING_FAST_MALLOC(GCTaskRunner);
-
- public:
-  explicit GCTaskRunner(Thread* thread)
-      : gc_task_observer_(std::make_unique<GCTaskObserver>()), thread_(thread) {
-    thread_->AddTaskObserver(gc_task_observer_.get());
-  }
-
-  ~GCTaskRunner() { thread_->RemoveTaskObserver(gc_task_observer_.get()); }
-
- private:
-  std::unique_ptr<GCTaskObserver> gc_task_observer_;
-  Thread* thread_;
-};
-
-}  // namespace blink
-
-#endif
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_TASK_RUNNER_H_
diff --git a/third_party/blink/renderer/platform/heap/handle.h b/third_party/blink/renderer/platform/heap/handle.h
index 9df15cc4..ee07268 100644
--- a/third_party/blink/renderer/platform/heap/handle.h
+++ b/third_party/blink/renderer/platform/heap/handle.h
@@ -38,7 +38,6 @@
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
-#include "third_party/blink/renderer/platform/heap/trace_traits.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
diff --git a/third_party/blink/renderer/platform/heap/heap.h b/third_party/blink/renderer/platform/heap/heap.h
index 9610e8ba..7cbe94f 100644
--- a/third_party/blink/renderer/platform/heap/heap.h
+++ b/third_party/blink/renderer/platform/heap/heap.h
@@ -1,751 +1,16 @@
-/*
- * 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 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_
 
-#include <limits>
-#include <memory>
-#include <unordered_set>
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "third_party/blink/renderer/platform/heap/finalizer_traits.h"
-#include "third_party/blink/renderer/platform/heap/gc_info.h"
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
-#include "third_party/blink/renderer/platform/heap/process_heap.h"
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/heap/thread_state_statistics.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
-#include "third_party/blink/renderer/platform/heap/worklist.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/sanitizers.h"
-#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
-
-namespace blink {
-
-namespace incremental_marking_test {
-class IncrementalMarkingScopeBase;
-}  // namespace incremental_marking_test
-
-class ConcurrentMarkingVisitor;
-class ThreadHeapStatsCollector;
-class PageBloomFilter;
-class PagePool;
-class ProcessHeapReporter;
-class RegionTree;
-class MarkingSchedulingOracle;
-
-using MarkingItem = TraceDescriptor;
-using NotFullyConstructedItem = const void*;
-
-struct EphemeronPairItem {
-  const void* key;
-  TraceDescriptor value_desc;
-};
-
-struct CustomCallbackItem {
-  WeakCallback callback;
-  const void* parameter;
-};
-
-struct NotSafeToConcurrentlyTraceItem {
-  TraceDescriptor desc;
-  size_t bailout_size;
-};
-
-using V8Reference = const TraceWrapperV8Reference<v8::Value>*;
-
-// Segment size of 512 entries necessary to avoid throughput regressions. Since
-// the work list is currently a temporary object this is not a problem.
-using MarkingWorklist = Worklist<MarkingItem, 512 /* local entries */>;
-using WriteBarrierWorklist = Worklist<HeapObjectHeader*, 64>;
-using NotFullyConstructedWorklist =
-    Worklist<NotFullyConstructedItem, 16 /* local entries */>;
-using WeakCallbackWorklist =
-    Worklist<CustomCallbackItem, 64 /* local entries */>;
-// Using large local segments here (sized 512 entries) to avoid throughput
-// regressions.
-using MovableReferenceWorklist =
-    Worklist<const MovableReference*, 256 /* local entries */>;
-using EphemeronPairsWorklist =
-    Worklist<EphemeronPairItem, 64 /* local entries */>;
-using V8ReferencesWorklist = Worklist<V8Reference, 16 /* local entries */>;
-using NotSafeToConcurrentlyTraceWorklist =
-    Worklist<NotSafeToConcurrentlyTraceItem, 64 /* local entries */>;
-
-class WeakContainersWorklist {
- public:
-  void Push(const HeapObjectHeader*);
-  void Erase(const HeapObjectHeader*);
-  bool Contains(const HeapObjectHeader*);
-
- private:
-  WTF::Mutex lock_;
-  std::unordered_set<const HeapObjectHeader*> objects_;
-};
-
-class PLATFORM_EXPORT HeapAllocHooks {
-  STATIC_ONLY(HeapAllocHooks);
-
- public:
-  // TODO(hajimehoshi): Pass a type name of the allocated object.
-  typedef void AllocationHook(Address, size_t, const char*);
-  typedef void FreeHook(Address);
-
-  // Sets allocation hook. Only one hook is supported.
-  static void SetAllocationHook(AllocationHook* hook) {
-    CHECK(!allocation_hook_ || !hook);
-    allocation_hook_ = hook;
-  }
-
-  // Sets free hook. Only one hook is supported.
-  static void SetFreeHook(FreeHook* hook) {
-    CHECK(!free_hook_ || !hook);
-    free_hook_ = hook;
-  }
-
-  static void AllocationHookIfEnabled(Address address,
-                                      size_t size,
-                                      const char* type_name) {
-    AllocationHook* allocation_hook = allocation_hook_;
-    if (UNLIKELY(!!allocation_hook))
-      allocation_hook(address, size, type_name);
-  }
-
-  static void FreeHookIfEnabled(Address address) {
-    FreeHook* free_hook = free_hook_;
-    if (UNLIKELY(!!free_hook))
-      free_hook(address);
-  }
-
- private:
-  static AllocationHook* allocation_hook_;
-  static FreeHook* free_hook_;
-};
-
-class HeapCompact;
-template <typename T>
-class Member;
-template <typename T>
-class WeakMember;
-template <typename T>
-class UntracedMember;
-
-namespace internal {
-
-class LivenessBrokerFactory;
-
-template <typename T, bool = NeedsAdjustPointer<T>::value>
-class ObjectAliveTrait;
-
-template <typename T>
-class ObjectAliveTrait<T, false> {
-  STATIC_ONLY(ObjectAliveTrait);
-
- public:
-  static bool IsHeapObjectAlive(const T* object) {
-    static_assert(sizeof(T), "T must be fully defined");
-    return HeapObjectHeader::FromPayload(object)->IsMarked();
-  }
-};
-
-template <typename T>
-class ObjectAliveTrait<T, true> {
-  STATIC_ONLY(ObjectAliveTrait);
-
- public:
-  NO_SANITIZE_ADDRESS
-  static bool IsHeapObjectAlive(const T* object) {
-    static_assert(sizeof(T), "T must be fully defined");
-    const HeapObjectHeader* header = HeapObjectHeader::FromPayload(
-        TraceTrait<T>::GetTraceDescriptor(object).base_object_payload);
-    DCHECK(!header->IsInConstruction() || header->IsMarked());
-    return header->IsMarked();
-  }
-};
-
-template <typename T, typename = int>
-struct IsGarbageCollectedContainer : std::false_type {};
-
-template <typename T>
-struct IsGarbageCollectedContainer<
-    T,
-    typename T::IsGarbageCollectedCollectionTypeMarker> : std::true_type {};
-
-}  // namespace internal
-
-class PLATFORM_EXPORT ThreadHeap {
-  USING_FAST_MALLOC(ThreadHeap);
-
-  using EphemeronProcessing = ThreadState::EphemeronProcessing;
-
- public:
-  explicit ThreadHeap(ThreadState*);
-  ~ThreadHeap();
-
-  MarkingWorklist* GetMarkingWorklist() const {
-    return marking_worklist_.get();
-  }
-
-  WriteBarrierWorklist* GetWriteBarrierWorklist() const {
-    return write_barrier_worklist_.get();
-  }
-
-  NotFullyConstructedWorklist* GetNotFullyConstructedWorklist() const {
-    return not_fully_constructed_worklist_.get();
-  }
-
-  NotFullyConstructedWorklist* GetPreviouslyNotFullyConstructedWorklist()
-      const {
-    return previously_not_fully_constructed_worklist_.get();
-  }
-
-  WeakCallbackWorklist* GetWeakCallbackWorklist() const {
-    return weak_callback_worklist_.get();
-  }
-
-  MovableReferenceWorklist* GetMovableReferenceWorklist() const {
-    return movable_reference_worklist_.get();
-  }
-
-  EphemeronPairsWorklist* GetDiscoveredEphemeronPairsWorklist() const {
-    return discovered_ephemeron_pairs_worklist_.get();
-  }
-
-  EphemeronPairsWorklist* GetEphemeronPairsToProcessWorklist() const {
-    return ephemeron_pairs_to_process_worklist_.get();
-  }
-
-  V8ReferencesWorklist* GetV8ReferencesWorklist() const {
-    return v8_references_worklist_.get();
-  }
-
-  NotSafeToConcurrentlyTraceWorklist* GetNotSafeToConcurrentlyTraceWorklist()
-      const {
-    return not_safe_to_concurrently_trace_worklist_.get();
-  }
-
-  WeakContainersWorklist* GetWeakContainersWorklist() const {
-    return weak_containers_worklist_.get();
-  }
-
-  // Register an ephemeron table for fixed-point iteration.
-  void RegisterWeakTable(void* container_object,
-                         EphemeronCallback);
-
-  // Heap compaction registration methods:
-
-  // Checks whether we need to register |addr| as a backing store or a slot
-  // containing reference to it.
-  bool ShouldRegisterMovingAddress();
-
-  RegionTree* GetRegionTree() { return region_tree_.get(); }
-
-  static inline size_t AllocationSizeFromSize(size_t size) {
-    // Add space for header.
-    size_t allocation_size = size + sizeof(HeapObjectHeader);
-    // The allocation size calculation can overflow for large sizes.
-    CHECK_GT(allocation_size, size);
-    // Align size with allocation granularity.
-    allocation_size = (allocation_size + kAllocationMask) & ~kAllocationMask;
-    return allocation_size;
-  }
-  Address AllocateOnArenaIndex(ThreadState*,
-                               size_t,
-                               int arena_index,
-                               uint32_t gc_info_index,
-                               const char* type_name);
-  template <typename T>
-  static Address Allocate(size_t);
-
-  void WeakProcessing(MarkingVisitor*);
-
-  // Moves not fully constructed objects to previously not fully constructed
-  // objects. Such objects can be iterated using the Trace() method and do
-  // not need to rely on conservative handling.
-  void FlushNotFullyConstructedObjects();
-
-  // Moves ephemeron pairs from |discovered_ephemeron_pairs_worklist_| to
-  // |ephemeron_pairs_to_process_worklist_|
-  void FlushEphemeronPairs(EphemeronProcessing);
-
-  // Marks not fully constructed objects.
-  void MarkNotFullyConstructedObjects(MarkingVisitor*);
-  // Marks the transitive closure including ephemerons.
-  bool AdvanceMarking(MarkingVisitor*, base::TimeTicks, EphemeronProcessing);
-  void VerifyMarking();
-
-  // Returns true if concurrent markers will have work to steal
-  bool HasWorkForConcurrentMarking() const;
-  // Returns the amount of work currently available for stealing (there could be
-  // work remaining even if this is 0).
-  size_t ConcurrentMarkingGlobalWorkSize() const;
-  // Returns true if marker is done
-  bool AdvanceConcurrentMarking(ConcurrentMarkingVisitor*,
-                                base::JobDelegate*,
-                                MarkingSchedulingOracle* marking_scheduler);
-
-  // Conservatively checks whether an address is a pointer in any of the
-  // thread heaps.  If so marks the object pointed to as live.
-  Address CheckAndMarkPointer(MarkingVisitor*, Address);
-
-  // Visits remembered sets.
-  void VisitRememberedSets(MarkingVisitor*);
-
-  size_t ObjectPayloadSizeForTesting();
-  void ResetAllocationPointForTesting();
-
-  PagePool* GetFreePagePool() { return free_page_pool_.get(); }
-
-  // This look-up uses the region search tree and a negative contains cache to
-  // provide an efficient mapping from arbitrary addresses to the containing
-  // heap-page if one exists.
-  BasePage* LookupPageForAddress(ConstAddress);
-
-  HeapCompact* Compaction();
-
-  // Get one of the heap structures for this thread.
-  // The thread heap is split into multiple heap parts based on object types
-  // and object sizes.
-  BaseArena* Arena(int arena_index) const {
-    DCHECK_LE(0, arena_index);
-    DCHECK_LT(arena_index, BlinkGC::kNumberOfArenas);
-    return arenas_[arena_index];
-  }
-
-  static bool IsVectorArenaIndex(int arena_index) {
-    return BlinkGC::kVectorArenaIndex == arena_index;
-  }
-  static bool IsNormalArenaIndex(int);
-
-  void MakeConsistentForGC();
-  // MakeConsistentForMutator() drops marks from marked objects and rebuild
-  // free lists. This is called after taking a snapshot and before resuming
-  // the executions of mutators.
-  void MakeConsistentForMutator();
-
-  // Unmarks all objects in the entire heap. This is supposed to be called in
-  // the beginning of major GC.
-  void Unmark();
-
-  void Compact();
-
-  bool AdvanceLazySweep(base::TimeTicks deadline);
-  bool AdvanceConcurrentSweep(base::JobDelegate*);
-
-  void PrepareForSweep(BlinkGC::CollectionType);
-  void RemoveAllPages();
-  void InvokeFinalizersOnSweptPages();
-  void CompleteSweep();
-
-  void CollectStatistics(ThreadState::Statistics* statistics);
-
-  ThreadHeapStatsCollector* stats_collector() const {
-    return heap_stats_collector_.get();
-  }
-
-#if defined(ADDRESS_SANITIZER)
-  void PoisonUnmarkedObjects();
-#endif
-
-#if DCHECK_IS_ON()
-  // Infrastructure to determine if an address is within one of the
-  // address ranges for the Blink heap. If the address is in the Blink
-  // heap the containing heap page is returned.
-  BasePage* FindPageFromAddress(Address);
-  BasePage* FindPageFromAddress(const void* pointer) {
-    return FindPageFromAddress(
-        reinterpret_cast<Address>(const_cast<void*>(pointer)));
-  }
-#endif
-
-  PageBloomFilter* page_bloom_filter() { return page_bloom_filter_.get(); }
-
-  bool IsInLastAllocatedRegion(Address address) const;
-  void SetLastAllocatedRegion(Address start, size_t length);
-
- private:
-  struct LastAllocatedRegion {
-    Address start = nullptr;
-    size_t length = 0;
-  };
-
-  static int ArenaIndexForObjectSize(size_t);
-
-  void SetupWorklists(bool);
-  void DestroyMarkingWorklists(BlinkGC::StackState);
-  void DestroyCompactionWorklists();
-
-  bool InvokeEphemeronCallbacks(EphemeronProcessing,
-                                MarkingVisitor*,
-                                base::TimeTicks);
-
-  bool FlushV8References(base::TimeTicks);
-
-  ThreadState* thread_state_;
-  std::unique_ptr<ThreadHeapStatsCollector> heap_stats_collector_;
-  std::unique_ptr<RegionTree> region_tree_;
-  std::unique_ptr<PageBloomFilter> page_bloom_filter_;
-  std::unique_ptr<PagePool> free_page_pool_;
-  std::unique_ptr<ProcessHeapReporter> process_heap_reporter_;
-
-  // All objects on this worklist have been fully initialized and assigned a
-  // trace callback for iterating the body of the object. This worklist should
-  // contain almost all objects.
-  std::unique_ptr<MarkingWorklist> marking_worklist_;
-
-  // Objects on this worklist have been collected in the write barrier. The
-  // worklist is different from |marking_worklist_| to minimize execution in the
-  // path where a write barrier is executed.
-  std::unique_ptr<WriteBarrierWorklist> write_barrier_worklist_;
-
-  // Objects on this worklist were observed to be in construction (in their
-  // constructor) and thus have been delayed for processing. They have not yet
-  // been assigned a valid header and trace callback.
-  std::unique_ptr<NotFullyConstructedWorklist> not_fully_constructed_worklist_;
-
-  // Objects on this worklist were previously in construction but have been
-  // moved here upon observing a safepoint, i.e., processing without stack. They
-  // have not yet been assigned a valid header and trace callback but are fully
-  // specified and can thus be iterated using the trace callback (which can be
-  // looked up dynamically).
-  std::unique_ptr<NotFullyConstructedWorklist>
-      previously_not_fully_constructed_worklist_;
-
-  // Worklist of weak callbacks accumulated for objects. Such callbacks are
-  // processed after finishing marking objects.
-  std::unique_ptr<WeakCallbackWorklist> weak_callback_worklist_;
-
-  // The worklist is to remember slots that are traced during
-  // marking phases. The mapping between the slots and the backing stores are
-  // created at the atomic pause phase.
-  std::unique_ptr<MovableReferenceWorklist> movable_reference_worklist_;
-
-  // Worklist of ephemeron callbacks. Used to pass new callbacks from
-  // MarkingVisitor to ThreadHeap.
-  std::unique_ptr<EphemeronPairsWorklist> discovered_ephemeron_pairs_worklist_;
-  std::unique_ptr<EphemeronPairsWorklist> ephemeron_pairs_to_process_worklist_;
-
-  // Worklist for storing the V8 references until ThreadHeap can flush them
-  // to V8.
-  std::unique_ptr<V8ReferencesWorklist> v8_references_worklist_;
-
-  std::unique_ptr<NotSafeToConcurrentlyTraceWorklist>
-      not_safe_to_concurrently_trace_worklist_;
-
-  std::unique_ptr<WeakContainersWorklist> weak_containers_worklist_;
-
-  std::unique_ptr<HeapCompact> compaction_;
-
-  LastAllocatedRegion last_allocated_region_;
-
-  BaseArena* arenas_[BlinkGC::kNumberOfArenas];
-
-  static ThreadHeap* main_thread_heap_;
-
-  static constexpr size_t kStepsBeforeEphemeronPairsFlush = 4u;
-  size_t steps_since_last_ephemeron_pairs_flush_ = 0;
-  static constexpr size_t kStepsBeforeEphemeronProcessing = 16u;
-  size_t steps_since_last_ephemeron_processing_ = 0;
-
-  friend class incremental_marking_test::IncrementalMarkingScopeBase;
-  template <typename T>
-  friend class Member;
-  friend class ThreadState;
-};
-
-template <typename T>
-class GarbageCollected {
-  IS_GARBAGE_COLLECTED_TYPE();
-
- public:
-  using ParentMostGarbageCollectedType = T;
-
-  // Must use MakeGarbageCollected.
-  void* operator new(size_t) = delete;
-  void* operator new[](size_t) = delete;
-  // The garbage collector is taking care of reclaiming the object. Also,
-  // virtual destructor requires an unambiguous, accessible 'operator delete'.
-  void operator delete(void*) { NOTREACHED(); }
-  void operator delete[](void*) = delete;
-
-  template <typename Derived>
-  static void* AllocateObject(size_t size) {
-    return ThreadHeap::Allocate<GCInfoFoldedType<Derived>>(size);
-  }
-
- protected:
-  // This trait in theory can be moved to gc_info.h, but that would cause
-  // significant memory bloat caused by huge number of ThreadHeap::Allocate<>
-  // instantiations, which linker is not able to fold.
-  template <typename Derived>
-  class GCInfoFolded {
-    static constexpr bool is_virtual_destructor_at_base =
-        std::has_virtual_destructor<ParentMostGarbageCollectedType>::value;
-    static constexpr bool both_trivially_destructible =
-        std::is_trivially_destructible<ParentMostGarbageCollectedType>::value &&
-        std::is_trivially_destructible<Derived>::value;
-    static constexpr bool has_custom_dispatch_at_base =
-        internal::HasFinalizeGarbageCollectedObject<
-            ParentMostGarbageCollectedType>::value;
-
-   public:
-    using Type = std::conditional_t<is_virtual_destructor_at_base ||
-                                        both_trivially_destructible ||
-                                        has_custom_dispatch_at_base,
-                                    ParentMostGarbageCollectedType,
-                                    Derived>;
-  };
-
-  template <typename Derived>
-  using GCInfoFoldedType = typename GCInfoFolded<Derived>::Type;
-
-  GarbageCollected() = default;
-
-  DISALLOW_COPY_AND_ASSIGN(GarbageCollected);
-};
-
-// Used for passing custom sizes to MakeGarbageCollected.
-struct AdditionalBytes {
-  explicit AdditionalBytes(size_t bytes) : value(bytes) {}
-  const size_t value;
-};
-
-template <typename T>
-struct MakeGarbageCollectedTrait {
-  template <typename... Args>
-  static T* Call(Args&&... args) {
-    static_assert(WTF::IsGarbageCollectedType<T>::value,
-                  "T needs to be a garbage collected object");
-    static_assert(
-        std::is_trivially_destructible<T>::value ||
-            std::has_virtual_destructor<T>::value || std::is_final<T>::value ||
-            internal::IsGarbageCollectedContainer<T>::value ||
-            internal::HasFinalizeGarbageCollectedObject<T>::value,
-        "Finalized GarbageCollected class should either have a virtual "
-        "destructor or be marked as final");
-    static_assert(!IsGarbageCollectedMixin<T>::value ||
-                      sizeof(T) <= kLargeObjectSizeThreshold,
-                  "GarbageCollectedMixin may not be a large object");
-    void* memory = T::template AllocateObject<T>(sizeof(T));
-    HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
-    // Placement new as regular operator new() is deleted.
-    T* object = ::new (memory) T(std::forward<Args>(args)...);
-    header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>();
-    return object;
-  }
-
-  template <typename... Args>
-  static T* Call(AdditionalBytes additional_bytes, Args&&... args) {
-    static_assert(WTF::IsGarbageCollectedType<T>::value,
-                  "T needs to be a garbage collected object");
-    static_assert(
-        std::is_trivially_destructible<T>::value ||
-            std::has_virtual_destructor<T>::value || std::is_final<T>::value ||
-            internal::IsGarbageCollectedContainer<T>::value ||
-            internal::HasFinalizeGarbageCollectedObject<T>::value,
-        "Finalized GarbageCollected class should either have a virtual "
-        "destructor or be marked as final.");
-    const size_t size = sizeof(T) + additional_bytes.value;
-    if (IsGarbageCollectedMixin<T>::value) {
-      // Ban large mixin so we can use PageFromObject() on them.
-      CHECK_GE(kLargeObjectSizeThreshold, size)
-          << "GarbageCollectedMixin may not be a large object";
-    }
-    void* memory = T::template AllocateObject<T>(size);
-    HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
-    // Placement new as regular operator new() is deleted.
-    T* object = ::new (memory) T(std::forward<Args>(args)...);
-    header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>();
-    return object;
-  }
-};
-
-template <typename T, typename = void>
-struct PostConstructionHookTrait {
-  static void Call(T*) {}
-};
-
-// Default MakeGarbageCollected: Constructs an instance of T, which is a garbage
-// collected type.
-template <typename T, typename... Args>
-T* MakeGarbageCollected(Args&&... args) {
-  T* object = MakeGarbageCollectedTrait<T>::Call(std::forward<Args>(args)...);
-  PostConstructionHookTrait<T>::Call(object);
-  return object;
-}
-
-// Constructs an instance of T, which is a garbage collected type. This special
-// version takes size which enables constructing inline objects.
-template <typename T, typename... Args>
-T* MakeGarbageCollected(AdditionalBytes additional_bytes, Args&&... args) {
-  T* object = MakeGarbageCollectedTrait<T>::Call(additional_bytes,
-                                                 std::forward<Args>(args)...);
-  PostConstructionHookTrait<T>::Call(object);
-  return object;
-}
-
-// Assigning class types to their arenas.
-//
-// We use sized arenas for most 'normal' objects to improve memory locality.
-// It seems that the same type of objects are likely to be accessed together,
-// which means that we want to group objects by type. That's one reason
-// why we provide dedicated arenas for popular types (e.g., Node, CSSValue),
-// but it's not practical to prepare dedicated arenas for all types.
-// Thus we group objects by their sizes, hoping that this will approximately
-// group objects by their types.
-//
-
-inline int ThreadHeap::ArenaIndexForObjectSize(size_t size) {
-  if (size < 64) {
-    if (size < 32)
-      return BlinkGC::kNormalPage1ArenaIndex;
-    return BlinkGC::kNormalPage2ArenaIndex;
-  }
-  if (size < 128)
-    return BlinkGC::kNormalPage3ArenaIndex;
-  return BlinkGC::kNormalPage4ArenaIndex;
-}
-
-inline bool ThreadHeap::IsNormalArenaIndex(int index) {
-  return index >= BlinkGC::kNormalPage1ArenaIndex &&
-         index <= BlinkGC::kNormalPage4ArenaIndex;
-}
-
-inline Address ThreadHeap::AllocateOnArenaIndex(ThreadState* state,
-                                                size_t size,
-                                                int arena_index,
-                                                uint32_t gc_info_index,
-                                                const char* type_name) {
-  DCHECK(state->IsAllocationAllowed());
-  DCHECK_NE(arena_index, BlinkGC::kLargeObjectArenaIndex);
-  NormalPageArena* arena = static_cast<NormalPageArena*>(Arena(arena_index));
-  Address address =
-      arena->AllocateObject(AllocationSizeFromSize(size), gc_info_index);
-  HeapAllocHooks::AllocationHookIfEnabled(address, size, type_name);
-  return address;
-}
-
-template <typename T>
-Address ThreadHeap::Allocate(size_t size) {
-  ThreadState* state = ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
-  const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(T);
-  return state->Heap().AllocateOnArenaIndex(
-      state, size, ThreadHeap::ArenaIndexForObjectSize(size),
-      GCInfoTrait<T>::Index(), type_name);
-}
-
-inline bool ThreadHeap::IsInLastAllocatedRegion(Address address) const {
-  return last_allocated_region_.start <= address &&
-         address <
-             (last_allocated_region_.start + last_allocated_region_.length);
-}
-
-inline void ThreadHeap::SetLastAllocatedRegion(Address start, size_t length) {
-  last_allocated_region_.start = start;
-  last_allocated_region_.length = length;
-}
-
-class PLATFORM_EXPORT LivenessBroker final {
- public:
-  template <typename T>
-  bool IsHeapObjectAlive(const T*) const;
-  template <typename T>
-  bool IsHeapObjectAlive(const WeakMember<T>&) const;
-  template <typename T>
-  bool IsHeapObjectAlive(const UntracedMember<T>&) const;
-
- private:
-  LivenessBroker() = default;
-  friend class internal::LivenessBrokerFactory;
-};
-
-template <typename T>
-bool LivenessBroker::IsHeapObjectAlive(const T* object) const {
-  static_assert(sizeof(T), "T must be fully defined");
-  // The strongification of collections relies on the fact that once a
-  // collection has been strongified, there is no way that it can contain
-  // non-live entries, so no entries will be removed. Since you can't set
-  // the mark bit on a null pointer, that means that null pointers are
-  // always 'alive'.
-  if (!object)
-    return true;
-  // TODO(keishi): some tests create CrossThreadPersistent on non attached
-  // threads.
-  if (!ThreadState::Current())
-    return true;
-  DCHECK(&ThreadState::Current()->Heap() ==
-         &PageFromObject(object)->Arena()->GetThreadState()->Heap());
-  return internal::ObjectAliveTrait<T>::IsHeapObjectAlive(object);
-}
-
-template <typename T>
-bool LivenessBroker::IsHeapObjectAlive(const WeakMember<T>& weak_member) const {
-  return IsHeapObjectAlive(weak_member.Get());
-}
-
-template <typename T>
-bool LivenessBroker::IsHeapObjectAlive(
-    const UntracedMember<T>& untraced_member) const {
-  return IsHeapObjectAlive(untraced_member.Get());
-}
-
-template <typename T>
-void Visitor::HandleWeakCell(const LivenessBroker& broker, const void* object) {
-  WeakMember<T>* weak_member =
-      reinterpret_cast<WeakMember<T>*>(const_cast<void*>(object));
-  if (weak_member->Get()) {
-    if (weak_member->IsHashTableDeletedValue()) {
-      // This can happen when weak fields are deleted while incremental marking
-      // is running. Deleted values need to be preserved to avoid reviving
-      // objects in containers.
-      return;
-    }
-    if (!broker.IsHeapObjectAlive(weak_member->Get()))
-      weak_member->Clear();
-  }
-}
-
-namespace internal {
-
-class LivenessBrokerFactory final {
- public:
-  static LivenessBroker Create() { return LivenessBroker(); }
-};
-
-}  // namespace internal
-
-}  // namespace blink
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/heap.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator.h b/third_party/blink/renderer/platform/heap/heap_allocator.h
index 1d49586..c90f1fc 100644
--- a/third_party/blink/renderer/platform/heap/heap_allocator.h
+++ b/third_party/blink/renderer/platform/heap/heap_allocator.h
@@ -1,919 +1,16 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
 
-#include <type_traits>
-
-#include "build/build_config.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
-#include "third_party/blink/renderer/platform/heap/marking_visitor.h"
-#include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
-#include "third_party/blink/renderer/platform/heap/trace_traits.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/construct_traits.h"
-#include "third_party/blink/renderer/platform/wtf/deque.h"
-#include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h"
-#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/hash_table.h"
-#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/list_hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/type_traits.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
 
-namespace blink {
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/heap_allocator.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
-#define DISALLOW_IN_CONTAINER()              \
- public:                                     \
-  using IsDisallowedInContainerMarker = int; \
-                                             \
- private:                                    \
-  friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
-
-// IsAllowedInContainer returns true if some type T supports being nested
-// arbitrarily in other containers. This is relevant for collections where some
-// collections assume that they are placed on a non-moving arena.
-template <typename T, typename = int>
-struct IsAllowedInContainer : std::true_type {};
-template <typename T>
-struct IsAllowedInContainer<T, typename T::IsDisallowedInContainerMarker>
-    : std::false_type {};
-
-// This is a static-only class used as a trait on collections to make them heap
-// allocated.  However see also HeapListHashSetAllocator.
-class PLATFORM_EXPORT HeapAllocator {
-  STATIC_ONLY(HeapAllocator);
-
- public:
-  using LivenessBroker = blink::LivenessBroker;
-  using Visitor = blink::Visitor;
-  static constexpr bool kIsGarbageCollected = true;
-
-  template <typename T>
-  static size_t MaxElementCountInBackingStore() {
-    return kMaxHeapObjectSize / sizeof(T);
-  }
-
-  template <typename T>
-  static size_t QuantizedSize(size_t count) {
-    CHECK(count <= MaxElementCountInBackingStore<T>());
-    return ThreadHeap::AllocationSizeFromSize(count * sizeof(T)) -
-           sizeof(HeapObjectHeader);
-  }
-  template <typename T>
-  static T* AllocateVectorBacking(size_t size) {
-    return reinterpret_cast<T*>(
-        MakeGarbageCollected<HeapVectorBacking<T>>(size / sizeof(T)));
-  }
-  static void FreeVectorBacking(void*);
-  static bool ExpandVectorBacking(void*, size_t);
-  static bool ShrinkVectorBacking(void* address,
-                                  size_t quantized_current_size,
-                                  size_t quantized_shrunk_size);
-
-  template <typename T, typename HashTable>
-  static T* AllocateHashTableBacking(size_t size) {
-    return reinterpret_cast<T*>(
-        MakeGarbageCollected<HeapHashTableBacking<HashTable>>(
-            size / sizeof(typename HashTable::ValueType)));
-  }
-  template <typename T, typename HashTable>
-  static T* AllocateZeroedHashTableBacking(size_t size) {
-    return AllocateHashTableBacking<T, HashTable>(size);
-  }
-  static void FreeHashTableBacking(void* address);
-  static bool ExpandHashTableBacking(void*, size_t);
-
-  static void TraceBackingStoreIfMarked(const void* address) {
-    // Trace backing store elements only if backing store was marked. The
-    // sweeper may be active on the backing store which requires atomic mark bit
-    // access. A precise filter is performed in
-    // MarkingVisitor::TraceMarkedBackingStore.
-    if (HeapObjectHeader::FromPayload(address)
-            ->IsMarked<HeapObjectHeader::AccessMode::kAtomic>()) {
-      MarkingVisitor::TraceMarkedBackingStore(address);
-    }
-  }
-
-  template <typename T>
-  static void BackingWriteBarrier(T** slot) {
-    MarkingVisitor::WriteBarrier(slot);
-  }
-
-  template <typename Return, typename Metadata>
-  static Return Malloc(size_t size, const char* type_name) {
-    return reinterpret_cast<Return>(
-        MarkAsConstructed(ThreadHeap::Allocate<Metadata>(size)));
-  }
-
-  // Compilers sometimes eagerly instantiates the unused 'operator delete', so
-  // we provide a version that asserts and fails at run-time if used.
-  static void Free(void*) { NOTREACHED(); }
-
-  template <typename T>
-  static void* NewArray(size_t bytes) {
-    NOTREACHED();
-    return nullptr;
-  }
-
-  static void DeleteArray(void* ptr) { NOTREACHED(); }
-
-  static bool IsAllocationAllowed() {
-    return ThreadState::Current()->IsAllocationAllowed();
-  }
-
-  static bool IsSweepForbidden() {
-    return ThreadState::Current()->SweepForbidden();
-  }
-
-  static bool IsIncrementalMarking() {
-    return ThreadState::IsAnyIncrementalMarking() &&
-           ThreadState::Current()->IsIncrementalMarking();
-  }
-
-  template <typename T, typename Traits>
-  static void Trace(Visitor* visitor, const T& t) {
-    TraceCollectionIfEnabled<WTF::WeakHandlingTrait<T>::value, T,
-                             Traits>::Trace(visitor, &t);
-  }
-
-  static void EnterGCForbiddenScope() {
-    ThreadState::Current()->EnterGCForbiddenScope();
-  }
-
-  static void LeaveGCForbiddenScope() {
-    ThreadState::Current()->LeaveGCForbiddenScope();
-  }
-
-  template <typename T, typename Traits>
-  static void NotifyNewObject(T* object) {
-#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION)
-    ThreadState* const thread_state = ThreadState::Current();
-    if (!thread_state->IsIncrementalMarking()) {
-      MarkingVisitor::GenerationalBarrier(reinterpret_cast<Address>(object),
-                                          thread_state);
-      return;
-    }
-#else
-    if (!ThreadState::IsAnyIncrementalMarking())
-      return;
-    // The object may have been in-place constructed as part of a large object.
-    // It is not safe to retrieve the page from the object here.
-    ThreadState* const thread_state = ThreadState::Current();
-    if (!thread_state->IsIncrementalMarking()) {
-      return;
-    }
-#endif  // BLINK_HEAP_YOUNG_GENERATION
-    // Eagerly trace the object ensuring that the object and all its children
-    // are discovered by the marker.
-    ThreadState::NoAllocationScope no_allocation_scope(thread_state);
-    DCHECK(thread_state->CurrentVisitor());
-    // No weak handling for write barriers. Modifying weakly reachable objects
-    // strongifies them for the current cycle.
-    DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*object));
-    TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace(
-        thread_state->CurrentVisitor(), object);
-  }
-
-  template <typename T, typename Traits>
-  static void NotifyNewObjects(T* array, size_t len) {
-#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION)
-    ThreadState* const thread_state = ThreadState::Current();
-    if (!thread_state->IsIncrementalMarking()) {
-      MarkingVisitor::GenerationalBarrier(reinterpret_cast<Address>(array),
-                                          thread_state);
-      return;
-    }
-#else
-    if (!ThreadState::IsAnyIncrementalMarking())
-      return;
-    // The object may have been in-place constructed as part of a large object.
-    // It is not safe to retrieve the page from the object here.
-    ThreadState* const thread_state = ThreadState::Current();
-    if (!thread_state->IsIncrementalMarking()) {
-      return;
-    }
-#endif  // BLINK_HEAP_YOUNG_GENERATION
-    // See |NotifyNewObject| for details.
-    ThreadState::NoAllocationScope no_allocation_scope(thread_state);
-    DCHECK(thread_state->CurrentVisitor());
-    // No weak handling for write barriers. Modifying weakly reachable objects
-    // strongifies them for the current cycle.
-    while (len-- > 0) {
-      DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*array));
-      TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace(
-          thread_state->CurrentVisitor(), array);
-      array++;
-    }
-  }
-
-  template <typename T>
-  static void TraceVectorBacking(Visitor* visitor,
-                                 const T* backing,
-                                 const T* const* backing_slot) {
-    visitor->TraceMovablePointer(backing_slot);
-    visitor->Trace(reinterpret_cast<const HeapVectorBacking<T>*>(backing));
-  }
-
-  template <typename T, typename HashTable>
-  static void TraceHashTableBackingStrongly(Visitor* visitor,
-                                            const T* backing,
-                                            const T* const* backing_slot) {
-    visitor->TraceMovablePointer(backing_slot);
-    visitor->Trace(
-        reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing));
-  }
-
-  template <typename T, typename HashTable>
-  static void TraceHashTableBackingWeakly(Visitor* visitor,
-                                          const T* backing,
-                                          const T* const* backing_slot,
-                                          WeakCallback callback,
-                                          const void* parameter) {
-    visitor->TraceMovablePointer(backing_slot);
-    visitor->TraceWeakContainer(
-        reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing),
-        reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>(
-            backing_slot),
-        TraceTrait<HeapHashTableBacking<HashTable>>::GetTraceDescriptor(
-            backing),
-        TraceTrait<HeapHashTableBacking<HashTable>>::GetWeakTraceDescriptor(
-            backing),
-        callback, parameter);
-  }
-
- private:
-  static Address MarkAsConstructed(Address address) {
-    HeapObjectHeader::FromPayload(reinterpret_cast<void*>(address))
-        ->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>();
-    return address;
-  }
-
-  static void BackingFree(void*);
-  static bool BackingExpand(void*, size_t);
-  static bool BackingShrink(void*,
-                            size_t quantized_current_size,
-                            size_t quantized_shrunk_size);
-
-  template <typename T, wtf_size_t u, typename V>
-  friend class WTF::Vector;
-  template <typename T, typename U, typename V, typename W>
-  friend class WTF::HashSet;
-  template <typename T,
-            typename U,
-            typename V,
-            typename W,
-            typename X,
-            typename Y>
-  friend class WTF::HashMap;
-};
-
-template <typename VisitorDispatcher, typename Value>
-static void TraceListHashSetValue(VisitorDispatcher visitor,
-                                  const Value& value) {
-  // We use the default hash traits for the value in the node, because
-  // ListHashSet does not let you specify any specific ones.
-  // We don't allow ListHashSet of WeakMember, so we set that one false
-  // (there's an assert elsewhere), but we have to specify some value for the
-  // strongify template argument, so we specify WTF::WeakPointersActWeak,
-  // arbitrarily.
-  TraceCollectionIfEnabled<WTF::kNoWeakHandling, Value,
-                           WTF::HashTraits<Value>>::Trace(visitor, &value);
-}
-
-// The inline capacity is just a dummy template argument to match the off-heap
-// allocator.
-// This inherits from the static-only HeapAllocator trait class, but we do
-// declare pointers to instances.  These pointers are always null, and no
-// objects are instantiated.
-template <typename ValueArg, wtf_size_t inlineCapacity>
-class HeapListHashSetAllocator : public HeapAllocator {
-  DISALLOW_NEW();
-
- public:
-  using TableAllocator = HeapAllocator;
-  using Node = WTF::ListHashSetNode<ValueArg, HeapListHashSetAllocator>;
-
-  class AllocatorProvider {
-    DISALLOW_NEW();
-
-   public:
-    // For the heap allocation we don't need an actual allocator object, so
-    // we just return null.
-    HeapListHashSetAllocator* Get() const { return nullptr; }
-
-    // No allocator object is needed.
-    void CreateAllocatorIfNeeded() {}
-    void ReleaseAllocator() {}
-
-    // There is no allocator object in the HeapListHashSet (unlike in the
-    // regular ListHashSet) so there is nothing to swap.
-    void Swap(AllocatorProvider& other) {}
-  };
-
-  void Deallocate(void* dummy) {}
-
-  // This is not a static method even though it could be, because it needs to
-  // match the one that the (off-heap) ListHashSetAllocator has.  The 'this'
-  // pointer will always be null.
-  void* AllocateNode() {
-    // Consider using a LinkedHashSet instead if this compile-time assert fails:
-    static_assert(!WTF::IsWeak<ValueArg>::value,
-                  "weak pointers in a ListHashSet will result in null entries "
-                  "in the set");
-
-    return Malloc<void*, Node>(
-        sizeof(Node),
-        nullptr /* Oilpan does not use the heap profiler at the moment. */);
-  }
-
-  template <typename VisitorDispatcher>
-  static void TraceValue(VisitorDispatcher visitor, const Node* node) {
-    TraceListHashSetValue(visitor, node->value_);
-  }
-};
-
-namespace internal {
-
-template <typename T>
-constexpr bool IsMember = WTF::IsSubclassOfTemplate<T, Member>::value;
-
-template <typename T>
-constexpr bool IsMemberOrWeakMemberType =
-    WTF::IsSubclassOfTemplate<T, Member>::value ||
-    WTF::IsSubclassOfTemplate<T, WeakMember>::value;
-
-}  // namespace internal
-
-template <typename KeyArg,
-          typename MappedArg,
-          typename HashArg = typename DefaultHash<KeyArg>::Hash,
-          typename KeyTraitsArg = HashTraits<KeyArg>,
-          typename MappedTraitsArg = HashTraits<MappedArg>>
-class HeapHashMap : public HashMap<KeyArg,
-                                   MappedArg,
-                                   HashArg,
-                                   KeyTraitsArg,
-                                   MappedTraitsArg,
-                                   HeapAllocator> {
-  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
-  DISALLOW_NEW();
-
-  static void CheckType() {
-    static_assert(std::is_trivially_destructible<HeapHashMap>::value,
-                  "HeapHashMap must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<KeyArg>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
-    static_assert(
-        IsAllowedInContainer<MappedArg>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
-    static_assert(
-        WTF::IsTraceable<KeyArg>::value || WTF::IsTraceable<MappedArg>::value,
-        "For hash maps without traceable elements, use HashMap<> "
-        "instead of HeapHashMap<>.");
-    static_assert(internal::IsMemberOrWeakMemberType<KeyArg> ||
-                      !WTF::IsTraceable<KeyArg>::value,
-                  "HeapHashMap supports only Member, WeakMember and "
-                  "non-traceable types as keys.");
-    static_assert(internal::IsMemberOrWeakMemberType<MappedArg> ||
-                      !WTF::IsTraceable<MappedArg>::value ||
-                      WTF::IsSubclassOfTemplate<MappedArg,
-                                                TraceWrapperV8Reference>::value,
-                  "HeapHashMap supports only Member, WeakMember, "
-                  "TraceWrapperV8Reference and "
-                  "non-traceable types as values.");
-  }
-
- public:
-  template <typename>
-  static void* AllocateObject(size_t size) {
-    return ThreadHeap::Allocate<
-        HeapHashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>>(
-        size);
-  }
-
-  HeapHashMap() { CheckType(); }
-};
-
-template <typename T, typename U, typename V, typename W, typename X>
-struct GCInfoTrait<HeapHashMap<T, U, V, W, X>>
-    : public GCInfoTrait<HashMap<T, U, V, W, X, HeapAllocator>> {};
-
-template <typename ValueArg,
-          typename HashArg = typename DefaultHash<ValueArg>::Hash,
-          typename TraitsArg = HashTraits<ValueArg>>
-class HeapHashSet
-    : public HashSet<ValueArg, HashArg, TraitsArg, HeapAllocator> {
-  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
-  DISALLOW_NEW();
-
-  static void CheckType() {
-    static_assert(internal::IsMemberOrWeakMemberType<ValueArg>,
-                  "HeapHashSet supports only Member and WeakMember.");
-    static_assert(std::is_trivially_destructible<HeapHashSet>::value,
-                  "HeapHashSet must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<ValueArg>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
-    static_assert(WTF::IsTraceable<ValueArg>::value,
-                  "For hash sets without traceable elements, use HashSet<> "
-                  "instead of HeapHashSet<>.");
-  }
-
- public:
-  template <typename>
-  static void* AllocateObject(size_t size) {
-    return ThreadHeap::Allocate<HeapHashSet<ValueArg, HashArg, TraitsArg>>(
-        size);
-  }
-
-  HeapHashSet() { CheckType(); }
-};
-
-template <typename T, typename U, typename V>
-struct GCInfoTrait<HeapHashSet<T, U, V>>
-    : public GCInfoTrait<HashSet<T, U, V, HeapAllocator>> {};
-
-template <typename ValueArg, typename TraitsArg = HashTraits<ValueArg>>
-class HeapLinkedHashSet
-    : public LinkedHashSet<ValueArg, TraitsArg, HeapAllocator> {
-  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
-  DISALLOW_NEW();
-
-  static void CheckType() {
-    static_assert(internal::IsMemberOrWeakMemberType<ValueArg>,
-                  "HeapLinkedHashSet supports only Member and WeakMember.");
-    // If not trivially destructible, we have to add a destructor which will
-    // hinder performance.
-    static_assert(std::is_trivially_destructible<HeapLinkedHashSet>::value,
-                  "HeapLinkedHashSet must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<ValueArg>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
-    static_assert(WTF::IsTraceable<ValueArg>::value,
-                  "For sets without traceable elements, use LinkedHashSet<> "
-                  "instead of HeapLinkedHashSet<>.");
-  }
-
- public:
-  template <typename>
-  static void* AllocateObject(size_t size) {
-    return ThreadHeap::Allocate<HeapLinkedHashSet<ValueArg, TraitsArg>>(size);
-  }
-
-  HeapLinkedHashSet() { CheckType(); }
-};
-
-template <typename T, typename U>
-struct GCInfoTrait<HeapLinkedHashSet<T, U>>
-    : public GCInfoTrait<LinkedHashSet<T, U, HeapAllocator>> {};
-
-template <typename ValueArg,
-          wtf_size_t inlineCapacity =
-              0,  // The inlineCapacity is just a dummy to
-                  // match ListHashSet (off-heap).
-          typename HashArg = typename DefaultHash<ValueArg>::Hash>
-class HeapListHashSet
-    : public ListHashSet<ValueArg,
-                         inlineCapacity,
-                         HashArg,
-                         HeapListHashSetAllocator<ValueArg, inlineCapacity>> {
-  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
-  DISALLOW_NEW();
-
-  static void CheckType() {
-    static_assert(internal::IsMemberOrWeakMemberType<ValueArg>,
-                  "HeapListHashSet supports only Member and WeakMember.");
-    static_assert(std::is_trivially_destructible<HeapListHashSet>::value,
-                  "HeapListHashSet must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<ValueArg>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
-    static_assert(WTF::IsTraceable<ValueArg>::value,
-                  "For sets without traceable elements, use ListHashSet<> "
-                  "instead of HeapListHashSet<>.");
-  }
-
- public:
-  template <typename>
-  static void* AllocateObject(size_t size) {
-    return ThreadHeap::Allocate<
-        HeapListHashSet<ValueArg, inlineCapacity, HashArg>>(size);
-  }
-
-  HeapListHashSet() { CheckType(); }
-};
-
-template <typename T, wtf_size_t inlineCapacity, typename U>
-struct GCInfoTrait<HeapListHashSet<T, inlineCapacity, U>>
-    : public GCInfoTrait<
-          ListHashSet<T,
-                      inlineCapacity,
-                      U,
-                      HeapListHashSetAllocator<T, inlineCapacity>>> {};
-
-template <typename Value,
-          typename HashFunctions = typename DefaultHash<Value>::Hash,
-          typename Traits = HashTraits<Value>>
-class HeapHashCountedSet
-    : public HashCountedSet<Value, HashFunctions, Traits, HeapAllocator> {
-  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
-  DISALLOW_NEW();
-
-  static void CheckType() {
-    static_assert(internal::IsMemberOrWeakMemberType<Value>,
-                  "HeapHashCountedSet supports only Member and WeakMember.");
-    static_assert(std::is_trivially_destructible<HeapHashCountedSet>::value,
-                  "HeapHashCountedSet must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<Value>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
-    static_assert(WTF::IsTraceable<Value>::value,
-                  "For counted sets without traceable elements, use "
-                  "HashCountedSet<> instead of HeapHashCountedSet<>.");
-  }
-
- public:
-  template <typename>
-  static void* AllocateObject(size_t size) {
-    return ThreadHeap::Allocate<
-        HeapHashCountedSet<Value, HashFunctions, Traits>>(size);
-  }
-
-  HeapHashCountedSet() { CheckType(); }
-};
-
-template <typename T, typename U, typename V>
-struct GCInfoTrait<HeapHashCountedSet<T, U, V>>
-    : public GCInfoTrait<HashCountedSet<T, U, V, HeapAllocator>> {};
-
-template <typename T, wtf_size_t inlineCapacity = 0>
-class HeapVector : public Vector<T, inlineCapacity, HeapAllocator> {
-  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
-  DISALLOW_NEW();
-
-  static void CheckType() {
-    static_assert(
-        std::is_trivially_destructible<HeapVector>::value || inlineCapacity,
-        "HeapVector must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<T>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
-    static_assert(WTF::IsTraceable<T>::value,
-                  "For vectors without traceable elements, use Vector<> "
-                  "instead of HeapVector<>.");
-    static_assert(!WTF::IsWeak<T>::value,
-                  "Weak types are not allowed in HeapVector.");
-    static_assert(WTF::IsTraceableInCollectionTrait<VectorTraits<T>>::value,
-                  "Type must be traceable in collection");
-  }
-
- public:
-  template <typename>
-  static void* AllocateObject(size_t size) {
-    // On-heap HeapVectors generally should not have inline capacity, but it is
-    // hard to avoid when using a type alias. Hence we only disallow the
-    // VectorTraits<T>::kNeedsDestruction case for now.
-    static_assert(inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction,
-                  "on-heap HeapVector<> should not have an inline capacity");
-    return ThreadHeap::Allocate<HeapVector<T, inlineCapacity>>(size);
-  }
-
-  HeapVector() { CheckType(); }
-
-  explicit HeapVector(wtf_size_t size)
-      : Vector<T, inlineCapacity, HeapAllocator>(size) {
-    CheckType();
-  }
-
-  HeapVector(wtf_size_t size, const T& val)
-      : Vector<T, inlineCapacity, HeapAllocator>(size, val) {
-    CheckType();
-  }
-
-  template <wtf_size_t otherCapacity>
-  HeapVector(const HeapVector<T, otherCapacity>& other)
-      : Vector<T, inlineCapacity, HeapAllocator>(other) {
-    CheckType();
-  }
-
-  HeapVector(std::initializer_list<T> elements)
-      : Vector<T, inlineCapacity, HeapAllocator>(elements) {
-    CheckType();
-  }
-};
-
-template <typename T, wtf_size_t inlineCapacity>
-struct GCInfoTrait<HeapVector<T, inlineCapacity>>
-    : public GCInfoTrait<Vector<T, inlineCapacity, HeapAllocator>> {};
-
-template <typename T>
-class HeapDeque : public Deque<T, 0, HeapAllocator> {
-  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
-  DISALLOW_NEW();
-
-  static void CheckType() {
-    static_assert(internal::IsMember<T>, "HeapDeque supports only Member.");
-    static_assert(std::is_trivially_destructible<HeapDeque>::value,
-                  "HeapDeque must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<T>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
-    static_assert(WTF::IsTraceable<T>::value,
-                  "For vectors without traceable elements, use Deque<> instead "
-                  "of HeapDeque<>");
-  }
-
- public:
-  template <typename>
-  static void* AllocateObject(size_t size) {
-    return ThreadHeap::Allocate<HeapDeque<T>>(size);
-  }
-
-  HeapDeque() { CheckType(); }
-
-  explicit HeapDeque(wtf_size_t size) : Deque<T, 0, HeapAllocator>(size) {
-    CheckType();
-  }
-
-  HeapDeque(wtf_size_t size, const T& val)
-      : Deque<T, 0, HeapAllocator>(size, val) {
-    CheckType();
-  }
-
-  HeapDeque& operator=(const HeapDeque& other) {
-    HeapDeque<T> copy(other);
-    Deque<T, 0, HeapAllocator>::Swap(copy);
-    return *this;
-  }
-
-  HeapDeque(const HeapDeque<T>& other) : Deque<T, 0, HeapAllocator>(other) {}
-};
-
-template <typename T>
-struct GCInfoTrait<HeapDeque<T>>
-    : public GCInfoTrait<Deque<T, 0, HeapAllocator>> {};
-
-}  // namespace blink
-
-namespace WTF {
-
-template <typename T>
-struct VectorTraits<blink::Member<T>> : VectorTraitsBase<blink::Member<T>> {
-  STATIC_ONLY(VectorTraits);
-  static const bool kNeedsDestruction = false;
-  static const bool kCanInitializeWithMemset = true;
-  static const bool kCanClearUnusedSlotsWithMemset = true;
-  static const bool kCanCopyWithMemcpy = true;
-  static const bool kCanMoveWithMemcpy = true;
-
-  static constexpr bool kCanTraceConcurrently = true;
-};
-
-// These traits are used in VectorBackedLinkedList to support WeakMember in
-// HeapLinkedHashSet though HeapVector<WeakMember> usage is still banned.
-// (See the discussion in https://crrev.com/c/2246014)
-template <typename T>
-struct VectorTraits<blink::WeakMember<T>>
-    : VectorTraitsBase<blink::WeakMember<T>> {
-  STATIC_ONLY(VectorTraits);
-  static const bool kNeedsDestruction = false;
-  static const bool kCanInitializeWithMemset = true;
-  static const bool kCanClearUnusedSlotsWithMemset = true;
-  static const bool kCanCopyWithMemcpy = true;
-  static const bool kCanMoveWithMemcpy = true;
-
-  static constexpr bool kCanTraceConcurrently = true;
-};
-
-template <typename T>
-struct VectorTraits<blink::UntracedMember<T>>
-    : VectorTraitsBase<blink::UntracedMember<T>> {
-  STATIC_ONLY(VectorTraits);
-  static const bool kNeedsDestruction = false;
-  static const bool kCanInitializeWithMemset = true;
-  static const bool kCanClearUnusedSlotsWithMemset = true;
-  static const bool kCanMoveWithMemcpy = true;
-};
-
-template <typename T>
-struct VectorTraits<blink::HeapVector<T, 0>>
-    : VectorTraitsBase<blink::HeapVector<T, 0>> {
-  STATIC_ONLY(VectorTraits);
-  static const bool kNeedsDestruction = false;
-  static const bool kCanInitializeWithMemset = true;
-  static const bool kCanClearUnusedSlotsWithMemset = true;
-  static const bool kCanMoveWithMemcpy = true;
-};
-
-template <typename T>
-struct VectorTraits<blink::HeapDeque<T>>
-    : VectorTraitsBase<blink::HeapDeque<T>> {
-  STATIC_ONLY(VectorTraits);
-  static const bool kNeedsDestruction = false;
-  static const bool kCanInitializeWithMemset = true;
-  static const bool kCanClearUnusedSlotsWithMemset = true;
-  static const bool kCanMoveWithMemcpy = true;
-};
-
-template <typename T, wtf_size_t inlineCapacity>
-struct VectorTraits<blink::HeapVector<T, inlineCapacity>>
-    : VectorTraitsBase<blink::HeapVector<T, inlineCapacity>> {
-  STATIC_ONLY(VectorTraits);
-  static const bool kNeedsDestruction = VectorTraits<T>::kNeedsDestruction;
-  static const bool kCanInitializeWithMemset =
-      VectorTraits<T>::kCanInitializeWithMemset;
-  static const bool kCanClearUnusedSlotsWithMemset =
-      VectorTraits<T>::kCanClearUnusedSlotsWithMemset;
-  static const bool kCanMoveWithMemcpy = VectorTraits<T>::kCanMoveWithMemcpy;
-};
-
-template <typename T>
-struct HashTraits<blink::Member<T>> : SimpleClassHashTraits<blink::Member<T>> {
-  STATIC_ONLY(HashTraits);
-  // FIXME: Implement proper const'ness for iterator types. Requires support
-  // in the marking Visitor.
-  using PeekInType = T*;
-  using IteratorGetType = blink::Member<T>*;
-  using IteratorConstGetType = const blink::Member<T>*;
-  using IteratorReferenceType = blink::Member<T>&;
-  using IteratorConstReferenceType = const blink::Member<T>&;
-  static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
-    return *x;
-  }
-  static IteratorConstReferenceType GetToReferenceConstConversion(
-      IteratorConstGetType x) {
-    return *x;
-  }
-
-  using PeekOutType = T*;
-
-  template <typename U>
-  static void Store(const U& value, blink::Member<T>& storage) {
-    storage = value;
-  }
-
-  static PeekOutType Peek(const blink::Member<T>& value) { return value; }
-
-  static void ConstructDeletedValue(blink::Member<T>& slot, bool) {
-    slot = WTF::kHashTableDeletedValue;
-  }
-
-  static constexpr bool kCanTraceConcurrently = true;
-};
-
-template <typename T>
-struct HashTraits<blink::WeakMember<T>>
-    : SimpleClassHashTraits<blink::WeakMember<T>> {
-  STATIC_ONLY(HashTraits);
-  static const bool kNeedsDestruction = false;
-  // FIXME: Implement proper const'ness for iterator types. Requires support
-  // in the marking Visitor.
-  using PeekInType = T*;
-  using IteratorGetType = blink::WeakMember<T>*;
-  using IteratorConstGetType = const blink::WeakMember<T>*;
-  using IteratorReferenceType = blink::WeakMember<T>&;
-  using IteratorConstReferenceType = const blink::WeakMember<T>&;
-  static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
-    return *x;
-  }
-  static IteratorConstReferenceType GetToReferenceConstConversion(
-      IteratorConstGetType x) {
-    return *x;
-  }
-
-  using PeekOutType = T*;
-
-  template <typename U>
-  static void Store(const U& value, blink::WeakMember<T>& storage) {
-    storage = value;
-  }
-
-  static PeekOutType Peek(const blink::WeakMember<T>& value) { return value; }
-
-  static void ConstructDeletedValue(blink::WeakMember<T>& slot, bool) {
-    slot = WTF::kHashTableDeletedValue;
-  }
-
-  static constexpr bool kCanTraceConcurrently = true;
-};
-
-template <typename T>
-struct HashTraits<blink::UntracedMember<T>>
-    : SimpleClassHashTraits<blink::UntracedMember<T>> {
-  STATIC_ONLY(HashTraits);
-  static const bool kNeedsDestruction = false;
-  // FIXME: Implement proper const'ness for iterator types.
-  using PeekInType = T*;
-  using IteratorGetType = blink::UntracedMember<T>*;
-  using IteratorConstGetType = const blink::UntracedMember<T>*;
-  using IteratorReferenceType = blink::UntracedMember<T>&;
-  using IteratorConstReferenceType = const blink::UntracedMember<T>&;
-  static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
-    return *x;
-  }
-  static IteratorConstReferenceType GetToReferenceConstConversion(
-      IteratorConstGetType x) {
-    return *x;
-  }
-  using PeekOutType = T*;
-
-  template <typename U>
-  static void Store(const U& value, blink::UntracedMember<T>& storage) {
-    storage = value;
-  }
-
-  static PeekOutType Peek(const blink::UntracedMember<T>& value) {
-    return value;
-  }
-};
-
-template <typename T, wtf_size_t inlineCapacity>
-struct IsTraceable<
-    ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>*> {
-  STATIC_ONLY(IsTraceable);
-  static_assert(sizeof(T), "T must be fully defined");
-  // All heap allocated node pointers need visiting to keep the nodes alive,
-  // regardless of whether they contain pointers to other heap allocated
-  // objects.
-  static const bool value = true;
-};
-
-template <typename T, wtf_size_t inlineCapacity>
-struct IsGarbageCollectedType<
-    ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>> {
-  static const bool value = true;
-};
-
-template <typename Set>
-struct IsGarbageCollectedType<ListHashSetIterator<Set>> {
-  static const bool value = IsGarbageCollectedType<Set>::value;
-};
-
-template <typename Set>
-struct IsGarbageCollectedType<ListHashSetConstIterator<Set>> {
-  static const bool value = IsGarbageCollectedType<Set>::value;
-};
-
-template <typename Set>
-struct IsGarbageCollectedType<ListHashSetReverseIterator<Set>> {
-  static const bool value = IsGarbageCollectedType<Set>::value;
-};
-
-template <typename Set>
-struct IsGarbageCollectedType<ListHashSetConstReverseIterator<Set>> {
-  static const bool value = IsGarbageCollectedType<Set>::value;
-};
-
-template <typename T, typename H>
-struct HandleHashTraits : SimpleClassHashTraits<H> {
-  STATIC_ONLY(HandleHashTraits);
-  // TODO: Implement proper const'ness for iterator types. Requires support
-  // in the marking Visitor.
-  using PeekInType = T*;
-  using IteratorGetType = H*;
-  using IteratorConstGetType = const H*;
-  using IteratorReferenceType = H&;
-  using IteratorConstReferenceType = const H&;
-  static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
-    return *x;
-  }
-  static IteratorConstReferenceType GetToReferenceConstConversion(
-      IteratorConstGetType x) {
-    return *x;
-  }
-
-  using PeekOutType = T*;
-
-  template <typename U>
-  static void Store(const U& value, H& storage) {
-    storage = value;
-  }
-
-  static PeekOutType Peek(const H& value) { return value; }
-};
-
-template <typename Value,
-          typename HashFunctions,
-          typename Traits,
-          typename VectorType>
-inline void CopyToVector(
-    const blink::HeapHashCountedSet<Value, HashFunctions, Traits>& set,
-    VectorType& vector) {
-  CopyToVector(static_cast<const HashCountedSet<Value, HashFunctions, Traits,
-                                                blink::HeapAllocator>&>(set),
-               vector);
-}
-
-}  // namespace WTF
-
-#endif
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_stats_collector.h b/third_party/blink/renderer/platform/heap/heap_stats_collector.h
index 344d439..1a6a45c 100644
--- a/third_party/blink/renderer/platform/heap/heap_stats_collector.h
+++ b/third_party/blink/renderer/platform/heap/heap_stats_collector.h
@@ -1,469 +1,16 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_
 
-#include <stddef.h>
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-#include "base/atomicops.h"
-#include "third_party/blink/renderer/platform/heap/blink_gc.h"
-#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-// Interface for observing changes to heap sizing.
-class PLATFORM_EXPORT ThreadHeapStatsObserver {
- public:
-  // Called upon allocating/releasing chunks of memory that contain objects.
-  //
-  // Must not trigger GC or allocate.
-  virtual void IncreaseAllocatedSpace(size_t) = 0;
-  virtual void DecreaseAllocatedSpace(size_t) = 0;
-
-  // Called once per GC cycle with the accurate number of live |bytes|.
-  //
-  // Must not trigger GC or allocate.
-  virtual void ResetAllocatedObjectSize(size_t bytes) = 0;
-
-  // Called after observing at least
-  // |ThreadHeapStatsCollector::kUpdateThreshold| changed bytes through
-  // allocation or explicit free. Reports both, negative and positive
-  // increments, to allow observer to decide whether absolute values or only the
-  // deltas is interesting.
-  //
-  // May trigger GC but most not allocate.
-  virtual void IncreaseAllocatedObjectSize(size_t) = 0;
-  virtual void DecreaseAllocatedObjectSize(size_t) = 0;
-};
-
-#define FOR_ALL_SCOPES(V)                    \
-  V(AtomicPauseCompaction)                   \
-  V(AtomicPauseMarkEpilogue)                 \
-  V(AtomicPauseMarkPrologue)                 \
-  V(AtomicPauseMarkRoots)                    \
-  V(AtomicPauseMarkTransitiveClosure)        \
-  V(AtomicPauseSweepAndCompact)              \
-  V(CompleteSweep)                           \
-  V(IncrementalMarkingFinalize)              \
-  V(IncrementalMarkingStartMarking)          \
-  V(IncrementalMarkingStep)                  \
-  V(IncrementalMarkingWithDeadline)          \
-  V(InvokePreFinalizers)                     \
-  V(LazySweepInIdle)                         \
-  V(LazySweepOnAllocation)                   \
-  V(MarkBailOutObjects)                      \
-  V(MarkInvokeEphemeronCallbacks)            \
-  V(MarkFlushV8References)                   \
-  V(MarkFlushEphemeronPairs)                 \
-  V(MarkProcessWorklists)                    \
-  V(MarkProcessMarkingWorklist)              \
-  V(MarkProcessWriteBarrierWorklist)         \
-  V(MarkProcessNotFullyconstructeddWorklist) \
-  V(MarkNotFullyConstructedObjects)          \
-  V(MarkWeakProcessing)                      \
-  V(UnifiedMarkingStep)                      \
-  V(VisitCrossThreadPersistents)             \
-  V(VisitPersistentRoots)                    \
-  V(VisitPersistents)                        \
-  V(VisitRoots)                              \
-  V(VisitStackRoots)                         \
-  V(VisitRememberedSets)
-
-#define FOR_ALL_CONCURRENT_SCOPES(V)        \
-  V(ConcurrentMarkInvokeEphemeronCallbacks) \
-  V(ConcurrentMarkingStep)                  \
-  V(ConcurrentSweepingStep)
-
-// Manages counters and statistics across garbage collection cycles.
-//
-// Usage:
-//   ThreadHeapStatsCollector stats_collector;
-//   stats_collector.NotifyMarkingStarted(<BlinkGC::CollectionType>,
-//                                        <BlinkGC::GCReason>);
-//   // Use tracer.
-//   stats_collector.NotifySweepingCompleted();
-//   // Previous event is available using stats_collector.previous().
-class PLATFORM_EXPORT ThreadHeapStatsCollector {
-  USING_FAST_MALLOC(ThreadHeapStatsCollector);
-
- public:
-  // These ids will form human readable names when used in Scopes.
-  enum Id {
-#define DECLARE_ENUM(name) k##name,
-    FOR_ALL_SCOPES(DECLARE_ENUM)
-#undef DECLARE_ENUM
-        kNumScopeIds,
-  };
-
-  enum ConcurrentId {
-#define DECLARE_ENUM(name) k##name,
-    FOR_ALL_CONCURRENT_SCOPES(DECLARE_ENUM)
-#undef DECLARE_ENUM
-        kNumConcurrentScopeIds
-  };
-
-  constexpr static const char* ToString(Id id, BlinkGC::CollectionType type) {
-    switch (id) {
-#define CASE(name)                                                    \
-  case k##name:                                                       \
-    return type == BlinkGC::CollectionType::kMajor ? "BlinkGC." #name \
-                                                   : "BlinkGC." #name \
-                                                     ".Minor";
-      FOR_ALL_SCOPES(CASE)
-#undef CASE
-      default:
-        NOTREACHED();
-    }
-    return nullptr;
-  }
-
-  constexpr static const char* ToString(ConcurrentId id,
-                                        BlinkGC::CollectionType type) {
-    switch (id) {
-#define CASE(name)                                                    \
-  case k##name:                                                       \
-    return type == BlinkGC::CollectionType::kMajor ? "BlinkGC." #name \
-                                                   : "BlinkGC." #name \
-                                                     ".Minor";
-      FOR_ALL_CONCURRENT_SCOPES(CASE)
-#undef CASE
-      default:
-        NOTREACHED();
-    }
-    return nullptr;
-  }
-
-  enum TraceCategory { kEnabled, kDisabled };
-  enum ScopeContext { kMutatorThread, kConcurrentThread };
-
-  // Trace a particular scope. Will emit a trace event and record the time in
-  // the corresponding ThreadHeapStatsCollector.
-  template <TraceCategory trace_category = kDisabled,
-            ScopeContext scope_category = kMutatorThread>
-  class PLATFORM_EXPORT InternalScope {
-    DISALLOW_NEW();
-    DISALLOW_COPY_AND_ASSIGN(InternalScope);
-
-    using IdType =
-        std::conditional_t<scope_category == kMutatorThread, Id, ConcurrentId>;
-
-   public:
-    template <typename... Args>
-    InternalScope(ThreadHeapStatsCollector* tracer, IdType id, Args... args)
-        : tracer_(tracer), start_time_(base::TimeTicks::Now()), id_(id) {
-      StartTrace(args...);
-    }
-
-    ~InternalScope() {
-      StopTrace();
-      IncreaseScopeTime(id_);
-    }
-
-   private:
-    inline constexpr static const char* TraceCategory();
-
-    inline void StartTrace();
-    template <typename Value1>
-    inline void StartTrace(const char* k1, Value1 v1);
-    template <typename Value1, typename Value2>
-    inline void StartTrace(const char* k1,
-                           Value1 v1,
-                           const char* k2,
-                           Value2 v2);
-    inline void StopTrace();
-
-    inline void IncreaseScopeTime(Id);
-    inline void IncreaseScopeTime(ConcurrentId);
-
-    ThreadHeapStatsCollector* const tracer_;
-    const base::TimeTicks start_time_;
-    const IdType id_;
-  };
-
-  using Scope = InternalScope<kDisabled>;
-  using EnabledScope = InternalScope<kEnabled>;
-  using ConcurrentScope = InternalScope<kDisabled, kConcurrentThread>;
-  using EnabledConcurrentScope = InternalScope<kEnabled, kConcurrentThread>;
-
-  // BlinkGCInV8Scope keeps track of time spent in Blink's GC when called by V8.
-  // This is necessary to avoid double-accounting of Blink's time when computing
-  // the overall time (V8 + Blink) spent in GC on the main thread.
-  class PLATFORM_EXPORT BlinkGCInV8Scope {
-    DISALLOW_NEW();
-    DISALLOW_COPY_AND_ASSIGN(BlinkGCInV8Scope);
-
-   public:
-    template <typename... Args>
-    BlinkGCInV8Scope(ThreadHeapStatsCollector* tracer)
-        : tracer_(tracer), start_time_(base::TimeTicks::Now()) {}
-
-    ~BlinkGCInV8Scope() {
-      if (tracer_)
-        tracer_->gc_nested_in_v8_ += base::TimeTicks::Now() - start_time_;
-    }
-
-   private:
-    ThreadHeapStatsCollector* const tracer_;
-    const base::TimeTicks start_time_;
-  };
-
-  // POD to hold interesting data accumulated during a garbage collection cycle.
-  // The event is always fully populated when looking at previous events but
-  // is only be partially populated when looking at the current event. See
-  // members on when they are available.
-  //
-  // Note that all getters include time for stand-alone as well as unified heap
-  // GCs. E.g., |atomic_marking_time()| report the marking time of the atomic
-  // phase, independent of whether the GC was a stand-alone or unified heap GC.
-  struct PLATFORM_EXPORT Event {
-    Event();
-
-    // Overall time spent in the GC cycle. This includes marking time as well as
-    // sweeping time.
-    base::TimeDelta gc_cycle_time() const;
-
-    // Time spent in the final atomic pause of a GC cycle.
-    base::TimeDelta atomic_pause_time() const;
-
-    // Time spent in the final atomic pause for marking the heap.
-    base::TimeDelta atomic_marking_time() const;
-
-    // Time spent in the final atomic pause in sweeping and compacting the heap.
-    base::TimeDelta atomic_sweep_and_compact_time() const;
-
-    // Time spent marking the roots.
-    base::TimeDelta roots_marking_time() const;
-
-    // Time spent incrementally marking the heap.
-    base::TimeDelta incremental_marking_time() const;
-
-    // Time spent processing worklist in the foreground thread.
-    base::TimeDelta worklist_processing_time_foreground() const;
-
-    // Time spent flushing v8 references (this is done only in the foreground)
-    base::TimeDelta flushing_v8_references_time() const;
-
-    // Time spent in foreground tasks marking the heap.
-    base::TimeDelta foreground_marking_time() const;
-
-    // Time spent in background tasks marking the heap.
-    base::TimeDelta background_marking_time() const;
-
-    // Overall time spent marking the heap.
-    base::TimeDelta marking_time() const;
-
-    // Time spent in foreground tasks sweeping the heap.
-    base::TimeDelta foreground_sweeping_time() const;
-
-    // Time spent in background tasks sweeping the heap.
-    base::TimeDelta background_sweeping_time() const;
-
-    // Overall time spent sweeping the heap.
-    base::TimeDelta sweeping_time() const;
-
-    // Marked bytes collected during sweeping.
-    size_t unique_id = -1;
-    size_t marked_bytes = 0;
-    size_t compaction_freed_bytes = 0;
-    size_t compaction_freed_pages = 0;
-    bool compaction_recorded_events = false;
-    base::TimeDelta scope_data[kNumScopeIds];
-    base::subtle::Atomic32 concurrent_scope_data[kNumConcurrentScopeIds]{0};
-    BlinkGC::GCReason reason = static_cast<BlinkGC::GCReason>(0);
-    BlinkGC::CollectionType collection_type = BlinkGC::CollectionType::kMajor;
-    size_t object_size_in_bytes_before_sweeping = 0;
-    size_t allocated_space_in_bytes_before_sweeping = 0;
-    size_t partition_alloc_bytes_before_sweeping = 0;
-    double live_object_rate = 0;
-    base::TimeDelta gc_nested_in_v8;
-    bool is_forced_gc = true;
-  };
-
-  // Indicates a new garbage collection cycle.
-  void NotifyMarkingStarted(BlinkGC::CollectionType,
-                            BlinkGC::GCReason,
-                            bool is_forced_gc);
-
-  // Indicates that marking of the current garbage collection cycle is
-  // completed.
-  void NotifyMarkingCompleted(size_t marked_bytes);
-
-  // Indicates the end of a garbage collection cycle. This means that sweeping
-  // is finished at this point.
-  void NotifySweepingCompleted();
-
-  void IncreaseScopeTime(Id id, base::TimeDelta time) {
-    DCHECK(is_started_);
-    current_.scope_data[id] += time;
-  }
-
-  void IncreaseConcurrentScopeTime(ConcurrentId id, base::TimeDelta time) {
-    using Atomic32 = base::subtle::Atomic32;
-    DCHECK(is_started_);
-    const int64_t ms = time.InMicroseconds();
-    DCHECK(ms <= std::numeric_limits<Atomic32>::max());
-    base::subtle::NoBarrier_AtomicIncrement(&current_.concurrent_scope_data[id],
-                                            static_cast<Atomic32>(ms));
-  }
-
-  void UpdateReason(BlinkGC::GCReason);
-  void IncreaseCompactionFreedSize(size_t);
-  void IncreaseCompactionFreedPages(size_t);
-  void IncreaseAllocatedObjectSize(size_t);
-  void DecreaseAllocatedObjectSize(size_t);
-  void IncreaseAllocatedSpace(size_t);
-  void DecreaseAllocatedSpace(size_t);
-  void IncreaseWrapperCount(size_t);
-  void DecreaseWrapperCount(size_t);
-  void IncreaseCollectedWrapperCount(size_t);
-
-  // Called by the GC when it hits a point where allocated memory may be
-  // reported and garbage collection is possible. This is necessary, as
-  // increments and decrements are reported as close to their actual
-  // allocation/reclamation as possible.
-  void AllocatedObjectSizeSafepoint();
-
-  // Size of objects on the heap. Based on marked bytes in the previous cycle
-  // and newly allocated bytes since the previous cycle.
-  size_t object_size_in_bytes() const;
-
-  size_t marked_bytes() const;
-  base::TimeDelta marking_time_so_far() const;
-
-  base::TimeDelta worklist_processing_time_foreground() const;
-
-  base::TimeDelta flushing_v8_references_time() const;
-
-  int64_t allocated_bytes_since_prev_gc() const;
-
-  size_t allocated_space_bytes() const;
-
-  size_t wrapper_count() const;
-  size_t collected_wrapper_count() const;
-
-  bool is_started() const { return is_started_; }
-
-  // Statistics for the previously running garbage collection.
-  const Event& previous() const { return previous_; }
-
-  void RegisterObserver(ThreadHeapStatsObserver* observer);
-  void UnregisterObserver(ThreadHeapStatsObserver* observer);
-
-  void IncreaseAllocatedObjectSizeForTesting(size_t);
-  void DecreaseAllocatedObjectSizeForTesting(size_t);
-
- private:
-  // Observers are implemented using virtual calls. Avoid notifications below
-  // reasonably interesting sizes.
-  static constexpr int64_t kUpdateThreshold = 1024;
-
-  // Invokes |callback| for all registered observers.
-  template <typename Callback>
-  void ForAllObservers(Callback callback);
-
-  void AllocatedObjectSizeSafepointImpl();
-
-  // Statistics for the currently running garbage collection. Note that the
-  // Event may not be fully populated yet as some phase may not have been run.
-  const Event& current() const { return current_; }
-
-  Event current_;
-  Event previous_;
-
-  // Allocated bytes since the last garbage collection. These bytes are reset
-  // after marking as they are accounted in marked_bytes then.
-  int64_t allocated_bytes_since_prev_gc_ = 0;
-  int64_t pos_delta_allocated_bytes_since_prev_gc_ = 0;
-  int64_t neg_delta_allocated_bytes_since_prev_gc_ = 0;
-
-  // Allocated space in bytes for all arenas.
-  size_t allocated_space_bytes_ = 0;
-
-  bool is_started_ = false;
-
-  // base::TimeDelta for RawScope. These don't need to be nested within a
-  // garbage collection cycle to make them easier to use.
-  base::TimeDelta gc_nested_in_v8_;
-
-  Vector<ThreadHeapStatsObserver*> observers_;
-
-  FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, InitialEmpty);
-  FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, IncreaseScopeTime);
-  FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, StopResetsCurrent);
-};
-
-template <ThreadHeapStatsCollector::TraceCategory trace_category,
-          ThreadHeapStatsCollector::ScopeContext scope_category>
-constexpr const char*
-ThreadHeapStatsCollector::InternalScope<trace_category,
-                                        scope_category>::TraceCategory() {
-  switch (trace_category) {
-    case kEnabled:
-      return "blink_gc,devtools.timeline";
-    case kDisabled:
-      return TRACE_DISABLED_BY_DEFAULT("blink_gc");
-  }
-}
-
-template <ThreadHeapStatsCollector::TraceCategory trace_category,
-          ThreadHeapStatsCollector::ScopeContext scope_category>
-void ThreadHeapStatsCollector::InternalScope<trace_category,
-                                             scope_category>::StartTrace() {
-  TRACE_EVENT_BEGIN0(TraceCategory(),
-                     ToString(id_, tracer_->current_.collection_type));
-}
-
-template <ThreadHeapStatsCollector::TraceCategory trace_category,
-          ThreadHeapStatsCollector::ScopeContext scope_category>
-template <typename Value1>
-void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>::
-    StartTrace(const char* k1, Value1 v1) {
-  TRACE_EVENT_BEGIN1(TraceCategory(),
-                     ToString(id_, tracer_->current_.collection_type), k1, v1);
-}
-
-template <ThreadHeapStatsCollector::TraceCategory trace_category,
-          ThreadHeapStatsCollector::ScopeContext scope_category>
-template <typename Value1, typename Value2>
-void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>::
-    StartTrace(const char* k1, Value1 v1, const char* k2, Value2 v2) {
-  TRACE_EVENT_BEGIN2(TraceCategory(),
-                     ToString(id_, tracer_->current_.collection_type), k1, v1,
-                     k2, v2);
-}
-
-template <ThreadHeapStatsCollector::TraceCategory trace_category,
-          ThreadHeapStatsCollector::ScopeContext scope_category>
-void ThreadHeapStatsCollector::InternalScope<trace_category,
-                                             scope_category>::StopTrace() {
-  TRACE_EVENT_END2(TraceCategory(),
-                   ToString(id_, tracer_->current_.collection_type), "epoch",
-                   tracer_->current_.unique_id, "forced",
-                   tracer_->current_.is_forced_gc);
-}
-
-template <ThreadHeapStatsCollector::TraceCategory trace_category,
-          ThreadHeapStatsCollector::ScopeContext scope_category>
-void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>::
-    IncreaseScopeTime(Id) {
-  tracer_->IncreaseScopeTime(id_, base::TimeTicks::Now() - start_time_);
-}
-
-template <ThreadHeapStatsCollector::TraceCategory trace_category,
-          ThreadHeapStatsCollector::ScopeContext scope_category>
-void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>::
-    IncreaseScopeTime(ConcurrentId) {
-  tracer_->IncreaseConcurrentScopeTime(id_,
-                                       base::TimeTicks::Now() - start_time_);
-}
-
-#undef FOR_ALL_SCOPES
-#undef FOR_ALL_CONCURRENT_SCOPES
-
-}  // namespace blink
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_test_utilities.cc b/third_party/blink/renderer/platform/heap/heap_test_utilities.cc
index 4bf47d6..3373e84 100644
--- a/third_party/blink/renderer/platform/heap/heap_test_utilities.cc
+++ b/third_party/blink/renderer/platform/heap/heap_test_utilities.cc
@@ -7,7 +7,7 @@
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_compact.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/heap/heap_test_utilities.h b/third_party/blink/renderer/platform/heap/heap_test_utilities.h
index e4e3a4c4..f9214bbf 100644
--- a/third_party/blink/renderer/platform/heap/heap_test_utilities.h
+++ b/third_party/blink/renderer/platform/heap/heap_test_utilities.h
@@ -14,7 +14,7 @@
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/trace_traits.h"
+#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/heap/heap_traits.h b/third_party/blink/renderer/platform/heap/heap_traits.h
index f72489d..4324520 100644
--- a/third_party/blink/renderer/platform/heap/heap_traits.h
+++ b/third_party/blink/renderer/platform/heap/heap_traits.h
@@ -1,40 +1,16 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TRAITS_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TRAITS_H_
 
-#include <type_traits>
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-namespace blink {
-
-// Given a type T, returns a type that is either Member<T> or just T depending
-// on whether T is a garbage-collected type.
-template <typename T>
-using AddMemberIfNeeded =
-    std::conditional_t<WTF::IsGarbageCollectedType<T>::value, Member<T>, T>;
-
-// Given a type T, returns a type that is either HeapVector<T>,
-// HeapVector<Member<T>> or Vector<T> depending on T.
-template <typename T>
-using VectorOf = std::conditional_t<WTF::IsTraceable<T>::value,
-                                    HeapVector<AddMemberIfNeeded<T>>,
-                                    Vector<T>>;
-
-// Given types T and U, returns a type that is one of the following:
-// - HeapVector<std::pair<V, X>>
-//   (where V is either T or Member<T> and X is either U or Member<U>)
-// - Vector<std::pair<T, U>>
-template <typename T, typename U>
-using VectorOfPairs = std::conditional_t<
-    WTF::IsTraceable<T>::value || WTF::IsTraceable<U>::value,
-    HeapVector<std::pair<AddMemberIfNeeded<T>, AddMemberIfNeeded<U>>>,
-    Vector<std::pair<T, U>>>;
-
-}  // namespace blink
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/heap_traits.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/heap/atomic_entry_flag.h b/third_party/blink/renderer/platform/heap/impl/atomic_entry_flag.h
similarity index 87%
rename from third_party/blink/renderer/platform/heap/atomic_entry_flag.h
rename to third_party/blink/renderer/platform/heap/impl/atomic_entry_flag.h
index 07f013a..46342d94 100644
--- a/third_party/blink/renderer/platform/heap/atomic_entry_flag.h
+++ b/third_party/blink/renderer/platform/heap/impl/atomic_entry_flag.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_ATOMIC_ENTRY_FLAG_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_ATOMIC_ENTRY_FLAG_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_ATOMIC_ENTRY_FLAG_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_ATOMIC_ENTRY_FLAG_H_
 
 #include <atomic>
 
@@ -48,4 +48,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_ATOMIC_ENTRY_FLAG_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_ATOMIC_ENTRY_FLAG_H_
diff --git a/third_party/blink/renderer/platform/heap/blink_gc.cc b/third_party/blink/renderer/platform/heap/impl/blink_gc.cc
similarity index 99%
rename from third_party/blink/renderer/platform/heap/blink_gc.cc
rename to third_party/blink/renderer/platform/heap/impl/blink_gc.cc
index 65881c15..58c86eb 100644
--- a/third_party/blink/renderer/platform/heap/blink_gc.cc
+++ b/third_party/blink/renderer/platform/heap/impl/blink_gc.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/platform/heap/blink_gc.h"
 
-
 namespace blink {
 
 const char* BlinkGC::ToString(BlinkGC::GCReason reason) {
diff --git a/third_party/blink/renderer/platform/heap/impl/blink_gc.h b/third_party/blink/renderer/platform/heap/impl/blink_gc.h
new file mode 100644
index 0000000..1aa6ec6
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/blink_gc.h
@@ -0,0 +1,126 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_H_
+
+// BlinkGC.h is a file that defines common things used by Blink GC.
+
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+#define PRINT_HEAP_STATS 0  // Enable this macro to print heap stats to stderr.
+
+namespace blink {
+
+class LivenessBroker;
+class MarkingVisitor;
+class Visitor;
+
+using Address = uint8_t*;
+using ConstAddress = const uint8_t*;
+
+using VisitorCallback = void (*)(Visitor*, const void*);
+using MarkingVisitorCallback = void (*)(MarkingVisitor*, const void*);
+using TraceCallback = VisitorCallback;
+using WeakCallback = void (*)(const LivenessBroker&, const void*);
+using EphemeronCallback = VisitorCallback;
+
+// Simple alias to avoid heap compaction type signatures turning into
+// a sea of generic |void*|s.
+using MovableReference = const void*;
+
+// List of all arenas. Includes typed arenas as well.
+#define FOR_EACH_ARENA(H) \
+  H(NormalPage1)          \
+  H(NormalPage2)          \
+  H(NormalPage3)          \
+  H(NormalPage4)          \
+  H(Vector)               \
+  H(HashTable)            \
+  H(Node)                 \
+  H(CSSValue)             \
+  H(LargeObject)
+
+class PLATFORM_EXPORT WorklistTaskId {
+ public:
+  static constexpr int MutatorThread = 0;
+  static constexpr int ConcurrentThreadBase = 1;
+};
+
+class PLATFORM_EXPORT BlinkGC final {
+  STATIC_ONLY(BlinkGC);
+
+ public:
+  // CollectionType represents generational collection. kMinor collects objects
+  // in the young generation (i.e. allocated since the previous collection
+  // cycle, since we use sticky bits), kMajor collects the entire heap.
+  enum class CollectionType { kMinor, kMajor };
+
+  // When garbage collecting we need to know whether or not there
+  // can be pointers to Blink GC managed objects on the stack for
+  // each thread. When threads reach a safe point they record
+  // whether or not they have pointers on the stack.
+  enum StackState { kNoHeapPointersOnStack, kHeapPointersOnStack };
+
+  enum MarkingType {
+    // The marking completes synchronously.
+    kAtomicMarking,
+    // The marking task is split and executed in chunks (either on the mutator
+    // thread or concurrently).
+    kIncrementalAndConcurrentMarking
+  };
+
+  enum SweepingType {
+    // The sweeping task is split into chunks and scheduled lazily and
+    // concurrently.
+    kConcurrentAndLazySweeping,
+    // The sweeping task executes synchronously right after marking.
+    kEagerSweeping,
+  };
+
+  // Commented out reasons have been used in the past but are not used any
+  // longer. We keep them here as the corresponding UMA histograms cannot be
+  // changed.
+  enum class GCReason {
+    // kIdleGC = 0
+    // kPreciseGC = 1
+    // kConservativeGC = 2
+    kForcedGCForTesting = 3,
+    // kMemoryPressureGC = 4
+    // kPageNavigationGC = 5
+    kThreadTerminationGC = 6,
+    // kTesting = 7
+    // kIncrementalIdleGC = 8
+    // kIncrementalV8FollowupGC = 9
+    kUnifiedHeapGC = 10,
+    kUnifiedHeapForMemoryReductionGC = 11,
+    kUnifiedHeapForcedForTestingGC = 12,
+    // Used by UMA_HISTOGRAM_ENUMERATION macro.
+    kMaxValue = kUnifiedHeapForcedForTestingGC,
+  };
+
+#define DeclareArenaIndex(name) k##name##ArenaIndex,
+  enum ArenaIndices {
+    FOR_EACH_ARENA(DeclareArenaIndex)
+    // Values used for iteration of heap segments.
+    kNumberOfArenas,
+  };
+#undef DeclareArenaIndex
+
+  enum V8GCType {
+    kV8MinorGC,
+    kV8MajorGC,
+  };
+
+  static const char* ToString(GCReason);
+  static const char* ToString(MarkingType);
+  static const char* ToString(StackState);
+  static const char* ToString(SweepingType);
+  static const char* ToString(ArenaIndices);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_H_
diff --git a/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.cc b/third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.cc
similarity index 98%
rename from third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.cc
rename to third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.cc
index d41056058..cb8ce72 100644
--- a/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.cc
+++ b/third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.cc
@@ -11,8 +11,8 @@
 #include "base/trace_event/process_memory_dump.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/heap/thread_state_statistics.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/web_memory_allocator_dump.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/threading.h"
diff --git a/third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.h b/third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.h
new file mode 100644
index 0000000..e730f8d
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.h
@@ -0,0 +1,47 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
+
+#include "base/trace_event/memory_dump_provider.h"
+#include "third_party/blink/renderer/platform/heap/blink_gc.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}  // namespace base
+
+namespace blink {
+
+class ThreadState;
+
+class PLATFORM_EXPORT BlinkGCMemoryDumpProvider final
+    : public base::trace_event::MemoryDumpProvider {
+  USING_FAST_MALLOC(BlinkGCMemoryDumpProvider);
+
+ public:
+  enum class HeapType { kBlinkMainThread, kBlinkWorkerThread };
+
+  ~BlinkGCMemoryDumpProvider() final;
+  BlinkGCMemoryDumpProvider(
+      ThreadState* thread_state,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      HeapType heap_type);
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&,
+                    base::trace_event::ProcessMemoryDump*) final;
+
+ private:
+  ThreadState* const thread_state_;
+  const HeapType heap_type_;
+  const std::string dump_base_name_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
diff --git a/third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h b/third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h
new file mode 100644
index 0000000..b6562e4
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h
@@ -0,0 +1,53 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_DISALLOW_NEW_WRAPPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_DISALLOW_NEW_WRAPPER_H_
+
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+
+namespace blink {
+
+// DisallowNewWrapper wraps a disallow new type in a GarbageCollected class.
+template <typename T>
+class DisallowNewWrapper final
+    : public GarbageCollected<DisallowNewWrapper<T>> {
+ public:
+  explicit DisallowNewWrapper(const T& value) : value_(value) {
+    static_assert(WTF::IsDisallowNew<T>::value,
+                  "T needs to be a disallow new type");
+    static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable");
+  }
+  explicit DisallowNewWrapper(T&& value) : value_(std::forward<T>(value)) {
+    static_assert(WTF::IsDisallowNew<T>::value,
+                  "T needs to be a disallow new type");
+    static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable");
+  }
+
+  const T& Value() const { return value_; }
+  T&& TakeValue() { return std::move(value_); }
+
+  void Trace(Visitor* visitor) const { visitor->Trace(value_); }
+
+ private:
+  T value_;
+};
+
+// Wraps a disallow new type in a GarbageCollected class, making it possible to
+// be referenced off heap from a Persistent.
+template <typename T>
+DisallowNewWrapper<T>* WrapDisallowNew(const T& value) {
+  return MakeGarbageCollected<DisallowNewWrapper<T>>(value);
+}
+
+template <typename T>
+DisallowNewWrapper<T>* WrapDisallowNew(T&& value) {
+  return MakeGarbageCollected<DisallowNewWrapper<T>>(std::forward<T>(value));
+}
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_DISALLOW_NEW_WRAPPER_H_
diff --git a/third_party/blink/renderer/platform/heap/finalizer_traits.h b/third_party/blink/renderer/platform/heap/impl/finalizer_traits.h
similarity index 92%
rename from third_party/blink/renderer/platform/heap/finalizer_traits.h
rename to third_party/blink/renderer/platform/heap/impl/finalizer_traits.h
index 1a450a4..2f0e0ee 100644
--- a/third_party/blink/renderer/platform/heap/finalizer_traits.h
+++ b/third_party/blink/renderer/platform/heap/impl/finalizer_traits.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_FINALIZER_TRAITS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_FINALIZER_TRAITS_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_FINALIZER_TRAITS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_FINALIZER_TRAITS_H_
 
 #include <type_traits>
 
@@ -92,4 +92,4 @@
 }  // namespace internal
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_FINALIZER_TRAITS_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_FINALIZER_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/heap/impl/garbage_collected.h b/third_party/blink/renderer/platform/heap/impl/garbage_collected.h
new file mode 100644
index 0000000..b7af662ed
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/garbage_collected.h
@@ -0,0 +1,117 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GARBAGE_COLLECTED_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GARBAGE_COLLECTED_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+
+namespace blink {
+
+template <typename T>
+class GarbageCollected;
+
+// GC_PLUGIN_IGNORE is used to make the plugin ignore a particular class or
+// field when checking for proper usage.  When using GC_PLUGIN_IGNORE
+// a bug-number should be provided as an argument where the bug describes
+// what needs to happen to remove the GC_PLUGIN_IGNORE again.
+#if defined(__clang__)
+#define GC_PLUGIN_IGNORE(bug) \
+  __attribute__((annotate("blink_gc_plugin_ignore")))
+#else
+#define GC_PLUGIN_IGNORE(bug)
+#endif
+
+// Template to determine if a class is a GarbageCollectedMixin by checking if it
+// has IsGarbageCollectedMixinMarker
+template <typename T>
+struct IsGarbageCollectedMixin {
+ private:
+  typedef char YesType;
+  struct NoType {
+    char padding[8];
+  };
+
+  template <typename U>
+  static YesType CheckMarker(typename U::IsGarbageCollectedMixinMarker*);
+  template <typename U>
+  static NoType CheckMarker(...);
+
+ public:
+  static const bool value = sizeof(CheckMarker<T>(nullptr)) == sizeof(YesType);
+};
+
+// TraceDescriptor is used to describe how to trace an object.
+struct TraceDescriptor {
+  STACK_ALLOCATED();
+
+ public:
+  // The adjusted base pointer of the object that should be traced.
+  const void* base_object_payload;
+  // A callback for tracing the object.
+  TraceCallback callback;
+};
+
+// The GarbageCollectedMixin interface can be used to automatically define
+// TraceTrait/ObjectAliveTrait on non-leftmost deriving classes which need
+// to be garbage collected.
+class PLATFORM_EXPORT GarbageCollectedMixin {
+ public:
+  typedef int IsGarbageCollectedMixinMarker;
+  virtual void Trace(Visitor*) const {}
+};
+
+// Base class for objects allocated in the Blink garbage-collected heap.
+//
+// Instances of GarbageCollected will be finalized if they are non-trivially
+// destructible.
+template <typename T>
+class GarbageCollected;
+
+template <typename T,
+          bool = WTF::IsSubclassOfTemplate<typename std::remove_const<T>::type,
+                                           GarbageCollected>::value>
+class NeedsAdjustPointer;
+
+template <typename T>
+class NeedsAdjustPointer<T, true> {
+  static_assert(sizeof(T), "T must be fully defined");
+
+ public:
+  static const bool value = false;
+};
+
+template <typename T>
+class NeedsAdjustPointer<T, false> {
+  static_assert(sizeof(T), "T must be fully defined");
+
+ public:
+  static const bool value =
+      IsGarbageCollectedMixin<typename std::remove_const<T>::type>::value;
+};
+
+// TODO(sof): migrate to wtf/TypeTraits.h
+template <typename T>
+class IsFullyDefined {
+  using TrueType = char;
+  struct FalseType {
+    char dummy[2];
+  };
+
+  template <typename U, size_t sz = sizeof(U)>
+  static TrueType IsSizeofKnown(U*);
+  static FalseType IsSizeofKnown(...);
+  static T& t_;
+
+ public:
+  static const bool value = sizeof(TrueType) == sizeof(IsSizeofKnown(&t_));
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GARBAGE_COLLECTED_H_
diff --git a/third_party/blink/renderer/platform/heap/gc_info.cc b/third_party/blink/renderer/platform/heap/impl/gc_info.cc
similarity index 98%
rename from third_party/blink/renderer/platform/heap/gc_info.cc
rename to third_party/blink/renderer/platform/heap/impl/gc_info.cc
index a318782..14361c2 100644
--- a/third_party/blink/renderer/platform/heap/gc_info.cc
+++ b/third_party/blink/renderer/platform/heap/impl/gc_info.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/gc_info.h"
+#include "third_party/blink/renderer/platform/heap/impl/gc_info.h"
 
 #include "base/allocator/partition_allocator/page_allocator.h"
 #include "base/bits.h"
diff --git a/third_party/blink/renderer/platform/heap/gc_info.h b/third_party/blink/renderer/platform/heap/impl/gc_info.h
similarity index 91%
rename from third_party/blink/renderer/platform/heap/gc_info.h
rename to third_party/blink/renderer/platform/heap/impl/gc_info.h
index 155b916..bec05ee6 100644
--- a/third_party/blink/renderer/platform/heap/gc_info.h
+++ b/third_party/blink/renderer/platform/heap/impl/gc_info.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_INFO_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_INFO_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_INFO_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_INFO_H_
 
 #include <atomic>
 #include "base/gtest_prod_util.h"
 #include "third_party/blink/renderer/platform/heap/blink_gc.h"
-#include "third_party/blink/renderer/platform/heap/finalizer_traits.h"
-#include "third_party/blink/renderer/platform/heap/name_traits.h"
+#include "third_party/blink/renderer/platform/heap/impl/finalizer_traits.h"
+#include "third_party/blink/renderer/platform/heap/impl/name_traits.h"
 #include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
 
 namespace blink {
@@ -125,4 +125,4 @@
 
 }  // namespace blink
 
-#endif
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_INFO_H_
diff --git a/third_party/blink/renderer/platform/heap/impl/gc_task_runner.h b/third_party/blink/renderer/platform/heap/impl/gc_task_runner.h
new file mode 100644
index 0000000..1e93f7f
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/gc_task_runner.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_TASK_RUNNER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_TASK_RUNNER_H_
+
+#include <memory>
+#include "base/location.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+
+namespace blink {
+
+class GCTaskObserver final : public Thread::TaskObserver {
+  USING_FAST_MALLOC(GCTaskObserver);
+
+ public:
+  GCTaskObserver() : nesting_(0) {}
+
+  ~GCTaskObserver() override {
+    // m_nesting can be 1 if this was unregistered in a task and
+    // didProcessTask was not called.
+    DCHECK(!nesting_ || nesting_ == 1);
+  }
+
+  void WillProcessTask(const base::PendingTask&, bool) override { nesting_++; }
+
+  void DidProcessTask(const base::PendingTask&) override {
+    // In the production code WebKit::initialize is called from inside the
+    // message loop so we can get didProcessTask() without corresponding
+    // willProcessTask once. This is benign.
+    if (nesting_)
+      nesting_--;
+
+    ThreadState::Current()->SafePoint(nesting_
+                                          ? BlinkGC::kHeapPointersOnStack
+                                          : BlinkGC::kNoHeapPointersOnStack);
+  }
+
+ private:
+  int nesting_;
+};
+
+class GCTaskRunner final {
+  USING_FAST_MALLOC(GCTaskRunner);
+
+ public:
+  explicit GCTaskRunner(Thread* thread)
+      : gc_task_observer_(std::make_unique<GCTaskObserver>()), thread_(thread) {
+    thread_->AddTaskObserver(gc_task_observer_.get());
+  }
+
+  ~GCTaskRunner() { thread_->RemoveTaskObserver(gc_task_observer_.get()); }
+
+ private:
+  std::unique_ptr<GCTaskObserver> gc_task_observer_;
+  Thread* thread_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_TASK_RUNNER_H_
diff --git a/third_party/blink/renderer/platform/heap/heap.cc b/third_party/blink/renderer/platform/heap/impl/heap.cc
similarity index 97%
rename from third_party/blink/renderer/platform/heap/heap.cc
rename to third_party/blink/renderer/platform/heap/impl/heap.cc
index 8c65c256..56359e8d 100644
--- a/third_party/blink/renderer/platform/heap/heap.cc
+++ b/third_party/blink/renderer/platform/heap/impl/heap.cc
@@ -40,13 +40,13 @@
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
 #include "third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h"
-#include "third_party/blink/renderer/platform/heap/heap_compact.h"
 #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
-#include "third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h"
-#include "third_party/blink/renderer/platform/heap/marking_visitor.h"
-#include "third_party/blink/renderer/platform/heap/page_bloom_filter.h"
-#include "third_party/blink/renderer/platform/heap/page_memory.h"
-#include "third_party/blink/renderer/platform/heap/page_pool.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
+#include "third_party/blink/renderer/platform/heap/impl/page_bloom_filter.h"
+#include "third_party/blink/renderer/platform/heap/impl/page_memory.h"
+#include "third_party/blink/renderer/platform/heap/impl/page_pool.h"
 #include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
 #include "third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h"
 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
@@ -728,8 +728,8 @@
 }
 
 void ThreadHeap::InvokeFinalizersOnSweptPages() {
-  for (size_t i = BlinkGC::kNormalPage1ArenaIndex;
-       i < BlinkGC::kNumberOfArenas; i++)
+  for (size_t i = BlinkGC::kNormalPage1ArenaIndex; i < BlinkGC::kNumberOfArenas;
+       i++)
     arenas_[i]->InvokeFinalizersOnSweptPages();
 }
 
diff --git a/third_party/blink/renderer/platform/heap/impl/heap.h b/third_party/blink/renderer/platform/heap/impl/heap.h
new file mode 100644
index 0000000..028f502
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/heap.h
@@ -0,0 +1,749 @@
+/*
+ * 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.
+ */
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_H_
+
+#include <limits>
+#include <memory>
+#include <unordered_set>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "third_party/blink/renderer/platform/heap/impl/gc_info.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h"
+#include "third_party/blink/renderer/platform/heap/impl/worklist.h"
+#include "third_party/blink/renderer/platform/heap/process_heap.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/sanitizers.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
+
+namespace blink {
+
+namespace incremental_marking_test {
+class IncrementalMarkingScopeBase;
+}  // namespace incremental_marking_test
+
+class ConcurrentMarkingVisitor;
+class ThreadHeapStatsCollector;
+class PageBloomFilter;
+class PagePool;
+class ProcessHeapReporter;
+class RegionTree;
+class MarkingSchedulingOracle;
+
+using MarkingItem = TraceDescriptor;
+using NotFullyConstructedItem = const void*;
+
+struct EphemeronPairItem {
+  const void* key;
+  TraceDescriptor value_desc;
+};
+
+struct CustomCallbackItem {
+  WeakCallback callback;
+  const void* parameter;
+};
+
+struct NotSafeToConcurrentlyTraceItem {
+  TraceDescriptor desc;
+  size_t bailout_size;
+};
+
+using V8Reference = const TraceWrapperV8Reference<v8::Value>*;
+
+// Segment size of 512 entries necessary to avoid throughput regressions. Since
+// the work list is currently a temporary object this is not a problem.
+using MarkingWorklist = Worklist<MarkingItem, 512 /* local entries */>;
+using WriteBarrierWorklist = Worklist<HeapObjectHeader*, 64>;
+using NotFullyConstructedWorklist =
+    Worklist<NotFullyConstructedItem, 16 /* local entries */>;
+using WeakCallbackWorklist =
+    Worklist<CustomCallbackItem, 64 /* local entries */>;
+// Using large local segments here (sized 512 entries) to avoid throughput
+// regressions.
+using MovableReferenceWorklist =
+    Worklist<const MovableReference*, 256 /* local entries */>;
+using EphemeronPairsWorklist =
+    Worklist<EphemeronPairItem, 64 /* local entries */>;
+using V8ReferencesWorklist = Worklist<V8Reference, 16 /* local entries */>;
+using NotSafeToConcurrentlyTraceWorklist =
+    Worklist<NotSafeToConcurrentlyTraceItem, 64 /* local entries */>;
+
+class WeakContainersWorklist {
+ public:
+  void Push(const HeapObjectHeader*);
+  void Erase(const HeapObjectHeader*);
+  bool Contains(const HeapObjectHeader*);
+
+ private:
+  WTF::Mutex lock_;
+  std::unordered_set<const HeapObjectHeader*> objects_;
+};
+
+class PLATFORM_EXPORT HeapAllocHooks {
+  STATIC_ONLY(HeapAllocHooks);
+
+ public:
+  // TODO(hajimehoshi): Pass a type name of the allocated object.
+  typedef void AllocationHook(Address, size_t, const char*);
+  typedef void FreeHook(Address);
+
+  // Sets allocation hook. Only one hook is supported.
+  static void SetAllocationHook(AllocationHook* hook) {
+    CHECK(!allocation_hook_ || !hook);
+    allocation_hook_ = hook;
+  }
+
+  // Sets free hook. Only one hook is supported.
+  static void SetFreeHook(FreeHook* hook) {
+    CHECK(!free_hook_ || !hook);
+    free_hook_ = hook;
+  }
+
+  static void AllocationHookIfEnabled(Address address,
+                                      size_t size,
+                                      const char* type_name) {
+    AllocationHook* allocation_hook = allocation_hook_;
+    if (UNLIKELY(!!allocation_hook))
+      allocation_hook(address, size, type_name);
+  }
+
+  static void FreeHookIfEnabled(Address address) {
+    FreeHook* free_hook = free_hook_;
+    if (UNLIKELY(!!free_hook))
+      free_hook(address);
+  }
+
+ private:
+  static AllocationHook* allocation_hook_;
+  static FreeHook* free_hook_;
+};
+
+class HeapCompact;
+template <typename T>
+class Member;
+template <typename T>
+class WeakMember;
+template <typename T>
+class UntracedMember;
+
+namespace internal {
+
+class LivenessBrokerFactory;
+
+template <typename T, bool = NeedsAdjustPointer<T>::value>
+class ObjectAliveTrait;
+
+template <typename T>
+class ObjectAliveTrait<T, false> {
+  STATIC_ONLY(ObjectAliveTrait);
+
+ public:
+  static bool IsHeapObjectAlive(const T* object) {
+    static_assert(sizeof(T), "T must be fully defined");
+    return HeapObjectHeader::FromPayload(object)->IsMarked();
+  }
+};
+
+template <typename T>
+class ObjectAliveTrait<T, true> {
+  STATIC_ONLY(ObjectAliveTrait);
+
+ public:
+  NO_SANITIZE_ADDRESS
+  static bool IsHeapObjectAlive(const T* object) {
+    static_assert(sizeof(T), "T must be fully defined");
+    const HeapObjectHeader* header = HeapObjectHeader::FromPayload(
+        TraceTrait<T>::GetTraceDescriptor(object).base_object_payload);
+    DCHECK(!header->IsInConstruction() || header->IsMarked());
+    return header->IsMarked();
+  }
+};
+
+template <typename T, typename = int>
+struct IsGarbageCollectedContainer : std::false_type {};
+
+template <typename T>
+struct IsGarbageCollectedContainer<
+    T,
+    typename T::IsGarbageCollectedCollectionTypeMarker> : std::true_type {};
+
+}  // namespace internal
+
+class PLATFORM_EXPORT ThreadHeap {
+  USING_FAST_MALLOC(ThreadHeap);
+
+  using EphemeronProcessing = ThreadState::EphemeronProcessing;
+
+ public:
+  explicit ThreadHeap(ThreadState*);
+  ~ThreadHeap();
+
+  MarkingWorklist* GetMarkingWorklist() const {
+    return marking_worklist_.get();
+  }
+
+  WriteBarrierWorklist* GetWriteBarrierWorklist() const {
+    return write_barrier_worklist_.get();
+  }
+
+  NotFullyConstructedWorklist* GetNotFullyConstructedWorklist() const {
+    return not_fully_constructed_worklist_.get();
+  }
+
+  NotFullyConstructedWorklist* GetPreviouslyNotFullyConstructedWorklist()
+      const {
+    return previously_not_fully_constructed_worklist_.get();
+  }
+
+  WeakCallbackWorklist* GetWeakCallbackWorklist() const {
+    return weak_callback_worklist_.get();
+  }
+
+  MovableReferenceWorklist* GetMovableReferenceWorklist() const {
+    return movable_reference_worklist_.get();
+  }
+
+  EphemeronPairsWorklist* GetDiscoveredEphemeronPairsWorklist() const {
+    return discovered_ephemeron_pairs_worklist_.get();
+  }
+
+  EphemeronPairsWorklist* GetEphemeronPairsToProcessWorklist() const {
+    return ephemeron_pairs_to_process_worklist_.get();
+  }
+
+  V8ReferencesWorklist* GetV8ReferencesWorklist() const {
+    return v8_references_worklist_.get();
+  }
+
+  NotSafeToConcurrentlyTraceWorklist* GetNotSafeToConcurrentlyTraceWorklist()
+      const {
+    return not_safe_to_concurrently_trace_worklist_.get();
+  }
+
+  WeakContainersWorklist* GetWeakContainersWorklist() const {
+    return weak_containers_worklist_.get();
+  }
+
+  // Register an ephemeron table for fixed-point iteration.
+  void RegisterWeakTable(void* container_object, EphemeronCallback);
+
+  // Heap compaction registration methods:
+
+  // Checks whether we need to register |addr| as a backing store or a slot
+  // containing reference to it.
+  bool ShouldRegisterMovingAddress();
+
+  RegionTree* GetRegionTree() { return region_tree_.get(); }
+
+  static inline size_t AllocationSizeFromSize(size_t size) {
+    // Add space for header.
+    size_t allocation_size = size + sizeof(HeapObjectHeader);
+    // The allocation size calculation can overflow for large sizes.
+    CHECK_GT(allocation_size, size);
+    // Align size with allocation granularity.
+    allocation_size = (allocation_size + kAllocationMask) & ~kAllocationMask;
+    return allocation_size;
+  }
+  Address AllocateOnArenaIndex(ThreadState*,
+                               size_t,
+                               int arena_index,
+                               uint32_t gc_info_index,
+                               const char* type_name);
+  template <typename T>
+  static Address Allocate(size_t);
+
+  void WeakProcessing(MarkingVisitor*);
+
+  // Moves not fully constructed objects to previously not fully constructed
+  // objects. Such objects can be iterated using the Trace() method and do
+  // not need to rely on conservative handling.
+  void FlushNotFullyConstructedObjects();
+
+  // Moves ephemeron pairs from |discovered_ephemeron_pairs_worklist_| to
+  // |ephemeron_pairs_to_process_worklist_|
+  void FlushEphemeronPairs(EphemeronProcessing);
+
+  // Marks not fully constructed objects.
+  void MarkNotFullyConstructedObjects(MarkingVisitor*);
+  // Marks the transitive closure including ephemerons.
+  bool AdvanceMarking(MarkingVisitor*, base::TimeTicks, EphemeronProcessing);
+  void VerifyMarking();
+
+  // Returns true if concurrent markers will have work to steal
+  bool HasWorkForConcurrentMarking() const;
+  // Returns the amount of work currently available for stealing (there could be
+  // work remaining even if this is 0).
+  size_t ConcurrentMarkingGlobalWorkSize() const;
+  // Returns true if marker is done
+  bool AdvanceConcurrentMarking(ConcurrentMarkingVisitor*,
+                                base::JobDelegate*,
+                                MarkingSchedulingOracle* marking_scheduler);
+
+  // Conservatively checks whether an address is a pointer in any of the
+  // thread heaps.  If so marks the object pointed to as live.
+  Address CheckAndMarkPointer(MarkingVisitor*, Address);
+
+  // Visits remembered sets.
+  void VisitRememberedSets(MarkingVisitor*);
+
+  size_t ObjectPayloadSizeForTesting();
+  void ResetAllocationPointForTesting();
+
+  PagePool* GetFreePagePool() { return free_page_pool_.get(); }
+
+  // This look-up uses the region search tree and a negative contains cache to
+  // provide an efficient mapping from arbitrary addresses to the containing
+  // heap-page if one exists.
+  BasePage* LookupPageForAddress(ConstAddress);
+
+  HeapCompact* Compaction();
+
+  // Get one of the heap structures for this thread.
+  // The thread heap is split into multiple heap parts based on object types
+  // and object sizes.
+  BaseArena* Arena(int arena_index) const {
+    DCHECK_LE(0, arena_index);
+    DCHECK_LT(arena_index, BlinkGC::kNumberOfArenas);
+    return arenas_[arena_index];
+  }
+
+  static bool IsVectorArenaIndex(int arena_index) {
+    return BlinkGC::kVectorArenaIndex == arena_index;
+  }
+  static bool IsNormalArenaIndex(int);
+
+  void MakeConsistentForGC();
+  // MakeConsistentForMutator() drops marks from marked objects and rebuild
+  // free lists. This is called after taking a snapshot and before resuming
+  // the executions of mutators.
+  void MakeConsistentForMutator();
+
+  // Unmarks all objects in the entire heap. This is supposed to be called in
+  // the beginning of major GC.
+  void Unmark();
+
+  void Compact();
+
+  bool AdvanceLazySweep(base::TimeTicks deadline);
+  bool AdvanceConcurrentSweep(base::JobDelegate*);
+
+  void PrepareForSweep(BlinkGC::CollectionType);
+  void RemoveAllPages();
+  void InvokeFinalizersOnSweptPages();
+  void CompleteSweep();
+
+  void CollectStatistics(ThreadState::Statistics* statistics);
+
+  ThreadHeapStatsCollector* stats_collector() const {
+    return heap_stats_collector_.get();
+  }
+
+#if defined(ADDRESS_SANITIZER)
+  void PoisonUnmarkedObjects();
+#endif
+
+#if DCHECK_IS_ON()
+  // Infrastructure to determine if an address is within one of the
+  // address ranges for the Blink heap. If the address is in the Blink
+  // heap the containing heap page is returned.
+  BasePage* FindPageFromAddress(Address);
+  BasePage* FindPageFromAddress(const void* pointer) {
+    return FindPageFromAddress(
+        reinterpret_cast<Address>(const_cast<void*>(pointer)));
+  }
+#endif
+
+  PageBloomFilter* page_bloom_filter() { return page_bloom_filter_.get(); }
+
+  bool IsInLastAllocatedRegion(Address address) const;
+  void SetLastAllocatedRegion(Address start, size_t length);
+
+ private:
+  struct LastAllocatedRegion {
+    Address start = nullptr;
+    size_t length = 0;
+  };
+
+  static int ArenaIndexForObjectSize(size_t);
+
+  void SetupWorklists(bool);
+  void DestroyMarkingWorklists(BlinkGC::StackState);
+  void DestroyCompactionWorklists();
+
+  bool InvokeEphemeronCallbacks(EphemeronProcessing,
+                                MarkingVisitor*,
+                                base::TimeTicks);
+
+  bool FlushV8References(base::TimeTicks);
+
+  ThreadState* thread_state_;
+  std::unique_ptr<ThreadHeapStatsCollector> heap_stats_collector_;
+  std::unique_ptr<RegionTree> region_tree_;
+  std::unique_ptr<PageBloomFilter> page_bloom_filter_;
+  std::unique_ptr<PagePool> free_page_pool_;
+  std::unique_ptr<ProcessHeapReporter> process_heap_reporter_;
+
+  // All objects on this worklist have been fully initialized and assigned a
+  // trace callback for iterating the body of the object. This worklist should
+  // contain almost all objects.
+  std::unique_ptr<MarkingWorklist> marking_worklist_;
+
+  // Objects on this worklist have been collected in the write barrier. The
+  // worklist is different from |marking_worklist_| to minimize execution in the
+  // path where a write barrier is executed.
+  std::unique_ptr<WriteBarrierWorklist> write_barrier_worklist_;
+
+  // Objects on this worklist were observed to be in construction (in their
+  // constructor) and thus have been delayed for processing. They have not yet
+  // been assigned a valid header and trace callback.
+  std::unique_ptr<NotFullyConstructedWorklist> not_fully_constructed_worklist_;
+
+  // Objects on this worklist were previously in construction but have been
+  // moved here upon observing a safepoint, i.e., processing without stack. They
+  // have not yet been assigned a valid header and trace callback but are fully
+  // specified and can thus be iterated using the trace callback (which can be
+  // looked up dynamically).
+  std::unique_ptr<NotFullyConstructedWorklist>
+      previously_not_fully_constructed_worklist_;
+
+  // Worklist of weak callbacks accumulated for objects. Such callbacks are
+  // processed after finishing marking objects.
+  std::unique_ptr<WeakCallbackWorklist> weak_callback_worklist_;
+
+  // The worklist is to remember slots that are traced during
+  // marking phases. The mapping between the slots and the backing stores are
+  // created at the atomic pause phase.
+  std::unique_ptr<MovableReferenceWorklist> movable_reference_worklist_;
+
+  // Worklist of ephemeron callbacks. Used to pass new callbacks from
+  // MarkingVisitor to ThreadHeap.
+  std::unique_ptr<EphemeronPairsWorklist> discovered_ephemeron_pairs_worklist_;
+  std::unique_ptr<EphemeronPairsWorklist> ephemeron_pairs_to_process_worklist_;
+
+  // Worklist for storing the V8 references until ThreadHeap can flush them
+  // to V8.
+  std::unique_ptr<V8ReferencesWorklist> v8_references_worklist_;
+
+  std::unique_ptr<NotSafeToConcurrentlyTraceWorklist>
+      not_safe_to_concurrently_trace_worklist_;
+
+  std::unique_ptr<WeakContainersWorklist> weak_containers_worklist_;
+
+  std::unique_ptr<HeapCompact> compaction_;
+
+  LastAllocatedRegion last_allocated_region_;
+
+  BaseArena* arenas_[BlinkGC::kNumberOfArenas];
+
+  static ThreadHeap* main_thread_heap_;
+
+  static constexpr size_t kStepsBeforeEphemeronPairsFlush = 4u;
+  size_t steps_since_last_ephemeron_pairs_flush_ = 0;
+  static constexpr size_t kStepsBeforeEphemeronProcessing = 16u;
+  size_t steps_since_last_ephemeron_processing_ = 0;
+
+  friend class incremental_marking_test::IncrementalMarkingScopeBase;
+  template <typename T>
+  friend class Member;
+  friend class ThreadState;
+};
+
+template <typename T>
+class GarbageCollected {
+  IS_GARBAGE_COLLECTED_TYPE();
+
+ public:
+  using ParentMostGarbageCollectedType = T;
+
+  // Must use MakeGarbageCollected.
+  void* operator new(size_t) = delete;
+  void* operator new[](size_t) = delete;
+  // The garbage collector is taking care of reclaiming the object. Also,
+  // virtual destructor requires an unambiguous, accessible 'operator delete'.
+  void operator delete(void*) { NOTREACHED(); }
+  void operator delete[](void*) = delete;
+
+  template <typename Derived>
+  static void* AllocateObject(size_t size) {
+    return ThreadHeap::Allocate<GCInfoFoldedType<Derived>>(size);
+  }
+
+ protected:
+  // This trait in theory can be moved to gc_info.h, but that would cause
+  // significant memory bloat caused by huge number of ThreadHeap::Allocate<>
+  // instantiations, which linker is not able to fold.
+  template <typename Derived>
+  class GCInfoFolded {
+    static constexpr bool is_virtual_destructor_at_base =
+        std::has_virtual_destructor<ParentMostGarbageCollectedType>::value;
+    static constexpr bool both_trivially_destructible =
+        std::is_trivially_destructible<ParentMostGarbageCollectedType>::value &&
+        std::is_trivially_destructible<Derived>::value;
+    static constexpr bool has_custom_dispatch_at_base =
+        internal::HasFinalizeGarbageCollectedObject<
+            ParentMostGarbageCollectedType>::value;
+
+   public:
+    using Type = std::conditional_t<is_virtual_destructor_at_base ||
+                                        both_trivially_destructible ||
+                                        has_custom_dispatch_at_base,
+                                    ParentMostGarbageCollectedType,
+                                    Derived>;
+  };
+
+  template <typename Derived>
+  using GCInfoFoldedType = typename GCInfoFolded<Derived>::Type;
+
+  GarbageCollected() = default;
+
+  DISALLOW_COPY_AND_ASSIGN(GarbageCollected);
+};
+
+// Used for passing custom sizes to MakeGarbageCollected.
+struct AdditionalBytes {
+  explicit AdditionalBytes(size_t bytes) : value(bytes) {}
+  const size_t value;
+};
+
+template <typename T>
+struct MakeGarbageCollectedTrait {
+  template <typename... Args>
+  static T* Call(Args&&... args) {
+    static_assert(WTF::IsGarbageCollectedType<T>::value,
+                  "T needs to be a garbage collected object");
+    static_assert(
+        std::is_trivially_destructible<T>::value ||
+            std::has_virtual_destructor<T>::value || std::is_final<T>::value ||
+            internal::IsGarbageCollectedContainer<T>::value ||
+            internal::HasFinalizeGarbageCollectedObject<T>::value,
+        "Finalized GarbageCollected class should either have a virtual "
+        "destructor or be marked as final");
+    static_assert(!IsGarbageCollectedMixin<T>::value ||
+                      sizeof(T) <= kLargeObjectSizeThreshold,
+                  "GarbageCollectedMixin may not be a large object");
+    void* memory = T::template AllocateObject<T>(sizeof(T));
+    HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
+    // Placement new as regular operator new() is deleted.
+    T* object = ::new (memory) T(std::forward<Args>(args)...);
+    header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>();
+    return object;
+  }
+
+  template <typename... Args>
+  static T* Call(AdditionalBytes additional_bytes, Args&&... args) {
+    static_assert(WTF::IsGarbageCollectedType<T>::value,
+                  "T needs to be a garbage collected object");
+    static_assert(
+        std::is_trivially_destructible<T>::value ||
+            std::has_virtual_destructor<T>::value || std::is_final<T>::value ||
+            internal::IsGarbageCollectedContainer<T>::value ||
+            internal::HasFinalizeGarbageCollectedObject<T>::value,
+        "Finalized GarbageCollected class should either have a virtual "
+        "destructor or be marked as final.");
+    const size_t size = sizeof(T) + additional_bytes.value;
+    if (IsGarbageCollectedMixin<T>::value) {
+      // Ban large mixin so we can use PageFromObject() on them.
+      CHECK_GE(kLargeObjectSizeThreshold, size)
+          << "GarbageCollectedMixin may not be a large object";
+    }
+    void* memory = T::template AllocateObject<T>(size);
+    HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
+    // Placement new as regular operator new() is deleted.
+    T* object = ::new (memory) T(std::forward<Args>(args)...);
+    header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>();
+    return object;
+  }
+};
+
+template <typename T, typename = void>
+struct PostConstructionHookTrait {
+  static void Call(T*) {}
+};
+
+// Default MakeGarbageCollected: Constructs an instance of T, which is a garbage
+// collected type.
+template <typename T, typename... Args>
+T* MakeGarbageCollected(Args&&... args) {
+  T* object = MakeGarbageCollectedTrait<T>::Call(std::forward<Args>(args)...);
+  PostConstructionHookTrait<T>::Call(object);
+  return object;
+}
+
+// Constructs an instance of T, which is a garbage collected type. This special
+// version takes size which enables constructing inline objects.
+template <typename T, typename... Args>
+T* MakeGarbageCollected(AdditionalBytes additional_bytes, Args&&... args) {
+  T* object = MakeGarbageCollectedTrait<T>::Call(additional_bytes,
+                                                 std::forward<Args>(args)...);
+  PostConstructionHookTrait<T>::Call(object);
+  return object;
+}
+
+// Assigning class types to their arenas.
+//
+// We use sized arenas for most 'normal' objects to improve memory locality.
+// It seems that the same type of objects are likely to be accessed together,
+// which means that we want to group objects by type. That's one reason
+// why we provide dedicated arenas for popular types (e.g., Node, CSSValue),
+// but it's not practical to prepare dedicated arenas for all types.
+// Thus we group objects by their sizes, hoping that this will approximately
+// group objects by their types.
+//
+
+inline int ThreadHeap::ArenaIndexForObjectSize(size_t size) {
+  if (size < 64) {
+    if (size < 32)
+      return BlinkGC::kNormalPage1ArenaIndex;
+    return BlinkGC::kNormalPage2ArenaIndex;
+  }
+  if (size < 128)
+    return BlinkGC::kNormalPage3ArenaIndex;
+  return BlinkGC::kNormalPage4ArenaIndex;
+}
+
+inline bool ThreadHeap::IsNormalArenaIndex(int index) {
+  return index >= BlinkGC::kNormalPage1ArenaIndex &&
+         index <= BlinkGC::kNormalPage4ArenaIndex;
+}
+
+inline Address ThreadHeap::AllocateOnArenaIndex(ThreadState* state,
+                                                size_t size,
+                                                int arena_index,
+                                                uint32_t gc_info_index,
+                                                const char* type_name) {
+  DCHECK(state->IsAllocationAllowed());
+  DCHECK_NE(arena_index, BlinkGC::kLargeObjectArenaIndex);
+  NormalPageArena* arena = static_cast<NormalPageArena*>(Arena(arena_index));
+  Address address =
+      arena->AllocateObject(AllocationSizeFromSize(size), gc_info_index);
+  HeapAllocHooks::AllocationHookIfEnabled(address, size, type_name);
+  return address;
+}
+
+template <typename T>
+Address ThreadHeap::Allocate(size_t size) {
+  ThreadState* state = ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
+  const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(T);
+  return state->Heap().AllocateOnArenaIndex(
+      state, size, ThreadHeap::ArenaIndexForObjectSize(size),
+      GCInfoTrait<T>::Index(), type_name);
+}
+
+inline bool ThreadHeap::IsInLastAllocatedRegion(Address address) const {
+  return last_allocated_region_.start <= address &&
+         address <
+             (last_allocated_region_.start + last_allocated_region_.length);
+}
+
+inline void ThreadHeap::SetLastAllocatedRegion(Address start, size_t length) {
+  last_allocated_region_.start = start;
+  last_allocated_region_.length = length;
+}
+
+class PLATFORM_EXPORT LivenessBroker final {
+ public:
+  template <typename T>
+  bool IsHeapObjectAlive(const T*) const;
+  template <typename T>
+  bool IsHeapObjectAlive(const WeakMember<T>&) const;
+  template <typename T>
+  bool IsHeapObjectAlive(const UntracedMember<T>&) const;
+
+ private:
+  LivenessBroker() = default;
+  friend class internal::LivenessBrokerFactory;
+};
+
+template <typename T>
+bool LivenessBroker::IsHeapObjectAlive(const T* object) const {
+  static_assert(sizeof(T), "T must be fully defined");
+  // The strongification of collections relies on the fact that once a
+  // collection has been strongified, there is no way that it can contain
+  // non-live entries, so no entries will be removed. Since you can't set
+  // the mark bit on a null pointer, that means that null pointers are
+  // always 'alive'.
+  if (!object)
+    return true;
+  // TODO(keishi): some tests create CrossThreadPersistent on non attached
+  // threads.
+  if (!ThreadState::Current())
+    return true;
+  DCHECK(&ThreadState::Current()->Heap() ==
+         &PageFromObject(object)->Arena()->GetThreadState()->Heap());
+  return internal::ObjectAliveTrait<T>::IsHeapObjectAlive(object);
+}
+
+template <typename T>
+bool LivenessBroker::IsHeapObjectAlive(const WeakMember<T>& weak_member) const {
+  return IsHeapObjectAlive(weak_member.Get());
+}
+
+template <typename T>
+bool LivenessBroker::IsHeapObjectAlive(
+    const UntracedMember<T>& untraced_member) const {
+  return IsHeapObjectAlive(untraced_member.Get());
+}
+
+template <typename T>
+void Visitor::HandleWeakCell(const LivenessBroker& broker, const void* object) {
+  WeakMember<T>* weak_member =
+      reinterpret_cast<WeakMember<T>*>(const_cast<void*>(object));
+  if (weak_member->Get()) {
+    if (weak_member->IsHashTableDeletedValue()) {
+      // This can happen when weak fields are deleted while incremental marking
+      // is running. Deleted values need to be preserved to avoid reviving
+      // objects in containers.
+      return;
+    }
+    if (!broker.IsHeapObjectAlive(weak_member->Get()))
+      weak_member->Clear();
+  }
+}
+
+namespace internal {
+
+class LivenessBrokerFactory final {
+ public:
+  static LivenessBroker Create() { return LivenessBroker(); }
+};
+
+}  // namespace internal
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator.cc b/third_party/blink/renderer/platform/heap/impl/heap_allocator.cc
similarity index 100%
rename from third_party/blink/renderer/platform/heap/heap_allocator.cc
rename to third_party/blink/renderer/platform/heap/impl/heap_allocator.cc
diff --git a/third_party/blink/renderer/platform/heap/impl/heap_allocator.h b/third_party/blink/renderer/platform/heap/impl/heap_allocator.h
new file mode 100644
index 0000000..b78ac9c
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/heap_allocator.h
@@ -0,0 +1,918 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_H_
+
+#include <type_traits>
+
+#include "build/build_config.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
+#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
+#include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/construct_traits.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
+#include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h"
+#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/hash_table.h"
+#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/list_hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+#define DISALLOW_IN_CONTAINER()              \
+ public:                                     \
+  using IsDisallowedInContainerMarker = int; \
+                                             \
+ private:                                    \
+  friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
+
+// IsAllowedInContainer returns true if some type T supports being nested
+// arbitrarily in other containers. This is relevant for collections where some
+// collections assume that they are placed on a non-moving arena.
+template <typename T, typename = int>
+struct IsAllowedInContainer : std::true_type {};
+template <typename T>
+struct IsAllowedInContainer<T, typename T::IsDisallowedInContainerMarker>
+    : std::false_type {};
+
+// This is a static-only class used as a trait on collections to make them heap
+// allocated.  However see also HeapListHashSetAllocator.
+class PLATFORM_EXPORT HeapAllocator {
+  STATIC_ONLY(HeapAllocator);
+
+ public:
+  using LivenessBroker = blink::LivenessBroker;
+  using Visitor = blink::Visitor;
+  static constexpr bool kIsGarbageCollected = true;
+
+  template <typename T>
+  static size_t MaxElementCountInBackingStore() {
+    return kMaxHeapObjectSize / sizeof(T);
+  }
+
+  template <typename T>
+  static size_t QuantizedSize(size_t count) {
+    CHECK(count <= MaxElementCountInBackingStore<T>());
+    return ThreadHeap::AllocationSizeFromSize(count * sizeof(T)) -
+           sizeof(HeapObjectHeader);
+  }
+  template <typename T>
+  static T* AllocateVectorBacking(size_t size) {
+    return reinterpret_cast<T*>(
+        MakeGarbageCollected<HeapVectorBacking<T>>(size / sizeof(T)));
+  }
+  static void FreeVectorBacking(void*);
+  static bool ExpandVectorBacking(void*, size_t);
+  static bool ShrinkVectorBacking(void* address,
+                                  size_t quantized_current_size,
+                                  size_t quantized_shrunk_size);
+
+  template <typename T, typename HashTable>
+  static T* AllocateHashTableBacking(size_t size) {
+    return reinterpret_cast<T*>(
+        MakeGarbageCollected<HeapHashTableBacking<HashTable>>(
+            size / sizeof(typename HashTable::ValueType)));
+  }
+  template <typename T, typename HashTable>
+  static T* AllocateZeroedHashTableBacking(size_t size) {
+    return AllocateHashTableBacking<T, HashTable>(size);
+  }
+  static void FreeHashTableBacking(void* address);
+  static bool ExpandHashTableBacking(void*, size_t);
+
+  static void TraceBackingStoreIfMarked(const void* address) {
+    // Trace backing store elements only if backing store was marked. The
+    // sweeper may be active on the backing store which requires atomic mark bit
+    // access. A precise filter is performed in
+    // MarkingVisitor::TraceMarkedBackingStore.
+    if (HeapObjectHeader::FromPayload(address)
+            ->IsMarked<HeapObjectHeader::AccessMode::kAtomic>()) {
+      MarkingVisitor::TraceMarkedBackingStore(address);
+    }
+  }
+
+  template <typename T>
+  static void BackingWriteBarrier(T** slot) {
+    MarkingVisitor::WriteBarrier(slot);
+  }
+
+  template <typename Return, typename Metadata>
+  static Return Malloc(size_t size, const char* type_name) {
+    return reinterpret_cast<Return>(
+        MarkAsConstructed(ThreadHeap::Allocate<Metadata>(size)));
+  }
+
+  // Compilers sometimes eagerly instantiates the unused 'operator delete', so
+  // we provide a version that asserts and fails at run-time if used.
+  static void Free(void*) { NOTREACHED(); }
+
+  template <typename T>
+  static void* NewArray(size_t bytes) {
+    NOTREACHED();
+    return nullptr;
+  }
+
+  static void DeleteArray(void* ptr) { NOTREACHED(); }
+
+  static bool IsAllocationAllowed() {
+    return ThreadState::Current()->IsAllocationAllowed();
+  }
+
+  static bool IsSweepForbidden() {
+    return ThreadState::Current()->SweepForbidden();
+  }
+
+  static bool IsIncrementalMarking() {
+    return ThreadState::IsAnyIncrementalMarking() &&
+           ThreadState::Current()->IsIncrementalMarking();
+  }
+
+  template <typename T, typename Traits>
+  static void Trace(Visitor* visitor, const T& t) {
+    TraceCollectionIfEnabled<WTF::WeakHandlingTrait<T>::value, T,
+                             Traits>::Trace(visitor, &t);
+  }
+
+  static void EnterGCForbiddenScope() {
+    ThreadState::Current()->EnterGCForbiddenScope();
+  }
+
+  static void LeaveGCForbiddenScope() {
+    ThreadState::Current()->LeaveGCForbiddenScope();
+  }
+
+  template <typename T, typename Traits>
+  static void NotifyNewObject(T* object) {
+#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION)
+    ThreadState* const thread_state = ThreadState::Current();
+    if (!thread_state->IsIncrementalMarking()) {
+      MarkingVisitor::GenerationalBarrier(reinterpret_cast<Address>(object),
+                                          thread_state);
+      return;
+    }
+#else
+    if (!ThreadState::IsAnyIncrementalMarking())
+      return;
+    // The object may have been in-place constructed as part of a large object.
+    // It is not safe to retrieve the page from the object here.
+    ThreadState* const thread_state = ThreadState::Current();
+    if (!thread_state->IsIncrementalMarking()) {
+      return;
+    }
+#endif  // BLINK_HEAP_YOUNG_GENERATION
+    // Eagerly trace the object ensuring that the object and all its children
+    // are discovered by the marker.
+    ThreadState::NoAllocationScope no_allocation_scope(thread_state);
+    DCHECK(thread_state->CurrentVisitor());
+    // No weak handling for write barriers. Modifying weakly reachable objects
+    // strongifies them for the current cycle.
+    DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*object));
+    TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace(
+        thread_state->CurrentVisitor(), object);
+  }
+
+  template <typename T, typename Traits>
+  static void NotifyNewObjects(T* array, size_t len) {
+#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION)
+    ThreadState* const thread_state = ThreadState::Current();
+    if (!thread_state->IsIncrementalMarking()) {
+      MarkingVisitor::GenerationalBarrier(reinterpret_cast<Address>(array),
+                                          thread_state);
+      return;
+    }
+#else
+    if (!ThreadState::IsAnyIncrementalMarking())
+      return;
+    // The object may have been in-place constructed as part of a large object.
+    // It is not safe to retrieve the page from the object here.
+    ThreadState* const thread_state = ThreadState::Current();
+    if (!thread_state->IsIncrementalMarking()) {
+      return;
+    }
+#endif  // BLINK_HEAP_YOUNG_GENERATION
+    // See |NotifyNewObject| for details.
+    ThreadState::NoAllocationScope no_allocation_scope(thread_state);
+    DCHECK(thread_state->CurrentVisitor());
+    // No weak handling for write barriers. Modifying weakly reachable objects
+    // strongifies them for the current cycle.
+    while (len-- > 0) {
+      DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*array));
+      TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace(
+          thread_state->CurrentVisitor(), array);
+      array++;
+    }
+  }
+
+  template <typename T>
+  static void TraceVectorBacking(Visitor* visitor,
+                                 const T* backing,
+                                 const T* const* backing_slot) {
+    visitor->TraceMovablePointer(backing_slot);
+    visitor->Trace(reinterpret_cast<const HeapVectorBacking<T>*>(backing));
+  }
+
+  template <typename T, typename HashTable>
+  static void TraceHashTableBackingStrongly(Visitor* visitor,
+                                            const T* backing,
+                                            const T* const* backing_slot) {
+    visitor->TraceMovablePointer(backing_slot);
+    visitor->Trace(
+        reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing));
+  }
+
+  template <typename T, typename HashTable>
+  static void TraceHashTableBackingWeakly(Visitor* visitor,
+                                          const T* backing,
+                                          const T* const* backing_slot,
+                                          WeakCallback callback,
+                                          const void* parameter) {
+    visitor->TraceMovablePointer(backing_slot);
+    visitor->TraceWeakContainer(
+        reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing),
+        reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>(
+            backing_slot),
+        TraceTrait<HeapHashTableBacking<HashTable>>::GetTraceDescriptor(
+            backing),
+        TraceTrait<HeapHashTableBacking<HashTable>>::GetWeakTraceDescriptor(
+            backing),
+        callback, parameter);
+  }
+
+ private:
+  static Address MarkAsConstructed(Address address) {
+    HeapObjectHeader::FromPayload(reinterpret_cast<void*>(address))
+        ->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>();
+    return address;
+  }
+
+  static void BackingFree(void*);
+  static bool BackingExpand(void*, size_t);
+  static bool BackingShrink(void*,
+                            size_t quantized_current_size,
+                            size_t quantized_shrunk_size);
+
+  template <typename T, wtf_size_t u, typename V>
+  friend class WTF::Vector;
+  template <typename T, typename U, typename V, typename W>
+  friend class WTF::HashSet;
+  template <typename T,
+            typename U,
+            typename V,
+            typename W,
+            typename X,
+            typename Y>
+  friend class WTF::HashMap;
+};
+
+template <typename VisitorDispatcher, typename Value>
+static void TraceListHashSetValue(VisitorDispatcher visitor,
+                                  const Value& value) {
+  // We use the default hash traits for the value in the node, because
+  // ListHashSet does not let you specify any specific ones.
+  // We don't allow ListHashSet of WeakMember, so we set that one false
+  // (there's an assert elsewhere), but we have to specify some value for the
+  // strongify template argument, so we specify WTF::WeakPointersActWeak,
+  // arbitrarily.
+  TraceCollectionIfEnabled<WTF::kNoWeakHandling, Value,
+                           WTF::HashTraits<Value>>::Trace(visitor, &value);
+}
+
+// The inline capacity is just a dummy template argument to match the off-heap
+// allocator.
+// This inherits from the static-only HeapAllocator trait class, but we do
+// declare pointers to instances.  These pointers are always null, and no
+// objects are instantiated.
+template <typename ValueArg, wtf_size_t inlineCapacity>
+class HeapListHashSetAllocator : public HeapAllocator {
+  DISALLOW_NEW();
+
+ public:
+  using TableAllocator = HeapAllocator;
+  using Node = WTF::ListHashSetNode<ValueArg, HeapListHashSetAllocator>;
+
+  class AllocatorProvider {
+    DISALLOW_NEW();
+
+   public:
+    // For the heap allocation we don't need an actual allocator object, so
+    // we just return null.
+    HeapListHashSetAllocator* Get() const { return nullptr; }
+
+    // No allocator object is needed.
+    void CreateAllocatorIfNeeded() {}
+    void ReleaseAllocator() {}
+
+    // There is no allocator object in the HeapListHashSet (unlike in the
+    // regular ListHashSet) so there is nothing to swap.
+    void Swap(AllocatorProvider& other) {}
+  };
+
+  void Deallocate(void* dummy) {}
+
+  // This is not a static method even though it could be, because it needs to
+  // match the one that the (off-heap) ListHashSetAllocator has.  The 'this'
+  // pointer will always be null.
+  void* AllocateNode() {
+    // Consider using a LinkedHashSet instead if this compile-time assert fails:
+    static_assert(!WTF::IsWeak<ValueArg>::value,
+                  "weak pointers in a ListHashSet will result in null entries "
+                  "in the set");
+
+    return Malloc<void*, Node>(
+        sizeof(Node),
+        nullptr /* Oilpan does not use the heap profiler at the moment. */);
+  }
+
+  template <typename VisitorDispatcher>
+  static void TraceValue(VisitorDispatcher visitor, const Node* node) {
+    TraceListHashSetValue(visitor, node->value_);
+  }
+};
+
+namespace internal {
+
+template <typename T>
+constexpr bool IsMember = WTF::IsSubclassOfTemplate<T, Member>::value;
+
+template <typename T>
+constexpr bool IsMemberOrWeakMemberType =
+    WTF::IsSubclassOfTemplate<T, Member>::value ||
+    WTF::IsSubclassOfTemplate<T, WeakMember>::value;
+
+}  // namespace internal
+
+template <typename KeyArg,
+          typename MappedArg,
+          typename HashArg = typename DefaultHash<KeyArg>::Hash,
+          typename KeyTraitsArg = HashTraits<KeyArg>,
+          typename MappedTraitsArg = HashTraits<MappedArg>>
+class HeapHashMap : public HashMap<KeyArg,
+                                   MappedArg,
+                                   HashArg,
+                                   KeyTraitsArg,
+                                   MappedTraitsArg,
+                                   HeapAllocator> {
+  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
+  DISALLOW_NEW();
+
+  static void CheckType() {
+    static_assert(std::is_trivially_destructible<HeapHashMap>::value,
+                  "HeapHashMap must be trivially destructible.");
+    static_assert(
+        IsAllowedInContainer<KeyArg>::value,
+        "Not allowed to directly nest type. Use Member<> indirection instead.");
+    static_assert(
+        IsAllowedInContainer<MappedArg>::value,
+        "Not allowed to directly nest type. Use Member<> indirection instead.");
+    static_assert(
+        WTF::IsTraceable<KeyArg>::value || WTF::IsTraceable<MappedArg>::value,
+        "For hash maps without traceable elements, use HashMap<> "
+        "instead of HeapHashMap<>.");
+    static_assert(internal::IsMemberOrWeakMemberType<KeyArg> ||
+                      !WTF::IsTraceable<KeyArg>::value,
+                  "HeapHashMap supports only Member, WeakMember and "
+                  "non-traceable types as keys.");
+    static_assert(internal::IsMemberOrWeakMemberType<MappedArg> ||
+                      !WTF::IsTraceable<MappedArg>::value ||
+                      WTF::IsSubclassOfTemplate<MappedArg,
+                                                TraceWrapperV8Reference>::value,
+                  "HeapHashMap supports only Member, WeakMember, "
+                  "TraceWrapperV8Reference and "
+                  "non-traceable types as values.");
+  }
+
+ public:
+  template <typename>
+  static void* AllocateObject(size_t size) {
+    return ThreadHeap::Allocate<
+        HeapHashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>>(
+        size);
+  }
+
+  HeapHashMap() { CheckType(); }
+};
+
+template <typename T, typename U, typename V, typename W, typename X>
+struct GCInfoTrait<HeapHashMap<T, U, V, W, X>>
+    : public GCInfoTrait<HashMap<T, U, V, W, X, HeapAllocator>> {};
+
+template <typename ValueArg,
+          typename HashArg = typename DefaultHash<ValueArg>::Hash,
+          typename TraitsArg = HashTraits<ValueArg>>
+class HeapHashSet
+    : public HashSet<ValueArg, HashArg, TraitsArg, HeapAllocator> {
+  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
+  DISALLOW_NEW();
+
+  static void CheckType() {
+    static_assert(internal::IsMemberOrWeakMemberType<ValueArg>,
+                  "HeapHashSet supports only Member and WeakMember.");
+    static_assert(std::is_trivially_destructible<HeapHashSet>::value,
+                  "HeapHashSet must be trivially destructible.");
+    static_assert(
+        IsAllowedInContainer<ValueArg>::value,
+        "Not allowed to directly nest type. Use Member<> indirection instead.");
+    static_assert(WTF::IsTraceable<ValueArg>::value,
+                  "For hash sets without traceable elements, use HashSet<> "
+                  "instead of HeapHashSet<>.");
+  }
+
+ public:
+  template <typename>
+  static void* AllocateObject(size_t size) {
+    return ThreadHeap::Allocate<HeapHashSet<ValueArg, HashArg, TraitsArg>>(
+        size);
+  }
+
+  HeapHashSet() { CheckType(); }
+};
+
+template <typename T, typename U, typename V>
+struct GCInfoTrait<HeapHashSet<T, U, V>>
+    : public GCInfoTrait<HashSet<T, U, V, HeapAllocator>> {};
+
+template <typename ValueArg, typename TraitsArg = HashTraits<ValueArg>>
+class HeapLinkedHashSet
+    : public LinkedHashSet<ValueArg, TraitsArg, HeapAllocator> {
+  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
+  DISALLOW_NEW();
+
+  static void CheckType() {
+    static_assert(internal::IsMemberOrWeakMemberType<ValueArg>,
+                  "HeapLinkedHashSet supports only Member and WeakMember.");
+    // If not trivially destructible, we have to add a destructor which will
+    // hinder performance.
+    static_assert(std::is_trivially_destructible<HeapLinkedHashSet>::value,
+                  "HeapLinkedHashSet must be trivially destructible.");
+    static_assert(
+        IsAllowedInContainer<ValueArg>::value,
+        "Not allowed to directly nest type. Use Member<> indirection instead.");
+    static_assert(WTF::IsTraceable<ValueArg>::value,
+                  "For sets without traceable elements, use LinkedHashSet<> "
+                  "instead of HeapLinkedHashSet<>.");
+  }
+
+ public:
+  template <typename>
+  static void* AllocateObject(size_t size) {
+    return ThreadHeap::Allocate<HeapLinkedHashSet<ValueArg, TraitsArg>>(size);
+  }
+
+  HeapLinkedHashSet() { CheckType(); }
+};
+
+template <typename T, typename U>
+struct GCInfoTrait<HeapLinkedHashSet<T, U>>
+    : public GCInfoTrait<LinkedHashSet<T, U, HeapAllocator>> {};
+
+template <typename ValueArg,
+          wtf_size_t inlineCapacity = 0,  // The inlineCapacity is just a dummy
+                                          // to match ListHashSet (off-heap).
+          typename HashArg = typename DefaultHash<ValueArg>::Hash>
+class HeapListHashSet
+    : public ListHashSet<ValueArg,
+                         inlineCapacity,
+                         HashArg,
+                         HeapListHashSetAllocator<ValueArg, inlineCapacity>> {
+  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
+  DISALLOW_NEW();
+
+  static void CheckType() {
+    static_assert(internal::IsMemberOrWeakMemberType<ValueArg>,
+                  "HeapListHashSet supports only Member and WeakMember.");
+    static_assert(std::is_trivially_destructible<HeapListHashSet>::value,
+                  "HeapListHashSet must be trivially destructible.");
+    static_assert(
+        IsAllowedInContainer<ValueArg>::value,
+        "Not allowed to directly nest type. Use Member<> indirection instead.");
+    static_assert(WTF::IsTraceable<ValueArg>::value,
+                  "For sets without traceable elements, use ListHashSet<> "
+                  "instead of HeapListHashSet<>.");
+  }
+
+ public:
+  template <typename>
+  static void* AllocateObject(size_t size) {
+    return ThreadHeap::Allocate<
+        HeapListHashSet<ValueArg, inlineCapacity, HashArg>>(size);
+  }
+
+  HeapListHashSet() { CheckType(); }
+};
+
+template <typename T, wtf_size_t inlineCapacity, typename U>
+struct GCInfoTrait<HeapListHashSet<T, inlineCapacity, U>>
+    : public GCInfoTrait<
+          ListHashSet<T,
+                      inlineCapacity,
+                      U,
+                      HeapListHashSetAllocator<T, inlineCapacity>>> {};
+
+template <typename Value,
+          typename HashFunctions = typename DefaultHash<Value>::Hash,
+          typename Traits = HashTraits<Value>>
+class HeapHashCountedSet
+    : public HashCountedSet<Value, HashFunctions, Traits, HeapAllocator> {
+  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
+  DISALLOW_NEW();
+
+  static void CheckType() {
+    static_assert(internal::IsMemberOrWeakMemberType<Value>,
+                  "HeapHashCountedSet supports only Member and WeakMember.");
+    static_assert(std::is_trivially_destructible<HeapHashCountedSet>::value,
+                  "HeapHashCountedSet must be trivially destructible.");
+    static_assert(
+        IsAllowedInContainer<Value>::value,
+        "Not allowed to directly nest type. Use Member<> indirection instead.");
+    static_assert(WTF::IsTraceable<Value>::value,
+                  "For counted sets without traceable elements, use "
+                  "HashCountedSet<> instead of HeapHashCountedSet<>.");
+  }
+
+ public:
+  template <typename>
+  static void* AllocateObject(size_t size) {
+    return ThreadHeap::Allocate<
+        HeapHashCountedSet<Value, HashFunctions, Traits>>(size);
+  }
+
+  HeapHashCountedSet() { CheckType(); }
+};
+
+template <typename T, typename U, typename V>
+struct GCInfoTrait<HeapHashCountedSet<T, U, V>>
+    : public GCInfoTrait<HashCountedSet<T, U, V, HeapAllocator>> {};
+
+template <typename T, wtf_size_t inlineCapacity = 0>
+class HeapVector : public Vector<T, inlineCapacity, HeapAllocator> {
+  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
+  DISALLOW_NEW();
+
+  static void CheckType() {
+    static_assert(
+        std::is_trivially_destructible<HeapVector>::value || inlineCapacity,
+        "HeapVector must be trivially destructible.");
+    static_assert(
+        IsAllowedInContainer<T>::value,
+        "Not allowed to directly nest type. Use Member<> indirection instead.");
+    static_assert(WTF::IsTraceable<T>::value,
+                  "For vectors without traceable elements, use Vector<> "
+                  "instead of HeapVector<>.");
+    static_assert(!WTF::IsWeak<T>::value,
+                  "Weak types are not allowed in HeapVector.");
+    static_assert(WTF::IsTraceableInCollectionTrait<VectorTraits<T>>::value,
+                  "Type must be traceable in collection");
+  }
+
+ public:
+  template <typename>
+  static void* AllocateObject(size_t size) {
+    // On-heap HeapVectors generally should not have inline capacity, but it is
+    // hard to avoid when using a type alias. Hence we only disallow the
+    // VectorTraits<T>::kNeedsDestruction case for now.
+    static_assert(inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction,
+                  "on-heap HeapVector<> should not have an inline capacity");
+    return ThreadHeap::Allocate<HeapVector<T, inlineCapacity>>(size);
+  }
+
+  HeapVector() { CheckType(); }
+
+  explicit HeapVector(wtf_size_t size)
+      : Vector<T, inlineCapacity, HeapAllocator>(size) {
+    CheckType();
+  }
+
+  HeapVector(wtf_size_t size, const T& val)
+      : Vector<T, inlineCapacity, HeapAllocator>(size, val) {
+    CheckType();
+  }
+
+  template <wtf_size_t otherCapacity>
+  HeapVector(const HeapVector<T, otherCapacity>& other)
+      : Vector<T, inlineCapacity, HeapAllocator>(other) {
+    CheckType();
+  }
+
+  HeapVector(std::initializer_list<T> elements)
+      : Vector<T, inlineCapacity, HeapAllocator>(elements) {
+    CheckType();
+  }
+};
+
+template <typename T, wtf_size_t inlineCapacity>
+struct GCInfoTrait<HeapVector<T, inlineCapacity>>
+    : public GCInfoTrait<Vector<T, inlineCapacity, HeapAllocator>> {};
+
+template <typename T>
+class HeapDeque : public Deque<T, 0, HeapAllocator> {
+  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
+  DISALLOW_NEW();
+
+  static void CheckType() {
+    static_assert(internal::IsMember<T>, "HeapDeque supports only Member.");
+    static_assert(std::is_trivially_destructible<HeapDeque>::value,
+                  "HeapDeque must be trivially destructible.");
+    static_assert(
+        IsAllowedInContainer<T>::value,
+        "Not allowed to directly nest type. Use Member<> indirection instead.");
+    static_assert(WTF::IsTraceable<T>::value,
+                  "For vectors without traceable elements, use Deque<> instead "
+                  "of HeapDeque<>");
+  }
+
+ public:
+  template <typename>
+  static void* AllocateObject(size_t size) {
+    return ThreadHeap::Allocate<HeapDeque<T>>(size);
+  }
+
+  HeapDeque() { CheckType(); }
+
+  explicit HeapDeque(wtf_size_t size) : Deque<T, 0, HeapAllocator>(size) {
+    CheckType();
+  }
+
+  HeapDeque(wtf_size_t size, const T& val)
+      : Deque<T, 0, HeapAllocator>(size, val) {
+    CheckType();
+  }
+
+  HeapDeque& operator=(const HeapDeque& other) {
+    HeapDeque<T> copy(other);
+    Deque<T, 0, HeapAllocator>::Swap(copy);
+    return *this;
+  }
+
+  HeapDeque(const HeapDeque<T>& other) : Deque<T, 0, HeapAllocator>(other) {}
+};
+
+template <typename T>
+struct GCInfoTrait<HeapDeque<T>>
+    : public GCInfoTrait<Deque<T, 0, HeapAllocator>> {};
+
+}  // namespace blink
+
+namespace WTF {
+
+template <typename T>
+struct VectorTraits<blink::Member<T>> : VectorTraitsBase<blink::Member<T>> {
+  STATIC_ONLY(VectorTraits);
+  static const bool kNeedsDestruction = false;
+  static const bool kCanInitializeWithMemset = true;
+  static const bool kCanClearUnusedSlotsWithMemset = true;
+  static const bool kCanCopyWithMemcpy = true;
+  static const bool kCanMoveWithMemcpy = true;
+
+  static constexpr bool kCanTraceConcurrently = true;
+};
+
+// These traits are used in VectorBackedLinkedList to support WeakMember in
+// HeapLinkedHashSet though HeapVector<WeakMember> usage is still banned.
+// (See the discussion in https://crrev.com/c/2246014)
+template <typename T>
+struct VectorTraits<blink::WeakMember<T>>
+    : VectorTraitsBase<blink::WeakMember<T>> {
+  STATIC_ONLY(VectorTraits);
+  static const bool kNeedsDestruction = false;
+  static const bool kCanInitializeWithMemset = true;
+  static const bool kCanClearUnusedSlotsWithMemset = true;
+  static const bool kCanCopyWithMemcpy = true;
+  static const bool kCanMoveWithMemcpy = true;
+
+  static constexpr bool kCanTraceConcurrently = true;
+};
+
+template <typename T>
+struct VectorTraits<blink::UntracedMember<T>>
+    : VectorTraitsBase<blink::UntracedMember<T>> {
+  STATIC_ONLY(VectorTraits);
+  static const bool kNeedsDestruction = false;
+  static const bool kCanInitializeWithMemset = true;
+  static const bool kCanClearUnusedSlotsWithMemset = true;
+  static const bool kCanMoveWithMemcpy = true;
+};
+
+template <typename T>
+struct VectorTraits<blink::HeapVector<T, 0>>
+    : VectorTraitsBase<blink::HeapVector<T, 0>> {
+  STATIC_ONLY(VectorTraits);
+  static const bool kNeedsDestruction = false;
+  static const bool kCanInitializeWithMemset = true;
+  static const bool kCanClearUnusedSlotsWithMemset = true;
+  static const bool kCanMoveWithMemcpy = true;
+};
+
+template <typename T>
+struct VectorTraits<blink::HeapDeque<T>>
+    : VectorTraitsBase<blink::HeapDeque<T>> {
+  STATIC_ONLY(VectorTraits);
+  static const bool kNeedsDestruction = false;
+  static const bool kCanInitializeWithMemset = true;
+  static const bool kCanClearUnusedSlotsWithMemset = true;
+  static const bool kCanMoveWithMemcpy = true;
+};
+
+template <typename T, wtf_size_t inlineCapacity>
+struct VectorTraits<blink::HeapVector<T, inlineCapacity>>
+    : VectorTraitsBase<blink::HeapVector<T, inlineCapacity>> {
+  STATIC_ONLY(VectorTraits);
+  static const bool kNeedsDestruction = VectorTraits<T>::kNeedsDestruction;
+  static const bool kCanInitializeWithMemset =
+      VectorTraits<T>::kCanInitializeWithMemset;
+  static const bool kCanClearUnusedSlotsWithMemset =
+      VectorTraits<T>::kCanClearUnusedSlotsWithMemset;
+  static const bool kCanMoveWithMemcpy = VectorTraits<T>::kCanMoveWithMemcpy;
+};
+
+template <typename T>
+struct HashTraits<blink::Member<T>> : SimpleClassHashTraits<blink::Member<T>> {
+  STATIC_ONLY(HashTraits);
+  // FIXME: Implement proper const'ness for iterator types. Requires support
+  // in the marking Visitor.
+  using PeekInType = T*;
+  using IteratorGetType = blink::Member<T>*;
+  using IteratorConstGetType = const blink::Member<T>*;
+  using IteratorReferenceType = blink::Member<T>&;
+  using IteratorConstReferenceType = const blink::Member<T>&;
+  static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
+    return *x;
+  }
+  static IteratorConstReferenceType GetToReferenceConstConversion(
+      IteratorConstGetType x) {
+    return *x;
+  }
+
+  using PeekOutType = T*;
+
+  template <typename U>
+  static void Store(const U& value, blink::Member<T>& storage) {
+    storage = value;
+  }
+
+  static PeekOutType Peek(const blink::Member<T>& value) { return value; }
+
+  static void ConstructDeletedValue(blink::Member<T>& slot, bool) {
+    slot = WTF::kHashTableDeletedValue;
+  }
+
+  static constexpr bool kCanTraceConcurrently = true;
+};
+
+template <typename T>
+struct HashTraits<blink::WeakMember<T>>
+    : SimpleClassHashTraits<blink::WeakMember<T>> {
+  STATIC_ONLY(HashTraits);
+  static const bool kNeedsDestruction = false;
+  // FIXME: Implement proper const'ness for iterator types. Requires support
+  // in the marking Visitor.
+  using PeekInType = T*;
+  using IteratorGetType = blink::WeakMember<T>*;
+  using IteratorConstGetType = const blink::WeakMember<T>*;
+  using IteratorReferenceType = blink::WeakMember<T>&;
+  using IteratorConstReferenceType = const blink::WeakMember<T>&;
+  static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
+    return *x;
+  }
+  static IteratorConstReferenceType GetToReferenceConstConversion(
+      IteratorConstGetType x) {
+    return *x;
+  }
+
+  using PeekOutType = T*;
+
+  template <typename U>
+  static void Store(const U& value, blink::WeakMember<T>& storage) {
+    storage = value;
+  }
+
+  static PeekOutType Peek(const blink::WeakMember<T>& value) { return value; }
+
+  static void ConstructDeletedValue(blink::WeakMember<T>& slot, bool) {
+    slot = WTF::kHashTableDeletedValue;
+  }
+
+  static constexpr bool kCanTraceConcurrently = true;
+};
+
+template <typename T>
+struct HashTraits<blink::UntracedMember<T>>
+    : SimpleClassHashTraits<blink::UntracedMember<T>> {
+  STATIC_ONLY(HashTraits);
+  static const bool kNeedsDestruction = false;
+  // FIXME: Implement proper const'ness for iterator types.
+  using PeekInType = T*;
+  using IteratorGetType = blink::UntracedMember<T>*;
+  using IteratorConstGetType = const blink::UntracedMember<T>*;
+  using IteratorReferenceType = blink::UntracedMember<T>&;
+  using IteratorConstReferenceType = const blink::UntracedMember<T>&;
+  static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
+    return *x;
+  }
+  static IteratorConstReferenceType GetToReferenceConstConversion(
+      IteratorConstGetType x) {
+    return *x;
+  }
+  using PeekOutType = T*;
+
+  template <typename U>
+  static void Store(const U& value, blink::UntracedMember<T>& storage) {
+    storage = value;
+  }
+
+  static PeekOutType Peek(const blink::UntracedMember<T>& value) {
+    return value;
+  }
+};
+
+template <typename T, wtf_size_t inlineCapacity>
+struct IsTraceable<
+    ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>*> {
+  STATIC_ONLY(IsTraceable);
+  static_assert(sizeof(T), "T must be fully defined");
+  // All heap allocated node pointers need visiting to keep the nodes alive,
+  // regardless of whether they contain pointers to other heap allocated
+  // objects.
+  static const bool value = true;
+};
+
+template <typename T, wtf_size_t inlineCapacity>
+struct IsGarbageCollectedType<
+    ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>> {
+  static const bool value = true;
+};
+
+template <typename Set>
+struct IsGarbageCollectedType<ListHashSetIterator<Set>> {
+  static const bool value = IsGarbageCollectedType<Set>::value;
+};
+
+template <typename Set>
+struct IsGarbageCollectedType<ListHashSetConstIterator<Set>> {
+  static const bool value = IsGarbageCollectedType<Set>::value;
+};
+
+template <typename Set>
+struct IsGarbageCollectedType<ListHashSetReverseIterator<Set>> {
+  static const bool value = IsGarbageCollectedType<Set>::value;
+};
+
+template <typename Set>
+struct IsGarbageCollectedType<ListHashSetConstReverseIterator<Set>> {
+  static const bool value = IsGarbageCollectedType<Set>::value;
+};
+
+template <typename T, typename H>
+struct HandleHashTraits : SimpleClassHashTraits<H> {
+  STATIC_ONLY(HandleHashTraits);
+  // TODO: Implement proper const'ness for iterator types. Requires support
+  // in the marking Visitor.
+  using PeekInType = T*;
+  using IteratorGetType = H*;
+  using IteratorConstGetType = const H*;
+  using IteratorReferenceType = H&;
+  using IteratorConstReferenceType = const H&;
+  static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
+    return *x;
+  }
+  static IteratorConstReferenceType GetToReferenceConstConversion(
+      IteratorConstGetType x) {
+    return *x;
+  }
+
+  using PeekOutType = T*;
+
+  template <typename U>
+  static void Store(const U& value, H& storage) {
+    storage = value;
+  }
+
+  static PeekOutType Peek(const H& value) { return value; }
+};
+
+template <typename Value,
+          typename HashFunctions,
+          typename Traits,
+          typename VectorType>
+inline void CopyToVector(
+    const blink::HeapHashCountedSet<Value, HashFunctions, Traits>& set,
+    VectorType& vector) {
+  CopyToVector(static_cast<const HashCountedSet<Value, HashFunctions, Traits,
+                                                blink::HeapAllocator>&>(set),
+               vector);
+}
+
+}  // namespace WTF
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_compact.cc b/third_party/blink/renderer/platform/heap/impl/heap_compact.cc
similarity index 84%
rename from third_party/blink/renderer/platform/heap/heap_compact.cc
rename to third_party/blink/renderer/platform/heap/impl/heap_compact.cc
index f750406..411ea51 100644
--- a/third_party/blink/renderer/platform/heap/heap_compact.cc
+++ b/third_party/blink/renderer/platform/heap/impl/heap_compact.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/heap_compact.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h"
 
 #include <memory>
 
@@ -170,70 +170,70 @@
 
 void HeapCompact::MovableObjectFixups::Relocate(Address from, Address to) {
 #if DCHECK_IS_ON()
-    moved_objects_.insert(from);
+  moved_objects_.insert(from);
 #endif  // DCHECK_IS_ON()
 
-    const HeapObjectHeader* header = HeapObjectHeader::FromPayload(to);
-    const size_t size = header->PayloadSize();
+  const HeapObjectHeader* header = HeapObjectHeader::FromPayload(to);
+  const size_t size = header->PayloadSize();
 
-    // Interior slots always need to be processed for moved objects.
-    // Consider an object A with slot A.x pointing to value B where A is
-    // allocated on a movable page itself. When B is finally moved, it needs to
-    // find the corresponding slot A.x. Object A may be moved already and the
-    // memory may have been freed, which would result in a crash.
-    if (!interior_fixups_.empty()) {
-      RelocateInteriorFixups(from, to, size);
-    }
+  // Interior slots always need to be processed for moved objects.
+  // Consider an object A with slot A.x pointing to value B where A is
+  // allocated on a movable page itself. When B is finally moved, it needs to
+  // find the corresponding slot A.x. Object A may be moved already and the
+  // memory may have been freed, which would result in a crash.
+  if (!interior_fixups_.empty()) {
+    RelocateInteriorFixups(from, to, size);
+  }
 
-    auto it = fixups_.find(from);
-    // This means that there is no corresponding slot for a live backing store.
-    // This may happen because a mutator may change the slot to point to a
-    // different backing store because e.g. incremental marking marked a backing
-    // store as live that was later on replaced.
-    if (it == fixups_.end()) {
-      return;
-    }
+  auto it = fixups_.find(from);
+  // This means that there is no corresponding slot for a live backing store.
+  // This may happen because a mutator may change the slot to point to a
+  // different backing store because e.g. incremental marking marked a backing
+  // store as live that was later on replaced.
+  if (it == fixups_.end()) {
+    return;
+  }
 
 #if DCHECK_IS_ON()
-    BasePage* from_page = PageFromObject(from);
-    DCHECK(relocatable_pages_.Contains(from_page));
+  BasePage* from_page = PageFromObject(from);
+  DCHECK(relocatable_pages_.Contains(from_page));
 #endif
 
-    // If the object is referenced by a slot that is contained on a compacted
-    // area itself, check whether it can be updated already.
-    MovableReference* slot = it->value;
-    auto interior_it = interior_fixups_.find(slot);
-    if (interior_it != interior_fixups_.end()) {
-      MovableReference* slot_location =
-          reinterpret_cast<MovableReference*>(interior_it->second);
-      if (!slot_location) {
-        interior_it->second = to;
+  // If the object is referenced by a slot that is contained on a compacted
+  // area itself, check whether it can be updated already.
+  MovableReference* slot = it->value;
+  auto interior_it = interior_fixups_.find(slot);
+  if (interior_it != interior_fixups_.end()) {
+    MovableReference* slot_location =
+        reinterpret_cast<MovableReference*>(interior_it->second);
+    if (!slot_location) {
+      interior_it->second = to;
 #if DCHECK_IS_ON()
-        // Check that the containing object has not been moved yet.
-        auto reverse_it = interior_slot_to_object_.find(slot);
-        DCHECK(interior_slot_to_object_.end() != reverse_it);
-        DCHECK(moved_objects_.end() == moved_objects_.find(reverse_it->value));
+      // Check that the containing object has not been moved yet.
+      auto reverse_it = interior_slot_to_object_.find(slot);
+      DCHECK(interior_slot_to_object_.end() != reverse_it);
+      DCHECK(moved_objects_.end() == moved_objects_.find(reverse_it->value));
 #endif  // DCHECK_IS_ON()
-      } else {
-        LOG_HEAP_COMPACTION()
-            << "Redirected slot: " << slot << " => " << slot_location;
-        slot = slot_location;
-      }
-    }
-
-    // If the slot has subsequently been updated, e.g. a destructor having
-    // mutated and expanded/shrunk the collection, do not update and relocate
-    // the slot -- |from| is no longer valid and referenced.
-    if (UNLIKELY(*slot != from)) {
+    } else {
       LOG_HEAP_COMPACTION()
-          << "No relocation: slot = " << slot << ", *slot = " << *slot
-          << ", from = " << from << ", to = " << to;
-      VerifyUpdatedSlot(slot);
-      return;
+          << "Redirected slot: " << slot << " => " << slot_location;
+      slot = slot_location;
     }
+  }
 
-    // Update the slots new value.
-    *slot = to;
+  // If the slot has subsequently been updated, e.g. a destructor having
+  // mutated and expanded/shrunk the collection, do not update and relocate
+  // the slot -- |from| is no longer valid and referenced.
+  if (UNLIKELY(*slot != from)) {
+    LOG_HEAP_COMPACTION() << "No relocation: slot = " << slot
+                          << ", *slot = " << *slot << ", from = " << from
+                          << ", to = " << to;
+    VerifyUpdatedSlot(slot);
+    return;
+  }
+
+  // Update the slots new value.
+  *slot = to;
 }
 
 void HeapCompact::MovableObjectFixups::RelocateInteriorFixups(Address from,
diff --git a/third_party/blink/renderer/platform/heap/heap_compact.h b/third_party/blink/renderer/platform/heap/impl/heap_compact.h
similarity index 95%
rename from third_party/blink/renderer/platform/heap/heap_compact.h
rename to third_party/blink/renderer/platform/heap/impl/heap_compact.h
index b241471..e39c9c5 100644
--- a/third_party/blink/renderer/platform/heap/heap_compact.h
+++ b/third_party/blink/renderer/platform/heap/impl/heap_compact.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_COMPACT_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_COMPACT_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_COMPACT_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_COMPACT_H_
 
 #include <memory>
 
@@ -164,4 +164,4 @@
 #define LOG_HEAP_FREELIST_VERBOSE() EAT_STREAM_PARAMETERS
 #endif
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_COMPACT_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_COMPACT_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_page.cc b/third_party/blink/renderer/platform/heap/impl/heap_page.cc
similarity index 99%
rename from third_party/blink/renderer/platform/heap/heap_page.cc
rename to third_party/blink/renderer/platform/heap/impl/heap_page.cc
index 9ba8a2f..1949d5c9 100644
--- a/third_party/blink/renderer/platform/heap/heap_page.cc
+++ b/third_party/blink/renderer/platform/heap/impl/heap_page.cc
@@ -28,7 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
 
 #include "base/allocator/partition_allocator/page_allocator.h"
 #include "base/auto_reset.h"
@@ -36,12 +36,12 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
 #include "third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h"
-#include "third_party/blink/renderer/platform/heap/heap_compact.h"
 #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
-#include "third_party/blink/renderer/platform/heap/marking_verifier.h"
-#include "third_party/blink/renderer/platform/heap/page_bloom_filter.h"
-#include "third_party/blink/renderer/platform/heap/page_memory.h"
-#include "third_party/blink/renderer/platform/heap/page_pool.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_verifier.h"
+#include "third_party/blink/renderer/platform/heap/impl/page_bloom_filter.h"
+#include "third_party/blink/renderer/platform/heap/impl/page_memory.h"
+#include "third_party/blink/renderer/platform/heap/impl/page_pool.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
 #include "third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h"
diff --git a/third_party/blink/renderer/platform/heap/heap_page.h b/third_party/blink/renderer/platform/heap/impl/heap_page.h
similarity index 98%
rename from third_party/blink/renderer/platform/heap/heap_page.h
rename to third_party/blink/renderer/platform/heap/impl/heap_page.h
index 98abc6b..1c26d4ff 100644
--- a/third_party/blink/renderer/platform/heap/heap_page.h
+++ b/third_party/blink/renderer/platform/heap/impl/heap_page.h
@@ -28,8 +28,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_PAGE_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_PAGE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_PAGE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_PAGE_H_
 
 #include <stdint.h>
 #include <array>
@@ -40,11 +40,11 @@
 #include "build/build_config.h"
 #include "third_party/blink/renderer/platform/heap/blink_gc.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/gc_info.h"
 #include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/heap/impl/gc_info.h"
+#include "third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h"
+#include "third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/heap/thread_state_statistics.h"
-#include "third_party/blink/renderer/platform/heap/unsanitized_atomic.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -968,9 +968,7 @@
 #endif
 
   // Remembers the page as containing inter-generational pointers.
-  void SetRemembered(bool remembered) {
-    is_remembered_ = remembered;
-  }
+  void SetRemembered(bool remembered) { is_remembered_ = remembered; }
   bool IsRemembered() const { return is_remembered_; }
 
  private:
@@ -1613,4 +1611,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_PAGE_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_PAGE_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_stats_collector.cc b/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.cc
similarity index 100%
rename from third_party/blink/renderer/platform/heap/heap_stats_collector.cc
rename to third_party/blink/renderer/platform/heap/impl/heap_stats_collector.cc
diff --git a/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h b/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h
new file mode 100644
index 0000000..cbac7c3
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h
@@ -0,0 +1,469 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_STATS_COLLECTOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_STATS_COLLECTOR_H_
+
+#include <stddef.h>
+
+#include "base/atomicops.h"
+#include "third_party/blink/renderer/platform/heap/blink_gc.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+// Interface for observing changes to heap sizing.
+class PLATFORM_EXPORT ThreadHeapStatsObserver {
+ public:
+  // Called upon allocating/releasing chunks of memory that contain objects.
+  //
+  // Must not trigger GC or allocate.
+  virtual void IncreaseAllocatedSpace(size_t) = 0;
+  virtual void DecreaseAllocatedSpace(size_t) = 0;
+
+  // Called once per GC cycle with the accurate number of live |bytes|.
+  //
+  // Must not trigger GC or allocate.
+  virtual void ResetAllocatedObjectSize(size_t bytes) = 0;
+
+  // Called after observing at least
+  // |ThreadHeapStatsCollector::kUpdateThreshold| changed bytes through
+  // allocation or explicit free. Reports both, negative and positive
+  // increments, to allow observer to decide whether absolute values or only the
+  // deltas is interesting.
+  //
+  // May trigger GC but most not allocate.
+  virtual void IncreaseAllocatedObjectSize(size_t) = 0;
+  virtual void DecreaseAllocatedObjectSize(size_t) = 0;
+};
+
+#define FOR_ALL_SCOPES(V)                    \
+  V(AtomicPauseCompaction)                   \
+  V(AtomicPauseMarkEpilogue)                 \
+  V(AtomicPauseMarkPrologue)                 \
+  V(AtomicPauseMarkRoots)                    \
+  V(AtomicPauseMarkTransitiveClosure)        \
+  V(AtomicPauseSweepAndCompact)              \
+  V(CompleteSweep)                           \
+  V(IncrementalMarkingFinalize)              \
+  V(IncrementalMarkingStartMarking)          \
+  V(IncrementalMarkingStep)                  \
+  V(IncrementalMarkingWithDeadline)          \
+  V(InvokePreFinalizers)                     \
+  V(LazySweepInIdle)                         \
+  V(LazySweepOnAllocation)                   \
+  V(MarkBailOutObjects)                      \
+  V(MarkInvokeEphemeronCallbacks)            \
+  V(MarkFlushV8References)                   \
+  V(MarkFlushEphemeronPairs)                 \
+  V(MarkProcessWorklists)                    \
+  V(MarkProcessMarkingWorklist)              \
+  V(MarkProcessWriteBarrierWorklist)         \
+  V(MarkProcessNotFullyconstructeddWorklist) \
+  V(MarkNotFullyConstructedObjects)          \
+  V(MarkWeakProcessing)                      \
+  V(UnifiedMarkingStep)                      \
+  V(VisitCrossThreadPersistents)             \
+  V(VisitPersistentRoots)                    \
+  V(VisitPersistents)                        \
+  V(VisitRoots)                              \
+  V(VisitStackRoots)                         \
+  V(VisitRememberedSets)
+
+#define FOR_ALL_CONCURRENT_SCOPES(V)        \
+  V(ConcurrentMarkInvokeEphemeronCallbacks) \
+  V(ConcurrentMarkingStep)                  \
+  V(ConcurrentSweepingStep)
+
+// Manages counters and statistics across garbage collection cycles.
+//
+// Usage:
+//   ThreadHeapStatsCollector stats_collector;
+//   stats_collector.NotifyMarkingStarted(<BlinkGC::CollectionType>,
+//                                        <BlinkGC::GCReason>);
+//   // Use tracer.
+//   stats_collector.NotifySweepingCompleted();
+//   // Previous event is available using stats_collector.previous().
+class PLATFORM_EXPORT ThreadHeapStatsCollector {
+  USING_FAST_MALLOC(ThreadHeapStatsCollector);
+
+ public:
+  // These ids will form human readable names when used in Scopes.
+  enum Id {
+#define DECLARE_ENUM(name) k##name,
+    FOR_ALL_SCOPES(DECLARE_ENUM)
+#undef DECLARE_ENUM
+        kNumScopeIds,
+  };
+
+  enum ConcurrentId {
+#define DECLARE_ENUM(name) k##name,
+    FOR_ALL_CONCURRENT_SCOPES(DECLARE_ENUM)
+#undef DECLARE_ENUM
+        kNumConcurrentScopeIds
+  };
+
+  constexpr static const char* ToString(Id id, BlinkGC::CollectionType type) {
+    switch (id) {
+#define CASE(name)                                                    \
+  case k##name:                                                       \
+    return type == BlinkGC::CollectionType::kMajor ? "BlinkGC." #name \
+                                                   : "BlinkGC." #name \
+                                                     ".Minor";
+      FOR_ALL_SCOPES(CASE)
+#undef CASE
+      default:
+        NOTREACHED();
+    }
+    return nullptr;
+  }
+
+  constexpr static const char* ToString(ConcurrentId id,
+                                        BlinkGC::CollectionType type) {
+    switch (id) {
+#define CASE(name)                                                    \
+  case k##name:                                                       \
+    return type == BlinkGC::CollectionType::kMajor ? "BlinkGC." #name \
+                                                   : "BlinkGC." #name \
+                                                     ".Minor";
+      FOR_ALL_CONCURRENT_SCOPES(CASE)
+#undef CASE
+      default:
+        NOTREACHED();
+    }
+    return nullptr;
+  }
+
+  enum TraceCategory { kEnabled, kDisabled };
+  enum ScopeContext { kMutatorThread, kConcurrentThread };
+
+  // Trace a particular scope. Will emit a trace event and record the time in
+  // the corresponding ThreadHeapStatsCollector.
+  template <TraceCategory trace_category = kDisabled,
+            ScopeContext scope_category = kMutatorThread>
+  class PLATFORM_EXPORT InternalScope {
+    DISALLOW_NEW();
+    DISALLOW_COPY_AND_ASSIGN(InternalScope);
+
+    using IdType =
+        std::conditional_t<scope_category == kMutatorThread, Id, ConcurrentId>;
+
+   public:
+    template <typename... Args>
+    InternalScope(ThreadHeapStatsCollector* tracer, IdType id, Args... args)
+        : tracer_(tracer), start_time_(base::TimeTicks::Now()), id_(id) {
+      StartTrace(args...);
+    }
+
+    ~InternalScope() {
+      StopTrace();
+      IncreaseScopeTime(id_);
+    }
+
+   private:
+    inline constexpr static const char* TraceCategory();
+
+    inline void StartTrace();
+    template <typename Value1>
+    inline void StartTrace(const char* k1, Value1 v1);
+    template <typename Value1, typename Value2>
+    inline void StartTrace(const char* k1,
+                           Value1 v1,
+                           const char* k2,
+                           Value2 v2);
+    inline void StopTrace();
+
+    inline void IncreaseScopeTime(Id);
+    inline void IncreaseScopeTime(ConcurrentId);
+
+    ThreadHeapStatsCollector* const tracer_;
+    const base::TimeTicks start_time_;
+    const IdType id_;
+  };
+
+  using Scope = InternalScope<kDisabled>;
+  using EnabledScope = InternalScope<kEnabled>;
+  using ConcurrentScope = InternalScope<kDisabled, kConcurrentThread>;
+  using EnabledConcurrentScope = InternalScope<kEnabled, kConcurrentThread>;
+
+  // BlinkGCInV8Scope keeps track of time spent in Blink's GC when called by V8.
+  // This is necessary to avoid double-accounting of Blink's time when computing
+  // the overall time (V8 + Blink) spent in GC on the main thread.
+  class PLATFORM_EXPORT BlinkGCInV8Scope {
+    DISALLOW_NEW();
+    DISALLOW_COPY_AND_ASSIGN(BlinkGCInV8Scope);
+
+   public:
+    template <typename... Args>
+    BlinkGCInV8Scope(ThreadHeapStatsCollector* tracer)
+        : tracer_(tracer), start_time_(base::TimeTicks::Now()) {}
+
+    ~BlinkGCInV8Scope() {
+      if (tracer_)
+        tracer_->gc_nested_in_v8_ += base::TimeTicks::Now() - start_time_;
+    }
+
+   private:
+    ThreadHeapStatsCollector* const tracer_;
+    const base::TimeTicks start_time_;
+  };
+
+  // POD to hold interesting data accumulated during a garbage collection cycle.
+  // The event is always fully populated when looking at previous events but
+  // is only be partially populated when looking at the current event. See
+  // members on when they are available.
+  //
+  // Note that all getters include time for stand-alone as well as unified heap
+  // GCs. E.g., |atomic_marking_time()| report the marking time of the atomic
+  // phase, independent of whether the GC was a stand-alone or unified heap GC.
+  struct PLATFORM_EXPORT Event {
+    Event();
+
+    // Overall time spent in the GC cycle. This includes marking time as well as
+    // sweeping time.
+    base::TimeDelta gc_cycle_time() const;
+
+    // Time spent in the final atomic pause of a GC cycle.
+    base::TimeDelta atomic_pause_time() const;
+
+    // Time spent in the final atomic pause for marking the heap.
+    base::TimeDelta atomic_marking_time() const;
+
+    // Time spent in the final atomic pause in sweeping and compacting the heap.
+    base::TimeDelta atomic_sweep_and_compact_time() const;
+
+    // Time spent marking the roots.
+    base::TimeDelta roots_marking_time() const;
+
+    // Time spent incrementally marking the heap.
+    base::TimeDelta incremental_marking_time() const;
+
+    // Time spent processing worklist in the foreground thread.
+    base::TimeDelta worklist_processing_time_foreground() const;
+
+    // Time spent flushing v8 references (this is done only in the foreground)
+    base::TimeDelta flushing_v8_references_time() const;
+
+    // Time spent in foreground tasks marking the heap.
+    base::TimeDelta foreground_marking_time() const;
+
+    // Time spent in background tasks marking the heap.
+    base::TimeDelta background_marking_time() const;
+
+    // Overall time spent marking the heap.
+    base::TimeDelta marking_time() const;
+
+    // Time spent in foreground tasks sweeping the heap.
+    base::TimeDelta foreground_sweeping_time() const;
+
+    // Time spent in background tasks sweeping the heap.
+    base::TimeDelta background_sweeping_time() const;
+
+    // Overall time spent sweeping the heap.
+    base::TimeDelta sweeping_time() const;
+
+    // Marked bytes collected during sweeping.
+    size_t unique_id = -1;
+    size_t marked_bytes = 0;
+    size_t compaction_freed_bytes = 0;
+    size_t compaction_freed_pages = 0;
+    bool compaction_recorded_events = false;
+    base::TimeDelta scope_data[kNumScopeIds];
+    base::subtle::Atomic32 concurrent_scope_data[kNumConcurrentScopeIds]{0};
+    BlinkGC::GCReason reason = static_cast<BlinkGC::GCReason>(0);
+    BlinkGC::CollectionType collection_type = BlinkGC::CollectionType::kMajor;
+    size_t object_size_in_bytes_before_sweeping = 0;
+    size_t allocated_space_in_bytes_before_sweeping = 0;
+    size_t partition_alloc_bytes_before_sweeping = 0;
+    double live_object_rate = 0;
+    base::TimeDelta gc_nested_in_v8;
+    bool is_forced_gc = true;
+  };
+
+  // Indicates a new garbage collection cycle.
+  void NotifyMarkingStarted(BlinkGC::CollectionType,
+                            BlinkGC::GCReason,
+                            bool is_forced_gc);
+
+  // Indicates that marking of the current garbage collection cycle is
+  // completed.
+  void NotifyMarkingCompleted(size_t marked_bytes);
+
+  // Indicates the end of a garbage collection cycle. This means that sweeping
+  // is finished at this point.
+  void NotifySweepingCompleted();
+
+  void IncreaseScopeTime(Id id, base::TimeDelta time) {
+    DCHECK(is_started_);
+    current_.scope_data[id] += time;
+  }
+
+  void IncreaseConcurrentScopeTime(ConcurrentId id, base::TimeDelta time) {
+    using Atomic32 = base::subtle::Atomic32;
+    DCHECK(is_started_);
+    const int64_t ms = time.InMicroseconds();
+    DCHECK(ms <= std::numeric_limits<Atomic32>::max());
+    base::subtle::NoBarrier_AtomicIncrement(&current_.concurrent_scope_data[id],
+                                            static_cast<Atomic32>(ms));
+  }
+
+  void UpdateReason(BlinkGC::GCReason);
+  void IncreaseCompactionFreedSize(size_t);
+  void IncreaseCompactionFreedPages(size_t);
+  void IncreaseAllocatedObjectSize(size_t);
+  void DecreaseAllocatedObjectSize(size_t);
+  void IncreaseAllocatedSpace(size_t);
+  void DecreaseAllocatedSpace(size_t);
+  void IncreaseWrapperCount(size_t);
+  void DecreaseWrapperCount(size_t);
+  void IncreaseCollectedWrapperCount(size_t);
+
+  // Called by the GC when it hits a point where allocated memory may be
+  // reported and garbage collection is possible. This is necessary, as
+  // increments and decrements are reported as close to their actual
+  // allocation/reclamation as possible.
+  void AllocatedObjectSizeSafepoint();
+
+  // Size of objects on the heap. Based on marked bytes in the previous cycle
+  // and newly allocated bytes since the previous cycle.
+  size_t object_size_in_bytes() const;
+
+  size_t marked_bytes() const;
+  base::TimeDelta marking_time_so_far() const;
+
+  base::TimeDelta worklist_processing_time_foreground() const;
+
+  base::TimeDelta flushing_v8_references_time() const;
+
+  int64_t allocated_bytes_since_prev_gc() const;
+
+  size_t allocated_space_bytes() const;
+
+  size_t wrapper_count() const;
+  size_t collected_wrapper_count() const;
+
+  bool is_started() const { return is_started_; }
+
+  // Statistics for the previously running garbage collection.
+  const Event& previous() const { return previous_; }
+
+  void RegisterObserver(ThreadHeapStatsObserver* observer);
+  void UnregisterObserver(ThreadHeapStatsObserver* observer);
+
+  void IncreaseAllocatedObjectSizeForTesting(size_t);
+  void DecreaseAllocatedObjectSizeForTesting(size_t);
+
+ private:
+  // Observers are implemented using virtual calls. Avoid notifications below
+  // reasonably interesting sizes.
+  static constexpr int64_t kUpdateThreshold = 1024;
+
+  // Invokes |callback| for all registered observers.
+  template <typename Callback>
+  void ForAllObservers(Callback callback);
+
+  void AllocatedObjectSizeSafepointImpl();
+
+  // Statistics for the currently running garbage collection. Note that the
+  // Event may not be fully populated yet as some phase may not have been run.
+  const Event& current() const { return current_; }
+
+  Event current_;
+  Event previous_;
+
+  // Allocated bytes since the last garbage collection. These bytes are reset
+  // after marking as they are accounted in marked_bytes then.
+  int64_t allocated_bytes_since_prev_gc_ = 0;
+  int64_t pos_delta_allocated_bytes_since_prev_gc_ = 0;
+  int64_t neg_delta_allocated_bytes_since_prev_gc_ = 0;
+
+  // Allocated space in bytes for all arenas.
+  size_t allocated_space_bytes_ = 0;
+
+  bool is_started_ = false;
+
+  // base::TimeDelta for RawScope. These don't need to be nested within a
+  // garbage collection cycle to make them easier to use.
+  base::TimeDelta gc_nested_in_v8_;
+
+  Vector<ThreadHeapStatsObserver*> observers_;
+
+  FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, InitialEmpty);
+  FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, IncreaseScopeTime);
+  FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, StopResetsCurrent);
+};
+
+template <ThreadHeapStatsCollector::TraceCategory trace_category,
+          ThreadHeapStatsCollector::ScopeContext scope_category>
+constexpr const char*
+ThreadHeapStatsCollector::InternalScope<trace_category,
+                                        scope_category>::TraceCategory() {
+  switch (trace_category) {
+    case kEnabled:
+      return "blink_gc,devtools.timeline";
+    case kDisabled:
+      return TRACE_DISABLED_BY_DEFAULT("blink_gc");
+  }
+}
+
+template <ThreadHeapStatsCollector::TraceCategory trace_category,
+          ThreadHeapStatsCollector::ScopeContext scope_category>
+void ThreadHeapStatsCollector::InternalScope<trace_category,
+                                             scope_category>::StartTrace() {
+  TRACE_EVENT_BEGIN0(TraceCategory(),
+                     ToString(id_, tracer_->current_.collection_type));
+}
+
+template <ThreadHeapStatsCollector::TraceCategory trace_category,
+          ThreadHeapStatsCollector::ScopeContext scope_category>
+template <typename Value1>
+void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>::
+    StartTrace(const char* k1, Value1 v1) {
+  TRACE_EVENT_BEGIN1(TraceCategory(),
+                     ToString(id_, tracer_->current_.collection_type), k1, v1);
+}
+
+template <ThreadHeapStatsCollector::TraceCategory trace_category,
+          ThreadHeapStatsCollector::ScopeContext scope_category>
+template <typename Value1, typename Value2>
+void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>::
+    StartTrace(const char* k1, Value1 v1, const char* k2, Value2 v2) {
+  TRACE_EVENT_BEGIN2(TraceCategory(),
+                     ToString(id_, tracer_->current_.collection_type), k1, v1,
+                     k2, v2);
+}
+
+template <ThreadHeapStatsCollector::TraceCategory trace_category,
+          ThreadHeapStatsCollector::ScopeContext scope_category>
+void ThreadHeapStatsCollector::InternalScope<trace_category,
+                                             scope_category>::StopTrace() {
+  TRACE_EVENT_END2(TraceCategory(),
+                   ToString(id_, tracer_->current_.collection_type), "epoch",
+                   tracer_->current_.unique_id, "forced",
+                   tracer_->current_.is_forced_gc);
+}
+
+template <ThreadHeapStatsCollector::TraceCategory trace_category,
+          ThreadHeapStatsCollector::ScopeContext scope_category>
+void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>::
+    IncreaseScopeTime(Id) {
+  tracer_->IncreaseScopeTime(id_, base::TimeTicks::Now() - start_time_);
+}
+
+template <ThreadHeapStatsCollector::TraceCategory trace_category,
+          ThreadHeapStatsCollector::ScopeContext scope_category>
+void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>::
+    IncreaseScopeTime(ConcurrentId) {
+  tracer_->IncreaseConcurrentScopeTime(id_,
+                                       base::TimeTicks::Now() - start_time_);
+}
+
+#undef FOR_ALL_SCOPES
+#undef FOR_ALL_CONCURRENT_SCOPES
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_STATS_COLLECTOR_H_
diff --git a/third_party/blink/renderer/platform/heap/impl/heap_traits.h b/third_party/blink/renderer/platform/heap/impl/heap_traits.h
new file mode 100644
index 0000000..36ac20e
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/heap_traits.h
@@ -0,0 +1,40 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TRAITS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TRAITS_H_
+
+#include <type_traits>
+#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+
+namespace blink {
+
+// Given a type T, returns a type that is either Member<T> or just T depending
+// on whether T is a garbage-collected type.
+template <typename T>
+using AddMemberIfNeeded =
+    std::conditional_t<WTF::IsGarbageCollectedType<T>::value, Member<T>, T>;
+
+// Given a type T, returns a type that is either HeapVector<T>,
+// HeapVector<Member<T>> or Vector<T> depending on T.
+template <typename T>
+using VectorOf = std::conditional_t<WTF::IsTraceable<T>::value,
+                                    HeapVector<AddMemberIfNeeded<T>>,
+                                    Vector<T>>;
+
+// Given types T and U, returns a type that is one of the following:
+// - HeapVector<std::pair<V, X>>
+//   (where V is either T or Member<T> and X is either U or Member<U>)
+// - Vector<std::pair<T, U>>
+template <typename T, typename U>
+using VectorOfPairs = std::conditional_t<
+    WTF::IsTraceable<T>::value || WTF::IsTraceable<U>::value,
+    HeapVector<std::pair<AddMemberIfNeeded<T>, AddMemberIfNeeded<U>>>,
+    Vector<std::pair<T, U>>>;
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc b/third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.cc
similarity index 97%
rename from third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc
rename to third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.cc
index b140239..8b05de2 100644
--- a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc
+++ b/third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h"
 
 #include "base/numerics/ranges.h"
 
diff --git a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h b/third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h
similarity index 88%
rename from third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h
rename to third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h
index f8634c4..19c9e0b 100644
--- a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h
+++ b/third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_SCHEDULING_ORACLE_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_SCHEDULING_ORACLE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_SCHEDULING_ORACLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_SCHEDULING_ORACLE_H_
 
 #include <atomic>
 
@@ -62,4 +62,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_SCHEDULING_ORACLE_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_SCHEDULING_ORACLE_H_
diff --git a/third_party/blink/renderer/platform/heap/marking_verifier.cc b/third_party/blink/renderer/platform/heap/impl/marking_verifier.cc
similarity index 95%
rename from third_party/blink/renderer/platform/heap/marking_verifier.cc
rename to third_party/blink/renderer/platform/heap/impl/marking_verifier.cc
index 45067dfe..58b049e 100644
--- a/third_party/blink/renderer/platform/heap/marking_verifier.cc
+++ b/third_party/blink/renderer/platform/heap/impl/marking_verifier.cc
@@ -2,10 +2,10 @@
 // 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/heap/marking_verifier.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_verifier.h"
 
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/heap/marking_verifier.h b/third_party/blink/renderer/platform/heap/impl/marking_verifier.h
similarity index 84%
rename from third_party/blink/renderer/platform/heap/marking_verifier.h
rename to third_party/blink/renderer/platform/heap/impl/marking_verifier.h
index f7ce363b..ee4266a 100644
--- a/third_party/blink/renderer/platform/heap/marking_verifier.h
+++ b/third_party/blink/renderer/platform/heap/impl/marking_verifier.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VERIFIER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VERIFIER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VERIFIER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VERIFIER_H_
 
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 
@@ -40,4 +40,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VERIFIER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VERIFIER_H_
diff --git a/third_party/blink/renderer/platform/heap/marking_visitor.cc b/third_party/blink/renderer/platform/heap/impl/marking_visitor.cc
similarity index 98%
rename from third_party/blink/renderer/platform/heap/marking_visitor.cc
rename to third_party/blink/renderer/platform/heap/impl/marking_visitor.cc
index 38a8176..7845ac1 100644
--- a/third_party/blink/renderer/platform/heap/marking_visitor.cc
+++ b/third_party/blink/renderer/platform/heap/impl/marking_visitor.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/marking_visitor.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
 
 #include "third_party/blink/renderer/platform/heap/blink_gc.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/heap/marking_visitor.h b/third_party/blink/renderer/platform/heap/impl/marking_visitor.h
similarity index 96%
rename from third_party/blink/renderer/platform/heap/marking_visitor.h
rename to third_party/blink/renderer/platform/heap/impl/marking_visitor.h
index 944dffe..9f8d9707 100644
--- a/third_party/blink/renderer/platform/heap/marking_visitor.h
+++ b/third_party/blink/renderer/platform/heap/impl/marking_visitor.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VISITOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VISITOR_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VISITOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VISITOR_H_
 
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 
 namespace blink {
@@ -262,4 +262,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VISITOR_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VISITOR_H_
diff --git a/third_party/blink/renderer/platform/heap/impl/member.h b/third_party/blink/renderer/platform/heap/impl/member.h
new file mode 100644
index 0000000..caf60bf
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/member.h
@@ -0,0 +1,577 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MEMBER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MEMBER_H_
+
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
+#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
+
+namespace WTF {
+template <typename P, typename Traits, typename Allocator>
+class MemberConstructTraits;
+}  // namespace WTF
+
+namespace blink {
+
+template <typename T>
+class Persistent;
+
+enum class TracenessMemberConfiguration {
+  kTraced,
+  kUntraced,
+};
+
+template <typename T,
+          TracenessMemberConfiguration tracenessConfiguration =
+              TracenessMemberConfiguration::kTraced>
+class MemberPointerVerifier {
+ public:
+  MemberPointerVerifier() = default;
+
+  void SaveCreationThreadState(T* pointer) {
+    if (tracenessConfiguration == TracenessMemberConfiguration::kUntraced) {
+      creation_thread_state_ = nullptr;
+    } else {
+      creation_thread_state_ = ThreadState::Current();
+      // Members should be created in an attached thread. But an empty
+      // value Member may be created on an unattached thread by a heap
+      // collection iterator.
+      DCHECK(creation_thread_state_ || !pointer);
+    }
+  }
+
+  void CheckPointer(T* pointer) {
+    if (!pointer)
+      return;
+
+    ThreadState* current = ThreadState::Current();
+    DCHECK(current);
+    if (tracenessConfiguration != TracenessMemberConfiguration::kUntraced) {
+      // creation_thread_state_ may be null when this is used in a heap
+      // collection which initialized the Member with memset and the
+      // constructor wasn't called.
+      if (creation_thread_state_) {
+        // Member should point to objects that belong in the same ThreadHeap.
+        DCHECK(creation_thread_state_->IsOnThreadHeap(pointer));
+        // Member should point to objects that belong in the same ThreadHeap.
+        DCHECK_EQ(&current->Heap(), &creation_thread_state_->Heap());
+      } else {
+        DCHECK(current->IsOnThreadHeap(pointer));
+      }
+    }
+
+    if (current->IsSweepingInProgress()) {
+      // During sweeping the object start bitmap is invalid. Check the header
+      // when the type is available and not pointing to a mixin.
+      if (IsFullyDefined<T>::value && !IsGarbageCollectedMixin<T>::value)
+        HeapObjectHeader::CheckFromPayload(pointer);
+    } else {
+      DCHECK(HeapObjectHeader::FromInnerAddress<
+             HeapObjectHeader::AccessMode::kAtomic>(pointer));
+    }
+  }
+
+ private:
+  const ThreadState* creation_thread_state_;
+};
+
+template <typename T,
+          TracenessMemberConfiguration tracenessConfiguration =
+              TracenessMemberConfiguration::kTraced>
+class MemberBase {
+  DISALLOW_NEW();
+
+ public:
+  MemberBase() : raw_(nullptr) { SaveCreationThreadState(); }
+
+  MemberBase(std::nullptr_t) : raw_(nullptr) { SaveCreationThreadState(); }
+
+  explicit MemberBase(T* raw) : raw_(raw) {
+    SaveCreationThreadState();
+    CheckPointer();
+    // No write barrier for initializing stores.
+  }
+
+  explicit MemberBase(T& raw) : raw_(&raw) {
+    SaveCreationThreadState();
+    CheckPointer();
+    // No write barrier for initializing stores.
+  }
+
+  MemberBase(WTF::HashTableDeletedValueType)
+      : raw_(reinterpret_cast<T*>(kHashTableDeletedRawValue)) {
+    SaveCreationThreadState();
+  }
+
+  MemberBase(const MemberBase& other) : raw_(other) {
+    SaveCreationThreadState();
+    CheckPointer();
+    // No write barrier for initializing stores.
+  }
+
+  template <typename U>
+  MemberBase(const Persistent<U>& other) : raw_(other) {
+    SaveCreationThreadState();
+    CheckPointer();
+    // No write barrier for initializing stores.
+  }
+
+  template <typename U>
+  MemberBase(const MemberBase<U>& other) : raw_(other) {
+    SaveCreationThreadState();
+    CheckPointer();
+    // No write barrier for initializing stores.
+  }
+
+  template <typename U>
+  MemberBase& operator=(const Persistent<U>& other) {
+    SetRaw(other);
+    CheckPointer();
+    WriteBarrier();
+    return *this;
+  }
+
+  MemberBase& operator=(const MemberBase& other) {
+    SetRaw(other);
+    CheckPointer();
+    WriteBarrier();
+    return *this;
+  }
+
+  template <typename U>
+  MemberBase& operator=(const MemberBase<U>& other) {
+    SetRaw(other);
+    CheckPointer();
+    WriteBarrier();
+    return *this;
+  }
+
+  template <typename U>
+  MemberBase& operator=(U* other) {
+    SetRaw(other);
+    CheckPointer();
+    WriteBarrier();
+    return *this;
+  }
+
+  MemberBase& operator=(WTF::HashTableDeletedValueType) {
+    SetRaw(reinterpret_cast<T*>(-1));
+    return *this;
+  }
+
+  MemberBase& operator=(std::nullptr_t) {
+    SetRaw(nullptr);
+    return *this;
+  }
+
+  void Swap(MemberBase<T>& other) {
+    T* tmp = GetRaw();
+    SetRaw(other.GetRaw());
+    other.SetRaw(tmp);
+    CheckPointer();
+    WriteBarrier();
+    other.WriteBarrier();
+  }
+
+  explicit operator bool() const { return GetRaw(); }
+  operator T*() const { return GetRaw(); }
+  T* operator->() const { return GetRaw(); }
+  T& operator*() const { return *GetRaw(); }
+
+  T* Get() const { return GetRaw(); }
+
+  void Clear() { SetRaw(nullptr); }
+
+  T* Release() {
+    T* result = GetRaw();
+    SetRaw(nullptr);
+    return result;
+  }
+
+  static bool IsMemberHashTableDeletedValue(const T* t) {
+    return t == reinterpret_cast<T*>(kHashTableDeletedRawValue);
+  }
+
+  bool IsHashTableDeletedValue() const {
+    return IsMemberHashTableDeletedValue(GetRaw());
+  }
+
+ protected:
+  static constexpr intptr_t kHashTableDeletedRawValue = -1;
+
+  enum class AtomicCtorTag { Atomic };
+
+  // MemberBase ctors that use atomic write to set raw_.
+
+  MemberBase(AtomicCtorTag, T* raw) {
+    SetRaw(raw);
+    SaveCreationThreadState();
+    CheckPointer();
+    // No write barrier for initializing stores.
+  }
+
+  MemberBase(AtomicCtorTag, T& raw) {
+    SetRaw(&raw);
+    SaveCreationThreadState();
+    CheckPointer();
+    // No write barrier for initializing stores.
+  }
+
+  void WriteBarrier() const {
+    MarkingVisitor::WriteBarrier(const_cast<std::remove_const_t<T>**>(&raw_));
+  }
+
+  void CheckPointer() {
+#if DCHECK_IS_ON()
+    // Should not be called for deleted hash table values. A value can be
+    // propagated here if a MemberBase containing the deleted value is copied.
+    if (IsHashTableDeletedValue())
+      return;
+    pointer_verifier_.CheckPointer(GetRaw());
+#endif  // DCHECK_IS_ON()
+  }
+
+  void SaveCreationThreadState() {
+#if DCHECK_IS_ON()
+    pointer_verifier_.SaveCreationThreadState(GetRaw());
+#endif  // DCHECK_IS_ON()
+  }
+
+  ALWAYS_INLINE void SetRaw(T* raw) {
+    if (tracenessConfiguration == TracenessMemberConfiguration::kUntraced)
+      raw_ = raw;
+    else
+      WTF::AsAtomicPtr(&raw_)->store(raw, std::memory_order_relaxed);
+  }
+  ALWAYS_INLINE T* GetRaw() const { return raw_; }
+
+ private:
+  // Thread safe version of Get() for marking visitors.
+  // This is used to prevent data races between concurrent marking visitors
+  // and writes on the main thread.
+  const T* GetSafe() const {
+    // TOOD(omerkatz): replace this cast with std::atomic_ref (C++20) once it
+    // becomes available
+    return WTF::AsAtomicPtr(&raw_)->load(std::memory_order_relaxed);
+  }
+
+  T* raw_;
+#if DCHECK_IS_ON()
+  MemberPointerVerifier<T, tracenessConfiguration> pointer_verifier_;
+#endif  // DCHECK_IS_ON()
+
+  friend class Visitor;
+};
+
+// Members are used in classes to contain strong pointers to other oilpan heap
+// allocated objects.
+// All Member fields of a class must be traced in the class' trace method.
+// During the mark phase of the GC all live objects are marked as live and
+// all Member fields of a live object will be traced marked as live as well.
+template <typename T>
+class Member : public MemberBase<T, TracenessMemberConfiguration::kTraced> {
+  DISALLOW_NEW();
+  typedef MemberBase<T, TracenessMemberConfiguration::kTraced> Parent;
+
+ public:
+  Member() : Parent() {}
+  Member(std::nullptr_t) : Parent(nullptr) {}
+  Member(T* raw) : Parent(raw) {}
+  Member(T& raw) : Parent(raw) {}
+  Member(WTF::HashTableDeletedValueType x) : Parent(x) {}
+
+  Member(const Member& other) : Parent(other) {}
+
+  template <typename U>
+  Member(const Member<U>& other) : Parent(other) {}
+
+  template <typename U>
+  Member(const Persistent<U>& other) : Parent(other) {}
+
+  template <typename U>
+  Member& operator=(const Persistent<U>& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  Member& operator=(const Member& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  Member& operator=(const Member<U>& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  Member& operator=(const WeakMember<U>& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  Member& operator=(U* other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  Member& operator=(WTF::HashTableDeletedValueType x) {
+    Parent::operator=(x);
+    return *this;
+  }
+
+  Member& operator=(std::nullptr_t) {
+    Parent::operator=(nullptr);
+    return *this;
+  }
+
+ private:
+  using typename Parent::AtomicCtorTag;
+  Member(AtomicCtorTag atomic, T* raw) : Parent(atomic, raw) {}
+  Member(AtomicCtorTag atomic, T& raw) : Parent(atomic, raw) {}
+
+  template <typename P, typename Traits, typename Allocator>
+  friend class WTF::MemberConstructTraits;
+};
+
+// WeakMember is similar to Member in that it is used to point to other oilpan
+// heap allocated objects.
+// However instead of creating a strong pointer to the object, the WeakMember
+// creates a weak pointer, which does not keep the pointee alive. Hence if all
+// pointers to to a heap allocated object are weak the object will be garbage
+// collected. At the time of GC the weak pointers will automatically be set to
+// null.
+template <typename T>
+class WeakMember : public MemberBase<T, TracenessMemberConfiguration::kTraced> {
+  typedef MemberBase<T, TracenessMemberConfiguration::kTraced> Parent;
+
+ public:
+  WeakMember() : Parent() {}
+
+  WeakMember(std::nullptr_t) : Parent(nullptr) {}
+
+  WeakMember(T* raw) : Parent(raw) {}
+
+  WeakMember(WTF::HashTableDeletedValueType x) : Parent(x) {}
+
+  template <typename U>
+  WeakMember(const Persistent<U>& other) : Parent(other) {}
+
+  template <typename U>
+  WeakMember(const Member<U>& other) : Parent(other) {}
+
+  template <typename U>
+  WeakMember& operator=(const Persistent<U>& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  WeakMember& operator=(const Member<U>& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  WeakMember& operator=(U* other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  WeakMember& operator=(std::nullptr_t) {
+    this->SetRaw(nullptr);
+    return *this;
+  }
+
+ private:
+  using typename Parent::AtomicCtorTag;
+  WeakMember(AtomicCtorTag atomic, T* raw) : Parent(atomic, raw) {}
+  WeakMember(AtomicCtorTag atomic, T& raw) : Parent(atomic, raw) {}
+
+  template <typename P, typename Traits, typename Allocator>
+  friend class WTF::MemberConstructTraits;
+};
+
+// UntracedMember is a pointer to an on-heap object that is not traced for some
+// reason. Please don't use this unless you understand what you're doing.
+// Basically, all pointers to on-heap objects must be stored in either of
+// Persistent, Member or WeakMember. It is not allowed to leave raw pointers to
+// on-heap objects. However, there can be scenarios where you have to use raw
+// pointers for some reason, and in that case you can use UntracedMember. Of
+// course, it must be guaranteed that the pointing on-heap object is kept alive
+// while the raw pointer is pointing to the object.
+template <typename T>
+class UntracedMember final
+    : public MemberBase<T, TracenessMemberConfiguration::kUntraced> {
+  typedef MemberBase<T, TracenessMemberConfiguration::kUntraced> Parent;
+
+ public:
+  UntracedMember() : Parent() {}
+
+  UntracedMember(std::nullptr_t) : Parent(nullptr) {}
+
+  UntracedMember(T* raw) : Parent(raw) {}
+
+  template <typename U>
+  UntracedMember(const Persistent<U>& other) : Parent(other) {}
+
+  template <typename U>
+  UntracedMember(const Member<U>& other) : Parent(other) {}
+
+  UntracedMember(WTF::HashTableDeletedValueType x) : Parent(x) {}
+
+  UntracedMember& operator=(const UntracedMember& other) {
+    this->SetRaw(other);
+    this->CheckPointer();
+    return *this;
+  }
+
+  template <typename U>
+  UntracedMember& operator=(const Persistent<U>& other) {
+    this->SetRaw(other);
+    this->CheckPointer();
+    return *this;
+  }
+
+  template <typename U>
+  UntracedMember& operator=(const Member<U>& other) {
+    this->SetRaw(other);
+    this->CheckPointer();
+    return *this;
+  }
+
+  template <typename U>
+  UntracedMember& operator=(U* other) {
+    this->SetRaw(other);
+    this->CheckPointer();
+    return *this;
+  }
+
+  UntracedMember& operator=(std::nullptr_t) {
+    this->SetRaw(nullptr);
+    return *this;
+  }
+};
+
+template <typename T>
+struct MemberTraceTraits {
+  STATIC_ONLY(MemberTraceTraits);
+
+ public:
+  static TraceDescriptor GetTraceDescriptor(const T* ref) {
+    return {ref, TraceTrait<T>::Trace};
+  }
+
+  static void Trace(Visitor* visitor, const void* ref) {
+    visitor->Trace(*static_cast<const T*>(ref));
+  }
+};
+
+template <typename T>
+struct TraceTrait<Member<T>> : public MemberTraceTraits<Member<T>> {};
+
+template <typename T>
+struct TraceTrait<WeakMember<T>> : public MemberTraceTraits<WeakMember<T>> {};
+
+}  // namespace blink
+
+namespace WTF {
+
+// PtrHash is the default hash for hash tables with Member<>-derived elements.
+template <typename T>
+struct MemberHash : PtrHash<T> {
+  STATIC_ONLY(MemberHash);
+  template <typename U>
+  static unsigned GetHash(const U& key) {
+    return PtrHash<T>::GetHash(key);
+  }
+  template <typename U, typename V>
+  static bool Equal(const U& a, const V& b) {
+    return a == b;
+  }
+};
+
+template <typename T>
+struct DefaultHash<blink::Member<T>> {
+  STATIC_ONLY(DefaultHash);
+  using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct DefaultHash<blink::WeakMember<T>> {
+  STATIC_ONLY(DefaultHash);
+  using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct DefaultHash<blink::UntracedMember<T>> {
+  STATIC_ONLY(DefaultHash);
+  using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct IsTraceable<blink::Member<T>> {
+  STATIC_ONLY(IsTraceable);
+  static const bool value = true;
+};
+
+template <typename T>
+struct IsWeak<blink::WeakMember<T>> : std::true_type {};
+
+template <typename T>
+struct IsTraceable<blink::WeakMember<T>> {
+  STATIC_ONLY(IsTraceable);
+  static const bool value = true;
+};
+
+template <typename T, typename Traits, typename Allocator>
+class MemberConstructTraits {
+  STATIC_ONLY(MemberConstructTraits);
+
+ public:
+  template <typename... Args>
+  static T* Construct(void* location, Args&&... args) {
+    return new (NotNull, location) T(std::forward<Args>(args)...);
+  }
+
+  static void NotifyNewElement(T* element) { element->WriteBarrier(); }
+
+  template <typename... Args>
+  static T* ConstructAndNotifyElement(void* location, Args&&... args) {
+    // ConstructAndNotifyElement updates an existing Member which might
+    // also be comncurrently traced while we update it. The regular ctors
+    // for Member don't use an atomic write which can lead to data races.
+    T* object = Construct(location, T::AtomicCtorTag::Atomic,
+                          std::forward<Args>(args)...);
+    NotifyNewElement(object);
+    return object;
+  }
+
+  static void NotifyNewElements(T* array, size_t len) {
+    while (len-- > 0) {
+      array->WriteBarrier();
+      array++;
+    }
+  }
+};
+
+template <typename T, typename Traits, typename Allocator>
+class ConstructTraits<blink::Member<T>, Traits, Allocator>
+    : public MemberConstructTraits<blink::Member<T>, Traits, Allocator> {};
+
+template <typename T, typename Traits, typename Allocator>
+class ConstructTraits<blink::WeakMember<T>, Traits, Allocator>
+    : public MemberConstructTraits<blink::WeakMember<T>, Traits, Allocator> {};
+
+}  // namespace WTF
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MEMBER_H_
diff --git a/third_party/blink/renderer/platform/heap/name_traits.h b/third_party/blink/renderer/platform/heap/impl/name_traits.h
similarity index 89%
rename from third_party/blink/renderer/platform/heap/name_traits.h
rename to third_party/blink/renderer/platform/heap/impl/name_traits.h
index 89961df0..c44305f 100644
--- a/third_party/blink/renderer/platform/heap/name_traits.h
+++ b/third_party/blink/renderer/platform/heap/impl/name_traits.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_NAME_TRAITS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_NAME_TRAITS_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_NAME_TRAITS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_NAME_TRAITS_H_
 
 #include <cstring>
 
@@ -59,4 +59,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_NAME_TRAITS_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_NAME_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/heap/page_bloom_filter.h b/third_party/blink/renderer/platform/heap/impl/page_bloom_filter.h
similarity index 81%
rename from third_party/blink/renderer/platform/heap/page_bloom_filter.h
rename to third_party/blink/renderer/platform/heap/impl/page_bloom_filter.h
index 5e881212..19263ae 100644
--- a/third_party/blink/renderer/platform/heap/page_bloom_filter.h
+++ b/third_party/blink/renderer/platform/heap/impl/page_bloom_filter.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_BLOOM_FILTER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_BLOOM_FILTER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_BLOOM_FILTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_BLOOM_FILTER_H_
 
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
 #include "third_party/blink/renderer/platform/wtf/bloom_filter.h"
 
 namespace blink {
@@ -45,4 +45,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_BLOOM_FILTER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_BLOOM_FILTER_H_
diff --git a/third_party/blink/renderer/platform/heap/page_memory.cc b/third_party/blink/renderer/platform/heap/impl/page_memory.cc
similarity index 98%
rename from third_party/blink/renderer/platform/heap/page_memory.cc
rename to third_party/blink/renderer/platform/heap/impl/page_memory.cc
index 86445fa..4d3ffc1 100644
--- a/third_party/blink/renderer/platform/heap/page_memory.cc
+++ b/third_party/blink/renderer/platform/heap/impl/page_memory.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/page_memory.h"
+#include "third_party/blink/renderer/platform/heap/impl/page_memory.h"
 
 #include "base/allocator/partition_allocator/oom.h"
 #include "base/allocator/partition_allocator/page_allocator.h"
diff --git a/third_party/blink/renderer/platform/heap/page_memory.h b/third_party/blink/renderer/platform/heap/impl/page_memory.h
similarity index 94%
rename from third_party/blink/renderer/platform/heap/page_memory.h
rename to third_party/blink/renderer/platform/heap/impl/page_memory.h
index 249a1eb6..ee13b21 100644
--- a/third_party/blink/renderer/platform/heap/page_memory.h
+++ b/third_party/blink/renderer/platform/heap/impl/page_memory.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_MEMORY_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_MEMORY_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_MEMORY_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_MEMORY_H_
 
 #include "base/atomic_ref_count.h"
 #include "base/containers/flat_map.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 
@@ -183,4 +183,4 @@
 
 }  // namespace blink
 
-#endif
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_MEMORY_H_
diff --git a/third_party/blink/renderer/platform/heap/page_pool.cc b/third_party/blink/renderer/platform/heap/impl/page_pool.cc
similarity index 90%
rename from third_party/blink/renderer/platform/heap/page_pool.cc
rename to third_party/blink/renderer/platform/heap/impl/page_pool.cc
index 100a780..b3c3141 100644
--- a/third_party/blink/renderer/platform/heap/page_pool.cc
+++ b/third_party/blink/renderer/platform/heap/impl/page_pool.cc
@@ -2,10 +2,10 @@
 // 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/heap/page_pool.h"
+#include "third_party/blink/renderer/platform/heap/impl/page_pool.h"
 
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/page_memory.h"
+#include "third_party/blink/renderer/platform/heap/impl/page_memory.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/heap/page_pool.h b/third_party/blink/renderer/platform/heap/impl/page_pool.h
similarity index 86%
rename from third_party/blink/renderer/platform/heap/page_pool.h
rename to third_party/blink/renderer/platform/heap/impl/page_pool.h
index 753d287..fdf448f 100644
--- a/third_party/blink/renderer/platform/heap/page_pool.h
+++ b/third_party/blink/renderer/platform/heap/impl/page_pool.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_POOL_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_POOL_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_POOL_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_POOL_H_
 
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -45,4 +45,4 @@
 
 }  // namespace blink
 
-#endif
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_POOL_H_
diff --git a/third_party/blink/renderer/platform/heap/impl/persistent.h b/third_party/blink/renderer/platform/heap/impl/persistent.h
new file mode 100644
index 0000000..00cff273
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/persistent.h
@@ -0,0 +1,971 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_H_
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "third_party/blink/renderer/platform/bindings/buildflags.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h"
+#include "third_party/blink/renderer/platform/heap/impl/persistent_node.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
+
+namespace blink {
+
+template <typename T>
+class CrossThreadWeakPersistent;
+
+// Wrapping type to force callers to go through macros that expand or drop
+// base::Location. This is needed to avoid adding the strings when not needed.
+// The type can be dropped once http://crbug.com/760702 is resolved and
+// ENABLE_LOCATION_SOURCE is disabled for release builds.
+class PersistentLocation final {
+ public:
+  PersistentLocation() = default;
+  explicit PersistentLocation(const base::Location& location)
+      : location_(location) {}
+  PersistentLocation(const PersistentLocation& other) = default;
+
+  const base::Location& get() const { return location_; }
+
+ private:
+  base::Location location_;
+};
+
+#if !BUILDFLAG(FROM_HERE_USES_LOCATION_BUILTINS) && \
+    BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+#if !BUILDFLAG(ENABLE_LOCATION_SOURCE)
+#define PERSISTENT_FROM_HERE \
+  PersistentLocation(::base::Location::CreateFromHere(__FILE__))
+#else
+#define PERSISTENT_FROM_HERE \
+  PersistentLocation(        \
+      ::base::Location::CreateFromHere(__func__, __FILE__, __LINE__))
+#endif
+#else
+#define PERSISTENT_FROM_HERE PersistentLocation()
+#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+
+template <typename T,
+          WeaknessPersistentConfiguration weaknessConfiguration,
+          CrossThreadnessPersistentConfiguration crossThreadnessConfiguration>
+class PersistentBase {
+  USING_FAST_MALLOC(PersistentBase);
+
+ public:
+  bool IsHashTableDeletedValue() const {
+    return raw_ == reinterpret_cast<T*>(-1);
+  }
+
+  T* Release() {
+    T* result = raw_;
+    AssignSafe(nullptr);
+    return result;
+  }
+
+  void Clear() {
+    // Note that this also frees up related data in the backend.
+    AssignSafe(nullptr);
+  }
+
+  T* Get() const {
+    CheckPointer();
+    return raw_;
+  }
+
+  // TODO(https://crbug.com/653394): Consider returning a thread-safe best
+  // guess of validity.
+  bool MaybeValid() const { return true; }
+
+  explicit operator bool() const { return Get(); }
+  T& operator*() const { return *Get(); }
+  operator T*() const { return Get(); }
+  T* operator->() const { return Get(); }
+
+  // Register the persistent node as a 'static reference',
+  // belonging to the current thread and a persistent that must
+  // be cleared when the ThreadState itself is cleared out and
+  // destructed.
+  //
+  // Static singletons arrange for this to happen, either to ensure
+  // clean LSan leak reports or to register a thread-local persistent
+  // needing to be cleared out before the thread is terminated.
+  PersistentBase* RegisterAsStaticReference() {
+    static_assert(weaknessConfiguration == kNonWeakPersistentConfiguration,
+                  "Can only register non-weak Persistent references as static "
+                  "references.");
+    if (PersistentNode* node = persistent_node_.Get()) {
+      ThreadState::Current()->RegisterStaticPersistentNode(node);
+      LEAK_SANITIZER_IGNORE_OBJECT(this);
+    }
+    return this;
+  }
+
+  NO_SANITIZE_ADDRESS
+  void ClearWithLockHeld() {
+    static_assert(
+        crossThreadnessConfiguration == kCrossThreadPersistentConfiguration,
+        "This Persistent does not require the cross-thread lock.");
+    PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired();
+    raw_ = nullptr;
+    persistent_node_.ClearWithLockHeld();
+  }
+
+  void UpdateLocation(const PersistentLocation& other) {
+#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+    location_ = other;
+#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+  }
+
+ protected:
+  ~PersistentBase() {
+    UninitializeSafe();
+    // Not resetting raw_ as it is not observable.
+  }
+
+  PersistentBase() : raw_(nullptr) {
+    SaveCreationThreadHeap();
+    // No initialization needed for empty handle.
+  }
+  PersistentBase(const PersistentLocation& location) : PersistentBase() {
+    UpdateLocation(location);
+  }
+
+  PersistentBase(std::nullptr_t) : raw_(nullptr) {
+    SaveCreationThreadHeap();
+    // No initialization needed for empty handle.
+  }
+  PersistentBase(const PersistentLocation& location, std::nullptr_t)
+      : PersistentBase(nullptr) {
+    UpdateLocation(location);
+  }
+
+  PersistentBase(T* raw) : raw_(raw) {
+    SaveCreationThreadHeap();
+    InitializeSafe();
+    CheckPointer();
+  }
+  PersistentBase(const PersistentLocation& location, T* raw)
+      : PersistentBase(raw) {
+    UpdateLocation(location);
+  }
+
+  PersistentBase(T& raw) : raw_(&raw) {
+    SaveCreationThreadHeap();
+    InitializeSafe();
+    CheckPointer();
+  }
+  PersistentBase(const PersistentLocation& location, T& raw)
+      : PersistentBase(raw) {
+    UpdateLocation(location);
+  }
+
+  PersistentBase(const PersistentBase& other) : raw_(other) {
+    SaveCreationThreadHeap();
+    InitializeSafe();
+    CheckPointer();
+  }
+  PersistentBase(const PersistentLocation& location, PersistentBase& other)
+      : PersistentBase(other) {
+    UpdateLocation(location);
+  }
+
+  template <typename U>
+  PersistentBase(const PersistentBase<U,
+                                      weaknessConfiguration,
+                                      crossThreadnessConfiguration>& other)
+      : raw_(other) {
+    SaveCreationThreadHeap();
+    InitializeSafe();
+    CheckPointer();
+  }
+  template <typename U>
+  PersistentBase(const PersistentLocation& location,
+                 const PersistentBase<U,
+                                      weaknessConfiguration,
+                                      crossThreadnessConfiguration>& other)
+      : PersistentBase(other) {
+    UpdateLocation(location);
+  }
+
+  template <typename U>
+  PersistentBase(const Member<U>& other) : raw_(other) {
+    SaveCreationThreadHeap();
+    InitializeSafe();
+    CheckPointer();
+  }
+  template <typename U>
+  PersistentBase(const PersistentLocation& location, const Member<U>& other)
+      : PersistentBase(other) {
+    UpdateLocation(location);
+  }
+
+  PersistentBase(WTF::HashTableDeletedValueType)
+      : raw_(reinterpret_cast<T*>(-1)) {
+    SaveCreationThreadHeap();
+    // No initialization needed for empty handle.
+  }
+  PersistentBase(const PersistentLocation& location,
+                 WTF::HashTableDeletedValueType)
+      : PersistentBase(WTF::kHashTableDeletedValue) {
+    UpdateLocation(location);
+  }
+
+  template <typename U>
+  PersistentBase& operator=(U* other) {
+    AssignSafe(other);
+    return *this;
+  }
+
+  PersistentBase& operator=(std::nullptr_t) {
+    AssignSafe(nullptr);
+    return *this;
+  }
+
+  template <typename U>
+  PersistentBase& operator=(const Member<U>& other) {
+    AssignSafe(other);
+    return *this;
+  }
+
+  // Using unsafe operations and assuming that caller acquires the lock for
+  // kCrossThreadPersistentConfiguration configuration.
+  PersistentBase& operator=(const PersistentBase& other) {
+    PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired();
+    AssignUnsafe(other);
+    return *this;
+  }
+
+  // Using unsafe operations and assuming that caller acquires the lock for
+  // kCrossThreadPersistentConfiguration configuration.
+  template <typename U>
+  PersistentBase& operator=(
+      const PersistentBase<U,
+                           weaknessConfiguration,
+                           crossThreadnessConfiguration>& other) {
+    PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired();
+    AssignUnsafe(other);
+    return *this;
+  }
+
+  // Using unsafe operations and assuming that caller acquires the lock for
+  // kCrossThreadPersistentConfiguration configuration.
+  template <typename U>
+  PersistentBase& operator=(
+      PersistentBase<U, weaknessConfiguration, crossThreadnessConfiguration>&&
+          other) {
+    PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired();
+    if (persistent_node_.IsInitialized()) {
+      // Drop persistent node if present as it's always possible to reuse the
+      // node (if present) from |other|.
+      persistent_node_.Uninitialize();
+    }
+    // Explicit cast enabling downcasting.
+    raw_ = static_cast<T*>(other.raw_);
+    other.raw_ = nullptr;
+    // Efficiently move by just rewiring the node pointer.
+    persistent_node_ = std::move(other.persistent_node_);
+    DCHECK(!other.persistent_node_.Get());
+    if (persistent_node_.IsInitialized()) {
+      // If |raw_| points to a non-null or deleted value, just reuse the node.
+      TraceCallback trace_callback =
+          TraceMethodDelegate<PersistentBase,
+                              &PersistentBase::TracePersistent>::Trampoline;
+      persistent_node_.Get()->Reinitialize(this, trace_callback);
+    }
+    CheckPointer();
+    return *this;
+  }
+
+  NO_SANITIZE_ADDRESS
+  bool IsNotNull() const { return raw_; }
+
+  NO_SANITIZE_ADDRESS
+  void AssignSafe(T* ptr) {
+    typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock;
+    AssignUnsafe(ptr);
+  }
+
+  NO_SANITIZE_ADDRESS
+  void AssignUnsafe(T* ptr) {
+    raw_ = ptr;
+    CheckPointer();
+    if (raw_ && !IsHashTableDeletedValue()) {
+      if (!persistent_node_.IsInitialized())
+        InitializeUnsafe();
+      return;
+    }
+    UninitializeUnsafe();
+  }
+
+  void TracePersistent(Visitor* visitor) const {
+    static_assert(sizeof(T), "T must be fully defined");
+    static_assert(IsGarbageCollectedType<T>::value,
+                  "T needs to be a garbage collected object");
+    DCHECK(!IsHashTableDeletedValue());
+    if (weaknessConfiguration == kWeakPersistentConfiguration) {
+      visitor->RegisterWeakCallback(HandleWeakPersistent, this);
+    } else {
+#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+      visitor->TraceRoot(raw_, location_.get());
+#else
+      visitor->TraceRoot(raw_, base::Location());
+#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+    }
+  }
+
+  NO_SANITIZE_ADDRESS
+  void InitializeSafe() {
+    DCHECK(!persistent_node_.IsInitialized());
+    if (!raw_ || IsHashTableDeletedValue())
+      return;
+
+    TraceCallback trace_callback =
+        TraceMethodDelegate<PersistentBase,
+                            &PersistentBase::TracePersistent>::Trampoline;
+    typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock;
+    persistent_node_.Initialize(this, trace_callback);
+  }
+
+  NO_SANITIZE_ADDRESS
+  void InitializeUnsafe() {
+    DCHECK(!persistent_node_.IsInitialized());
+    if (!raw_ || IsHashTableDeletedValue())
+      return;
+
+    TraceCallback trace_callback =
+        TraceMethodDelegate<PersistentBase,
+                            &PersistentBase::TracePersistent>::Trampoline;
+    persistent_node_.Initialize(this, trace_callback);
+  }
+
+  void UninitializeSafe() {
+    if (persistent_node_.IsInitialized()) {
+      typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock;
+      persistent_node_.Uninitialize();
+    }
+  }
+
+  void UninitializeUnsafe() {
+    if (persistent_node_.IsInitialized())
+      persistent_node_.Uninitialize();
+  }
+
+  void CheckPointer() const {
+#if DCHECK_IS_ON()
+    if (!raw_ || IsHashTableDeletedValue())
+      return;
+
+    if (crossThreadnessConfiguration != kCrossThreadPersistentConfiguration) {
+      ThreadState* current = ThreadState::Current();
+      DCHECK(current);
+      // m_creationThreadState may be null when this is used in a heap
+      // collection which initialized the Persistent with memset and the
+      // constructor wasn't called.
+      if (creation_thread_state_) {
+        // Member should point to objects that belong in the same ThreadHeap.
+        DCHECK_EQ(&ThreadState::FromObject(raw_)->Heap(),
+                  &creation_thread_state_->Heap());
+        // Member should point to objects that belong in the same ThreadHeap.
+        DCHECK_EQ(&current->Heap(), &creation_thread_state_->Heap());
+      }
+    }
+#endif
+  }
+
+  void SaveCreationThreadHeap() {
+#if DCHECK_IS_ON()
+    if (crossThreadnessConfiguration == kCrossThreadPersistentConfiguration) {
+      creation_thread_state_ = nullptr;
+    } else {
+      creation_thread_state_ = ThreadState::Current();
+      DCHECK(creation_thread_state_);
+    }
+#endif
+  }
+
+  static void HandleWeakPersistent(const LivenessBroker& broker,
+                                   const void* persistent_pointer) {
+    using Base =
+        PersistentBase<typename std::remove_const<T>::type,
+                       weaknessConfiguration, crossThreadnessConfiguration>;
+    Base* persistent =
+        reinterpret_cast<Base*>(const_cast<void*>(persistent_pointer));
+    T* object = persistent->Get();
+    if (object && !broker.IsHeapObjectAlive(object))
+      ClearWeakPersistent(persistent);
+  }
+
+  static void ClearWeakPersistent(
+      PersistentBase<std::remove_const_t<T>,
+                     kWeakPersistentConfiguration,
+                     kCrossThreadPersistentConfiguration>* persistent) {
+    PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired();
+    persistent->ClearWithLockHeld();
+  }
+
+  static void ClearWeakPersistent(
+      PersistentBase<std::remove_const_t<T>,
+                     kWeakPersistentConfiguration,
+                     kSingleThreadPersistentConfiguration>* persistent) {
+    persistent->Clear();
+  }
+
+  template <typename BadPersistent>
+  static void ClearWeakPersistent(BadPersistent* non_weak_persistent) {
+    NOTREACHED();
+  }
+
+  // raw_ is accessed most, so put it at the first field.
+  T* raw_;
+
+  // The pointer to the underlying persistent node.
+  //
+  // Since accesses are atomics in the cross-thread case, a different type is
+  // needed to prevent the compiler producing an error when it encounters
+  // operations that are legal on raw pointers but not on atomics, or
+  // vice-versa.
+  std::conditional_t<
+      crossThreadnessConfiguration == kCrossThreadPersistentConfiguration,
+      CrossThreadPersistentNodePtr<weaknessConfiguration>,
+      PersistentNodePtr<ThreadingTrait<T>::kAffinity, weaknessConfiguration>>
+      persistent_node_;
+
+#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+  PersistentLocation location_;
+#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+
+#if DCHECK_IS_ON()
+  const ThreadState* creation_thread_state_;
+#endif
+
+  template <typename F,
+            WeaknessPersistentConfiguration,
+            CrossThreadnessPersistentConfiguration>
+  friend class PersistentBase;
+};
+
+// Persistent is a way to create a strong pointer from an off-heap object
+// to another on-heap object. As long as the Persistent handle is alive
+// the GC will keep the object pointed to alive. The Persistent handle is
+// always a GC root from the point of view of the GC.
+//
+// We have to construct and destruct Persistent in the same thread.
+template <typename T>
+class Persistent : public PersistentBase<T,
+                                         kNonWeakPersistentConfiguration,
+                                         kSingleThreadPersistentConfiguration> {
+  using Parent = PersistentBase<T,
+                                kNonWeakPersistentConfiguration,
+                                kSingleThreadPersistentConfiguration>;
+
+ public:
+  Persistent() : Parent() {}
+  Persistent(const PersistentLocation& location) : Parent(location) {}
+  Persistent(std::nullptr_t) : Parent(nullptr) {}
+  Persistent(const PersistentLocation& location, std::nullptr_t)
+      : Parent(location, nullptr) {}
+  Persistent(T* raw) : Parent(raw) {}
+  Persistent(const PersistentLocation& location, T* raw)
+      : Parent(location, raw) {}
+  Persistent(T& raw) : Parent(raw) {}
+  Persistent(const PersistentLocation& location, T& raw)
+      : Parent(location, raw) {}
+  Persistent(const Persistent& other) : Parent(other) {}
+  Persistent(const PersistentLocation& location, const Persistent& other)
+      : Parent(location, other) {}
+  template <typename U>
+  Persistent(const Persistent<U>& other) : Parent(other) {}
+  template <typename U>
+  Persistent(const PersistentLocation& location, const Persistent<U>& other)
+      : Parent(location, other) {}
+  template <typename U>
+  Persistent(const Member<U>& other) : Parent(other) {}
+  template <typename U>
+  Persistent(const PersistentLocation& location, const Member<U>& other)
+      : Parent(location, other) {}
+  Persistent(WTF::HashTableDeletedValueType x) : Parent(x) {}
+  Persistent(const PersistentLocation& location,
+             WTF::HashTableDeletedValueType x)
+      : Parent(location, x) {}
+
+  template <typename U>
+  Persistent& operator=(U* other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  Persistent& operator=(std::nullptr_t) {
+    Parent::operator=(nullptr);
+    return *this;
+  }
+
+  Persistent& operator=(const Persistent& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  Persistent& operator=(const Persistent<U>& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  Persistent& operator=(const Member<U>& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+};
+
+// WeakPersistent is a way to create a weak pointer from an off-heap object
+// to an on-heap object. The m_raw is automatically cleared when the pointee
+// gets collected.
+//
+// We have to construct and destruct WeakPersistent in the same thread.
+//
+// Note that collections of WeakPersistents are not supported. Use a collection
+// of WeakMembers instead.
+//
+//   HashSet<WeakPersistent<T>> m_set; // wrong
+//   Persistent<HeapHashSet<WeakMember<T>>> m_set; // correct
+template <typename T>
+class WeakPersistent
+    : public PersistentBase<T,
+                            kWeakPersistentConfiguration,
+                            kSingleThreadPersistentConfiguration> {
+  using Parent = PersistentBase<T,
+                                kWeakPersistentConfiguration,
+                                kSingleThreadPersistentConfiguration>;
+
+ public:
+  WeakPersistent() : Parent() {}
+  WeakPersistent(std::nullptr_t) : Parent(nullptr) {}
+  WeakPersistent(T* raw) : Parent(raw) {}
+  WeakPersistent(T& raw) : Parent(raw) {}
+  WeakPersistent(const WeakPersistent& other) : Parent(other) {}
+  template <typename U>
+  WeakPersistent(const WeakPersistent<U>& other) : Parent(other) {}
+  template <typename U>
+  WeakPersistent(const Member<U>& other) : Parent(other) {}
+
+  template <typename U>
+  WeakPersistent& operator=(U* other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  WeakPersistent& operator=(std::nullptr_t) {
+    Parent::operator=(nullptr);
+    return *this;
+  }
+
+  WeakPersistent& operator=(const WeakPersistent& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  WeakPersistent& operator=(const WeakPersistent<U>& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  WeakPersistent& operator=(const Member<U>& other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  NO_SANITIZE_ADDRESS
+  bool IsClearedUnsafe() const { return this->IsNotNull(); }
+};
+
+// CrossThreadPersistent allows for holding onto an object strongly on a
+// different thread.
+//
+// Thread-safe operations:
+// - Construction
+// - Destruction
+// - Copy and move construction and assignment
+// - Clearing
+// - Deref if treated as immutable reference or if externally synchronized (e.g.
+//   mutex, task). The current implementation of Get() uses a raw load (on
+//   purpose) which prohibits mutation while accessing the reference on a
+//   different thread.
+template <typename T>
+class CrossThreadPersistent
+    : public PersistentBase<T,
+                            kNonWeakPersistentConfiguration,
+                            kCrossThreadPersistentConfiguration> {
+  using Parent = PersistentBase<T,
+                                kNonWeakPersistentConfiguration,
+                                kCrossThreadPersistentConfiguration>;
+
+ public:
+  CrossThreadPersistent() : Parent() {}
+  CrossThreadPersistent(const PersistentLocation& location)
+      : Parent(location) {}
+  CrossThreadPersistent(std::nullptr_t) : Parent(nullptr) {}
+  CrossThreadPersistent(const PersistentLocation& location, std::nullptr_t)
+      : Parent(location, nullptr) {}
+  explicit CrossThreadPersistent(T* raw) : Parent(raw) {}
+  CrossThreadPersistent(const PersistentLocation& location, T* raw)
+      : Parent(location, raw) {}
+  explicit CrossThreadPersistent(T& raw) : Parent(raw) {}
+  CrossThreadPersistent(const PersistentLocation& location, T& raw)
+      : Parent(location, raw) {}
+  CrossThreadPersistent(const CrossThreadPersistent& other) { *this = other; }
+  CrossThreadPersistent(const PersistentLocation& location,
+                        const CrossThreadPersistent& other) {
+    *this = other;
+  }
+  template <typename U>
+  CrossThreadPersistent(const CrossThreadPersistent<U>& other) {
+    *this = other;
+  }
+  template <typename U>
+  CrossThreadPersistent(const PersistentLocation& location,
+                        const CrossThreadPersistent<U>& other) {
+    *this = other;
+  }
+  template <typename U>
+  CrossThreadPersistent(const Member<U>& other) : Parent(other) {}
+  template <typename U>
+  CrossThreadPersistent(const PersistentLocation& location,
+                        const Member<U>& other)
+      : Parent(location, other) {}
+  CrossThreadPersistent(WTF::HashTableDeletedValueType x) : Parent(x) {}
+  CrossThreadPersistent(const PersistentLocation& location,
+                        WTF::HashTableDeletedValueType x)
+      : Parent(location, x) {}
+  template <typename U>
+  CrossThreadPersistent(const CrossThreadWeakPersistent<U>& other) {
+    *this = other;
+  }
+
+  // Instead of using release(), assign then clear() instead.
+  // Using release() with per thread heap enabled can cause the object to be
+  // destroyed before assigning it to a new handle.
+  T* Release() = delete;
+
+  template <typename U>
+  CrossThreadPersistent& operator=(U* other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  CrossThreadPersistent& operator=(std::nullptr_t) {
+    Parent::operator=(nullptr);
+    return *this;
+  }
+
+  CrossThreadPersistent& operator=(const CrossThreadPersistent& other) {
+    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  CrossThreadPersistent& operator=(const CrossThreadPersistent<U>& other) {
+    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  CrossThreadPersistent& operator=(const CrossThreadWeakPersistent<U>&);
+};
+
+// CrossThreadWeakPersistent combines behavior of CrossThreadPersistent and
+// WeakPersistent, i.e., it allows holding onto an object weakly on a different
+// thread.
+//
+// Thread-safe operations:
+// - Construction
+// - Destruction
+// - Copy and move construction and assignment
+// - Clearing
+//
+// Note that this does not include dereferencing and using the raw pointer as
+// there is no guarantee that the object will be alive at the time it is used.
+template <typename T>
+class CrossThreadWeakPersistent
+    : public PersistentBase<T,
+                            kWeakPersistentConfiguration,
+                            kCrossThreadPersistentConfiguration> {
+  using Parent = PersistentBase<T,
+                                kWeakPersistentConfiguration,
+                                kCrossThreadPersistentConfiguration>;
+
+ public:
+  CrossThreadWeakPersistent() : Parent() {}
+  explicit CrossThreadWeakPersistent(T* raw) : Parent(raw) {}
+  explicit CrossThreadWeakPersistent(T& raw) : Parent(raw) {}
+  CrossThreadWeakPersistent(const CrossThreadWeakPersistent& other) {
+    *this = other;
+  }
+  template <typename U>
+  CrossThreadWeakPersistent(const CrossThreadWeakPersistent<U>& other) {
+    *this = other;
+  }
+  CrossThreadWeakPersistent(CrossThreadWeakPersistent&& other) {
+    *this = std::move(other);
+  }
+  template <typename U>
+  CrossThreadWeakPersistent(CrossThreadWeakPersistent<U>&& other) {
+    *this = std::move(other);
+  }
+
+  CrossThreadWeakPersistent& operator=(const CrossThreadWeakPersistent& other) {
+    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
+    Parent::operator=(other);
+    return *this;
+  }
+
+  template <typename U>
+  CrossThreadWeakPersistent& operator=(
+      const CrossThreadWeakPersistent<U>& other) {
+    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
+    Parent::operator=(other);
+    return *this;
+  }
+
+  CrossThreadWeakPersistent& operator=(CrossThreadWeakPersistent&& other) {
+    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
+    Parent::operator=(std::move(other));
+    return *this;
+  }
+
+  template <typename U>
+  CrossThreadWeakPersistent& operator=(CrossThreadWeakPersistent<U>&& other) {
+    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
+    Parent::operator=(std::move(other));
+    return *this;
+  }
+
+  template <typename U>
+  CrossThreadWeakPersistent& operator=(U* other) {
+    Parent::operator=(other);
+    return *this;
+  }
+
+  // Create a CrossThreadPersistent that keeps the underlying object alive if
+  // there is still on set. Can be used to work with an object on a different
+  // thread than it was allocated. Note that CTP does not block threads from
+  // terminating, in which case the reference would still be invalid.
+  const CrossThreadPersistent<T> Lock() const {
+    return CrossThreadPersistent<T>(*this);
+  }
+
+  // Disallow directly using CrossThreadWeakPersistent. Users must go through
+  // CrossThreadPersistent to access the pointee. Note that this does not
+  // guarantee that the object is still alive at that point. Users must check
+  // the state of CTP manually before invoking any calls.
+  T* operator->() const = delete;
+  T& operator*() const = delete;
+  operator T*() const = delete;
+  T* Get() const = delete;
+
+ private:
+  template <typename U>
+  friend class CrossThreadPersistent;
+};
+
+template <typename T>
+template <typename U>
+CrossThreadPersistent<T>& CrossThreadPersistent<T>::operator=(
+    const CrossThreadWeakPersistent<U>& other) {
+  MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
+  using ParentU = PersistentBase<U, kWeakPersistentConfiguration,
+                                 kCrossThreadPersistentConfiguration>;
+  this->AssignUnsafe(static_cast<const ParentU&>(other).Get());
+  return *this;
+}
+
+template <typename T>
+Persistent<T> WrapPersistentInternal(const PersistentLocation& location,
+                                     T* value) {
+  return Persistent<T>(location, value);
+}
+
+template <typename T>
+Persistent<T> WrapPersistentInternal(T* value) {
+  return Persistent<T>(value);
+}
+
+#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+#define WrapPersistent(value) \
+  WrapPersistentInternal(PERSISTENT_FROM_HERE, value)
+#else
+#define WrapPersistent(value) WrapPersistentInternal(value)
+#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+
+template <typename T,
+          typename = std::enable_if_t<WTF::IsGarbageCollectedType<T>::value>>
+Persistent<T> WrapPersistentIfNeeded(T* value) {
+  return Persistent<T>(value);
+}
+
+template <typename T>
+T& WrapPersistentIfNeeded(T& value) {
+  return value;
+}
+
+template <typename T>
+WeakPersistent<T> WrapWeakPersistent(T* value) {
+  return WeakPersistent<T>(value);
+}
+
+template <typename T>
+CrossThreadPersistent<T> WrapCrossThreadPersistentInternal(
+    const PersistentLocation& location,
+    T* value) {
+  return CrossThreadPersistent<T>(location, value);
+}
+
+template <typename T>
+CrossThreadPersistent<T> WrapCrossThreadPersistentInternal(T* value) {
+  return CrossThreadPersistent<T>(value);
+}
+
+#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+#define WrapCrossThreadPersistent(value) \
+  WrapCrossThreadPersistentInternal(PERSISTENT_FROM_HERE, value)
+#else
+#define WrapCrossThreadPersistent(value) \
+  WrapCrossThreadPersistentInternal(value)
+#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+
+template <typename T>
+CrossThreadWeakPersistent<T> WrapCrossThreadWeakPersistent(T* value) {
+  return CrossThreadWeakPersistent<T>(value);
+}
+
+// Comparison operators between (Weak)Members, Persistents, and UntracedMembers.
+template <typename T, typename U>
+inline bool operator==(const Member<T>& a, const Member<U>& b) {
+  return a.Get() == b.Get();
+}
+template <typename T, typename U>
+inline bool operator!=(const Member<T>& a, const Member<U>& b) {
+  return a.Get() != b.Get();
+}
+template <typename T, typename U>
+inline bool operator==(const Persistent<T>& a, const Persistent<U>& b) {
+  return a.Get() == b.Get();
+}
+template <typename T, typename U>
+inline bool operator!=(const Persistent<T>& a, const Persistent<U>& b) {
+  return a.Get() != b.Get();
+}
+
+template <typename T, typename U>
+inline bool operator==(const Member<T>& a, const Persistent<U>& b) {
+  return a.Get() == b.Get();
+}
+template <typename T, typename U>
+inline bool operator!=(const Member<T>& a, const Persistent<U>& b) {
+  return a.Get() != b.Get();
+}
+template <typename T, typename U>
+inline bool operator==(const Persistent<T>& a, const Member<U>& b) {
+  return a.Get() == b.Get();
+}
+template <typename T, typename U>
+inline bool operator!=(const Persistent<T>& a, const Member<U>& b) {
+  return a.Get() != b.Get();
+}
+
+}  // namespace blink
+
+namespace WTF {
+
+template <
+    typename T,
+    blink::WeaknessPersistentConfiguration weaknessConfiguration,
+    blink::CrossThreadnessPersistentConfiguration crossThreadnessConfiguration>
+struct VectorTraits<blink::PersistentBase<T,
+                                          weaknessConfiguration,
+                                          crossThreadnessConfiguration>>
+    : VectorTraitsBase<blink::PersistentBase<T,
+                                             weaknessConfiguration,
+                                             crossThreadnessConfiguration>> {
+  STATIC_ONLY(VectorTraits);
+  static const bool kNeedsDestruction = true;
+  static const bool kCanInitializeWithMemset = true;
+  static const bool kCanClearUnusedSlotsWithMemset = false;
+  static const bool kCanMoveWithMemcpy = true;
+};
+
+template <typename T>
+struct HashTraits<blink::Persistent<T>>
+    : HandleHashTraits<T, blink::Persistent<T>> {};
+
+template <typename T>
+struct HashTraits<blink::CrossThreadPersistent<T>>
+    : HandleHashTraits<T, blink::CrossThreadPersistent<T>> {};
+
+template <typename T>
+struct DefaultHash<blink::Persistent<T>> {
+  STATIC_ONLY(DefaultHash);
+  using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct DefaultHash<blink::WeakPersistent<T>> {
+  STATIC_ONLY(DefaultHash);
+  using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct DefaultHash<blink::CrossThreadPersistent<T>> {
+  STATIC_ONLY(DefaultHash);
+  using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct DefaultHash<blink::CrossThreadWeakPersistent<T>> {
+  STATIC_ONLY(DefaultHash);
+  using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct CrossThreadCopier<blink::CrossThreadPersistent<T>>
+    : public CrossThreadCopierPassThrough<blink::CrossThreadPersistent<T>> {
+  STATIC_ONLY(CrossThreadCopier);
+};
+
+template <typename T>
+struct CrossThreadCopier<blink::CrossThreadWeakPersistent<T>>
+    : public CrossThreadCopierPassThrough<blink::CrossThreadWeakPersistent<T>> {
+  STATIC_ONLY(CrossThreadCopier);
+};
+
+}  // namespace WTF
+
+namespace base {
+
+template <typename T>
+struct IsWeakReceiver<blink::WeakPersistent<T>> : std::true_type {};
+
+template <typename T>
+struct IsWeakReceiver<blink::CrossThreadWeakPersistent<T>> : std::true_type {};
+
+template <typename T>
+struct BindUnwrapTraits<blink::CrossThreadWeakPersistent<T>> {
+  static blink::CrossThreadPersistent<T> Unwrap(
+      const blink::CrossThreadWeakPersistent<T>& wrapped) {
+    return blink::CrossThreadPersistent<T>(wrapped);
+  }
+};
+}  // namespace base
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_H_
diff --git a/third_party/blink/renderer/platform/heap/persistent_node.cc b/third_party/blink/renderer/platform/heap/impl/persistent_node.cc
similarity index 98%
rename from third_party/blink/renderer/platform/heap/persistent_node.cc
rename to third_party/blink/renderer/platform/heap/impl/persistent_node.cc
index 0dd7b23..64733dc5 100644
--- a/third_party/blink/renderer/platform/heap/persistent_node.cc
+++ b/third_party/blink/renderer/platform/heap/impl/persistent_node.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/persistent_node.h"
+#include "third_party/blink/renderer/platform/heap/impl/persistent_node.h"
 
 #include "base/debug/alias.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -17,7 +17,7 @@
  public:
   void Trace(Visitor* visitor) const {}
 };
-}
+}  // namespace
 
 PersistentRegionBase::~PersistentRegionBase() {
   PersistentNodeSlots* slots = slots_;
diff --git a/third_party/blink/renderer/platform/heap/persistent_node.h b/third_party/blink/renderer/platform/heap/impl/persistent_node.h
similarity index 97%
rename from third_party/blink/renderer/platform/heap/persistent_node.h
rename to third_party/blink/renderer/platform/heap/impl/persistent_node.h
index b591db1..d8c2b08 100644
--- a/third_party/blink/renderer/platform/heap/persistent_node.h
+++ b/third_party/blink/renderer/platform/heap/impl/persistent_node.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_NODE_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_NODE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_NODE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_NODE_H_
 
 #include <atomic>
 #include <memory>
@@ -382,4 +382,4 @@
 
 }  // namespace blink
 
-#endif
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_NODE_H_
diff --git a/third_party/blink/renderer/platform/heap/process_heap.cc b/third_party/blink/renderer/platform/heap/impl/process_heap.cc
similarity index 93%
rename from third_party/blink/renderer/platform/heap/process_heap.cc
rename to third_party/blink/renderer/platform/heap/impl/process_heap.cc
index df929e8..038a738 100644
--- a/third_party/blink/renderer/platform/heap/process_heap.cc
+++ b/third_party/blink/renderer/platform/heap/impl/process_heap.cc
@@ -6,9 +6,9 @@
 
 #include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
 #include "third_party/blink/public/common/features.h"
-#include "third_party/blink/renderer/platform/heap/gc_info.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/persistent_node.h"
+#include "third_party/blink/renderer/platform/heap/impl/gc_info.h"
+#include "third_party/blink/renderer/platform/heap/impl/persistent_node.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/heap/impl/process_heap.h b/third_party/blink/renderer/platform/heap/impl/process_heap.h
new file mode 100644
index 0000000..91112a7c
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/process_heap.h
@@ -0,0 +1,69 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PROCESS_HEAP_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PROCESS_HEAP_H_
+
+#include <atomic>
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
+
+namespace blink {
+
+class CrossThreadPersistentRegion;
+
+class PLATFORM_EXPORT ProcessHeap {
+  STATIC_ONLY(ProcessHeap);
+
+ public:
+  static void Init();
+
+  static CrossThreadPersistentRegion& GetCrossThreadPersistentRegion();
+  static CrossThreadPersistentRegion& GetCrossThreadWeakPersistentRegion();
+
+  // Access to the CrossThreadPersistentRegion from multiple threads has to be
+  // prevented as allocation, freeing, and iteration of nodes may otherwise
+  // cause data races.
+  //
+  // Examples include:
+  // - Iteration of strong cross-thread Persistents.
+  // - Iteration and processing of weak cross-thread Persistents. The lock
+  //   needs to span both operations as iteration of weak persistents only
+  //   registers memory regions that are then processed afterwards.
+  // - Marking phase in garbage collection: The whole phase requires locking
+  //   as CrossThreadWeakPersistents may be converted to CrossThreadPersistent
+  //   which must observe GC as an atomic operation.
+  static Mutex& CrossThreadPersistentMutex();
+
+  static void IncreaseTotalAllocatedObjectSize(size_t delta) {
+    total_allocated_object_size_.fetch_add(delta, std::memory_order_relaxed);
+  }
+  static void DecreaseTotalAllocatedObjectSize(size_t delta) {
+    total_allocated_object_size_.fetch_sub(delta, std::memory_order_relaxed);
+  }
+  static size_t TotalAllocatedObjectSize() {
+    return total_allocated_object_size_.load(std::memory_order_relaxed);
+  }
+  static void IncreaseTotalAllocatedSpace(size_t delta) {
+    total_allocated_space_.fetch_add(delta, std::memory_order_relaxed);
+  }
+  static void DecreaseTotalAllocatedSpace(size_t delta) {
+    total_allocated_space_.fetch_sub(delta, std::memory_order_relaxed);
+  }
+  static size_t TotalAllocatedSpace() {
+    return total_allocated_space_.load(std::memory_order_relaxed);
+  }
+  static void ResetHeapCounters();
+
+ private:
+  static std::atomic_size_t total_allocated_space_;
+  static std::atomic_size_t total_allocated_object_size_;
+
+  friend class ThreadState;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PROCESS_HEAP_H_
diff --git a/third_party/blink/renderer/platform/heap/thread_state.cc b/third_party/blink/renderer/platform/heap/impl/thread_state.cc
similarity index 99%
rename from third_party/blink/renderer/platform/heap/thread_state.cc
rename to third_party/blink/renderer/platform/heap/impl/thread_state.cc
index bece34a..228902f 100644
--- a/third_party/blink/renderer/platform/heap/thread_state.cc
+++ b/third_party/blink/renderer/platform/heap/impl/thread_state.cc
@@ -53,11 +53,11 @@
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
-#include "third_party/blink/renderer/platform/heap/heap_compact.h"
 #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
-#include "third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h"
-#include "third_party/blink/renderer/platform/heap/marking_visitor.h"
-#include "third_party/blink/renderer/platform/heap/page_pool.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
+#include "third_party/blink/renderer/platform/heap/impl/page_pool.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
 #include "third_party/blink/renderer/platform/heap/unified_heap_controller.h"
@@ -1153,8 +1153,8 @@
     skip_incremental_marking_for_testing_ = false;
   } else {
     complete = MarkPhaseAdvanceMarking(
-            marking_scheduling_->GetNextIncrementalStepDurationForTask(
-                Heap().stats_collector()->object_size_in_bytes()),
+        marking_scheduling_->GetNextIncrementalStepDurationForTask(
+            Heap().stats_collector()->object_size_in_bytes()),
         EphemeronProcessing::kPartialProcessing);
   }
 
@@ -1638,7 +1638,6 @@
 
   incremental_marking_scheduler_->Cancel();
 
-
   current_gc_data_.visitor->FlushCompactionWorklists();
   current_gc_data_.visitor.reset();
 
diff --git a/third_party/blink/renderer/platform/heap/impl/thread_state.h b/third_party/blink/renderer/platform/heap/impl/thread_state.h
new file mode 100644
index 0000000..ee318bd6
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/thread_state.h
@@ -0,0 +1,716 @@
+/*
+ * 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.
+ */
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_H_
+
+#include <atomic>
+#include <memory>
+
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "base/task/post_job.h"
+#include "third_party/blink/renderer/platform/heap/blink_gc.h"
+#include "third_party/blink/renderer/platform/heap/impl/atomic_entry_flag.h"
+#include "third_party/blink/renderer/platform/heap/impl/threading_traits.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/sanitizers.h"
+#include "third_party/blink/renderer/platform/wtf/thread_specific.h"
+#include "third_party/blink/renderer/platform/wtf/threading.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace v8 {
+class EmbedderGraph;
+class Isolate;
+}  // namespace v8
+
+namespace blink {
+
+namespace incremental_marking_test {
+class IncrementalMarkingScope;
+}  // namespace incremental_marking_test
+
+class MarkingVisitor;
+class MarkingSchedulingOracle;
+class PersistentNode;
+class PersistentRegion;
+class ThreadHeap;
+class ThreadState;
+template <ThreadAffinity affinity>
+class ThreadStateFor;
+class UnifiedHeapController;
+class Visitor;
+
+// Declare that a class has a pre-finalizer which gets invoked before objects
+// get swept. It is thus safe to touch on-heap objects that may be collected in
+// the same GC cycle. This is useful when it's not possible to avoid touching
+// on-heap objects in a destructor which is forbidden.
+//
+// Note that:
+// (a) Pre-finalizers *must* not resurrect dead objects.
+// (b) Run on the same thread they are registered.
+// (c) Decrease GC performance which means that they should only be used if
+//     absolute necessary.
+//
+// Usage:
+//   class Foo : GarbageCollected<Foo> {
+//     USING_PRE_FINALIZER(Foo, Dispose);
+//    private:
+//     void Dispose() {
+//       bar_->...; // It is safe to touch other on-heap objects.
+//     }
+//     Member<Bar> bar_;
+//   };
+#define USING_PRE_FINALIZER(Class, PreFinalizer)                             \
+ public:                                                                     \
+  static bool InvokePreFinalizer(const LivenessBroker& info, void* object) { \
+    Class* self = reinterpret_cast<Class*>(object);                          \
+    if (info.IsHeapObjectAlive(self))                                        \
+      return false;                                                          \
+    self->Class::PreFinalizer();                                             \
+    return true;                                                             \
+  }                                                                          \
+                                                                             \
+ private:                                                                    \
+  ThreadState::PrefinalizerRegistration<Class> prefinalizer_dummy_{this};    \
+  using UsingPreFinalizerMacroNeedsTrailingSemiColon = char
+
+class PLATFORM_EXPORT BlinkGCObserver {
+  USING_FAST_MALLOC(BlinkGCObserver);
+
+ public:
+  // The constructor automatically register this object to ThreadState's
+  // observer lists. The argument must not be null.
+  explicit BlinkGCObserver(ThreadState*);
+
+  // The destructor automatically unregister this object from ThreadState's
+  // observer lists.
+  virtual ~BlinkGCObserver();
+
+  virtual void OnCompleteSweepDone() = 0;
+
+ private:
+  // As a ThreadState must live when a BlinkGCObserver lives, holding a raw
+  // pointer is safe.
+  ThreadState* thread_state_;
+};
+
+class PLATFORM_EXPORT ThreadState final {
+  USING_FAST_MALLOC(ThreadState);
+
+ public:
+  // Register the pre-finalizer for the |self| object. The class T be using
+  // USING_PRE_FINALIZER() macro.
+  template <typename T>
+  class PrefinalizerRegistration final {
+    DISALLOW_NEW();
+
+   public:
+    PrefinalizerRegistration(T* self) {  // NOLINT
+      static_assert(sizeof(&T::InvokePreFinalizer) > 0,
+                    "USING_PRE_FINALIZER(T) must be defined.");
+      ThreadState* state =
+          ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
+#if DCHECK_IS_ON()
+      DCHECK(state->CheckThread());
+#endif
+      DCHECK(!state->SweepForbidden());
+      DCHECK(std::find(state->ordered_pre_finalizers_.begin(),
+                       state->ordered_pre_finalizers_.end(),
+                       PreFinalizer(self, T::InvokePreFinalizer)) ==
+             state->ordered_pre_finalizers_.end());
+      state->ordered_pre_finalizers_.emplace_back(self, T::InvokePreFinalizer);
+    }
+  };
+
+  // See setGCState() for possible state transitions.
+  enum GCState {
+    kNoGCScheduled,
+    kIncrementalMarkingStepPaused,
+    kIncrementalMarkingStepScheduled,
+    kIncrementalMarkingFinalizeScheduled,
+    kForcedGCForTestingScheduled,
+    kIncrementalGCScheduled,
+  };
+
+  // The phase that the GC is in. The GCPhase will not return kNone for mutators
+  // running during incremental marking and lazy sweeping. See SetGCPhase() for
+  // possible state transitions.
+  enum class GCPhase {
+    // GC is doing nothing.
+    kNone,
+    // GC is in marking phase.
+    kMarking,
+    // GC is in sweeping phase.
+    kSweeping,
+  };
+
+  enum class EphemeronProcessing {
+    kPartialProcessing,  // Perofrm one ephemeron processing iteration every
+                         // few step
+    kFullProcessing  // Perofrm full fixed-point ephemeron processing on each
+                     // step
+  };
+
+  class AtomicPauseScope;
+  class GCForbiddenScope;
+  class LsanDisabledScope;
+  class NoAllocationScope;
+  class StatisticsCollector;
+  struct Statistics;
+  class SweepForbiddenScope;
+  class HeapPointersOnStackScope;
+
+  using V8BuildEmbedderGraphCallback = void (*)(v8::Isolate*,
+                                                v8::EmbedderGraph*,
+                                                void*);
+
+  // Returns true if some thread (possibly the current thread) may be doing
+  // incremental marking. If false is returned, the *current* thread is
+  // definitely not doing incremental marking. See atomic_entry_flag.h for
+  // details.
+  //
+  // For an exact check, use ThreadState::IsIncrementalMarking.
+  ALWAYS_INLINE static bool IsAnyIncrementalMarking() {
+    return incremental_marking_flag_.MightBeEntered();
+  }
+
+  static ThreadState* AttachMainThread();
+
+  // Associate ThreadState object with the current thread. After this
+  // call thread can start using the garbage collected heap infrastructure.
+  // It also has to periodically check for safepoints.
+  static ThreadState* AttachCurrentThread();
+
+  // Disassociate attached ThreadState from the current thread. The thread
+  // can no longer use the garbage collected heap after this call.
+  //
+  // When ThreadState is detaching from non-main thread its heap is expected to
+  // be empty (because it is going away). Perform registered cleanup tasks and
+  // garbage collection to sweep away any objects that are left on this heap.
+  //
+  // This method asserts that no objects remain after this cleanup. If assertion
+  // does not hold we crash as we are potentially in the dangling pointer
+  // situation.
+  static void DetachCurrentThread();
+
+  static ThreadState* Current() { return **thread_specific_; }
+
+  static ThreadState* MainThreadState() {
+    return reinterpret_cast<ThreadState*>(main_thread_state_storage_);
+  }
+
+  static ThreadState* FromObject(const void*);
+
+  bool IsMainThread() const { return this == MainThreadState(); }
+  bool CheckThread() const { return thread_ == CurrentThread(); }
+
+  ThreadHeap& Heap() const { return *heap_; }
+  base::PlatformThreadId ThreadId() const { return thread_; }
+
+  // Associates |ThreadState| with a given |v8::Isolate|, essentially tying
+  // there garbage collectors together.
+  void AttachToIsolate(v8::Isolate*, V8BuildEmbedderGraphCallback);
+
+  // Removes the association from a potentially attached |v8::Isolate|.
+  void DetachFromIsolate();
+
+  // Returns an |UnifiedHeapController| if ThreadState is attached to a V8
+  // isolate (see |AttachToIsolate|) and nullptr otherwise.
+  UnifiedHeapController* unified_heap_controller() const {
+    DCHECK(isolate_);
+    return unified_heap_controller_.get();
+  }
+
+  void PerformIdleLazySweep(base::TimeTicks deadline);
+  void PerformConcurrentSweep(base::JobDelegate*);
+
+  void ScheduleForcedGCForTesting();
+  void ScheduleGCIfNeeded();
+  void SetGCState(GCState);
+  GCState GetGCState() const { return gc_state_; }
+  void SetGCPhase(GCPhase);
+
+  // Immediately starts incremental marking and schedules further steps if
+  // necessary.
+  void StartIncrementalMarking(BlinkGC::GCReason);
+
+  // Returns true if marking is in progress.
+  bool IsMarkingInProgress() const { return gc_phase_ == GCPhase::kMarking; }
+
+  // Returns true if unified heap marking is in progress.
+  bool IsUnifiedGCMarkingInProgress() const {
+    return IsMarkingInProgress() && IsUnifiedHeapGC();
+  }
+
+  // Returns true if sweeping is in progress.
+  bool IsSweepingInProgress() const { return gc_phase_ == GCPhase::kSweeping; }
+
+  // Returns true if the current GC is a memory reducing GC.
+  bool IsMemoryReducingGC() const {
+    return current_gc_data_.reason ==
+               BlinkGC::GCReason::kUnifiedHeapForMemoryReductionGC ||
+           current_gc_data_.reason ==
+               BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC;
+  }
+
+  bool IsUnifiedHeapGC() const {
+    return current_gc_data_.reason == BlinkGC::GCReason::kUnifiedHeapGC ||
+           current_gc_data_.reason ==
+               BlinkGC::GCReason::kUnifiedHeapForMemoryReductionGC ||
+           current_gc_data_.reason ==
+               BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC;
+  }
+
+  bool FinishIncrementalMarkingIfRunning(BlinkGC::CollectionType,
+                                         BlinkGC::StackState,
+                                         BlinkGC::MarkingType,
+                                         BlinkGC::SweepingType,
+                                         BlinkGC::GCReason);
+
+  void EnableIncrementalMarkingBarrier();
+  void DisableIncrementalMarkingBarrier();
+
+  void RestartIncrementalMarkingIfPaused();
+
+  void CompleteSweep();
+
+  // Returns whether it is currently allowed to allocate an object. Mainly used
+  // for sanity checks asserts.
+  bool IsAllocationAllowed() const {
+    // Allocation is not allowed during atomic marking pause, but it is allowed
+    // during atomic sweeping pause.
+    return !InAtomicMarkingPause() && !no_allocation_count_;
+  }
+
+  // Returns whether it is currently forbidden to trigger a GC.
+  bool IsGCForbidden() const { return gc_forbidden_count_; }
+
+  // Returns whether it is currently forbidden to sweep objects.
+  bool SweepForbidden() const { return sweep_forbidden_; }
+
+  bool in_atomic_pause() const { return in_atomic_pause_; }
+
+  bool InAtomicMarkingPause() const {
+    return in_atomic_pause() && IsMarkingInProgress();
+  }
+  bool InAtomicSweepingPause() const {
+    return in_atomic_pause() && IsSweepingInProgress();
+  }
+
+  bool IsIncrementalMarking() const { return incremental_marking_; }
+  void SetIncrementalMarking(bool value) { incremental_marking_ = value; }
+
+  void SafePoint(BlinkGC::StackState);
+
+  // A region of non-weak PersistentNodes allocated on the given thread.
+  PersistentRegion* GetPersistentRegion() const {
+    return persistent_region_.get();
+  }
+
+  // A region of PersistentNodes for WeakPersistents allocated on the given
+  // thread.
+  PersistentRegion* GetWeakPersistentRegion() const {
+    return weak_persistent_region_.get();
+  }
+
+  void RegisterStaticPersistentNode(PersistentNode*);
+  void ReleaseStaticPersistentNodes();
+  void FreePersistentNode(PersistentRegion*, PersistentNode*);
+
+  v8::Isolate* GetIsolate() const { return isolate_; }
+
+  // Returns |true| if |object| resides on this thread's heap.
+  // It is well-defined to call this method on any heap allocated
+  // reference, provided its associated heap hasn't been detached
+  // and shut down. Its behavior is undefined for any other pointer
+  // value.
+  bool IsOnThreadHeap(const void* object) const {
+    return &FromObject(object)->Heap() == &Heap();
+  }
+
+  ALWAYS_INLINE bool IsOnStack(Address address) const {
+    return reinterpret_cast<Address>(start_of_stack_) >= address &&
+           address >= (reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(
+                          WTF::GetCurrentStackPosition())));
+  }
+
+  int GcAge() const { return gc_age_; }
+
+  MarkingVisitor* CurrentVisitor() const {
+    return current_gc_data_.visitor.get();
+  }
+
+  // Returns true if the marking verifier is enabled, false otherwise.
+  bool IsVerifyMarkingEnabled() const;
+
+  void SkipIncrementalMarkingForTesting() {
+    skip_incremental_marking_for_testing_ = true;
+  }
+
+  // Performs stand-alone garbage collections considering only C++ objects for
+  // testing.
+  //
+  // Since it only considers C++ objects this type of GC is mostly useful for
+  // unit tests.
+  void CollectGarbageForTesting(BlinkGC::CollectionType,
+                                BlinkGC::StackState,
+                                BlinkGC::MarkingType,
+                                BlinkGC::SweepingType,
+                                BlinkGC::GCReason);
+
+  // Forced garbage collection for testing:
+  // - Performs unified heap garbage collections if ThreadState is attached to a
+  //   v8::Isolate using ThreadState::AttachToIsolate.
+  // - Otherwise, performs stand-alone garbage collections.
+  // - Collects garbage as long as live memory decreases (capped at 5).
+  void CollectAllGarbageForTesting(
+      BlinkGC::StackState stack_state =
+          BlinkGC::StackState::kNoHeapPointersOnStack);
+
+  // Enables compaction for next garbage collection.
+  void EnableCompactionForNextGCForTesting();
+
+  bool RequiresForcedGCForTesting() const {
+    return current_gc_data_.stack_state ==
+               BlinkGC::StackState::kHeapPointersOnStack &&
+           !forced_scheduled_gc_for_testing_;
+  }
+
+  void EnterNoHeapVerificationScopeForTesting() {
+    ++disable_heap_verification_scope_;
+  }
+  void LeaveNoHeapVerificationScopeForTesting() {
+    --disable_heap_verification_scope_;
+  }
+
+ private:
+  class IncrementalMarkingScheduler;
+
+  // Stores whether some ThreadState is currently in incremental marking.
+  static AtomicEntryFlag incremental_marking_flag_;
+
+  static WTF::ThreadSpecific<ThreadState*>* thread_specific_;
+
+  // We can't create a static member of type ThreadState here because it will
+  // introduce global constructor and destructor. We would like to manage
+  // lifetime of the ThreadState attached to the main thread explicitly instead
+  // and still use normal constructor and destructor for the ThreadState class.
+  // For this we reserve static storage for the main ThreadState and lazily
+  // construct ThreadState in it using placement new.
+  static uint8_t main_thread_state_storage_[];
+
+  // Callback executed directly after pushing all callee-saved registers.
+  // |end_of_stack| denotes the end of the stack that can hold references to
+  // managed objects.
+  static void VisitStackAfterPushingRegisters(ThreadState*,
+                                              intptr_t* end_of_stack);
+
+  static bool IsForcedGC(BlinkGC::GCReason reason) {
+    return reason == BlinkGC::GCReason::kThreadTerminationGC ||
+           reason == BlinkGC::GCReason::kForcedGCForTesting ||
+           reason == BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC;
+  }
+
+  ThreadState();
+  ~ThreadState();
+
+  void EnterNoAllocationScope() { no_allocation_count_++; }
+  void LeaveNoAllocationScope() { no_allocation_count_--; }
+
+  void EnterAtomicPause() {
+    DCHECK(!in_atomic_pause_);
+    in_atomic_pause_ = true;
+  }
+  void LeaveAtomicPause() {
+    DCHECK(in_atomic_pause_);
+    in_atomic_pause_ = false;
+  }
+
+  void EnterGCForbiddenScope() { gc_forbidden_count_++; }
+  void LeaveGCForbiddenScope() {
+    DCHECK_GT(gc_forbidden_count_, 0u);
+    gc_forbidden_count_--;
+  }
+
+  void EnterStaticReferenceRegistrationDisabledScope();
+  void LeaveStaticReferenceRegistrationDisabledScope();
+
+  // Performs stand-alone garbage collections considering only C++ objects.
+  //
+  // Use the public *ForTesting calls for calling GC in tests.
+  void CollectGarbage(BlinkGC::CollectionType,
+                      BlinkGC::StackState,
+                      BlinkGC::MarkingType,
+                      BlinkGC::SweepingType,
+                      BlinkGC::GCReason);
+
+  // The following methods are used to compose RunAtomicPause. Public users
+  // should use the CollectGarbage entrypoint. Internal users should use these
+  // methods to compose a full garbage collection.
+  void AtomicPauseMarkPrologue(BlinkGC::CollectionType,
+                               BlinkGC::StackState,
+                               BlinkGC::MarkingType,
+                               BlinkGC::GCReason);
+  void AtomicPauseMarkRoots(BlinkGC::StackState,
+                            BlinkGC::MarkingType,
+                            BlinkGC::GCReason);
+  void AtomicPauseMarkTransitiveClosure();
+  void AtomicPauseMarkEpilogue(BlinkGC::MarkingType);
+  void AtomicPauseSweepAndCompact(BlinkGC::CollectionType,
+                                  BlinkGC::MarkingType marking_type,
+                                  BlinkGC::SweepingType sweeping_type);
+  void AtomicPauseEpilogue();
+
+  // RunAtomicPause composes the final atomic pause that finishes a mark-compact
+  // phase of a garbage collection. Depending on SweepingType it may also finish
+  // sweeping or schedule lazy/concurrent sweeping.
+  void RunAtomicPause(BlinkGC::CollectionType,
+                      BlinkGC::StackState,
+                      BlinkGC::MarkingType,
+                      BlinkGC::SweepingType,
+                      BlinkGC::GCReason);
+
+  // The version is needed to be able to start incremental marking.
+  void MarkPhasePrologue(BlinkGC::CollectionType,
+                         BlinkGC::StackState,
+                         BlinkGC::MarkingType,
+                         BlinkGC::GCReason);
+  void MarkPhaseEpilogue(BlinkGC::MarkingType);
+  void MarkPhaseVisitRoots();
+  void MarkPhaseVisitNotFullyConstructedObjects();
+  bool MarkPhaseAdvanceMarkingBasedOnSchedule(base::TimeDelta,
+                                              EphemeronProcessing);
+  bool MarkPhaseAdvanceMarking(base::TimeDelta, EphemeronProcessing);
+  void VerifyMarking(BlinkGC::MarkingType);
+
+  // Visit the stack after pushing registers onto the stack.
+  void PushRegistersAndVisitStack();
+
+  // Visit local thread stack and trace all pointers conservatively. Never call
+  // directly but always call through |PushRegistersAndVisitStack|.
+  void VisitStackImpl(MarkingVisitor*, Address*, Address*);
+  void VisitStack(MarkingVisitor*, Address*);
+  void VisitUnsafeStack(MarkingVisitor*);
+
+  // Visit the asan fake stack frame corresponding to a slot on the real machine
+  // stack if there is one. Never call directly but always call through
+  // |PushRegistersAndVisitStack|.
+  void VisitAsanFakeStackForPointer(MarkingVisitor*,
+                                    Address,
+                                    Address*,
+                                    Address*);
+
+  // Visit all non-weak persistents allocated on this thread.
+  void VisitPersistents(Visitor*);
+
+  // Visit all weak persistents allocated on this thread.
+  void VisitWeakPersistents(Visitor*);
+
+  // Visit card tables (remembered sets) containing inter-generational pointers.
+  void VisitRememberedSets(MarkingVisitor*);
+
+  // Incremental marking implementation functions.
+  void IncrementalMarkingStartForTesting();
+  void IncrementalMarkingStart(BlinkGC::GCReason);
+  // Incremental marking step advance marking on the mutator thread. This method
+  // also reschedules concurrent marking tasks if needed. The duration parameter
+  // applies only to incremental marking steps on the mutator thread.
+  void IncrementalMarkingStep(BlinkGC::StackState);
+  void IncrementalMarkingFinalize();
+
+  // Returns true if concurrent marking is finished (i.e. all current threads
+  // terminated and the worklist is empty)
+  bool ConcurrentMarkingStep();
+  void ScheduleConcurrentMarking();
+  void PerformConcurrentMark(base::JobDelegate* job);
+
+  // Schedule helpers.
+  void ScheduleIdleLazySweep();
+  void ScheduleConcurrentAndLazySweep();
+
+  void NotifySweepDone();
+  void PostSweep();
+
+  // See |DetachCurrentThread|.
+  void RunTerminationGC();
+
+  void RunScheduledGC(BlinkGC::StackState);
+
+  void SynchronizeAndFinishConcurrentSweeping();
+
+  void InvokePreFinalizers();
+
+  // Adds the given observer to the ThreadState's observer list. This doesn't
+  // take ownership of the argument. The argument must not be null. The argument
+  // must not be registered before calling this.
+  void AddObserver(BlinkGCObserver*);
+
+  // Removes the given observer from the ThreadState's observer list. This
+  // doesn't take ownership of the argument. The argument must not be null.
+  // The argument must be registered before calling this.
+  void RemoveObserver(BlinkGCObserver*);
+
+  bool IsForcedGC() const { return IsForcedGC(current_gc_data_.reason); }
+
+  // Returns whether stack scanning is forced. This is currently only used in
+  // platform tests where non nested tasks can be run with heap pointers on
+  // stack.
+  bool HeapPointersOnStackForced() const {
+    return heap_pointers_on_stack_forced_;
+  }
+
+#if defined(ADDRESS_SANITIZER)
+  // Poisons payload of unmarked objects.
+  //
+  // Also unpoisons memory areas for handles that may require resetting which
+  // can race with destructors. Note that cross-thread access still requires
+  // synchronization using a lock.
+  void PoisonUnmarkedObjects();
+#endif  // ADDRESS_SANITIZER
+
+  std::unique_ptr<ThreadHeap> heap_;
+  base::PlatformThreadId thread_;
+  std::unique_ptr<PersistentRegion> persistent_region_;
+  std::unique_ptr<PersistentRegion> weak_persistent_region_;
+
+  // Start of the stack which is the boundary until conservative stack scanning
+  // needs to search for managed pointers.
+  Address* start_of_stack_;
+
+  bool in_atomic_pause_ = false;
+  bool sweep_forbidden_ = false;
+  bool heap_pointers_on_stack_forced_ = false;
+  bool incremental_marking_ = false;
+  bool should_optimize_for_load_time_ = false;
+  bool forced_scheduled_gc_for_testing_ = false;
+  size_t no_allocation_count_ = 0;
+  size_t gc_forbidden_count_ = 0;
+  size_t static_persistent_registration_disabled_count_ = 0;
+
+  GCState gc_state_ = GCState::kNoGCScheduled;
+  GCPhase gc_phase_ = GCPhase::kNone;
+  BlinkGC::GCReason reason_for_scheduled_gc_ =
+      BlinkGC::GCReason::kForcedGCForTesting;
+
+  using PreFinalizerCallback = bool (*)(const LivenessBroker&, void*);
+  using PreFinalizer = std::pair<void*, PreFinalizerCallback>;
+
+  // Pre-finalizers are called in the reverse order in which they are
+  // registered by the constructors (including constructors of Mixin objects)
+  // for an object, by processing the ordered_pre_finalizers_ back-to-front.
+  Deque<PreFinalizer> ordered_pre_finalizers_;
+
+  v8::Isolate* isolate_ = nullptr;
+  V8BuildEmbedderGraphCallback v8_build_embedder_graph_ = nullptr;
+  std::unique_ptr<UnifiedHeapController> unified_heap_controller_;
+
+#if defined(ADDRESS_SANITIZER)
+  void* asan_fake_stack_;
+#endif
+
+  HashSet<BlinkGCObserver*> observers_;
+
+  // PersistentNodes that are stored in static references;
+  // references that either have to be cleared upon the thread
+  // detaching from Oilpan and shutting down or references we
+  // have to clear before initiating LSan's leak detection.
+  HashSet<PersistentNode*> static_persistents_;
+
+  int gc_age_ = 0;
+
+  struct GCData {
+    BlinkGC::CollectionType collection_type;
+    BlinkGC::StackState stack_state;
+    BlinkGC::MarkingType marking_type;
+    BlinkGC::GCReason reason;
+    std::unique_ptr<MarkingVisitor> visitor;
+  };
+  GCData current_gc_data_;
+
+  std::unique_ptr<IncrementalMarkingScheduler> incremental_marking_scheduler_;
+  std::unique_ptr<MarkingSchedulingOracle> marking_scheduling_;
+
+  base::JobHandle marker_handle_;
+
+  base::JobHandle sweeper_handle_;
+  std::atomic_bool has_unswept_pages_{false};
+
+  size_t disable_heap_verification_scope_ = 0;
+
+  bool skip_incremental_marking_for_testing_ = false;
+
+  size_t last_concurrently_marked_bytes_ = 0;
+  base::TimeTicks last_concurrently_marked_bytes_update_;
+  bool concurrent_marking_priority_increased_ = false;
+
+  friend class BlinkGCObserver;
+  friend class incremental_marking_test::IncrementalMarkingScope;
+  friend class IncrementalMarkingTestDriver;
+  friend class HeapAllocator;
+  template <typename T>
+  friend class PrefinalizerRegistration;
+  friend class TestGCScope;
+  friend class TestSupportingGC;
+  friend class ThreadStateSchedulingTest;
+  friend class UnifiedHeapController;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadState);
+};
+
+template <>
+class ThreadStateFor<kMainThreadOnly> {
+  STATIC_ONLY(ThreadStateFor);
+
+ public:
+  static ThreadState* GetState() {
+    // This specialization must only be used from the main thread.
+    DCHECK(ThreadState::Current()->IsMainThread());
+    return ThreadState::MainThreadState();
+  }
+};
+
+template <>
+class ThreadStateFor<kAnyThread> {
+  STATIC_ONLY(ThreadStateFor);
+
+ public:
+  static ThreadState* GetState() { return ThreadState::Current(); }
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_H_
diff --git a/third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h b/third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h
new file mode 100644
index 0000000..07e22c9
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h
@@ -0,0 +1,128 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_SCOPES_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_SCOPES_H_
+
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+
+#if defined(LEAK_SANITIZER)
+#include "third_party/blink/renderer/platform/wtf/leak_annotations.h"
+#endif
+
+namespace blink {
+
+// The NoAllocationScope class is used in debug mode to catch unwanted
+// allocations. E.g. allocations during GC.
+class ThreadState::NoAllocationScope final {
+  STACK_ALLOCATED();
+  DISALLOW_COPY_AND_ASSIGN(NoAllocationScope);
+
+ public:
+  explicit NoAllocationScope(ThreadState* state) : state_(state) {
+    state_->EnterNoAllocationScope();
+  }
+  ~NoAllocationScope() { state_->LeaveNoAllocationScope(); }
+
+ private:
+  ThreadState* const state_;
+};
+
+class ThreadState::SweepForbiddenScope final {
+  STACK_ALLOCATED();
+  DISALLOW_COPY_AND_ASSIGN(SweepForbiddenScope);
+
+ public:
+  explicit SweepForbiddenScope(ThreadState* state) : state_(state) {
+    DCHECK(!state_->sweep_forbidden_);
+    state_->sweep_forbidden_ = true;
+  }
+  ~SweepForbiddenScope() {
+    DCHECK(state_->sweep_forbidden_);
+    state_->sweep_forbidden_ = false;
+  }
+
+ private:
+  ThreadState* const state_;
+};
+
+class ThreadState::GCForbiddenScope final {
+  STACK_ALLOCATED();
+
+ public:
+  explicit GCForbiddenScope(ThreadState* thread_state)
+      : thread_state_(thread_state) {
+    thread_state_->EnterGCForbiddenScope();
+  }
+  ~GCForbiddenScope() { thread_state_->LeaveGCForbiddenScope(); }
+
+ private:
+  ThreadState* const thread_state_;
+};
+
+// Used to mark when we are in an atomic pause for GC.
+class ThreadState::AtomicPauseScope final {
+  STACK_ALLOCATED();
+
+ public:
+  explicit AtomicPauseScope(ThreadState* thread_state)
+      : thread_state_(thread_state), gc_forbidden_scope(thread_state) {
+    thread_state_->EnterAtomicPause();
+  }
+  ~AtomicPauseScope() { thread_state_->LeaveAtomicPause(); }
+
+ private:
+  ThreadState* const thread_state_;
+  GCForbiddenScope gc_forbidden_scope;
+};
+
+class ThreadState::HeapPointersOnStackScope final {
+  STACK_ALLOCATED();
+
+ public:
+  explicit HeapPointersOnStackScope(ThreadState* state) : state_(state) {
+    DCHECK(!state_->heap_pointers_on_stack_forced_);
+    state_->heap_pointers_on_stack_forced_ = true;
+  }
+  ~HeapPointersOnStackScope() {
+    DCHECK(state_->heap_pointers_on_stack_forced_);
+    state_->heap_pointers_on_stack_forced_ = false;
+  }
+
+ private:
+  ThreadState* const state_;
+};
+
+#if defined(LEAK_SANITIZER)
+class ThreadState::LsanDisabledScope final {
+  STACK_ALLOCATED();
+  DISALLOW_COPY_AND_ASSIGN(LsanDisabledScope);
+
+ public:
+  explicit LsanDisabledScope(ThreadState* thread_state)
+      : thread_state_(thread_state) {
+    __lsan_disable();
+    if (thread_state_)
+      thread_state_->EnterStaticReferenceRegistrationDisabledScope();
+  }
+
+  ~LsanDisabledScope() {
+    __lsan_enable();
+    if (thread_state_)
+      thread_state_->LeaveStaticReferenceRegistrationDisabledScope();
+  }
+
+ private:
+  ThreadState* const thread_state_;
+};
+
+#define LEAK_SANITIZER_DISABLED_SCOPE \
+  ThreadState::LsanDisabledScope lsan_disabled_scope(ThreadState::Current())
+#else
+#define LEAK_SANITIZER_DISABLED_SCOPE
+#endif
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_SCOPES_H_
diff --git a/third_party/blink/renderer/platform/heap/thread_state_statistics.cc b/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.cc
similarity index 92%
rename from third_party/blink/renderer/platform/heap/thread_state_statistics.cc
rename to third_party/blink/renderer/platform/heap/impl/thread_state_statistics.cc
index 90a684c..d845f85d 100644
--- a/third_party/blink/renderer/platform/heap/thread_state_statistics.cc
+++ b/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/thread_state_statistics.h"
+#include "third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h"
 
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
diff --git a/third_party/blink/renderer/platform/heap/thread_state_statistics.h b/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h
similarity index 86%
rename from third_party/blink/renderer/platform/heap/thread_state_statistics.h
rename to third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h
index c2a3a6f..9eb1efa6 100644
--- a/third_party/blink/renderer/platform/heap/thread_state_statistics.h
+++ b/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_STATISTICS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_STATISTICS_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_STATISTICS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_STATISTICS_H_
 
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 
@@ -64,4 +64,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_STATISTICS_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_STATISTICS_H_
diff --git a/third_party/blink/renderer/platform/heap/threading_traits.h b/third_party/blink/renderer/platform/heap/impl/threading_traits.h
similarity index 95%
rename from third_party/blink/renderer/platform/heap/threading_traits.h
rename to third_party/blink/renderer/platform/heap/impl/threading_traits.h
index 95fa0c7e..bfae97b 100644
--- a/third_party/blink/renderer/platform/heap/threading_traits.h
+++ b/third_party/blink/renderer/platform/heap/impl/threading_traits.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREADING_TRAITS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREADING_TRAITS_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREADING_TRAITS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREADING_TRAITS_H_
 
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
@@ -165,4 +165,4 @@
 
 }  // namespace blink
 
-#endif
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREADING_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/heap/trace_traits.h b/third_party/blink/renderer/platform/heap/impl/trace_traits.h
similarity index 97%
rename from third_party/blink/renderer/platform/heap/trace_traits.h
rename to third_party/blink/renderer/platform/heap/impl/trace_traits.h
index 7bfab484..668da56 100644
--- a/third_party/blink/renderer/platform/heap/trace_traits.h
+++ b/third_party/blink/renderer/platform/heap/impl/trace_traits.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_TRACE_TRAITS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_TRACE_TRAITS_H_
 
 #include "base/optional.h"
-#include "third_party/blink/renderer/platform/heap/gc_info.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/gc_info.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -378,4 +378,4 @@
 
 }  // namespace WTF
 
-#endif
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_TRACE_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_controller.cc b/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.cc
similarity index 98%
rename from third_party/blink/renderer/platform/heap/unified_heap_controller.cc
rename to third_party/blink/renderer/platform/heap/impl/unified_heap_controller.cc
index df02a2d..43a4e29 100644
--- a/third_party/blink/renderer/platform/heap/unified_heap_controller.cc
+++ b/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.cc
@@ -12,7 +12,7 @@
 #include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
-#include "third_party/blink/renderer/platform/heap/marking_visitor.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
diff --git a/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.h b/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.h
new file mode 100644
index 0000000..c42283c
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.h
@@ -0,0 +1,75 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_CONTROLLER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_CONTROLLER_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class ThreadState;
+
+// UnifiedHeapController ties V8's garbage collector to Oilpan for performing a
+// garbage collection across both managed heaps.
+//
+// Unified heap garbage collections are triggered by V8 and mark the full
+// transitive closure of V8 and Blink (Oilpan) objects. The garbage collection
+// is initially triggered by V8. Both collecters report live references using
+// the EmbedderHeapTracer APIs. V8 and Blink both run separate incremental
+// marking steps to compute their live closures, respectively. The final atomic
+// pause is then initiated by V8 and triggers a fixed-point computation between
+// V8 and Blink where both GCs report live references to each other and drain
+// their marking work lists until they are empty and no new references are
+// found.
+//
+// Oilpan does not consider references from DOM wrappers (JavaScript objects on
+// V8's heap) as roots for such garbage collections.
+class PLATFORM_EXPORT UnifiedHeapController final
+    : public v8::EmbedderHeapTracer,
+      public ThreadHeapStatsObserver {
+  DISALLOW_IMPLICIT_CONSTRUCTORS(UnifiedHeapController);
+
+ public:
+  explicit UnifiedHeapController(ThreadState*);
+  ~UnifiedHeapController() override;
+
+  // v8::EmbedderHeapTracer implementation.
+  void TracePrologue(v8::EmbedderHeapTracer::TraceFlags) final;
+  void TraceEpilogue(v8::EmbedderHeapTracer::TraceSummary*) final;
+  void EnterFinalPause(EmbedderStackState) final;
+  void RegisterV8References(const std::vector<std::pair<void*, void*>>&) final;
+  bool AdvanceTracing(double) final;
+  bool IsTracingDone() final;
+  bool IsRootForNonTracingGC(const v8::TracedReference<v8::Value>&) final;
+  bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>&) final;
+  void ResetHandleInNonTracingGC(const v8::TracedReference<v8::Value>&) final;
+
+  ThreadState* thread_state() const { return thread_state_; }
+
+  // ThreadHeapStatsObserver implementation.
+  void IncreaseAllocatedObjectSize(size_t) final;
+  void DecreaseAllocatedObjectSize(size_t) final;
+  // Not needed.
+  void ResetAllocatedObjectSize(size_t) final {}
+  void IncreaseAllocatedSpace(size_t) final {}
+  void DecreaseAllocatedSpace(size_t) final {}
+
+ private:
+  void ReportBufferedAllocatedSizeIfPossible();
+
+  ThreadState* const thread_state_;
+  // Returns whether the Blink heap has been fully processed.
+  bool is_tracing_done_ = false;
+
+  // Buffered allocated size. Only positive values are forwarded to V8.
+  int64_t buffered_allocated_size_ = 0;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_CONTROLLER_H_
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.cc b/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.cc
similarity index 100%
rename from third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.cc
rename to third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.cc
diff --git a/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h b/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h
new file mode 100644
index 0000000..8d589b4
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h
@@ -0,0 +1,89 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_MARKING_VISITOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_MARKING_VISITOR_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
+
+namespace v8 {
+class EmbedderHeapTracer;
+}
+
+namespace blink {
+
+struct WrapperTypeInfo;
+
+// Marking visitor for unified heap garbage collections. Extends the regular
+// Oilpan marking visitor by also providing write barriers and visitation
+// methods that allow for announcing reachable objects to V8. Visitor can be
+// used from any thread.
+class PLATFORM_EXPORT UnifiedHeapMarkingVisitorBase {
+ public:
+  virtual ~UnifiedHeapMarkingVisitorBase() = default;
+
+ protected:
+  UnifiedHeapMarkingVisitorBase(ThreadState*, v8::Isolate*, int);
+
+  // Visitation methods that announce reachable wrappers to V8.
+  void VisitImpl(const TraceWrapperV8Reference<v8::Value>&);
+
+  v8::Isolate* const isolate_;
+  v8::EmbedderHeapTracer* const controller_;
+  V8ReferencesWorklist::View v8_references_worklist_;
+
+ private:
+  int task_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(UnifiedHeapMarkingVisitorBase);
+};
+
+// Same as the base visitor with the difference that it is bound to main thread.
+// Also implements various sorts of write barriers that should only be called
+// from the main thread.
+class PLATFORM_EXPORT UnifiedHeapMarkingVisitor
+    : public MarkingVisitor,
+      public UnifiedHeapMarkingVisitorBase {
+ public:
+  // Write barriers for annotating a write during incremental marking.
+  static void WriteBarrier(const TraceWrapperV8Reference<v8::Value>&);
+  static void WriteBarrier(v8::Isolate*, const WrapperTypeInfo*, const void*);
+
+  UnifiedHeapMarkingVisitor(ThreadState*, MarkingMode, v8::Isolate*);
+  ~UnifiedHeapMarkingVisitor() override = default;
+
+ protected:
+  using Visitor::Visit;
+  void Visit(const TraceWrapperV8Reference<v8::Value>&) final;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UnifiedHeapMarkingVisitor);
+};
+
+// Same as the base visitor with the difference that it is bound to a
+// concurrent thread.
+class PLATFORM_EXPORT ConcurrentUnifiedHeapMarkingVisitor
+    : public ConcurrentMarkingVisitor,
+      public UnifiedHeapMarkingVisitorBase {
+ public:
+  ConcurrentUnifiedHeapMarkingVisitor(ThreadState*,
+                                      MarkingMode,
+                                      v8::Isolate*,
+                                      int task_id);
+  ~ConcurrentUnifiedHeapMarkingVisitor() override = default;
+
+  void FlushWorklists() override;
+
+ protected:
+  using Visitor::Visit;
+  void Visit(const TraceWrapperV8Reference<v8::Value>&) final;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ConcurrentUnifiedHeapMarkingVisitor);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_MARKING_VISITOR_H_
diff --git a/third_party/blink/renderer/platform/heap/unsanitized_atomic.cc b/third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.cc
similarity index 97%
rename from third_party/blink/renderer/platform/heap/unsanitized_atomic.cc
rename to third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.cc
index c175fdb0..5bd25b9 100644
--- a/third_party/blink/renderer/platform/heap/unsanitized_atomic.cc
+++ b/third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/unsanitized_atomic.h"
+#include "third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.h"
 
 #include "cstdint"
 
diff --git a/third_party/blink/renderer/platform/heap/unsanitized_atomic.h b/third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.h
similarity index 89%
rename from third_party/blink/renderer/platform/heap/unsanitized_atomic.h
rename to third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.h
index 9242e92..7c6828d 100644
--- a/third_party/blink/renderer/platform/heap/unsanitized_atomic.h
+++ b/third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNSANITIZED_ATOMIC_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNSANITIZED_ATOMIC_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNSANITIZED_ATOMIC_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNSANITIZED_ATOMIC_H_
 
 #include <atomic>
 
@@ -62,4 +62,4 @@
 }  // namespace internal
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNSANITIZED_ATOMIC_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNSANITIZED_ATOMIC_H_
diff --git a/third_party/blink/renderer/platform/heap/impl/visitor.h b/third_party/blink/renderer/platform/heap/impl/visitor.h
new file mode 100644
index 0000000..434bf88
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/impl/visitor.h
@@ -0,0 +1,312 @@
+/*
+ * 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.
+ */
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_VISITOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_VISITOR_H_
+
+#include <memory>
+#include "third_party/blink/renderer/platform/heap/blink_gc.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+
+namespace base {
+class Location;
+}
+
+namespace v8 {
+class Value;
+}
+
+namespace blink {
+
+class LivenessBroker;
+template <typename T>
+struct TraceTrait;
+class ThreadState;
+class Visitor;
+template <typename T>
+class TraceWrapperV8Reference;
+
+// The TraceMethodDelegate is used to convert a trace method for type T to a
+// TraceCallback.  This allows us to pass a type's trace method as a parameter
+// to the PersistentNode constructor. The PersistentNode constructor needs the
+// specific trace method due an issue with the Windows compiler which
+// instantiates even unused variables. This causes problems
+// in header files where we have only forward declarations of classes.
+//
+// This interface is safe to use on concurrent threads. All accesses (reads)
+// from member are done atomically.
+template <typename T, void (T::*method)(Visitor*) const>
+struct TraceMethodDelegate {
+  STATIC_ONLY(TraceMethodDelegate);
+  static void Trampoline(Visitor* visitor, const void* self) {
+    (reinterpret_cast<const T*>(self)->*method)(visitor);
+  }
+};
+
+template <typename T, void (T::*method)(const LivenessBroker&)>
+struct WeakCallbackMethodDelegate {
+  STATIC_ONLY(WeakCallbackMethodDelegate);
+  static void Trampoline(const LivenessBroker& info, const void* self) {
+    (reinterpret_cast<T*>(const_cast<void*>(self))->*method)(info);
+  }
+};
+
+// Visitor is used to traverse Oilpan's object graph.
+class PLATFORM_EXPORT Visitor {
+  USING_FAST_MALLOC(Visitor);
+
+ public:
+  explicit Visitor(ThreadState* state) : state_(state) {}
+  virtual ~Visitor() = default;
+
+  inline ThreadState* State() const { return state_; }
+  inline ThreadHeap& Heap() const { return state_->Heap(); }
+
+  // Static visitor implementation forwarding to dynamic interface.
+
+  template <typename T>
+  void TraceRoot(const T* t, const base::Location& location) {
+    static_assert(sizeof(T), "T must be fully defined");
+    static_assert(IsGarbageCollectedType<T>::value,
+                  "T needs to be a garbage collected object");
+    if (!t)
+      return;
+    VisitRoot(t, TraceDescriptorFor(t), location);
+  }
+
+  template <typename T>
+  void Trace(const Member<T>& t) {
+    const T* value = t.GetSafe();
+
+    DCHECK(!Member<T>::IsMemberHashTableDeletedValue(value));
+
+    Trace(value);
+  }
+
+  // TraceStrongly strongifies WeakMembers.
+  template <typename T>
+  ALWAYS_INLINE void TraceStrongly(const WeakMember<T>& t) {
+    const T* value = t.GetSafe();
+
+    DCHECK(!WeakMember<T>::IsMemberHashTableDeletedValue(value));
+
+    Trace<T>(value);
+  }
+  // Fallback methods used only when we need to trace raw pointers of T. This is
+  // the case when a member is a union where we do not support members.
+  template <typename T>
+  void Trace(T* t) {
+    Trace(const_cast<const T*>(t));
+  }
+  template <typename T>
+  void Trace(const T* t) {
+    static_assert(sizeof(T), "T must be fully defined");
+    static_assert(IsGarbageCollectedType<T>::value,
+                  "T needs to be a garbage collected object");
+    if (!t)
+      return;
+    Visit(t, TraceDescriptorFor(t));
+  }
+
+  // WeakMember version of the templated trace method. It doesn't keep
+  // the traced thing alive, but will write null to the WeakMember later
+  // if the pointed-to object is dead. It's lying for this to be const,
+  // but the overloading resolver prioritizes constness too high when
+  // picking the correct overload, so all these trace methods have to have
+  // the same constness on their argument to allow the type to decide.
+  template <typename T>
+  void Trace(const WeakMember<T>& weak_member) {
+    static_assert(sizeof(T), "T must be fully defined");
+    static_assert(IsGarbageCollectedType<T>::value,
+                  "T needs to be a garbage collected object");
+
+    const T* value = weak_member.GetSafe();
+
+    if (!value)
+      return;
+
+    DCHECK(!WeakMember<T>::IsMemberHashTableDeletedValue(value));
+    VisitWeak(value, &weak_member, TraceDescriptorFor(value),
+              &HandleWeakCell<T>);
+  }
+
+  // Fallback trace method for part objects to allow individual trace methods
+  // to trace through a part object with visitor->trace(m_partObject). This
+  // takes a const argument, because otherwise it will match too eagerly: a
+  // non-const argument would match a non-const Vector<T>& argument better
+  // than the specialization that takes const Vector<T>&. For a similar reason,
+  // the other specializations take a const argument even though they are
+  // usually used with non-const arguments, otherwise this function would match
+  // too well.
+  template <typename T>
+  void Trace(const T& t) {
+    static_assert(sizeof(T), "T must be fully defined");
+    if (std::is_polymorphic<T>::value) {
+      const intptr_t vtable = *reinterpret_cast<const intptr_t*>(&t);
+      if (!vtable)
+        return;
+    }
+    TraceTrait<T>::Trace(this, &t);
+  }
+
+  template <typename T, typename U>
+  void TraceEphemeron(const WeakMember<T>& key, const U* value) {
+    const T* t = key.GetSafe();
+    if (!t)
+      return;
+    VisitEphemeron(TraceDescriptorFor(t).base_object_payload,
+                   TraceDescriptorFor(value));
+  }
+
+  template <typename T>
+  void TraceWeakContainer(const T* object,
+                          const T* const* slot,
+                          TraceDescriptor strong_desc,
+                          TraceDescriptor weak_dec,
+                          WeakCallback weak_callback,
+                          const void* weak_callback_parameter) {
+    static_assert(sizeof(T), "T must be fully defined");
+    static_assert(IsGarbageCollectedType<T>::value,
+                  "T needs to be a garbage collected object");
+    VisitWeakContainer(reinterpret_cast<const void*>(object),
+                       reinterpret_cast<const void* const*>(slot), strong_desc,
+                       weak_dec, weak_callback, weak_callback_parameter);
+  }
+
+  template <typename T>
+  void TraceMovablePointer(const T* const* slot) {
+    RegisterMovableSlot(reinterpret_cast<const void* const*>(slot));
+  }
+
+  // Cross-component tracing interface.
+  template <typename V8Type>
+  void Trace(const TraceWrapperV8Reference<V8Type>& v8reference) {
+    Visit(v8reference.template Cast<v8::Value>());
+  }
+
+  // Dynamic visitor interface.
+
+  // Adds a |callback| that is invoked with |parameter| after liveness has been
+  // computed on the whole object graph. The |callback| may use the provided
+  // |LivenessBroker| to determine whether an object is considered alive or
+  // dead.
+  //
+  // - Upon returning from the callback all references to dead objects must have
+  //   been cleared.
+  // - Any operation that extends the object graph, including allocation
+  //   or reviving objects, is prohibited.
+  // - Clearing out pointers is allowed.
+  // - Removing elements from heap collections is allowed as these collections
+  //   are aware of custom weakness and won't resize their backings.
+  virtual void RegisterWeakCallback(WeakCallback callback,
+                                    const void* parameter) {}
+
+  // Registers an instance method using |RegisterWeakCallback|. See description
+  // below.
+  template <typename T, void (T::*method)(const LivenessBroker&)>
+  void RegisterWeakCallbackMethod(const T* obj) {
+    RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>::Trampoline,
+                         obj);
+  }
+
+  // Returns whether the visitor is used in a concurrent setting.
+  virtual bool IsConcurrent() const { return false; }
+
+  // Defers invoking |desc| to the main thread when running concurrently.
+  // Returns true if |desc| has been queued for later processing and false if
+  // running in a non-concurrent setting.
+  //
+  // This can be used to defer processing data structures to the main thread
+  // when support for concurrent processing is missing.
+  virtual bool DeferredTraceIfConcurrent(TraceDescriptor, size_t) {
+    return false;
+  }
+
+ protected:
+  // Visits an object through a strong reference.
+  virtual void Visit(const void*, TraceDescriptor) {}
+
+  // Visits an object through a weak reference.
+  virtual void VisitWeak(const void*,
+                         const void*,
+                         TraceDescriptor,
+                         WeakCallback) {}
+
+  // Visits cross-component references to V8.
+  virtual void Visit(const TraceWrapperV8Reference<v8::Value>&) {}
+
+  virtual void VisitRoot(const void* t,
+                         TraceDescriptor desc,
+                         const base::Location&) {
+    Visit(t, desc);
+  }
+
+  // Visits ephemeron pairs which are a combination of weak and strong keys and
+  // values.
+  virtual void VisitEphemeron(const void*, TraceDescriptor) {}
+
+  // Visits a container |object| holding ephemeron pairs held from |slot|.  The
+  // descriptor |strong_desc| can be used to enforce strong treatment of
+  // |object|. The |weak_desc| descriptor is invoked repeatedly until no
+  // more new objects are found. It is expected that |weak_desc| processing
+  // ultimately yields in a call to VisitEphemeron. After marking all reachable
+  // objects, |weak_callback| is invoked with |weak_callback_parameter|. It is
+  // expected that this callback is used to reset non-live entries in the
+  // ephemeron container.
+  virtual void VisitWeakContainer(const void* object,
+                                  const void* const* slot,
+                                  TraceDescriptor strong_desc,
+                                  TraceDescriptor weak_desc,
+                                  WeakCallback weak_callback,
+                                  const void* weak_callback_parameter) {}
+
+  virtual void RegisterMovableSlot(const void* const* slot) {}
+
+  template <typename T>
+  static TraceDescriptor TraceDescriptorFor(const T* traceable) {
+    return TraceTrait<T>::GetTraceDescriptor(traceable);
+  }
+
+ private:
+  template <typename T>
+  static void HandleWeakCell(const LivenessBroker&, const void*);
+
+  ThreadState* const state_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_VISITOR_H_
diff --git a/third_party/blink/renderer/platform/heap/worklist.h b/third_party/blink/renderer/platform/heap/impl/worklist.h
similarity index 98%
rename from third_party/blink/renderer/platform/heap/worklist.h
rename to third_party/blink/renderer/platform/heap/impl/worklist.h
index 6bce8f5..a26c6189 100644
--- a/third_party/blink/renderer/platform/heap/worklist.h
+++ b/third_party/blink/renderer/platform/heap/impl/worklist.h
@@ -8,8 +8,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WORKLIST_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WORKLIST_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_WORKLIST_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_WORKLIST_H_
 
 #include <atomic>
 #include <cstddef>
@@ -466,4 +466,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WORKLIST_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_WORKLIST_H_
diff --git a/third_party/blink/renderer/platform/heap/member.h b/third_party/blink/renderer/platform/heap/member.h
index d2ffd56..4dbf5fd1 100644
--- a/third_party/blink/renderer/platform/heap/member.h
+++ b/third_party/blink/renderer/platform/heap/member.h
@@ -1,578 +1,16 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_
 
-#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
-#include "third_party/blink/renderer/platform/heap/marking_visitor.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
-#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
 
-namespace WTF {
-template <typename P, typename Traits, typename Allocator>
-class MemberConstructTraits;
-}  // namespace WTF
-
-namespace blink {
-
-template <typename T>
-class Persistent;
-
-enum class TracenessMemberConfiguration {
-  kTraced,
-  kUntraced,
-};
-
-template <typename T,
-          TracenessMemberConfiguration tracenessConfiguration =
-              TracenessMemberConfiguration::kTraced>
-class MemberPointerVerifier {
- public:
-  MemberPointerVerifier() = default;
-
-  void SaveCreationThreadState(T* pointer) {
-    if (tracenessConfiguration == TracenessMemberConfiguration::kUntraced) {
-      creation_thread_state_ = nullptr;
-    } else {
-      creation_thread_state_ = ThreadState::Current();
-      // Members should be created in an attached thread. But an empty
-      // value Member may be created on an unattached thread by a heap
-      // collection iterator.
-      DCHECK(creation_thread_state_ || !pointer);
-    }
-  }
-
-  void CheckPointer(T* pointer) {
-    if (!pointer)
-      return;
-
-    ThreadState* current = ThreadState::Current();
-    DCHECK(current);
-    if (tracenessConfiguration != TracenessMemberConfiguration::kUntraced) {
-      // creation_thread_state_ may be null when this is used in a heap
-      // collection which initialized the Member with memset and the
-      // constructor wasn't called.
-      if (creation_thread_state_) {
-        // Member should point to objects that belong in the same ThreadHeap.
-        DCHECK(creation_thread_state_->IsOnThreadHeap(pointer));
-        // Member should point to objects that belong in the same ThreadHeap.
-        DCHECK_EQ(&current->Heap(), &creation_thread_state_->Heap());
-      } else {
-        DCHECK(current->IsOnThreadHeap(pointer));
-      }
-    }
-
-    if (current->IsSweepingInProgress()) {
-      // During sweeping the object start bitmap is invalid. Check the header
-      // when the type is available and not pointing to a mixin.
-      if (IsFullyDefined<T>::value && !IsGarbageCollectedMixin<T>::value)
-        HeapObjectHeader::CheckFromPayload(pointer);
-    } else {
-      DCHECK(HeapObjectHeader::FromInnerAddress<
-             HeapObjectHeader::AccessMode::kAtomic>(pointer));
-    }
-  }
-
- private:
-  const ThreadState* creation_thread_state_;
-};
-
-template <typename T,
-          TracenessMemberConfiguration tracenessConfiguration =
-              TracenessMemberConfiguration::kTraced>
-class MemberBase {
-  DISALLOW_NEW();
-
- public:
-  MemberBase() : raw_(nullptr) { SaveCreationThreadState(); }
-
-  MemberBase(std::nullptr_t) : raw_(nullptr) { SaveCreationThreadState(); }
-
-  explicit MemberBase(T* raw) : raw_(raw) {
-    SaveCreationThreadState();
-    CheckPointer();
-    // No write barrier for initializing stores.
-  }
-
-  explicit MemberBase(T& raw) : raw_(&raw) {
-    SaveCreationThreadState();
-    CheckPointer();
-    // No write barrier for initializing stores.
-  }
-
-  MemberBase(WTF::HashTableDeletedValueType)
-      : raw_(reinterpret_cast<T*>(kHashTableDeletedRawValue)) {
-    SaveCreationThreadState();
-  }
-
-  MemberBase(const MemberBase& other) : raw_(other) {
-    SaveCreationThreadState();
-    CheckPointer();
-    // No write barrier for initializing stores.
-  }
-
-  template <typename U>
-  MemberBase(const Persistent<U>& other) : raw_(other) {
-    SaveCreationThreadState();
-    CheckPointer();
-    // No write barrier for initializing stores.
-  }
-
-  template <typename U>
-  MemberBase(const MemberBase<U>& other) : raw_(other) {
-    SaveCreationThreadState();
-    CheckPointer();
-    // No write barrier for initializing stores.
-  }
-
-  template <typename U>
-  MemberBase& operator=(const Persistent<U>& other) {
-    SetRaw(other);
-    CheckPointer();
-    WriteBarrier();
-    return *this;
-  }
-
-  MemberBase& operator=(const MemberBase& other) {
-    SetRaw(other);
-    CheckPointer();
-    WriteBarrier();
-    return *this;
-  }
-
-  template <typename U>
-  MemberBase& operator=(const MemberBase<U>& other) {
-    SetRaw(other);
-    CheckPointer();
-    WriteBarrier();
-    return *this;
-  }
-
-  template <typename U>
-  MemberBase& operator=(U* other) {
-    SetRaw(other);
-    CheckPointer();
-    WriteBarrier();
-    return *this;
-  }
-
-  MemberBase& operator=(WTF::HashTableDeletedValueType) {
-    SetRaw(reinterpret_cast<T*>(-1));
-    return *this;
-  }
-
-  MemberBase& operator=(std::nullptr_t) {
-    SetRaw(nullptr);
-    return *this;
-  }
-
-  void Swap(MemberBase<T>& other) {
-    T* tmp = GetRaw();
-    SetRaw(other.GetRaw());
-    other.SetRaw(tmp);
-    CheckPointer();
-    WriteBarrier();
-    other.WriteBarrier();
-  }
-
-  explicit operator bool() const { return GetRaw(); }
-  operator T*() const { return GetRaw(); }
-  T* operator->() const { return GetRaw(); }
-  T& operator*() const { return *GetRaw(); }
-
-  T* Get() const { return GetRaw(); }
-
-  void Clear() { SetRaw(nullptr); }
-
-  T* Release() {
-    T* result = GetRaw();
-    SetRaw(nullptr);
-    return result;
-  }
-
-  static bool IsMemberHashTableDeletedValue(const T* t) {
-    return t == reinterpret_cast<T*>(kHashTableDeletedRawValue);
-  }
-
-  bool IsHashTableDeletedValue() const {
-    return IsMemberHashTableDeletedValue(GetRaw());
-  }
-
- protected:
-  static constexpr intptr_t kHashTableDeletedRawValue = -1;
-
-  enum class AtomicCtorTag { Atomic };
-
-  // MemberBase ctors that use atomic write to set raw_.
-
-  MemberBase(AtomicCtorTag, T* raw) {
-    SetRaw(raw);
-    SaveCreationThreadState();
-    CheckPointer();
-    // No write barrier for initializing stores.
-  }
-
-  MemberBase(AtomicCtorTag, T& raw) {
-    SetRaw(&raw);
-    SaveCreationThreadState();
-    CheckPointer();
-    // No write barrier for initializing stores.
-  }
-
-  void WriteBarrier() const {
-    MarkingVisitor::WriteBarrier(const_cast<std::remove_const_t<T>**>(&raw_));
-  }
-
-  void CheckPointer() {
-#if DCHECK_IS_ON()
-    // Should not be called for deleted hash table values. A value can be
-    // propagated here if a MemberBase containing the deleted value is copied.
-    if (IsHashTableDeletedValue())
-      return;
-    pointer_verifier_.CheckPointer(GetRaw());
-#endif  // DCHECK_IS_ON()
-  }
-
-  void SaveCreationThreadState() {
-#if DCHECK_IS_ON()
-    pointer_verifier_.SaveCreationThreadState(GetRaw());
-#endif  // DCHECK_IS_ON()
-  }
-
-  ALWAYS_INLINE void SetRaw(T* raw) {
-    if (tracenessConfiguration == TracenessMemberConfiguration::kUntraced)
-      raw_ = raw;
-    else
-      WTF::AsAtomicPtr(&raw_)->store(raw, std::memory_order_relaxed);
-  }
-  ALWAYS_INLINE T* GetRaw() const { return raw_; }
-
- private:
-  // Thread safe version of Get() for marking visitors.
-  // This is used to prevent data races between concurrent marking visitors
-  // and writes on the main thread.
-  const T* GetSafe() const {
-    // TOOD(omerkatz): replace this cast with std::atomic_ref (C++20) once it
-    // becomes available
-    return WTF::AsAtomicPtr(&raw_)->load(std::memory_order_relaxed);
-  }
-
-  T* raw_;
-#if DCHECK_IS_ON()
-  MemberPointerVerifier<T, tracenessConfiguration> pointer_verifier_;
-#endif  // DCHECK_IS_ON()
-
-  friend class Visitor;
-};
-
-// Members are used in classes to contain strong pointers to other oilpan heap
-// allocated objects.
-// All Member fields of a class must be traced in the class' trace method.
-// During the mark phase of the GC all live objects are marked as live and
-// all Member fields of a live object will be traced marked as live as well.
-template <typename T>
-class Member : public MemberBase<T, TracenessMemberConfiguration::kTraced> {
-  DISALLOW_NEW();
-  typedef MemberBase<T, TracenessMemberConfiguration::kTraced> Parent;
-
- public:
-  Member() : Parent() {}
-  Member(std::nullptr_t) : Parent(nullptr) {}
-  Member(T* raw) : Parent(raw) {}
-  Member(T& raw) : Parent(raw) {}
-  Member(WTF::HashTableDeletedValueType x) : Parent(x) {}
-
-  Member(const Member& other) : Parent(other) {}
-
-  template <typename U>
-  Member(const Member<U>& other) : Parent(other) {
-  }
-
-  template <typename U>
-  Member(const Persistent<U>& other) : Parent(other) {}
-
-  template <typename U>
-  Member& operator=(const Persistent<U>& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  Member& operator=(const Member& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  Member& operator=(const Member<U>& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  Member& operator=(const WeakMember<U>& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  Member& operator=(U* other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  Member& operator=(WTF::HashTableDeletedValueType x) {
-    Parent::operator=(x);
-    return *this;
-  }
-
-  Member& operator=(std::nullptr_t) {
-    Parent::operator=(nullptr);
-    return *this;
-  }
-
- private:
-  using typename Parent::AtomicCtorTag;
-  Member(AtomicCtorTag atomic, T* raw) : Parent(atomic, raw) {}
-  Member(AtomicCtorTag atomic, T& raw) : Parent(atomic, raw) {}
-
-  template <typename P, typename Traits, typename Allocator>
-  friend class WTF::MemberConstructTraits;
-};
-
-// WeakMember is similar to Member in that it is used to point to other oilpan
-// heap allocated objects.
-// However instead of creating a strong pointer to the object, the WeakMember
-// creates a weak pointer, which does not keep the pointee alive. Hence if all
-// pointers to to a heap allocated object are weak the object will be garbage
-// collected. At the time of GC the weak pointers will automatically be set to
-// null.
-template <typename T>
-class WeakMember : public MemberBase<T, TracenessMemberConfiguration::kTraced> {
-  typedef MemberBase<T, TracenessMemberConfiguration::kTraced> Parent;
-
- public:
-  WeakMember() : Parent() {}
-
-  WeakMember(std::nullptr_t) : Parent(nullptr) {}
-
-  WeakMember(T* raw) : Parent(raw) {}
-
-  WeakMember(WTF::HashTableDeletedValueType x) : Parent(x) {}
-
-  template <typename U>
-  WeakMember(const Persistent<U>& other) : Parent(other) {}
-
-  template <typename U>
-  WeakMember(const Member<U>& other) : Parent(other) {}
-
-  template <typename U>
-  WeakMember& operator=(const Persistent<U>& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  WeakMember& operator=(const Member<U>& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  WeakMember& operator=(U* other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  WeakMember& operator=(std::nullptr_t) {
-    this->SetRaw(nullptr);
-    return *this;
-  }
-
- private:
-  using typename Parent::AtomicCtorTag;
-  WeakMember(AtomicCtorTag atomic, T* raw) : Parent(atomic, raw) {}
-  WeakMember(AtomicCtorTag atomic, T& raw) : Parent(atomic, raw) {}
-
-  template <typename P, typename Traits, typename Allocator>
-  friend class WTF::MemberConstructTraits;
-};
-
-// UntracedMember is a pointer to an on-heap object that is not traced for some
-// reason. Please don't use this unless you understand what you're doing.
-// Basically, all pointers to on-heap objects must be stored in either of
-// Persistent, Member or WeakMember. It is not allowed to leave raw pointers to
-// on-heap objects. However, there can be scenarios where you have to use raw
-// pointers for some reason, and in that case you can use UntracedMember. Of
-// course, it must be guaranteed that the pointing on-heap object is kept alive
-// while the raw pointer is pointing to the object.
-template <typename T>
-class UntracedMember final
-    : public MemberBase<T, TracenessMemberConfiguration::kUntraced> {
-  typedef MemberBase<T, TracenessMemberConfiguration::kUntraced> Parent;
-
- public:
-  UntracedMember() : Parent() {}
-
-  UntracedMember(std::nullptr_t) : Parent(nullptr) {}
-
-  UntracedMember(T* raw) : Parent(raw) {}
-
-  template <typename U>
-  UntracedMember(const Persistent<U>& other) : Parent(other) {}
-
-  template <typename U>
-  UntracedMember(const Member<U>& other) : Parent(other) {}
-
-  UntracedMember(WTF::HashTableDeletedValueType x) : Parent(x) {}
-
-  UntracedMember& operator=(const UntracedMember& other) {
-    this->SetRaw(other);
-    this->CheckPointer();
-    return *this;
-  }
-
-  template <typename U>
-  UntracedMember& operator=(const Persistent<U>& other) {
-    this->SetRaw(other);
-    this->CheckPointer();
-    return *this;
-  }
-
-  template <typename U>
-  UntracedMember& operator=(const Member<U>& other) {
-    this->SetRaw(other);
-    this->CheckPointer();
-    return *this;
-  }
-
-  template <typename U>
-  UntracedMember& operator=(U* other) {
-    this->SetRaw(other);
-    this->CheckPointer();
-    return *this;
-  }
-
-  UntracedMember& operator=(std::nullptr_t) {
-    this->SetRaw(nullptr);
-    return *this;
-  }
-};
-
-template <typename T>
-struct MemberTraceTraits {
-  STATIC_ONLY(MemberTraceTraits);
-
- public:
-  static TraceDescriptor GetTraceDescriptor(const T* ref) {
-    return {ref, TraceTrait<T>::Trace};
-  }
-
-  static void Trace(Visitor* visitor, const void* ref) {
-    visitor->Trace(*static_cast<const T*>(ref));
-  }
-};
-
-template <typename T>
-struct TraceTrait<Member<T>> : public MemberTraceTraits<Member<T>> {};
-
-template <typename T>
-struct TraceTrait<WeakMember<T>> : public MemberTraceTraits<WeakMember<T>> {};
-
-}  // namespace blink
-
-namespace WTF {
-
-// PtrHash is the default hash for hash tables with Member<>-derived elements.
-template <typename T>
-struct MemberHash : PtrHash<T> {
-  STATIC_ONLY(MemberHash);
-  template <typename U>
-  static unsigned GetHash(const U& key) {
-    return PtrHash<T>::GetHash(key);
-  }
-  template <typename U, typename V>
-  static bool Equal(const U& a, const V& b) {
-    return a == b;
-  }
-};
-
-template <typename T>
-struct DefaultHash<blink::Member<T>> {
-  STATIC_ONLY(DefaultHash);
-  using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct DefaultHash<blink::WeakMember<T>> {
-  STATIC_ONLY(DefaultHash);
-  using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct DefaultHash<blink::UntracedMember<T>> {
-  STATIC_ONLY(DefaultHash);
-  using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct IsTraceable<blink::Member<T>> {
-  STATIC_ONLY(IsTraceable);
-  static const bool value = true;
-};
-
-template <typename T>
-struct IsWeak<blink::WeakMember<T>> : std::true_type {};
-
-template <typename T>
-struct IsTraceable<blink::WeakMember<T>> {
-  STATIC_ONLY(IsTraceable);
-  static const bool value = true;
-};
-
-template <typename T, typename Traits, typename Allocator>
-class MemberConstructTraits {
-  STATIC_ONLY(MemberConstructTraits);
-
- public:
-  template <typename... Args>
-  static T* Construct(void* location, Args&&... args) {
-    return new (NotNull, location) T(std::forward<Args>(args)...);
-  }
-
-  static void NotifyNewElement(T* element) { element->WriteBarrier(); }
-
-  template <typename... Args>
-  static T* ConstructAndNotifyElement(void* location, Args&&... args) {
-    // ConstructAndNotifyElement updates an existing Member which might
-    // also be comncurrently traced while we update it. The regular ctors
-    // for Member don't use an atomic write which can lead to data races.
-    T* object = Construct(location, T::AtomicCtorTag::Atomic,
-                          std::forward<Args>(args)...);
-    NotifyNewElement(object);
-    return object;
-  }
-
-  static void NotifyNewElements(T* array, size_t len) {
-    while (len-- > 0) {
-      array->WriteBarrier();
-      array++;
-    }
-  }
-};
-
-template <typename T, typename Traits, typename Allocator>
-class ConstructTraits<blink::Member<T>, Traits, Allocator>
-    : public MemberConstructTraits<blink::Member<T>, Traits, Allocator> {};
-
-template <typename T, typename Traits, typename Allocator>
-class ConstructTraits<blink::WeakMember<T>, Traits, Allocator>
-    : public MemberConstructTraits<blink::WeakMember<T>, Traits, Allocator> {};
-
-}  // namespace WTF
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/member.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/member.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_
diff --git a/third_party/blink/renderer/platform/heap/persistent.h b/third_party/blink/renderer/platform/heap/persistent.h
index 32cadc00..77fd0d5c 100644
--- a/third_party/blink/renderer/platform/heap/persistent.h
+++ b/third_party/blink/renderer/platform/heap/persistent.h
@@ -1,971 +1,16 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_H_
 
-#include "base/bind.h"
-#include "base/location.h"
-#include "third_party/blink/renderer/platform/bindings/buildflags.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
-#include "third_party/blink/renderer/platform/heap/heap_compact.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "third_party/blink/renderer/platform/heap/persistent_node.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-namespace blink {
-
-template <typename T>
-class CrossThreadWeakPersistent;
-
-// Wrapping type to force callers to go through macros that expand or drop
-// base::Location. This is needed to avoid adding the strings when not needed.
-// The type can be dropped once http://crbug.com/760702 is resolved and
-// ENABLE_LOCATION_SOURCE is disabled for release builds.
-class PersistentLocation final {
- public:
-  PersistentLocation() = default;
-  explicit PersistentLocation(const base::Location& location)
-      : location_(location) {}
-  PersistentLocation(const PersistentLocation& other) = default;
-
-  const base::Location& get() const { return location_; }
-
- private:
-  base::Location location_;
-};
-
-#if !BUILDFLAG(FROM_HERE_USES_LOCATION_BUILTINS) && \
-    BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-#if !BUILDFLAG(ENABLE_LOCATION_SOURCE)
-#define PERSISTENT_FROM_HERE \
-  PersistentLocation(::base::Location::CreateFromHere(__FILE__))
-#else
-#define PERSISTENT_FROM_HERE \
-  PersistentLocation(        \
-      ::base::Location::CreateFromHere(__func__, __FILE__, __LINE__))
-#endif
-#else
-#define PERSISTENT_FROM_HERE PersistentLocation()
-#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-
-template <typename T,
-          WeaknessPersistentConfiguration weaknessConfiguration,
-          CrossThreadnessPersistentConfiguration crossThreadnessConfiguration>
-class PersistentBase {
-  USING_FAST_MALLOC(PersistentBase);
-
- public:
-  bool IsHashTableDeletedValue() const {
-    return raw_ == reinterpret_cast<T*>(-1);
-  }
-
-  T* Release() {
-    T* result = raw_;
-    AssignSafe(nullptr);
-    return result;
-  }
-
-  void Clear() {
-    // Note that this also frees up related data in the backend.
-    AssignSafe(nullptr);
-  }
-
-  T* Get() const {
-    CheckPointer();
-    return raw_;
-  }
-
-  // TODO(https://crbug.com/653394): Consider returning a thread-safe best
-  // guess of validity.
-  bool MaybeValid() const { return true; }
-
-  explicit operator bool() const { return Get(); }
-  T& operator*() const { return *Get(); }
-  operator T*() const { return Get(); }
-  T* operator->() const { return Get(); }
-
-  // Register the persistent node as a 'static reference',
-  // belonging to the current thread and a persistent that must
-  // be cleared when the ThreadState itself is cleared out and
-  // destructed.
-  //
-  // Static singletons arrange for this to happen, either to ensure
-  // clean LSan leak reports or to register a thread-local persistent
-  // needing to be cleared out before the thread is terminated.
-  PersistentBase* RegisterAsStaticReference() {
-    static_assert(weaknessConfiguration == kNonWeakPersistentConfiguration,
-                  "Can only register non-weak Persistent references as static "
-                  "references.");
-    if (PersistentNode* node = persistent_node_.Get()) {
-      ThreadState::Current()->RegisterStaticPersistentNode(node);
-      LEAK_SANITIZER_IGNORE_OBJECT(this);
-    }
-    return this;
-  }
-
-  NO_SANITIZE_ADDRESS
-  void ClearWithLockHeld() {
-    static_assert(
-        crossThreadnessConfiguration == kCrossThreadPersistentConfiguration,
-        "This Persistent does not require the cross-thread lock.");
-    PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired();
-    raw_ = nullptr;
-    persistent_node_.ClearWithLockHeld();
-  }
-
-  void UpdateLocation(const PersistentLocation& other) {
-#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-    location_ = other;
-#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-  }
-
- protected:
-  ~PersistentBase() {
-    UninitializeSafe();
-    // Not resetting raw_ as it is not observable.
-  }
-
-  PersistentBase() : raw_(nullptr) {
-    SaveCreationThreadHeap();
-    // No initialization needed for empty handle.
-  }
-  PersistentBase(const PersistentLocation& location) : PersistentBase() {
-    UpdateLocation(location);
-  }
-
-  PersistentBase(std::nullptr_t) : raw_(nullptr) {
-    SaveCreationThreadHeap();
-    // No initialization needed for empty handle.
-  }
-  PersistentBase(const PersistentLocation& location, std::nullptr_t)
-      : PersistentBase(nullptr) {
-    UpdateLocation(location);
-  }
-
-  PersistentBase(T* raw) : raw_(raw) {
-    SaveCreationThreadHeap();
-    InitializeSafe();
-    CheckPointer();
-  }
-  PersistentBase(const PersistentLocation& location, T* raw)
-      : PersistentBase(raw) {
-    UpdateLocation(location);
-  }
-
-  PersistentBase(T& raw) : raw_(&raw) {
-    SaveCreationThreadHeap();
-    InitializeSafe();
-    CheckPointer();
-  }
-  PersistentBase(const PersistentLocation& location, T& raw)
-      : PersistentBase(raw) {
-    UpdateLocation(location);
-  }
-
-  PersistentBase(const PersistentBase& other) : raw_(other) {
-    SaveCreationThreadHeap();
-    InitializeSafe();
-    CheckPointer();
-  }
-  PersistentBase(const PersistentLocation& location, PersistentBase& other)
-      : PersistentBase(other) {
-    UpdateLocation(location);
-  }
-
-  template <typename U>
-  PersistentBase(const PersistentBase<U,
-                                      weaknessConfiguration,
-                                      crossThreadnessConfiguration>& other)
-      : raw_(other) {
-    SaveCreationThreadHeap();
-    InitializeSafe();
-    CheckPointer();
-  }
-  template <typename U>
-  PersistentBase(const PersistentLocation& location,
-                 const PersistentBase<U,
-                                      weaknessConfiguration,
-                                      crossThreadnessConfiguration>& other)
-      : PersistentBase(other) {
-    UpdateLocation(location);
-  }
-
-  template <typename U>
-  PersistentBase(const Member<U>& other) : raw_(other) {
-    SaveCreationThreadHeap();
-    InitializeSafe();
-    CheckPointer();
-  }
-  template <typename U>
-  PersistentBase(const PersistentLocation& location, const Member<U>& other)
-      : PersistentBase(other) {
-    UpdateLocation(location);
-  }
-
-  PersistentBase(WTF::HashTableDeletedValueType)
-      : raw_(reinterpret_cast<T*>(-1)) {
-    SaveCreationThreadHeap();
-    // No initialization needed for empty handle.
-  }
-  PersistentBase(const PersistentLocation& location,
-                 WTF::HashTableDeletedValueType)
-      : PersistentBase(WTF::kHashTableDeletedValue) {
-    UpdateLocation(location);
-  }
-
-  template <typename U>
-  PersistentBase& operator=(U* other) {
-    AssignSafe(other);
-    return *this;
-  }
-
-  PersistentBase& operator=(std::nullptr_t) {
-    AssignSafe(nullptr);
-    return *this;
-  }
-
-  template <typename U>
-  PersistentBase& operator=(const Member<U>& other) {
-    AssignSafe(other);
-    return *this;
-  }
-
-  // Using unsafe operations and assuming that caller acquires the lock for
-  // kCrossThreadPersistentConfiguration configuration.
-  PersistentBase& operator=(const PersistentBase& other) {
-    PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired();
-    AssignUnsafe(other);
-    return *this;
-  }
-
-  // Using unsafe operations and assuming that caller acquires the lock for
-  // kCrossThreadPersistentConfiguration configuration.
-  template <typename U>
-  PersistentBase& operator=(
-      const PersistentBase<U,
-                           weaknessConfiguration,
-                           crossThreadnessConfiguration>& other) {
-    PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired();
-    AssignUnsafe(other);
-    return *this;
-  }
-
-  // Using unsafe operations and assuming that caller acquires the lock for
-  // kCrossThreadPersistentConfiguration configuration.
-  template <typename U>
-  PersistentBase& operator=(
-      PersistentBase<U, weaknessConfiguration, crossThreadnessConfiguration>&&
-          other) {
-    PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired();
-    if (persistent_node_.IsInitialized()) {
-      // Drop persistent node if present as it's always possible to reuse the
-      // node (if present) from |other|.
-      persistent_node_.Uninitialize();
-    }
-    // Explicit cast enabling downcasting.
-    raw_ = static_cast<T*>(other.raw_);
-    other.raw_ = nullptr;
-    // Efficiently move by just rewiring the node pointer.
-    persistent_node_ = std::move(other.persistent_node_);
-    DCHECK(!other.persistent_node_.Get());
-    if (persistent_node_.IsInitialized()) {
-      // If |raw_| points to a non-null or deleted value, just reuse the node.
-      TraceCallback trace_callback =
-          TraceMethodDelegate<PersistentBase,
-                              &PersistentBase::TracePersistent>::Trampoline;
-      persistent_node_.Get()->Reinitialize(this, trace_callback);
-    }
-    CheckPointer();
-    return *this;
-  }
-
-  NO_SANITIZE_ADDRESS
-  bool IsNotNull() const { return raw_; }
-
-  NO_SANITIZE_ADDRESS
-  void AssignSafe(T* ptr) {
-    typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock;
-    AssignUnsafe(ptr);
-  }
-
-  NO_SANITIZE_ADDRESS
-  void AssignUnsafe(T* ptr) {
-    raw_ = ptr;
-    CheckPointer();
-    if (raw_ && !IsHashTableDeletedValue()) {
-      if (!persistent_node_.IsInitialized())
-        InitializeUnsafe();
-      return;
-    }
-    UninitializeUnsafe();
-  }
-
-  void TracePersistent(Visitor* visitor) const {
-    static_assert(sizeof(T), "T must be fully defined");
-    static_assert(IsGarbageCollectedType<T>::value,
-                  "T needs to be a garbage collected object");
-    DCHECK(!IsHashTableDeletedValue());
-    if (weaknessConfiguration == kWeakPersistentConfiguration) {
-      visitor->RegisterWeakCallback(HandleWeakPersistent, this);
-    } else {
-#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-      visitor->TraceRoot(raw_, location_.get());
-#else
-      visitor->TraceRoot(raw_, base::Location());
-#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-    }
-  }
-
-  NO_SANITIZE_ADDRESS
-  void InitializeSafe() {
-    DCHECK(!persistent_node_.IsInitialized());
-    if (!raw_ || IsHashTableDeletedValue())
-      return;
-
-    TraceCallback trace_callback =
-        TraceMethodDelegate<PersistentBase,
-                            &PersistentBase::TracePersistent>::Trampoline;
-    typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock;
-    persistent_node_.Initialize(this, trace_callback);
-  }
-
-  NO_SANITIZE_ADDRESS
-  void InitializeUnsafe() {
-    DCHECK(!persistent_node_.IsInitialized());
-    if (!raw_ || IsHashTableDeletedValue())
-      return;
-
-    TraceCallback trace_callback =
-        TraceMethodDelegate<PersistentBase,
-                            &PersistentBase::TracePersistent>::Trampoline;
-    persistent_node_.Initialize(this, trace_callback);
-  }
-
-  void UninitializeSafe() {
-    if (persistent_node_.IsInitialized()) {
-      typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock;
-      persistent_node_.Uninitialize();
-    }
-  }
-
-  void UninitializeUnsafe() {
-    if (persistent_node_.IsInitialized())
-      persistent_node_.Uninitialize();
-  }
-
-  void CheckPointer() const {
-#if DCHECK_IS_ON()
-    if (!raw_ || IsHashTableDeletedValue())
-      return;
-
-    if (crossThreadnessConfiguration != kCrossThreadPersistentConfiguration) {
-      ThreadState* current = ThreadState::Current();
-      DCHECK(current);
-      // m_creationThreadState may be null when this is used in a heap
-      // collection which initialized the Persistent with memset and the
-      // constructor wasn't called.
-      if (creation_thread_state_) {
-        // Member should point to objects that belong in the same ThreadHeap.
-        DCHECK_EQ(&ThreadState::FromObject(raw_)->Heap(),
-                  &creation_thread_state_->Heap());
-        // Member should point to objects that belong in the same ThreadHeap.
-        DCHECK_EQ(&current->Heap(), &creation_thread_state_->Heap());
-      }
-    }
-#endif
-  }
-
-  void SaveCreationThreadHeap() {
-#if DCHECK_IS_ON()
-    if (crossThreadnessConfiguration == kCrossThreadPersistentConfiguration) {
-      creation_thread_state_ = nullptr;
-    } else {
-      creation_thread_state_ = ThreadState::Current();
-      DCHECK(creation_thread_state_);
-    }
-#endif
-  }
-
-  static void HandleWeakPersistent(const LivenessBroker& broker,
-                                   const void* persistent_pointer) {
-    using Base =
-        PersistentBase<typename std::remove_const<T>::type,
-                       weaknessConfiguration, crossThreadnessConfiguration>;
-    Base* persistent =
-        reinterpret_cast<Base*>(const_cast<void*>(persistent_pointer));
-    T* object = persistent->Get();
-    if (object && !broker.IsHeapObjectAlive(object))
-      ClearWeakPersistent(persistent);
-  }
-
-  static void ClearWeakPersistent(
-      PersistentBase<std::remove_const_t<T>,
-                     kWeakPersistentConfiguration,
-                     kCrossThreadPersistentConfiguration>* persistent) {
-    PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired();
-    persistent->ClearWithLockHeld();
-  }
-
-  static void ClearWeakPersistent(
-      PersistentBase<std::remove_const_t<T>,
-                     kWeakPersistentConfiguration,
-                     kSingleThreadPersistentConfiguration>* persistent) {
-    persistent->Clear();
-  }
-
-  template <typename BadPersistent>
-  static void ClearWeakPersistent(BadPersistent* non_weak_persistent) {
-    NOTREACHED();
-  }
-
-  // raw_ is accessed most, so put it at the first field.
-  T* raw_;
-
-  // The pointer to the underlying persistent node.
-  //
-  // Since accesses are atomics in the cross-thread case, a different type is
-  // needed to prevent the compiler producing an error when it encounters
-  // operations that are legal on raw pointers but not on atomics, or
-  // vice-versa.
-  std::conditional_t<
-      crossThreadnessConfiguration == kCrossThreadPersistentConfiguration,
-      CrossThreadPersistentNodePtr<weaknessConfiguration>,
-      PersistentNodePtr<ThreadingTrait<T>::kAffinity, weaknessConfiguration>>
-      persistent_node_;
-
-#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-  PersistentLocation location_;
-#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-
-#if DCHECK_IS_ON()
-  const ThreadState* creation_thread_state_;
-#endif
-
-  template <typename F,
-            WeaknessPersistentConfiguration,
-            CrossThreadnessPersistentConfiguration>
-  friend class PersistentBase;
-};
-
-// Persistent is a way to create a strong pointer from an off-heap object
-// to another on-heap object. As long as the Persistent handle is alive
-// the GC will keep the object pointed to alive. The Persistent handle is
-// always a GC root from the point of view of the GC.
-//
-// We have to construct and destruct Persistent in the same thread.
-template <typename T>
-class Persistent : public PersistentBase<T,
-                                         kNonWeakPersistentConfiguration,
-                                         kSingleThreadPersistentConfiguration> {
-  using Parent = PersistentBase<T,
-                                kNonWeakPersistentConfiguration,
-                                kSingleThreadPersistentConfiguration>;
-
- public:
-  Persistent() : Parent() {}
-  Persistent(const PersistentLocation& location) : Parent(location) {}
-  Persistent(std::nullptr_t) : Parent(nullptr) {}
-  Persistent(const PersistentLocation& location, std::nullptr_t)
-      : Parent(location, nullptr) {}
-  Persistent(T* raw) : Parent(raw) {}
-  Persistent(const PersistentLocation& location, T* raw)
-      : Parent(location, raw) {}
-  Persistent(T& raw) : Parent(raw) {}
-  Persistent(const PersistentLocation& location, T& raw)
-      : Parent(location, raw) {}
-  Persistent(const Persistent& other) : Parent(other) {}
-  Persistent(const PersistentLocation& location, const Persistent& other)
-      : Parent(location, other) {}
-  template <typename U>
-  Persistent(const Persistent<U>& other) : Parent(other) {}
-  template <typename U>
-  Persistent(const PersistentLocation& location, const Persistent<U>& other)
-      : Parent(location, other) {}
-  template <typename U>
-  Persistent(const Member<U>& other) : Parent(other) {}
-  template <typename U>
-  Persistent(const PersistentLocation& location, const Member<U>& other)
-      : Parent(location, other) {}
-  Persistent(WTF::HashTableDeletedValueType x) : Parent(x) {}
-  Persistent(const PersistentLocation& location,
-             WTF::HashTableDeletedValueType x)
-      : Parent(location, x) {}
-
-  template <typename U>
-  Persistent& operator=(U* other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  Persistent& operator=(std::nullptr_t) {
-    Parent::operator=(nullptr);
-    return *this;
-  }
-
-  Persistent& operator=(const Persistent& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  Persistent& operator=(const Persistent<U>& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  Persistent& operator=(const Member<U>& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-};
-
-// WeakPersistent is a way to create a weak pointer from an off-heap object
-// to an on-heap object. The m_raw is automatically cleared when the pointee
-// gets collected.
-//
-// We have to construct and destruct WeakPersistent in the same thread.
-//
-// Note that collections of WeakPersistents are not supported. Use a collection
-// of WeakMembers instead.
-//
-//   HashSet<WeakPersistent<T>> m_set; // wrong
-//   Persistent<HeapHashSet<WeakMember<T>>> m_set; // correct
-template <typename T>
-class WeakPersistent
-    : public PersistentBase<T,
-                            kWeakPersistentConfiguration,
-                            kSingleThreadPersistentConfiguration> {
-  using Parent = PersistentBase<T,
-                                kWeakPersistentConfiguration,
-                                kSingleThreadPersistentConfiguration>;
-
- public:
-  WeakPersistent() : Parent() {}
-  WeakPersistent(std::nullptr_t) : Parent(nullptr) {}
-  WeakPersistent(T* raw) : Parent(raw) {}
-  WeakPersistent(T& raw) : Parent(raw) {}
-  WeakPersistent(const WeakPersistent& other) : Parent(other) {}
-  template <typename U>
-  WeakPersistent(const WeakPersistent<U>& other) : Parent(other) {}
-  template <typename U>
-  WeakPersistent(const Member<U>& other) : Parent(other) {}
-
-  template <typename U>
-  WeakPersistent& operator=(U* other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  WeakPersistent& operator=(std::nullptr_t) {
-    Parent::operator=(nullptr);
-    return *this;
-  }
-
-  WeakPersistent& operator=(const WeakPersistent& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  WeakPersistent& operator=(const WeakPersistent<U>& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  WeakPersistent& operator=(const Member<U>& other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  NO_SANITIZE_ADDRESS
-  bool IsClearedUnsafe() const { return this->IsNotNull(); }
-};
-
-// CrossThreadPersistent allows for holding onto an object strongly on a
-// different thread.
-//
-// Thread-safe operations:
-// - Construction
-// - Destruction
-// - Copy and move construction and assignment
-// - Clearing
-// - Deref if treated as immutable reference or if externally synchronized (e.g.
-//   mutex, task). The current implementation of Get() uses a raw load (on
-//   purpose) which prohibits mutation while accessing the reference on a
-//   different thread.
-template <typename T>
-class CrossThreadPersistent
-    : public PersistentBase<T,
-                            kNonWeakPersistentConfiguration,
-                            kCrossThreadPersistentConfiguration> {
-  using Parent = PersistentBase<T,
-                                kNonWeakPersistentConfiguration,
-                                kCrossThreadPersistentConfiguration>;
-
- public:
-  CrossThreadPersistent() : Parent() {}
-  CrossThreadPersistent(const PersistentLocation& location)
-      : Parent(location) {}
-  CrossThreadPersistent(std::nullptr_t) : Parent(nullptr) {}
-  CrossThreadPersistent(const PersistentLocation& location, std::nullptr_t)
-      : Parent(location, nullptr) {}
-  explicit CrossThreadPersistent(T* raw) : Parent(raw) {}
-  CrossThreadPersistent(const PersistentLocation& location, T* raw)
-      : Parent(location, raw) {}
-  explicit CrossThreadPersistent(T& raw) : Parent(raw) {}
-  CrossThreadPersistent(const PersistentLocation& location, T& raw)
-      : Parent(location, raw) {}
-  CrossThreadPersistent(const CrossThreadPersistent& other) { *this = other; }
-  CrossThreadPersistent(const PersistentLocation& location,
-                        const CrossThreadPersistent& other) {
-    *this = other;
-  }
-  template <typename U>
-  CrossThreadPersistent(const CrossThreadPersistent<U>& other) {
-    *this = other;
-  }
-  template <typename U>
-  CrossThreadPersistent(const PersistentLocation& location,
-                        const CrossThreadPersistent<U>& other) {
-    *this = other;
-  }
-  template <typename U>
-  CrossThreadPersistent(const Member<U>& other) : Parent(other) {}
-  template <typename U>
-  CrossThreadPersistent(const PersistentLocation& location,
-                        const Member<U>& other)
-      : Parent(location, other) {}
-  CrossThreadPersistent(WTF::HashTableDeletedValueType x) : Parent(x) {}
-  CrossThreadPersistent(const PersistentLocation& location,
-                        WTF::HashTableDeletedValueType x)
-      : Parent(location, x) {}
-  template <typename U>
-  CrossThreadPersistent(const CrossThreadWeakPersistent<U>& other) {
-    *this = other;
-  }
-
-  // Instead of using release(), assign then clear() instead.
-  // Using release() with per thread heap enabled can cause the object to be
-  // destroyed before assigning it to a new handle.
-  T* Release() = delete;
-
-  template <typename U>
-  CrossThreadPersistent& operator=(U* other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  CrossThreadPersistent& operator=(std::nullptr_t) {
-    Parent::operator=(nullptr);
-    return *this;
-  }
-
-  CrossThreadPersistent& operator=(const CrossThreadPersistent& other) {
-    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  CrossThreadPersistent& operator=(const CrossThreadPersistent<U>& other) {
-    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  CrossThreadPersistent& operator=(const CrossThreadWeakPersistent<U>&);
-};
-
-// CrossThreadWeakPersistent combines behavior of CrossThreadPersistent and
-// WeakPersistent, i.e., it allows holding onto an object weakly on a different
-// thread.
-//
-// Thread-safe operations:
-// - Construction
-// - Destruction
-// - Copy and move construction and assignment
-// - Clearing
-//
-// Note that this does not include dereferencing and using the raw pointer as
-// there is no guarantee that the object will be alive at the time it is used.
-template <typename T>
-class CrossThreadWeakPersistent
-    : public PersistentBase<T,
-                            kWeakPersistentConfiguration,
-                            kCrossThreadPersistentConfiguration> {
-  using Parent = PersistentBase<T,
-                                kWeakPersistentConfiguration,
-                                kCrossThreadPersistentConfiguration>;
-
- public:
-  CrossThreadWeakPersistent() : Parent() {}
-  explicit CrossThreadWeakPersistent(T* raw) : Parent(raw) {}
-  explicit CrossThreadWeakPersistent(T& raw) : Parent(raw) {}
-  CrossThreadWeakPersistent(const CrossThreadWeakPersistent& other) {
-    *this = other;
-  }
-  template <typename U>
-  CrossThreadWeakPersistent(const CrossThreadWeakPersistent<U>& other) {
-    *this = other;
-  }
-  CrossThreadWeakPersistent(CrossThreadWeakPersistent&& other) {
-    *this = std::move(other);
-  }
-  template <typename U>
-  CrossThreadWeakPersistent(CrossThreadWeakPersistent<U>&& other) {
-    *this = std::move(other);
-  }
-
-  CrossThreadWeakPersistent& operator=(const CrossThreadWeakPersistent& other) {
-    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
-    Parent::operator=(other);
-    return *this;
-  }
-
-  template <typename U>
-  CrossThreadWeakPersistent& operator=(
-      const CrossThreadWeakPersistent<U>& other) {
-    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
-    Parent::operator=(other);
-    return *this;
-  }
-
-  CrossThreadWeakPersistent& operator=(CrossThreadWeakPersistent&& other) {
-    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
-    Parent::operator=(std::move(other));
-    return *this;
-  }
-
-  template <typename U>
-  CrossThreadWeakPersistent& operator=(CrossThreadWeakPersistent<U>&& other) {
-    MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
-    Parent::operator=(std::move(other));
-    return *this;
-  }
-
-  template <typename U>
-  CrossThreadWeakPersistent& operator=(U* other) {
-    Parent::operator=(other);
-    return *this;
-  }
-
-  // Create a CrossThreadPersistent that keeps the underlying object alive if
-  // there is still on set. Can be used to work with an object on a different
-  // thread than it was allocated. Note that CTP does not block threads from
-  // terminating, in which case the reference would still be invalid.
-  const CrossThreadPersistent<T> Lock() const {
-    return CrossThreadPersistent<T>(*this);
-  }
-
-  // Disallow directly using CrossThreadWeakPersistent. Users must go through
-  // CrossThreadPersistent to access the pointee. Note that this does not
-  // guarantee that the object is still alive at that point. Users must check
-  // the state of CTP manually before invoking any calls.
-  T* operator->() const = delete;
-  T& operator*() const = delete;
-  operator T*() const = delete;
-  T* Get() const = delete;
-
- private:
-  template <typename U>
-  friend class CrossThreadPersistent;
-};
-
-template <typename T>
-template <typename U>
-CrossThreadPersistent<T>& CrossThreadPersistent<T>::operator=(
-    const CrossThreadWeakPersistent<U>& other) {
-  MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex());
-  using ParentU = PersistentBase<U, kWeakPersistentConfiguration,
-                                 kCrossThreadPersistentConfiguration>;
-  this->AssignUnsafe(static_cast<const ParentU&>(other).Get());
-  return *this;
-}
-
-template <typename T>
-Persistent<T> WrapPersistentInternal(const PersistentLocation& location,
-                                     T* value) {
-  return Persistent<T>(location, value);
-}
-
-template <typename T>
-Persistent<T> WrapPersistentInternal(T* value) {
-  return Persistent<T>(value);
-}
-
-#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-#define WrapPersistent(value) \
-  WrapPersistentInternal(PERSISTENT_FROM_HERE, value)
-#else
-#define WrapPersistent(value) WrapPersistentInternal(value)
-#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-
-template <typename T,
-          typename = std::enable_if_t<WTF::IsGarbageCollectedType<T>::value>>
-Persistent<T> WrapPersistentIfNeeded(T* value) {
-  return Persistent<T>(value);
-}
-
-template <typename T>
-T& WrapPersistentIfNeeded(T& value) {
-  return value;
-}
-
-template <typename T>
-WeakPersistent<T> WrapWeakPersistent(T* value) {
-  return WeakPersistent<T>(value);
-}
-
-template <typename T>
-CrossThreadPersistent<T> WrapCrossThreadPersistentInternal(
-    const PersistentLocation& location,
-    T* value) {
-  return CrossThreadPersistent<T>(location, value);
-}
-
-template <typename T>
-CrossThreadPersistent<T> WrapCrossThreadPersistentInternal(T* value) {
-  return CrossThreadPersistent<T>(value);
-}
-
-#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-#define WrapCrossThreadPersistent(value) \
-  WrapCrossThreadPersistentInternal(PERSISTENT_FROM_HERE, value)
-#else
-#define WrapCrossThreadPersistent(value) \
-  WrapCrossThreadPersistentInternal(value)
-#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-
-template <typename T>
-CrossThreadWeakPersistent<T> WrapCrossThreadWeakPersistent(T* value) {
-  return CrossThreadWeakPersistent<T>(value);
-}
-
-// Comparison operators between (Weak)Members, Persistents, and UntracedMembers.
-template <typename T, typename U>
-inline bool operator==(const Member<T>& a, const Member<U>& b) {
-  return a.Get() == b.Get();
-}
-template <typename T, typename U>
-inline bool operator!=(const Member<T>& a, const Member<U>& b) {
-  return a.Get() != b.Get();
-}
-template <typename T, typename U>
-inline bool operator==(const Persistent<T>& a, const Persistent<U>& b) {
-  return a.Get() == b.Get();
-}
-template <typename T, typename U>
-inline bool operator!=(const Persistent<T>& a, const Persistent<U>& b) {
-  return a.Get() != b.Get();
-}
-
-template <typename T, typename U>
-inline bool operator==(const Member<T>& a, const Persistent<U>& b) {
-  return a.Get() == b.Get();
-}
-template <typename T, typename U>
-inline bool operator!=(const Member<T>& a, const Persistent<U>& b) {
-  return a.Get() != b.Get();
-}
-template <typename T, typename U>
-inline bool operator==(const Persistent<T>& a, const Member<U>& b) {
-  return a.Get() == b.Get();
-}
-template <typename T, typename U>
-inline bool operator!=(const Persistent<T>& a, const Member<U>& b) {
-  return a.Get() != b.Get();
-}
-
-}  // namespace blink
-
-namespace WTF {
-
-template <
-    typename T,
-    blink::WeaknessPersistentConfiguration weaknessConfiguration,
-    blink::CrossThreadnessPersistentConfiguration crossThreadnessConfiguration>
-struct VectorTraits<blink::PersistentBase<T,
-                                          weaknessConfiguration,
-                                          crossThreadnessConfiguration>>
-    : VectorTraitsBase<blink::PersistentBase<T,
-                                             weaknessConfiguration,
-                                             crossThreadnessConfiguration>> {
-  STATIC_ONLY(VectorTraits);
-  static const bool kNeedsDestruction = true;
-  static const bool kCanInitializeWithMemset = true;
-  static const bool kCanClearUnusedSlotsWithMemset = false;
-  static const bool kCanMoveWithMemcpy = true;
-};
-
-template <typename T>
-struct HashTraits<blink::Persistent<T>>
-    : HandleHashTraits<T, blink::Persistent<T>> {};
-
-template <typename T>
-struct HashTraits<blink::CrossThreadPersistent<T>>
-    : HandleHashTraits<T, blink::CrossThreadPersistent<T>> {};
-
-template <typename T>
-struct DefaultHash<blink::Persistent<T>> {
-  STATIC_ONLY(DefaultHash);
-  using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct DefaultHash<blink::WeakPersistent<T>> {
-  STATIC_ONLY(DefaultHash);
-  using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct DefaultHash<blink::CrossThreadPersistent<T>> {
-  STATIC_ONLY(DefaultHash);
-  using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct DefaultHash<blink::CrossThreadWeakPersistent<T>> {
-  STATIC_ONLY(DefaultHash);
-  using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct CrossThreadCopier<blink::CrossThreadPersistent<T>>
-    : public CrossThreadCopierPassThrough<blink::CrossThreadPersistent<T>> {
-  STATIC_ONLY(CrossThreadCopier);
-};
-
-template <typename T>
-struct CrossThreadCopier<blink::CrossThreadWeakPersistent<T>>
-    : public CrossThreadCopierPassThrough<blink::CrossThreadWeakPersistent<T>> {
-  STATIC_ONLY(CrossThreadCopier);
-};
-
-}  // namespace WTF
-
-namespace base {
-
-template <typename T>
-struct IsWeakReceiver<blink::WeakPersistent<T>> : std::true_type {};
-
-template <typename T>
-struct IsWeakReceiver<blink::CrossThreadWeakPersistent<T>> : std::true_type {};
-
-template <typename T>
-struct BindUnwrapTraits<blink::CrossThreadWeakPersistent<T>> {
-  static blink::CrossThreadPersistent<T> Unwrap(
-      const blink::CrossThreadWeakPersistent<T>& wrapped) {
-    return blink::CrossThreadPersistent<T>(wrapped);
-  }
-};
-}
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/persistent.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_H_
diff --git a/third_party/blink/renderer/platform/heap/process_heap.h b/third_party/blink/renderer/platform/heap/process_heap.h
index 8217afd2..5f8d21f 100644
--- a/third_party/blink/renderer/platform/heap/process_heap.h
+++ b/third_party/blink/renderer/platform/heap/process_heap.h
@@ -1,69 +1,16 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_
 
-#include <atomic>
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-namespace blink {
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/process_heap.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
-class CrossThreadPersistentRegion;
-
-class PLATFORM_EXPORT ProcessHeap {
-  STATIC_ONLY(ProcessHeap);
-
- public:
-  static void Init();
-
-  static CrossThreadPersistentRegion& GetCrossThreadPersistentRegion();
-  static CrossThreadPersistentRegion& GetCrossThreadWeakPersistentRegion();
-
-  // Access to the CrossThreadPersistentRegion from multiple threads has to be
-  // prevented as allocation, freeing, and iteration of nodes may otherwise
-  // cause data races.
-  //
-  // Examples include:
-  // - Iteration of strong cross-thread Persistents.
-  // - Iteration and processing of weak cross-thread Persistents. The lock
-  //   needs to span both operations as iteration of weak persistents only
-  //   registers memory regions that are then processed afterwards.
-  // - Marking phase in garbage collection: The whole phase requires locking
-  //   as CrossThreadWeakPersistents may be converted to CrossThreadPersistent
-  //   which must observe GC as an atomic operation.
-  static Mutex& CrossThreadPersistentMutex();
-
-  static void IncreaseTotalAllocatedObjectSize(size_t delta) {
-    total_allocated_object_size_.fetch_add(delta, std::memory_order_relaxed);
-  }
-  static void DecreaseTotalAllocatedObjectSize(size_t delta) {
-    total_allocated_object_size_.fetch_sub(delta, std::memory_order_relaxed);
-  }
-  static size_t TotalAllocatedObjectSize() {
-    return total_allocated_object_size_.load(std::memory_order_relaxed);
-  }
-  static void IncreaseTotalAllocatedSpace(size_t delta) {
-    total_allocated_space_.fetch_add(delta, std::memory_order_relaxed);
-  }
-  static void DecreaseTotalAllocatedSpace(size_t delta) {
-    total_allocated_space_.fetch_sub(delta, std::memory_order_relaxed);
-  }
-  static size_t TotalAllocatedSpace() {
-    return total_allocated_space_.load(std::memory_order_relaxed);
-  }
-  static void ResetHeapCounters();
-
- private:
-  static std::atomic_size_t total_allocated_space_;
-  static std::atomic_size_t total_allocated_object_size_;
-
-  friend class ThreadState;
-};
-
-}  // namespace blink
-
-#endif
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_
diff --git a/third_party/blink/renderer/platform/heap/test/card_table_test.cc b/third_party/blink/renderer/platform/heap/test/card_table_test.cc
index c36e612..eb61f36 100644
--- a/third_party/blink/renderer/platform/heap/test/card_table_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/card_table_test.cc
@@ -5,8 +5,8 @@
 #include <vector>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/heap/test/gc_info_test.cc b/third_party/blink/renderer/platform/heap/test/gc_info_test.cc
index 0a4e667c..3e007c35 100644
--- a/third_party/blink/renderer/platform/heap/test/gc_info_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/gc_info_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/gc_info.h"
+#include "third_party/blink/renderer/platform/heap/impl/gc_info.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/blink/renderer/platform/heap/test/heap_compact_test.cc b/third_party/blink/renderer/platform/heap/test/heap_compact_test.cc
index 7d9c1bc..98f3f40 100644
--- a/third_party/blink/renderer/platform/heap/test/heap_compact_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/heap_compact_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/heap_compact.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
diff --git a/third_party/blink/renderer/platform/heap/test/heap_test.cc b/third_party/blink/renderer/platform/heap/test/heap_test.cc
index 4b87332a..a445c8d 100644
--- a/third_party/blink/renderer/platform/heap/test/heap_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/heap_test.cc
@@ -50,7 +50,7 @@
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
-#include "third_party/blink/renderer/platform/heap/marking_visitor.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
 #include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
diff --git a/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc b/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc
index 74d7f717..df88d7b0 100644
--- a/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc
@@ -13,12 +13,12 @@
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
-#include "third_party/blink/renderer/platform/heap/heap_compact.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h"
+#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/heap/trace_traits.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
diff --git a/third_party/blink/renderer/platform/heap/test/marking_scheduling_oracle_test.cc b/third_party/blink/renderer/platform/heap/test/marking_scheduling_oracle_test.cc
index 65bfc55c..ad2839d 100644
--- a/third_party/blink/renderer/platform/heap/test/marking_scheduling_oracle_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/marking_scheduling_oracle_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h"
 
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/third_party/blink/renderer/platform/heap/test/marking_verifier_test.cc b/third_party/blink/renderer/platform/heap/test/marking_verifier_test.cc
index 8e8a9f9..38eebbe 100644
--- a/third_party/blink/renderer/platform/heap/test/marking_verifier_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/marking_verifier_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/marking_verifier.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_verifier.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
diff --git a/third_party/blink/renderer/platform/heap/test/name_trait_test.cc b/third_party/blink/renderer/platform/heap/test/name_trait_test.cc
index d83ab701..39e1eff 100644
--- a/third_party/blink/renderer/platform/heap/test/name_trait_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/name_trait_test.cc
@@ -7,7 +7,7 @@
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
-#include "third_party/blink/renderer/platform/heap/name_traits.h"
+#include "third_party/blink/renderer/platform/heap/impl/name_traits.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/heap/test/object_start_bitmap_test.cc b/third_party/blink/renderer/platform/heap/test/object_start_bitmap_test.cc
index af1db162..cdb20c5c 100644
--- a/third_party/blink/renderer/platform/heap/test/object_start_bitmap_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/object_start_bitmap_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
diff --git a/third_party/blink/renderer/platform/heap/test/worklist_test.cc b/third_party/blink/renderer/platform/heap/test/worklist_test.cc
index 1030cba..206e6f4 100644
--- a/third_party/blink/renderer/platform/heap/test/worklist_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/worklist_test.cc
@@ -8,7 +8,7 @@
 // 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/heap/worklist.h"
+#include "third_party/blink/renderer/platform/heap/impl/worklist.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/blink/renderer/platform/heap/thread_state.h b/third_party/blink/renderer/platform/heap/thread_state.h
index 41499ec..050bac6b 100644
--- a/third_party/blink/renderer/platform/heap/thread_state.h
+++ b/third_party/blink/renderer/platform/heap/thread_state.h
@@ -1,717 +1,16 @@
-/*
- * 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 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
 
-#include <atomic>
-#include <memory>
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "base/task/post_job.h"
-#include "third_party/blink/renderer/platform/heap/atomic_entry_flag.h"
-#include "third_party/blink/renderer/platform/heap/blink_gc.h"
-#include "third_party/blink/renderer/platform/heap/threading_traits.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/sanitizers.h"
-#include "third_party/blink/renderer/platform/wtf/thread_specific.h"
-#include "third_party/blink/renderer/platform/wtf/threading.h"
-#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace v8 {
-class EmbedderGraph;
-class Isolate;
-}  // namespace v8
-
-namespace blink {
-
-namespace incremental_marking_test {
-class IncrementalMarkingScope;
-}  // namespace incremental_marking_test
-
-class MarkingVisitor;
-class MarkingSchedulingOracle;
-class PersistentNode;
-class PersistentRegion;
-class ThreadHeap;
-class ThreadState;
-template <ThreadAffinity affinity>
-class ThreadStateFor;
-class UnifiedHeapController;
-class Visitor;
-
-// Declare that a class has a pre-finalizer which gets invoked before objects
-// get swept. It is thus safe to touch on-heap objects that may be collected in
-// the same GC cycle. This is useful when it's not possible to avoid touching
-// on-heap objects in a destructor which is forbidden.
-//
-// Note that:
-// (a) Pre-finalizers *must* not resurrect dead objects.
-// (b) Run on the same thread they are registered.
-// (c) Decrease GC performance which means that they should only be used if
-//     absolute necessary.
-//
-// Usage:
-//   class Foo : GarbageCollected<Foo> {
-//     USING_PRE_FINALIZER(Foo, Dispose);
-//    private:
-//     void Dispose() {
-//       bar_->...; // It is safe to touch other on-heap objects.
-//     }
-//     Member<Bar> bar_;
-//   };
-#define USING_PRE_FINALIZER(Class, PreFinalizer)                             \
- public:                                                                     \
-  static bool InvokePreFinalizer(const LivenessBroker& info, void* object) { \
-    Class* self = reinterpret_cast<Class*>(object);                          \
-    if (info.IsHeapObjectAlive(self))                                        \
-      return false;                                                          \
-    self->Class::PreFinalizer();                                             \
-    return true;                                                             \
-  }                                                                          \
-                                                                             \
- private:                                                                    \
-  ThreadState::PrefinalizerRegistration<Class> prefinalizer_dummy_{this};    \
-  using UsingPreFinalizerMacroNeedsTrailingSemiColon = char
-
-class PLATFORM_EXPORT BlinkGCObserver {
-  USING_FAST_MALLOC(BlinkGCObserver);
-
- public:
-  // The constructor automatically register this object to ThreadState's
-  // observer lists. The argument must not be null.
-  explicit BlinkGCObserver(ThreadState*);
-
-  // The destructor automatically unregister this object from ThreadState's
-  // observer lists.
-  virtual ~BlinkGCObserver();
-
-  virtual void OnCompleteSweepDone() = 0;
-
- private:
-  // As a ThreadState must live when a BlinkGCObserver lives, holding a raw
-  // pointer is safe.
-  ThreadState* thread_state_;
-};
-
-class PLATFORM_EXPORT ThreadState final {
-  USING_FAST_MALLOC(ThreadState);
-
- public:
-  // Register the pre-finalizer for the |self| object. The class T be using
-  // USING_PRE_FINALIZER() macro.
-  template <typename T>
-  class PrefinalizerRegistration final {
-    DISALLOW_NEW();
-
-   public:
-    PrefinalizerRegistration(T* self) {  // NOLINT
-      static_assert(sizeof(&T::InvokePreFinalizer) > 0,
-                    "USING_PRE_FINALIZER(T) must be defined.");
-      ThreadState* state =
-          ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
-#if DCHECK_IS_ON()
-      DCHECK(state->CheckThread());
-#endif
-      DCHECK(!state->SweepForbidden());
-      DCHECK(std::find(state->ordered_pre_finalizers_.begin(),
-                       state->ordered_pre_finalizers_.end(),
-                       PreFinalizer(self, T::InvokePreFinalizer)) ==
-             state->ordered_pre_finalizers_.end());
-      state->ordered_pre_finalizers_.emplace_back(self, T::InvokePreFinalizer);
-    }
-  };
-
-  // See setGCState() for possible state transitions.
-  enum GCState {
-    kNoGCScheduled,
-    kIncrementalMarkingStepPaused,
-    kIncrementalMarkingStepScheduled,
-    kIncrementalMarkingFinalizeScheduled,
-    kForcedGCForTestingScheduled,
-    kIncrementalGCScheduled,
-  };
-
-  // The phase that the GC is in. The GCPhase will not return kNone for mutators
-  // running during incremental marking and lazy sweeping. See SetGCPhase() for
-  // possible state transitions.
-  enum class GCPhase {
-    // GC is doing nothing.
-    kNone,
-    // GC is in marking phase.
-    kMarking,
-    // GC is in sweeping phase.
-    kSweeping,
-  };
-
-  enum class EphemeronProcessing {
-    kPartialProcessing,  // Perofrm one ephemeron processing iteration every
-                         // few step
-    kFullProcessing  // Perofrm full fixed-point ephemeron processing on each
-                     // step
-  };
-
-  class AtomicPauseScope;
-  class GCForbiddenScope;
-  class LsanDisabledScope;
-  class NoAllocationScope;
-  class StatisticsCollector;
-  struct Statistics;
-  class SweepForbiddenScope;
-  class HeapPointersOnStackScope;
-
-  using V8BuildEmbedderGraphCallback = void (*)(v8::Isolate*,
-                                                v8::EmbedderGraph*,
-                                                void*);
-
-  // Returns true if some thread (possibly the current thread) may be doing
-  // incremental marking. If false is returned, the *current* thread is
-  // definitely not doing incremental marking. See atomic_entry_flag.h for
-  // details.
-  //
-  // For an exact check, use ThreadState::IsIncrementalMarking.
-  ALWAYS_INLINE static bool IsAnyIncrementalMarking() {
-    return incremental_marking_flag_.MightBeEntered();
-  }
-
-  static ThreadState* AttachMainThread();
-
-  // Associate ThreadState object with the current thread. After this
-  // call thread can start using the garbage collected heap infrastructure.
-  // It also has to periodically check for safepoints.
-  static ThreadState* AttachCurrentThread();
-
-  // Disassociate attached ThreadState from the current thread. The thread
-  // can no longer use the garbage collected heap after this call.
-  //
-  // When ThreadState is detaching from non-main thread its heap is expected to
-  // be empty (because it is going away). Perform registered cleanup tasks and
-  // garbage collection to sweep away any objects that are left on this heap.
-  //
-  // This method asserts that no objects remain after this cleanup. If assertion
-  // does not hold we crash as we are potentially in the dangling pointer
-  // situation.
-  static void DetachCurrentThread();
-
-  static ThreadState* Current() { return **thread_specific_; }
-
-  static ThreadState* MainThreadState() {
-    return reinterpret_cast<ThreadState*>(main_thread_state_storage_);
-  }
-
-  static ThreadState* FromObject(const void*);
-
-  bool IsMainThread() const { return this == MainThreadState(); }
-  bool CheckThread() const { return thread_ == CurrentThread(); }
-
-  ThreadHeap& Heap() const { return *heap_; }
-  base::PlatformThreadId ThreadId() const { return thread_; }
-
-  // Associates |ThreadState| with a given |v8::Isolate|, essentially tying
-  // there garbage collectors together.
-  void AttachToIsolate(v8::Isolate*,
-                       V8BuildEmbedderGraphCallback);
-
-  // Removes the association from a potentially attached |v8::Isolate|.
-  void DetachFromIsolate();
-
-  // Returns an |UnifiedHeapController| if ThreadState is attached to a V8
-  // isolate (see |AttachToIsolate|) and nullptr otherwise.
-  UnifiedHeapController* unified_heap_controller() const {
-    DCHECK(isolate_);
-    return unified_heap_controller_.get();
-  }
-
-  void PerformIdleLazySweep(base::TimeTicks deadline);
-  void PerformConcurrentSweep(base::JobDelegate*);
-
-  void ScheduleForcedGCForTesting();
-  void ScheduleGCIfNeeded();
-  void SetGCState(GCState);
-  GCState GetGCState() const { return gc_state_; }
-  void SetGCPhase(GCPhase);
-
-  // Immediately starts incremental marking and schedules further steps if
-  // necessary.
-  void StartIncrementalMarking(BlinkGC::GCReason);
-
-  // Returns true if marking is in progress.
-  bool IsMarkingInProgress() const { return gc_phase_ == GCPhase::kMarking; }
-
-  // Returns true if unified heap marking is in progress.
-  bool IsUnifiedGCMarkingInProgress() const {
-    return IsMarkingInProgress() && IsUnifiedHeapGC();
-  }
-
-  // Returns true if sweeping is in progress.
-  bool IsSweepingInProgress() const { return gc_phase_ == GCPhase::kSweeping; }
-
-  // Returns true if the current GC is a memory reducing GC.
-  bool IsMemoryReducingGC() const {
-    return current_gc_data_.reason ==
-               BlinkGC::GCReason::kUnifiedHeapForMemoryReductionGC ||
-           current_gc_data_.reason ==
-               BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC;
-  }
-
-  bool IsUnifiedHeapGC() const {
-    return current_gc_data_.reason == BlinkGC::GCReason::kUnifiedHeapGC ||
-           current_gc_data_.reason ==
-               BlinkGC::GCReason::kUnifiedHeapForMemoryReductionGC ||
-           current_gc_data_.reason ==
-               BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC;
-  }
-
-  bool FinishIncrementalMarkingIfRunning(BlinkGC::CollectionType,
-                                         BlinkGC::StackState,
-                                         BlinkGC::MarkingType,
-                                         BlinkGC::SweepingType,
-                                         BlinkGC::GCReason);
-
-  void EnableIncrementalMarkingBarrier();
-  void DisableIncrementalMarkingBarrier();
-
-  void RestartIncrementalMarkingIfPaused();
-
-  void CompleteSweep();
-
-  // Returns whether it is currently allowed to allocate an object. Mainly used
-  // for sanity checks asserts.
-  bool IsAllocationAllowed() const {
-    // Allocation is not allowed during atomic marking pause, but it is allowed
-    // during atomic sweeping pause.
-    return !InAtomicMarkingPause() && !no_allocation_count_;
-  }
-
-  // Returns whether it is currently forbidden to trigger a GC.
-  bool IsGCForbidden() const { return gc_forbidden_count_; }
-
-  // Returns whether it is currently forbidden to sweep objects.
-  bool SweepForbidden() const { return sweep_forbidden_; }
-
-  bool in_atomic_pause() const { return in_atomic_pause_; }
-
-  bool InAtomicMarkingPause() const {
-    return in_atomic_pause() && IsMarkingInProgress();
-  }
-  bool InAtomicSweepingPause() const {
-    return in_atomic_pause() && IsSweepingInProgress();
-  }
-
-  bool IsIncrementalMarking() const { return incremental_marking_; }
-  void SetIncrementalMarking(bool value) { incremental_marking_ = value; }
-
-  void SafePoint(BlinkGC::StackState);
-
-  // A region of non-weak PersistentNodes allocated on the given thread.
-  PersistentRegion* GetPersistentRegion() const {
-    return persistent_region_.get();
-  }
-
-  // A region of PersistentNodes for WeakPersistents allocated on the given
-  // thread.
-  PersistentRegion* GetWeakPersistentRegion() const {
-    return weak_persistent_region_.get();
-  }
-
-  void RegisterStaticPersistentNode(PersistentNode*);
-  void ReleaseStaticPersistentNodes();
-  void FreePersistentNode(PersistentRegion*, PersistentNode*);
-
-  v8::Isolate* GetIsolate() const { return isolate_; }
-
-  // Returns |true| if |object| resides on this thread's heap.
-  // It is well-defined to call this method on any heap allocated
-  // reference, provided its associated heap hasn't been detached
-  // and shut down. Its behavior is undefined for any other pointer
-  // value.
-  bool IsOnThreadHeap(const void* object) const {
-    return &FromObject(object)->Heap() == &Heap();
-  }
-
-  ALWAYS_INLINE bool IsOnStack(Address address) const {
-    return reinterpret_cast<Address>(start_of_stack_) >= address &&
-           address >= (reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(
-                          WTF::GetCurrentStackPosition())));
-  }
-
-  int GcAge() const { return gc_age_; }
-
-  MarkingVisitor* CurrentVisitor() const {
-    return current_gc_data_.visitor.get();
-  }
-
-  // Returns true if the marking verifier is enabled, false otherwise.
-  bool IsVerifyMarkingEnabled() const;
-
-  void SkipIncrementalMarkingForTesting() {
-    skip_incremental_marking_for_testing_ = true;
-  }
-
-  // Performs stand-alone garbage collections considering only C++ objects for
-  // testing.
-  //
-  // Since it only considers C++ objects this type of GC is mostly useful for
-  // unit tests.
-  void CollectGarbageForTesting(BlinkGC::CollectionType,
-                                BlinkGC::StackState,
-                                BlinkGC::MarkingType,
-                                BlinkGC::SweepingType,
-                                BlinkGC::GCReason);
-
-  // Forced garbage collection for testing:
-  // - Performs unified heap garbage collections if ThreadState is attached to a
-  //   v8::Isolate using ThreadState::AttachToIsolate.
-  // - Otherwise, performs stand-alone garbage collections.
-  // - Collects garbage as long as live memory decreases (capped at 5).
-  void CollectAllGarbageForTesting(
-      BlinkGC::StackState stack_state =
-          BlinkGC::StackState::kNoHeapPointersOnStack);
-
-  // Enables compaction for next garbage collection.
-  void EnableCompactionForNextGCForTesting();
-
-  bool RequiresForcedGCForTesting() const {
-    return current_gc_data_.stack_state ==
-               BlinkGC::StackState::kHeapPointersOnStack &&
-           !forced_scheduled_gc_for_testing_;
-  }
-
-  void EnterNoHeapVerificationScopeForTesting() {
-    ++disable_heap_verification_scope_;
-  }
-  void LeaveNoHeapVerificationScopeForTesting() {
-    --disable_heap_verification_scope_;
-  }
-
- private:
-  class IncrementalMarkingScheduler;
-
-  // Stores whether some ThreadState is currently in incremental marking.
-  static AtomicEntryFlag incremental_marking_flag_;
-
-  static WTF::ThreadSpecific<ThreadState*>* thread_specific_;
-
-  // We can't create a static member of type ThreadState here because it will
-  // introduce global constructor and destructor. We would like to manage
-  // lifetime of the ThreadState attached to the main thread explicitly instead
-  // and still use normal constructor and destructor for the ThreadState class.
-  // For this we reserve static storage for the main ThreadState and lazily
-  // construct ThreadState in it using placement new.
-  static uint8_t main_thread_state_storage_[];
-
-  // Callback executed directly after pushing all callee-saved registers.
-  // |end_of_stack| denotes the end of the stack that can hold references to
-  // managed objects.
-  static void VisitStackAfterPushingRegisters(ThreadState*,
-                                              intptr_t* end_of_stack);
-
-  static bool IsForcedGC(BlinkGC::GCReason reason) {
-    return reason == BlinkGC::GCReason::kThreadTerminationGC ||
-           reason == BlinkGC::GCReason::kForcedGCForTesting ||
-           reason == BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC;
-  }
-
-  ThreadState();
-  ~ThreadState();
-
-  void EnterNoAllocationScope() { no_allocation_count_++; }
-  void LeaveNoAllocationScope() { no_allocation_count_--; }
-
-  void EnterAtomicPause() {
-    DCHECK(!in_atomic_pause_);
-    in_atomic_pause_ = true;
-  }
-  void LeaveAtomicPause() {
-    DCHECK(in_atomic_pause_);
-    in_atomic_pause_ = false;
-  }
-
-  void EnterGCForbiddenScope() { gc_forbidden_count_++; }
-  void LeaveGCForbiddenScope() {
-    DCHECK_GT(gc_forbidden_count_, 0u);
-    gc_forbidden_count_--;
-  }
-
-  void EnterStaticReferenceRegistrationDisabledScope();
-  void LeaveStaticReferenceRegistrationDisabledScope();
-
-  // Performs stand-alone garbage collections considering only C++ objects.
-  //
-  // Use the public *ForTesting calls for calling GC in tests.
-  void CollectGarbage(BlinkGC::CollectionType,
-                      BlinkGC::StackState,
-                      BlinkGC::MarkingType,
-                      BlinkGC::SweepingType,
-                      BlinkGC::GCReason);
-
-  // The following methods are used to compose RunAtomicPause. Public users
-  // should use the CollectGarbage entrypoint. Internal users should use these
-  // methods to compose a full garbage collection.
-  void AtomicPauseMarkPrologue(BlinkGC::CollectionType,
-                               BlinkGC::StackState,
-                               BlinkGC::MarkingType,
-                               BlinkGC::GCReason);
-  void AtomicPauseMarkRoots(BlinkGC::StackState,
-                            BlinkGC::MarkingType,
-                            BlinkGC::GCReason);
-  void AtomicPauseMarkTransitiveClosure();
-  void AtomicPauseMarkEpilogue(BlinkGC::MarkingType);
-  void AtomicPauseSweepAndCompact(BlinkGC::CollectionType,
-                                  BlinkGC::MarkingType marking_type,
-                                  BlinkGC::SweepingType sweeping_type);
-  void AtomicPauseEpilogue();
-
-  // RunAtomicPause composes the final atomic pause that finishes a mark-compact
-  // phase of a garbage collection. Depending on SweepingType it may also finish
-  // sweeping or schedule lazy/concurrent sweeping.
-  void RunAtomicPause(BlinkGC::CollectionType,
-                      BlinkGC::StackState,
-                      BlinkGC::MarkingType,
-                      BlinkGC::SweepingType,
-                      BlinkGC::GCReason);
-
-  // The version is needed to be able to start incremental marking.
-  void MarkPhasePrologue(BlinkGC::CollectionType,
-                         BlinkGC::StackState,
-                         BlinkGC::MarkingType,
-                         BlinkGC::GCReason);
-  void MarkPhaseEpilogue(BlinkGC::MarkingType);
-  void MarkPhaseVisitRoots();
-  void MarkPhaseVisitNotFullyConstructedObjects();
-  bool MarkPhaseAdvanceMarkingBasedOnSchedule(base::TimeDelta,
-                                              EphemeronProcessing);
-  bool MarkPhaseAdvanceMarking(base::TimeDelta, EphemeronProcessing);
-  void VerifyMarking(BlinkGC::MarkingType);
-
-  // Visit the stack after pushing registers onto the stack.
-  void PushRegistersAndVisitStack();
-
-  // Visit local thread stack and trace all pointers conservatively. Never call
-  // directly but always call through |PushRegistersAndVisitStack|.
-  void VisitStackImpl(MarkingVisitor*, Address*, Address*);
-  void VisitStack(MarkingVisitor*, Address*);
-  void VisitUnsafeStack(MarkingVisitor*);
-
-  // Visit the asan fake stack frame corresponding to a slot on the real machine
-  // stack if there is one. Never call directly but always call through
-  // |PushRegistersAndVisitStack|.
-  void VisitAsanFakeStackForPointer(MarkingVisitor*,
-                                    Address,
-                                    Address*,
-                                    Address*);
-
-  // Visit all non-weak persistents allocated on this thread.
-  void VisitPersistents(Visitor*);
-
-  // Visit all weak persistents allocated on this thread.
-  void VisitWeakPersistents(Visitor*);
-
-  // Visit card tables (remembered sets) containing inter-generational pointers.
-  void VisitRememberedSets(MarkingVisitor*);
-
-  // Incremental marking implementation functions.
-  void IncrementalMarkingStartForTesting();
-  void IncrementalMarkingStart(BlinkGC::GCReason);
-  // Incremental marking step advance marking on the mutator thread. This method
-  // also reschedules concurrent marking tasks if needed. The duration parameter
-  // applies only to incremental marking steps on the mutator thread.
-  void IncrementalMarkingStep(BlinkGC::StackState);
-  void IncrementalMarkingFinalize();
-
-  // Returns true if concurrent marking is finished (i.e. all current threads
-  // terminated and the worklist is empty)
-  bool ConcurrentMarkingStep();
-  void ScheduleConcurrentMarking();
-  void PerformConcurrentMark(base::JobDelegate* job);
-
-  // Schedule helpers.
-  void ScheduleIdleLazySweep();
-  void ScheduleConcurrentAndLazySweep();
-
-  void NotifySweepDone();
-  void PostSweep();
-
-  // See |DetachCurrentThread|.
-  void RunTerminationGC();
-
-  void RunScheduledGC(BlinkGC::StackState);
-
-  void SynchronizeAndFinishConcurrentSweeping();
-
-  void InvokePreFinalizers();
-
-  // Adds the given observer to the ThreadState's observer list. This doesn't
-  // take ownership of the argument. The argument must not be null. The argument
-  // must not be registered before calling this.
-  void AddObserver(BlinkGCObserver*);
-
-  // Removes the given observer from the ThreadState's observer list. This
-  // doesn't take ownership of the argument. The argument must not be null.
-  // The argument must be registered before calling this.
-  void RemoveObserver(BlinkGCObserver*);
-
-  bool IsForcedGC() const { return IsForcedGC(current_gc_data_.reason); }
-
-  // Returns whether stack scanning is forced. This is currently only used in
-  // platform tests where non nested tasks can be run with heap pointers on
-  // stack.
-  bool HeapPointersOnStackForced() const {
-    return heap_pointers_on_stack_forced_;
-  }
-
-#if defined(ADDRESS_SANITIZER)
-  // Poisons payload of unmarked objects.
-  //
-  // Also unpoisons memory areas for handles that may require resetting which
-  // can race with destructors. Note that cross-thread access still requires
-  // synchronization using a lock.
-  void PoisonUnmarkedObjects();
-#endif  // ADDRESS_SANITIZER
-
-  std::unique_ptr<ThreadHeap> heap_;
-  base::PlatformThreadId thread_;
-  std::unique_ptr<PersistentRegion> persistent_region_;
-  std::unique_ptr<PersistentRegion> weak_persistent_region_;
-
-  // Start of the stack which is the boundary until conservative stack scanning
-  // needs to search for managed pointers.
-  Address* start_of_stack_;
-
-  bool in_atomic_pause_ = false;
-  bool sweep_forbidden_ = false;
-  bool heap_pointers_on_stack_forced_ = false;
-  bool incremental_marking_ = false;
-  bool should_optimize_for_load_time_ = false;
-  bool forced_scheduled_gc_for_testing_ = false;
-  size_t no_allocation_count_ = 0;
-  size_t gc_forbidden_count_ = 0;
-  size_t static_persistent_registration_disabled_count_ = 0;
-
-  GCState gc_state_ = GCState::kNoGCScheduled;
-  GCPhase gc_phase_ = GCPhase::kNone;
-  BlinkGC::GCReason reason_for_scheduled_gc_ =
-      BlinkGC::GCReason::kForcedGCForTesting;
-
-  using PreFinalizerCallback = bool (*)(const LivenessBroker&, void*);
-  using PreFinalizer = std::pair<void*, PreFinalizerCallback>;
-
-  // Pre-finalizers are called in the reverse order in which they are
-  // registered by the constructors (including constructors of Mixin objects)
-  // for an object, by processing the ordered_pre_finalizers_ back-to-front.
-  Deque<PreFinalizer> ordered_pre_finalizers_;
-
-  v8::Isolate* isolate_ = nullptr;
-  V8BuildEmbedderGraphCallback v8_build_embedder_graph_ = nullptr;
-  std::unique_ptr<UnifiedHeapController> unified_heap_controller_;
-
-#if defined(ADDRESS_SANITIZER)
-  void* asan_fake_stack_;
-#endif
-
-  HashSet<BlinkGCObserver*> observers_;
-
-  // PersistentNodes that are stored in static references;
-  // references that either have to be cleared upon the thread
-  // detaching from Oilpan and shutting down or references we
-  // have to clear before initiating LSan's leak detection.
-  HashSet<PersistentNode*> static_persistents_;
-
-  int gc_age_ = 0;
-
-  struct GCData {
-    BlinkGC::CollectionType collection_type;
-    BlinkGC::StackState stack_state;
-    BlinkGC::MarkingType marking_type;
-    BlinkGC::GCReason reason;
-    std::unique_ptr<MarkingVisitor> visitor;
-  };
-  GCData current_gc_data_;
-
-  std::unique_ptr<IncrementalMarkingScheduler> incremental_marking_scheduler_;
-  std::unique_ptr<MarkingSchedulingOracle> marking_scheduling_;
-
-  base::JobHandle marker_handle_;
-
-  base::JobHandle sweeper_handle_;
-  std::atomic_bool has_unswept_pages_{false};
-
-  size_t disable_heap_verification_scope_ = 0;
-
-  bool skip_incremental_marking_for_testing_ = false;
-
-  size_t last_concurrently_marked_bytes_ = 0;
-  base::TimeTicks last_concurrently_marked_bytes_update_;
-  bool concurrent_marking_priority_increased_ = false;
-
-  friend class BlinkGCObserver;
-  friend class incremental_marking_test::IncrementalMarkingScope;
-  friend class IncrementalMarkingTestDriver;
-  friend class HeapAllocator;
-  template <typename T>
-  friend class PrefinalizerRegistration;
-  friend class TestGCScope;
-  friend class TestSupportingGC;
-  friend class ThreadStateSchedulingTest;
-  friend class UnifiedHeapController;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadState);
-};
-
-template <>
-class ThreadStateFor<kMainThreadOnly> {
-  STATIC_ONLY(ThreadStateFor);
-
- public:
-  static ThreadState* GetState() {
-    // This specialization must only be used from the main thread.
-    DCHECK(ThreadState::Current()->IsMainThread());
-    return ThreadState::MainThreadState();
-  }
-};
-
-template <>
-class ThreadStateFor<kAnyThread> {
-  STATIC_ONLY(ThreadStateFor);
-
- public:
-  static ThreadState* GetState() { return ThreadState::Current(); }
-};
-
-}  // namespace blink
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/thread_state.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
diff --git a/third_party/blink/renderer/platform/heap/thread_state_scopes.h b/third_party/blink/renderer/platform/heap/thread_state_scopes.h
index bde958d..5abe1320 100644
--- a/third_party/blink/renderer/platform/heap/thread_state_scopes.h
+++ b/third_party/blink/renderer/platform/heap/thread_state_scopes.h
@@ -1,128 +1,16 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_SCOPES_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_SCOPES_H_
 
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-#if defined(LEAK_SANITIZER)
-#include "third_party/blink/renderer/platform/wtf/leak_annotations.h"
-#endif
-
-namespace blink {
-
-// The NoAllocationScope class is used in debug mode to catch unwanted
-// allocations. E.g. allocations during GC.
-class ThreadState::NoAllocationScope final {
-  STACK_ALLOCATED();
-  DISALLOW_COPY_AND_ASSIGN(NoAllocationScope);
-
- public:
-  explicit NoAllocationScope(ThreadState* state) : state_(state) {
-    state_->EnterNoAllocationScope();
-  }
-  ~NoAllocationScope() { state_->LeaveNoAllocationScope(); }
-
- private:
-  ThreadState* const state_;
-};
-
-class ThreadState::SweepForbiddenScope final {
-  STACK_ALLOCATED();
-  DISALLOW_COPY_AND_ASSIGN(SweepForbiddenScope);
-
- public:
-  explicit SweepForbiddenScope(ThreadState* state) : state_(state) {
-    DCHECK(!state_->sweep_forbidden_);
-    state_->sweep_forbidden_ = true;
-  }
-  ~SweepForbiddenScope() {
-    DCHECK(state_->sweep_forbidden_);
-    state_->sweep_forbidden_ = false;
-  }
-
- private:
-  ThreadState* const state_;
-};
-
-class ThreadState::GCForbiddenScope final {
-  STACK_ALLOCATED();
-
- public:
-  explicit GCForbiddenScope(ThreadState* thread_state)
-      : thread_state_(thread_state) {
-    thread_state_->EnterGCForbiddenScope();
-  }
-  ~GCForbiddenScope() { thread_state_->LeaveGCForbiddenScope(); }
-
- private:
-  ThreadState* const thread_state_;
-};
-
-// Used to mark when we are in an atomic pause for GC.
-class ThreadState::AtomicPauseScope final {
-  STACK_ALLOCATED();
-
- public:
-  explicit AtomicPauseScope(ThreadState* thread_state)
-      : thread_state_(thread_state), gc_forbidden_scope(thread_state) {
-    thread_state_->EnterAtomicPause();
-  }
-  ~AtomicPauseScope() { thread_state_->LeaveAtomicPause(); }
-
- private:
-  ThreadState* const thread_state_;
-  GCForbiddenScope gc_forbidden_scope;
-};
-
-class ThreadState::HeapPointersOnStackScope final {
-  STACK_ALLOCATED();
-
- public:
-  explicit HeapPointersOnStackScope(ThreadState* state) : state_(state) {
-    DCHECK(!state_->heap_pointers_on_stack_forced_);
-    state_->heap_pointers_on_stack_forced_ = true;
-  }
-  ~HeapPointersOnStackScope() {
-    DCHECK(state_->heap_pointers_on_stack_forced_);
-    state_->heap_pointers_on_stack_forced_ = false;
-  }
-
- private:
-  ThreadState* const state_;
-};
-
-#if defined(LEAK_SANITIZER)
-class ThreadState::LsanDisabledScope final {
-  STACK_ALLOCATED();
-  DISALLOW_COPY_AND_ASSIGN(LsanDisabledScope);
-
- public:
-  explicit LsanDisabledScope(ThreadState* thread_state)
-      : thread_state_(thread_state) {
-    __lsan_disable();
-    if (thread_state_)
-      thread_state_->EnterStaticReferenceRegistrationDisabledScope();
-  }
-
-  ~LsanDisabledScope() {
-    __lsan_enable();
-    if (thread_state_)
-      thread_state_->LeaveStaticReferenceRegistrationDisabledScope();
-  }
-
- private:
-  ThreadState* const thread_state_;
-};
-
-#define LEAK_SANITIZER_DISABLED_SCOPE \
-  ThreadState::LsanDisabledScope lsan_disabled_scope(ThreadState::Current())
-#else
-#define LEAK_SANITIZER_DISABLED_SCOPE
-#endif
-
-}  // namespace blink
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_SCOPES_H_
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_controller.h b/third_party/blink/renderer/platform/heap/unified_heap_controller.h
index 5ec55f9..9d197c4 100644
--- a/third_party/blink/renderer/platform/heap/unified_heap_controller.h
+++ b/third_party/blink/renderer/platform/heap/unified_heap_controller.h
@@ -1,75 +1,16 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_
 
-#include "base/macros.h"
-#include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "v8/include/v8.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-namespace blink {
-
-class ThreadState;
-
-// UnifiedHeapController ties V8's garbage collector to Oilpan for performing a
-// garbage collection across both managed heaps.
-//
-// Unified heap garbage collections are triggered by V8 and mark the full
-// transitive closure of V8 and Blink (Oilpan) objects. The garbage collection
-// is initially triggered by V8. Both collecters report live references using
-// the EmbedderHeapTracer APIs. V8 and Blink both run separate incremental
-// marking steps to compute their live closures, respectively. The final atomic
-// pause is then initiated by V8 and triggers a fixed-point computation between
-// V8 and Blink where both GCs report live references to each other and drain
-// their marking work lists until they are empty and no new references are
-// found.
-//
-// Oilpan does not consider references from DOM wrappers (JavaScript objects on
-// V8's heap) as roots for such garbage collections.
-class PLATFORM_EXPORT UnifiedHeapController final
-    : public v8::EmbedderHeapTracer,
-      public ThreadHeapStatsObserver {
-  DISALLOW_IMPLICIT_CONSTRUCTORS(UnifiedHeapController);
-
- public:
-  explicit UnifiedHeapController(ThreadState*);
-  ~UnifiedHeapController() override;
-
-  // v8::EmbedderHeapTracer implementation.
-  void TracePrologue(v8::EmbedderHeapTracer::TraceFlags) final;
-  void TraceEpilogue(v8::EmbedderHeapTracer::TraceSummary*) final;
-  void EnterFinalPause(EmbedderStackState) final;
-  void RegisterV8References(const std::vector<std::pair<void*, void*>>&) final;
-  bool AdvanceTracing(double) final;
-  bool IsTracingDone() final;
-  bool IsRootForNonTracingGC(const v8::TracedReference<v8::Value>&) final;
-  bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>&) final;
-  void ResetHandleInNonTracingGC(const v8::TracedReference<v8::Value>&) final;
-
-  ThreadState* thread_state() const { return thread_state_; }
-
-  // ThreadHeapStatsObserver implementation.
-  void IncreaseAllocatedObjectSize(size_t) final;
-  void DecreaseAllocatedObjectSize(size_t) final;
-  // Not needed.
-  void ResetAllocatedObjectSize(size_t) final {}
-  void IncreaseAllocatedSpace(size_t) final {}
-  void DecreaseAllocatedSpace(size_t) final {}
-
- private:
-  void ReportBufferedAllocatedSizeIfPossible();
-
-  ThreadState* const thread_state_;
-  // Returns whether the Blink heap has been fully processed.
-  bool is_tracing_done_ = false;
-
-  // Buffered allocated size. Only positive values are forwarded to V8.
-  int64_t buffered_allocated_size_ = 0;
-};
-
-}  // namespace blink
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/unified_heap_controller.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h b/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
index 6ff6cb6a..4d13146 100644
--- a/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
+++ b/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
@@ -1,90 +1,16 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_
 
-#include "base/macros.h"
-#include "third_party/blink/renderer/platform/heap/marking_visitor.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-namespace v8 {
-class EmbedderHeapTracer;
-}
-
-namespace blink {
-
-struct WrapperTypeInfo;
-
-// Marking visitor for unified heap garbage collections. Extends the regular
-// Oilpan marking visitor by also providing write barriers and visitation
-// methods that allow for announcing reachable objects to V8. Visitor can be
-// used from any thread.
-class PLATFORM_EXPORT UnifiedHeapMarkingVisitorBase {
- public:
-  virtual ~UnifiedHeapMarkingVisitorBase() = default;
-
- protected:
-  UnifiedHeapMarkingVisitorBase(ThreadState*, v8::Isolate*, int);
-
-  // Visitation methods that announce reachable wrappers to V8.
-  void VisitImpl(const TraceWrapperV8Reference<v8::Value>&);
-
-  v8::Isolate* const isolate_;
-  v8::EmbedderHeapTracer* const controller_;
-  V8ReferencesWorklist::View v8_references_worklist_;
-
- private:
-  int task_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(UnifiedHeapMarkingVisitorBase);
-};
-
-// Same as the base visitor with the difference that it is bound to main thread.
-// Also implements various sorts of write barriers that should only be called
-// from the main thread.
-class PLATFORM_EXPORT UnifiedHeapMarkingVisitor
-    : public MarkingVisitor,
-      public UnifiedHeapMarkingVisitorBase {
- public:
-  // Write barriers for annotating a write during incremental marking.
-  static void WriteBarrier(const TraceWrapperV8Reference<v8::Value>&);
-  static void WriteBarrier(v8::Isolate*, const WrapperTypeInfo*, const void*);
-
-  UnifiedHeapMarkingVisitor(ThreadState*, MarkingMode, v8::Isolate*);
-  ~UnifiedHeapMarkingVisitor() override = default;
-
- protected:
-  using Visitor::Visit;
-  void Visit(const TraceWrapperV8Reference<v8::Value>&) final;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(UnifiedHeapMarkingVisitor);
-};
-
-// Same as the base visitor with the difference that it is bound to a
-// concurrent thread.
-class PLATFORM_EXPORT ConcurrentUnifiedHeapMarkingVisitor
-    : public ConcurrentMarkingVisitor,
-      public UnifiedHeapMarkingVisitorBase {
- public:
-  ConcurrentUnifiedHeapMarkingVisitor(ThreadState*,
-                                      MarkingMode,
-                                      v8::Isolate*,
-                                      int task_id);
-  ~ConcurrentUnifiedHeapMarkingVisitor() override = default;
-
-
-  void FlushWorklists() override;
-
- protected:
-  using Visitor::Visit;
-  void Visit(const TraceWrapperV8Reference<v8::Value>&) final;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ConcurrentUnifiedHeapMarkingVisitor);
-};
-
-}  // namespace blink
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h b/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h
new file mode 100644
index 0000000..bf86021
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h b/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h
new file mode 100644
index 0000000..8773bd7
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h b/third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h
new file mode 100644
index 0000000..17471d3
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_DISALLOW_NEW_WRAPPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_DISALLOW_NEW_WRAPPER_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_DISALLOW_NEW_WRAPPER_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h b/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h
new file mode 100644
index 0000000..5867016
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h
@@ -0,0 +1,9 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h b/third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h
new file mode 100644
index 0000000..2ef207a
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GC_TASK_RUNNER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GC_TASK_RUNNER_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GC_TASK_RUNNER_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h b/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h
new file mode 100644
index 0000000..8fc666e
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h b/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h
new file mode 100644
index 0000000..7c5cd8d
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h b/third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h
new file mode 100644
index 0000000..042d806
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_STATS_COLLECTOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_STATS_COLLECTOR_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_STATS_COLLECTOR_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h b/third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h
new file mode 100644
index 0000000..59d9b9e2
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TRAITS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TRAITS_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/member.h b/third_party/blink/renderer/platform/heap/v8_wrapper/member.h
new file mode 100644
index 0000000..5ad8e07
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/member.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h b/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h
new file mode 100644
index 0000000..8f5d12f2
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h b/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h
new file mode 100644
index 0000000..254f163b
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h b/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h
new file mode 100644
index 0000000..585c3c9
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h b/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h
new file mode 100644
index 0000000..8378cf6
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h b/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h
new file mode 100644
index 0000000..36fe078
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_CONTROLLER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_CONTROLLER_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_CONTROLLER_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h b/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h
new file mode 100644
index 0000000..0a4d66e
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h b/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h
new file mode 100644
index 0000000..10f987d
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_VISITOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_VISITOR_H_
+
+// TODO(chromium:1056170): Implement wrapper.
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_VISITOR_H_
diff --git a/third_party/blink/renderer/platform/heap/visitor.h b/third_party/blink/renderer/platform/heap/visitor.h
index 3d2cc0d..31e34200 100644
--- a/third_party/blink/renderer/platform/heap/visitor.h
+++ b/third_party/blink/renderer/platform/heap/visitor.h
@@ -1,314 +1,16 @@
-/*
- * 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 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_
 
-#include <memory>
-#include "third_party/blink/renderer/platform/heap/blink_gc.h"
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
-#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 
-namespace base {
-class Location;
-}
-
-namespace v8 {
-class Value;
-}
-
-namespace blink {
-
-template <typename T>
-class GarbageCollected;
-class LivenessBroker;
-template <typename T>
-struct TraceTrait;
-class ThreadState;
-class Visitor;
-template <typename T>
-class TraceWrapperV8Reference;
-
-// The TraceMethodDelegate is used to convert a trace method for type T to a
-// TraceCallback.  This allows us to pass a type's trace method as a parameter
-// to the PersistentNode constructor. The PersistentNode constructor needs the
-// specific trace method due an issue with the Windows compiler which
-// instantiates even unused variables. This causes problems
-// in header files where we have only forward declarations of classes.
-//
-// This interface is safe to use on concurrent threads. All accesses (reads)
-// from member are done atomically.
-template <typename T, void (T::*method)(Visitor*) const>
-struct TraceMethodDelegate {
-  STATIC_ONLY(TraceMethodDelegate);
-  static void Trampoline(Visitor* visitor, const void* self) {
-    (reinterpret_cast<const T*>(self)->*method)(visitor);
-  }
-};
-
-template <typename T, void (T::*method)(const LivenessBroker&)>
-struct WeakCallbackMethodDelegate {
-  STATIC_ONLY(WeakCallbackMethodDelegate);
-  static void Trampoline(const LivenessBroker& info, const void* self) {
-    (reinterpret_cast<T*>(const_cast<void*>(self))->*method)(info);
-  }
-};
-
-// Visitor is used to traverse Oilpan's object graph.
-class PLATFORM_EXPORT Visitor {
-  USING_FAST_MALLOC(Visitor);
-
- public:
-  explicit Visitor(ThreadState* state) : state_(state) {}
-  virtual ~Visitor() = default;
-
-  inline ThreadState* State() const { return state_; }
-  inline ThreadHeap& Heap() const { return state_->Heap(); }
-
-  // Static visitor implementation forwarding to dynamic interface.
-
-  template <typename T>
-  void TraceRoot(const T* t, const base::Location& location) {
-    static_assert(sizeof(T), "T must be fully defined");
-    static_assert(IsGarbageCollectedType<T>::value,
-                  "T needs to be a garbage collected object");
-    if (!t)
-      return;
-    VisitRoot(t, TraceDescriptorFor(t), location);
-  }
-
-  template <typename T>
-  void Trace(const Member<T>& t) {
-    const T* value = t.GetSafe();
-
-    DCHECK(!Member<T>::IsMemberHashTableDeletedValue(value));
-
-    Trace(value);
-  }
-
-  // TraceStrongly strongifies WeakMembers.
-  template <typename T>
-  ALWAYS_INLINE void TraceStrongly(const WeakMember<T>& t) {
-    const T* value = t.GetSafe();
-
-    DCHECK(!WeakMember<T>::IsMemberHashTableDeletedValue(value));
-
-    Trace<T>(value);
-  }
-  // Fallback methods used only when we need to trace raw pointers of T. This is
-  // the case when a member is a union where we do not support members.
-  template <typename T>
-  void Trace(T* t) {
-    Trace(const_cast<const T*>(t));
-  }
-  template <typename T>
-  void Trace(const T* t) {
-    static_assert(sizeof(T), "T must be fully defined");
-    static_assert(IsGarbageCollectedType<T>::value,
-                  "T needs to be a garbage collected object");
-    if (!t)
-      return;
-    Visit(t, TraceDescriptorFor(t));
-  }
-
-  // WeakMember version of the templated trace method. It doesn't keep
-  // the traced thing alive, but will write null to the WeakMember later
-  // if the pointed-to object is dead. It's lying for this to be const,
-  // but the overloading resolver prioritizes constness too high when
-  // picking the correct overload, so all these trace methods have to have
-  // the same constness on their argument to allow the type to decide.
-  template <typename T>
-  void Trace(const WeakMember<T>& weak_member) {
-    static_assert(sizeof(T), "T must be fully defined");
-    static_assert(IsGarbageCollectedType<T>::value,
-                  "T needs to be a garbage collected object");
-
-    const T* value = weak_member.GetSafe();
-
-    if (!value)
-      return;
-
-    DCHECK(!WeakMember<T>::IsMemberHashTableDeletedValue(value));
-    VisitWeak(value, &weak_member, TraceDescriptorFor(value),
-              &HandleWeakCell<T>);
-  }
-
-  // Fallback trace method for part objects to allow individual trace methods
-  // to trace through a part object with visitor->trace(m_partObject). This
-  // takes a const argument, because otherwise it will match too eagerly: a
-  // non-const argument would match a non-const Vector<T>& argument better
-  // than the specialization that takes const Vector<T>&. For a similar reason,
-  // the other specializations take a const argument even though they are
-  // usually used with non-const arguments, otherwise this function would match
-  // too well.
-  template <typename T>
-  void Trace(const T& t) {
-    static_assert(sizeof(T), "T must be fully defined");
-    if (std::is_polymorphic<T>::value) {
-      const intptr_t vtable = *reinterpret_cast<const intptr_t*>(&t);
-      if (!vtable)
-        return;
-    }
-    TraceTrait<T>::Trace(this, &t);
-  }
-
-  template <typename T, typename U>
-  void TraceEphemeron(const WeakMember<T>& key, const U* value) {
-    const T* t = key.GetSafe();
-    if (!t)
-      return;
-    VisitEphemeron(TraceDescriptorFor(t).base_object_payload,
-                   TraceDescriptorFor(value));
-  }
-
-  template <typename T>
-  void TraceWeakContainer(const T* object,
-                          const T* const* slot,
-                          TraceDescriptor strong_desc,
-                          TraceDescriptor weak_dec,
-                          WeakCallback weak_callback,
-                          const void* weak_callback_parameter) {
-    static_assert(sizeof(T), "T must be fully defined");
-    static_assert(IsGarbageCollectedType<T>::value,
-                  "T needs to be a garbage collected object");
-    VisitWeakContainer(reinterpret_cast<const void*>(object),
-                       reinterpret_cast<const void* const*>(slot), strong_desc,
-                       weak_dec, weak_callback, weak_callback_parameter);
-  }
-
-  template <typename T>
-  void TraceMovablePointer(const T* const* slot) {
-    RegisterMovableSlot(reinterpret_cast<const void* const*>(slot));
-  }
-
-  // Cross-component tracing interface.
-  template <typename V8Type>
-  void Trace(const TraceWrapperV8Reference<V8Type>& v8reference) {
-    Visit(v8reference.template Cast<v8::Value>());
-  }
-
-  // Dynamic visitor interface.
-
-  // Adds a |callback| that is invoked with |parameter| after liveness has been
-  // computed on the whole object graph. The |callback| may use the provided
-  // |LivenessBroker| to determine whether an object is considered alive or
-  // dead.
-  //
-  // - Upon returning from the callback all references to dead objects must have
-  //   been cleared.
-  // - Any operation that extends the object graph, including allocation
-  //   or reviving objects, is prohibited.
-  // - Clearing out pointers is allowed.
-  // - Removing elements from heap collections is allowed as these collections
-  //   are aware of custom weakness and won't resize their backings.
-  virtual void RegisterWeakCallback(WeakCallback callback,
-                                    const void* parameter) {}
-
-  // Registers an instance method using |RegisterWeakCallback|. See description
-  // below.
-  template <typename T, void (T::*method)(const LivenessBroker&)>
-  void RegisterWeakCallbackMethod(const T* obj) {
-    RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>::Trampoline,
-                         obj);
-  }
-
-  // Returns whether the visitor is used in a concurrent setting.
-  virtual bool IsConcurrent() const { return false; }
-
-  // Defers invoking |desc| to the main thread when running concurrently.
-  // Returns true if |desc| has been queued for later processing and false if
-  // running in a non-concurrent setting.
-  //
-  // This can be used to defer processing data structures to the main thread
-  // when support for concurrent processing is missing.
-  virtual bool DeferredTraceIfConcurrent(TraceDescriptor, size_t) {
-    return false;
-  }
-
- protected:
-  // Visits an object through a strong reference.
-  virtual void Visit(const void*, TraceDescriptor) {}
-
-  // Visits an object through a weak reference.
-  virtual void VisitWeak(const void*,
-                         const void*,
-                         TraceDescriptor,
-                         WeakCallback) {}
-
-  // Visits cross-component references to V8.
-  virtual void Visit(const TraceWrapperV8Reference<v8::Value>&) {}
-
-  virtual void VisitRoot(const void* t,
-                         TraceDescriptor desc,
-                         const base::Location&) {
-    Visit(t, desc);
-  }
-
-  // Visits ephemeron pairs which are a combination of weak and strong keys and
-  // values.
-  virtual void VisitEphemeron(const void*, TraceDescriptor) {}
-
-  // Visits a container |object| holding ephemeron pairs held from |slot|.  The
-  // descriptor |strong_desc| can be used to enforce strong treatment of
-  // |object|. The |weak_desc| descriptor is invoked repeatedly until no
-  // more new objects are found. It is expected that |weak_desc| processing
-  // ultimately yields in a call to VisitEphemeron. After marking all reachable
-  // objects, |weak_callback| is invoked with |weak_callback_parameter|. It is
-  // expected that this callback is used to reset non-live entries in the
-  // ephemeron container.
-  virtual void VisitWeakContainer(const void* object,
-                                  const void* const* slot,
-                                  TraceDescriptor strong_desc,
-                                  TraceDescriptor weak_desc,
-                                  WeakCallback weak_callback,
-                                  const void* weak_callback_parameter) {}
-
-  virtual void RegisterMovableSlot(const void* const* slot) {}
-
-  template <typename T>
-  static TraceDescriptor TraceDescriptorFor(const T* traceable) {
-    return TraceTrait<T>::GetTraceDescriptor(traceable);
-  }
-
- private:
-  template <typename T>
-  static void HandleWeakCell(const LivenessBroker&, const void*);
-
-  ThreadState* const state_;
-};
-
-}  // namespace blink
+#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h"
+#else  // !BLINK_HEAP_USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/visitor.h"
+#endif  // !BLINK_HEAP_USE_V8_OILPAN
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
index e11f91f..00ebccc0 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
@@ -5,7 +5,6 @@
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
 
 #include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h"
-#include "third_party/blink/renderer/platform/heap/trace_traits.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 0c023c10..51b5093 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -921,7 +921,10 @@
     },
     {
       name: "GetDisplayMedia",
-      status: {"Android": "", "default": "stable"},
+      status: {
+        "Android": "experimental",
+        "default": "stable",
+        },
     },
     {
       name: "GroupEffect",
diff --git a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc
index b83d215..52c9b96 100644
--- a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc
+++ b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc
@@ -354,7 +354,7 @@
         embed_render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>();
     shared_quad_state->SetAll(
         child_transform, gfx::Rect(child_size), gfx::Rect(child_size),
-        gfx::RRectF() /* rounded_corner_bounds */, gfx::Rect() /* clip_rect */,
+        gfx::MaskFilterInfo(), gfx::Rect() /* clip_rect */,
         false /* is_clipped */, are_contents_opaque /* are_contents_opaque */,
         1.f /* opacity */, SkBlendMode::kSrcOver, 0 /* sorting_context_id */);
     surface_quad->SetNew(
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 4fc02947..ee92e66 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -210393,7 +210393,7 @@
       []
      ],
      "exify.js": [
-      "c16b25e8676afef23133c2b35c1c6dc5623af473",
+      "b6c22e196c64a8532d05c1ea5e1453c5534c753b",
       []
      ]
     },
@@ -231662,7 +231662,7 @@
      []
     ],
     "resize-observer.idl": [
-     "0d2aa2863a79409e4904c35f2754f644aed9e0a2",
+     "d4973b77ce9aabf5c4c2141f0341e6e0fe263012",
      []
     ],
     "resource-timing.idl": [
@@ -231670,7 +231670,7 @@
      []
     ],
     "sanitizer-api.tentative.idl": [
-     "11653d1a186aa3159aaf5e44f5b0ff6ecf1dc50a",
+     "129c2962b31039d2a579b510ffb53b39225e19ff",
      []
     ],
     "savedata.idl": [
@@ -238065,10 +238065,6 @@
      "a006732015be3bbf07c79ecd11d8a50c4ebbda3f",
      []
     ],
-    "idlharness.window-expected.txt": [
-     "e58b1e13396f06b3816e8f62a7c1b1d70b28df96",
-     []
-    ],
     "resources": {
      "iframe.html": [
       "518317b520b68cbf92b09e67a57f1ecd27243747",
@@ -242139,24 +242135,6 @@
      "bf60a89d442ca7f26c61d19af6531aed1a2f5227",
      []
     ],
-    "piping": {
-     "pipe-through.any-expected.txt": [
-      "a7d386a986fe9341dfbb88c849f65097a365bec9",
-      []
-     ],
-     "pipe-through.any.serviceworker-expected.txt": [
-      "a7d386a986fe9341dfbb88c849f65097a365bec9",
-      []
-     ],
-     "pipe-through.any.sharedworker-expected.txt": [
-      "a7d386a986fe9341dfbb88c849f65097a365bec9",
-      []
-     ],
-     "pipe-through.any.worker-expected.txt": [
-      "a7d386a986fe9341dfbb88c849f65097a365bec9",
-      []
-     ]
-    },
     "readable-byte-streams": {
      "bad-buffers-and-views.any-expected.txt": [
       "9a39ea475532ce53b4cb586da6ebb4efde071336",
@@ -308884,7 +308862,7 @@
      ]
     ],
     "density-corrected-natural-size.html": [
-     "0b90b74f439b587f0aabb393c72a42db1a23ad61",
+     "b2241a6f7b51ecd35153d954a24cd835ecd174a1",
      [
       null,
       {}
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/resize-observer.idl b/third_party/blink/web_tests/external/wpt/interfaces/resize-observer.idl
index 0d2aa28..d4973b7 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/resize-observer.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/resize-observer.idl
@@ -35,10 +35,3 @@
     readonly attribute unrestricted double inlineSize;
     readonly attribute unrestricted double blockSize;
 };
-
-interface ResizeObservation {
-    constructor(Element target);
-    readonly attribute Element target;
-    readonly attribute ResizeObserverBoxOptions observedBox;
-    readonly attribute FrozenArray<ResizeObserverSize> lastReportedSizes;
-};
diff --git a/third_party/blink/web_tests/external/wpt/mixed-content/tentative/autoupgrades/audio-upgrade.https.sub.html b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/autoupgrades/audio-upgrade.https.sub.html
new file mode 100644
index 0000000..0731ef6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/autoupgrades/audio-upgrade.https.sub.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Autoupgrade mixed content: Audio.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+</head>
+<body>
+  <script>
+    async_test(t => assert_audio_loads(t), "Audio autoupgraded");
+
+    function assert_audio_loads(test) {
+        // Since autoupgrades don't upgrade custom ports, we use the https port with an HTTP scheme. A successful autoupgrade will result in the right URL loading (and no autoupgrade will result in failure).
+        var url = new URL("http://{{host}}:{{ports[https][0]}}/mixed-content/tentative/resources/test.wav")
+        var i = document.createElement('audio');
+        i.oncanplaythrough = test.step_func_done(_ => {
+            assert_equals(i.duration, 1, "Length");
+        });
+        i.onerror = test.unreached_func("Audio should load successfully from " + url);
+        i.src = url;
+    }
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/http/tests/mixed-autoupgrade/optionally/image-upgrade.https.html b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/autoupgrades/image-upgrade.https.sub.html
similarity index 68%
rename from third_party/blink/web_tests/http/tests/mixed-autoupgrade/optionally/image-upgrade.https.html
rename to third_party/blink/web_tests/external/wpt/mixed-content/tentative/autoupgrades/image-upgrade.https.sub.html
index b39e13b..03b5c3e 100644
--- a/third_party/blink/web_tests/http/tests/mixed-autoupgrade/optionally/image-upgrade.https.html
+++ b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/autoupgrades/image-upgrade.https.sub.html
@@ -11,7 +11,8 @@
     async_test(t => assert_image_loads(t), "Image autoupgraded");
 
     function assert_image_loads(test) {
-        var url = new URL("http://web-platform.test:8443/mixed-autoupgrade/resources/pass.png")
+        // Since autoupgrades don't upgrade custom ports, we use the https port with an HTTP scheme. A successful autoupgrade will result in the right URL loading (and no autoupgrade will result in failure).
+        var url = new URL("http://{{host}}:{{ports[https][0]}}/mixed-content/tentative/resources/pass.png")
         var i = document.createElement('img');
         i.onload = test.step_func_done(_ => {
             assert_equals(i.naturalHeight, 64, "Height.");
diff --git a/third_party/blink/web_tests/external/wpt/mixed-content/tentative/autoupgrades/video-upgrade.https.sub.html b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/autoupgrades/video-upgrade.https.sub.html
new file mode 100644
index 0000000..45ec718
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/autoupgrades/video-upgrade.https.sub.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Autoupgrade mixed content: Video.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+</head>
+<body>
+  <script>
+    async_test(t => assert_video_loads(t), "Video autoupgraded");
+
+    function assert_video_loads(test) {
+        // Since autoupgrades don't upgrade custom ports, we use the https port with an HTTP scheme. A successful autoupgrade will result in the right URL loading (and no autoupgrade will result in failure).
+        var url = new URL("http://{{host}}:{{ports[https][0]}}/mixed-content/tentative/resources/test.ogv")
+        var i = document.createElement('video');
+        i.oncanplaythrough = test.step_func_done(_ => {
+            assert_equals(Math.floor(i.duration), 300, "Length.");
+        });
+        i.onerror = test.unreached_func("Video should load successfully from " + url);
+        i.src = url;
+    }
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mixed-content/tentative/resources/pass.png b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/resources/pass.png
new file mode 100644
index 0000000..2fa1e0a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/resources/pass.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/mixed-content/tentative/resources/test.ogv b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/resources/test.ogv
new file mode 100644
index 0000000..0f83996
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/resources/test.ogv
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/mixed-content/tentative/resources/test.wav b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/resources/test.wav
new file mode 100644
index 0000000..85dc1ea
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mixed-content/tentative/resources/test.wav
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/resources/picker-common.js b/third_party/blink/web_tests/fast/forms/resources/picker-common.js
index 7ed1552..fbf71720 100644
--- a/third_party/blink/web_tests/fast/forms/resources/picker-common.js
+++ b/third_party/blink/web_tests/fast/forms/resources/picker-common.js
@@ -93,6 +93,7 @@
     return internals.pagePopupWindow;
 }
 
+// TODO(crbug.com/1047176) - use clickToOpenPickerWithPromise instead
 function clickToOpenPicker(x, y, callback, errorCallback) {
     eventSender.mouseMoveTo(x, y);
     eventSender.mouseDown();
@@ -104,6 +105,28 @@
         errorCallback();
 }
 
+// Uses test_driver to open the picker.
+function clickToOpenPickerWithPromise(x, y, callback, errorCallback) {
+    return new Promise((resolve, reject)=>{
+      var actions = new test_driver.Actions();
+      actions
+          .pointerMove(x, y)
+          .pointerDown()
+          .pointerUp()
+          .send();
+      waitUntil(()=>internals.pagePopupWindow).then(()=>{
+        popupWindow = internals.pagePopupWindow;
+        if (typeof callback === "function")
+          setPopupOpenCallback(callback);
+        resolve();
+      }).catch((err)=>{
+          if (typeof errorCallback === "function" && !popupWindow)
+            errorCallback();
+         reject();
+      });
+    });
+}
+
 function setPopupOpenCallback(callback) {
     console.assert(popupWindow);
     popupOpenCallback = callback;
diff --git a/third_party/blink/web_tests/fast/forms/select-popup/popup-menu-scrollbar-button-scrolls.html b/third_party/blink/web_tests/fast/forms/select-popup/popup-menu-scrollbar-button-scrolls.html
index 16d6634..41e49b2 100644
--- a/third_party/blink/web_tests/fast/forms/select-popup/popup-menu-scrollbar-button-scrolls.html
+++ b/third_party/blink/web_tests/fast/forms/select-popup/popup-menu-scrollbar-button-scrolls.html
@@ -3,7 +3,11 @@
 <head>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-actions.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
 <script src="../resources/common.js"></script>
+<script src="../../../resources/gesture-util.js"></script>
 <script src="../resources/picker-common.js"></script>
 </head>
 <body>
@@ -41,27 +45,27 @@
 internals.settings.setScrollAnimatorEnabled(false);
 
 let test = async_test(function(test) {
-  openPicker(menu, test.step_func(testScrollbarScroll),
+  var selectRect = menu.getBoundingClientRect();
+  clickToOpenPickerWithPromise(selectRect.left, selectRect.top, test.step_func(testScrollbarScroll),
       test.unreached_func('Picker failed to open'));
 }, "Scrollbar clicks in a popup must scroll");
 
-function testScrollbarScroll() {
+async function testScrollbarScroll() {
     let picker = internals.pagePopupWindow.global.picker;
     let scrollEvents = 0;
 
-    // Click on the scrollbar forward button, and then validate with
-    // a pixel test that the scrollbar/scrollable area scrolled.
-    //
-    // Note: when there is an active popup, eventSender's events are sent with
-    // coordinates relative to the popup itself, so we don't need to take the
-    // outer select element's position into account.
+    // Click on the scrollbar forward button, and then validate
+    // that the scrollbar/scrollable area scrolled.
     let selectElement = internals.pagePopupWindow.global.picker._selectElement;
     let innerSelectRect = selectElement.getBoundingClientRect();
-    let scrollbarX = innerSelectRect.x + innerSelectRect.width - 5;
-    let scrollbarY = innerSelectRect.y + innerSelectRect.height - 10;
-    eventSender.mouseMoveTo(scrollbarX, scrollbarY);
-    eventSender.mouseDown();
-    eventSender.mouseUp();
+    let scrollbarX = innerSelectRect.x + innerSelectRect.width - 5 + popupWindow.screenX;
+    let scrollbarY = innerSelectRect.y + innerSelectRect.height - 10 + popupWindow.screenY;
+    let actions = new test_driver.Actions();
+    await actions
+      .pointerMove(scrollbarX, scrollbarY)
+      .pointerDown()
+      .pointerUp()
+      .send();
     requestAnimationFrame(test.step_func(function() {
       requestAnimationFrame(test.step_func(function() {
           assert_greater_than(selectElement.scrollTop, 0);
diff --git a/third_party/blink/web_tests/external/wpt/resize-observer/idlharness.window-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/resize-observer/idlharness.window-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/resize-observer/idlharness.window-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/resize-observer/idlharness.window-expected.txt
diff --git a/third_party/subresource-filter-ruleset/README.chromium b/third_party/subresource-filter-ruleset/README.chromium
index 4b4e46d..41cacba1 100644
--- a/third_party/subresource-filter-ruleset/README.chromium
+++ b/third_party/subresource-filter-ruleset/README.chromium
@@ -1,6 +1,6 @@
 Name: EasyList
 URL: https://easylist.to/easylist/easylist.txt
-Version: 202009101144
+Version: 202010221614
 License: Creative Commons Attribution-ShareAlike 3.0 Unported
 License File: NOT_SHIPPED
 Security Critical: no
diff --git a/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1 b/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1
index ac7d7bad..56419e6 100644
--- a/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1
+++ b/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1
@@ -1 +1 @@
-d6319e359a3f2016f4866941beda29ff29194301
\ No newline at end of file
+83bced6c2676ed8d7c57a84c9a8d4f76c08f79e2
\ No newline at end of file
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index 26a71bc..e543e08 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -168,13 +168,10 @@
   "chrome/browser/resources/read_later/read_later_resources.grd": {
     "includes": [1760],
   },
-  "chrome/browser/resources/settings/os_settings_resources_vulcanized.grd": {
+  "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/settings/chromeos/os_settings_resources.grd": {
+    "META": {"sizes": {"includes": [1000],}},
     "includes": [1770],
   },
-  "chrome/browser/resources/settings/os_settings_resources.grd": {
-    "includes": [1780],
-    "structures": [1800],
-  },
   "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/settings/settings_resources.grd": {
     "META": {"sizes": {"includes": [500],}},
     "includes": [1830],
diff --git a/tools/metrics/histograms/histograms_xml/ash/histograms.xml b/tools/metrics/histograms/histograms_xml/ash/histograms.xml
index 7b8c6d5f..54fd96db 100644
--- a/tools/metrics/histograms/histograms_xml/ash/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/ash/histograms.xml
@@ -118,8 +118,8 @@
   </summary>
 </histogram>
 
-<histogram name="Ash.AmbientMode.EngagementTime.{TabletOrClamshell}"
-    units="hours" expires_after="2021-05-01">
+<histogram name="Ash.AmbientMode.EngagementTime.{TabletOrClamshell}" units="ms"
+    expires_after="2021-05-01">
   <owner>cowmoo@google.com</owner>
   <owner>xiaohuic@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/background/histograms.xml b/tools/metrics/histograms/histograms_xml/background/histograms.xml
index 269345e4..2a55ed12 100644
--- a/tools/metrics/histograms/histograms_xml/background/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/background/histograms.xml
@@ -116,7 +116,7 @@
 </histogram>
 
 <histogram name="BackgroundFetch.MatchCalledFromDocumentScope"
-    enum="ScopeMatchCalledFrom" expires_after="2020-11-30">
+    enum="ScopeMatchCalledFrom" expires_after="2021-11-30">
   <owner>nator@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
   <owner>peter@chromium.org</owner>
@@ -127,7 +127,7 @@
 </histogram>
 
 <histogram name="BackgroundFetch.MatchCalledWhenFetchIsIncomplete"
-    enum="FetchStatusWhenMatchCalled" expires_after="2020-11-30">
+    enum="FetchStatusWhenMatchCalled" expires_after="2021-11-30">
   <owner>nator@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
   <owner>peter@chromium.org</owner>
@@ -139,7 +139,7 @@
 </histogram>
 
 <histogram name="BackgroundFetch.PercentOfRequestsForWhichUpdatesAreSent"
-    units="%" expires_after="2020-11-30">
+    units="%" expires_after="2021-11-30">
   <owner>nator@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
   <owner>peter@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
index 133b35f..450a253 100644
--- a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
@@ -260,6 +260,16 @@
   </summary>
 </histogram>
 
+<histogram name="SubresourceFilter.PageLoad.AdsInterventionTriggered"
+    enum="AdsViolations" expires_after="M90">
+  <owner>yaoxia@google.com</owner>
+  <owner>chrome-ads-uma@google.com</owner>
+  <summary>
+    Records that an ads violation has been triggered on a page load. Logged at
+    the time the ads violation is detected.
+  </summary>
+</histogram>
+
 <histogram name="SubresourceFilter.PageLoad.NumSubresourceLoads.Disallowed"
     units="resource loads" expires_after="M85">
   <owner>csharrison@chromium.org</owner>
@@ -345,6 +355,19 @@
   </summary>
 </histogram>
 
+<histogram name="SubresourceFilter.PageLoad.TimeSinceLastActiveAdsIntervention"
+    units="hours" expires_after="M90">
+  <owner>yaoxia@google.com</owner>
+  <owner>chrome-ads-uma@google.com</owner>
+  <summary>
+    Records the time since the last ads intervention when loading a page that
+    has previously triggered an ads intervention. This is limited by the maximum
+    expiry time of intervention data, 7 days. Recorded at the time page
+    activation is computed during page load when a previous intervention was
+    previously recorded and has not expired from the intervention data.
+  </summary>
+</histogram>
+
 <histogram name="SubresourceFilter.RulesetVerificationStatus"
     enum="RulesetVerificationStatus" expires_after="M77">
   <owner>yaoxia@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/uma/histograms.xml b/tools/metrics/histograms/histograms_xml/uma/histograms.xml
index 3a8f72f..edb8fe85 100644
--- a/tools/metrics/histograms/histograms_xml/uma/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/uma/histograms.xml
@@ -678,6 +678,26 @@
   </summary>
 </histogram>
 
+<histogram name="UMA.UserActionsCount" enum="Boolean"
+    expires_after="2021-04-01">
+  <owner>mpearson@chromium.org</owner>
+  <owner>src/base/metrics/OWNERS</owner>
+  <summary>
+    Emitted when a user action is recorded.
+
+    Intended to be used to estimate how many user actions are lost due lack of
+    being persisted in the same way histograms are. One way to use this
+    histogram is to look as the count in this histogram in logs that come from
+    the previous session. All of those user actions will have been lost.
+
+    Also note that user actions can be lost due to being truncated before
+    uploading a UMA record. Those logs user actions are recorded in the
+    histogram UMA.TruncatedEvents.UserAction.
+
+    There may be other ways user actions are dropped too.
+  </summary>
+</histogram>
+
 <histogram name="UMA.UserDemographics.Status" enum="UserDemographicsStatus"
     expires_after="2021-04-15">
   <owner>vincb@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
index fe07239..ce9862a 100644
--- a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
@@ -709,7 +709,7 @@
 </histogram>
 
 <histogram name="WebRTC.Audio.TargetJitterBufferDelayMs" units="ms"
-    expires_after="2020-10-25">
+    expires_after="2021-10-25">
   <owner>hlundin@chromium.org</owner>
   <summary>
     The target jitter buffer delay for the receiving side. Sampled once every 10
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index a23ddaf..b8ef13c 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -444,6 +444,7 @@
 crbug.com/1088419 [ android-nexus-5x android-webview ] v8.browsing_mobile/browse:media:imgur:2019 [ Skip ]
 crbug.com/1112337 [ android ] v8.browsing_mobile/browse:news:cricbuzz:2019 [ Skip ]
 crbug.com/1139057 [ mobile ] v8.browsing_mobile/browse:social:facebook:2019 [ Skip ]
+crbug.com/1143740 [ android-pixel-2 android-webview ] v8.browsing_mobile/browse:media:imgur:2019 [ Skip ]
 
 # Benchmark: v8.browsing_mobile-future
 crbug.com/1036141 [ android-webview ] v8.browsing_mobile-future/browse:shopping:lazada:2019 [ Skip ]
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index b6848f2..ad61236d 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -162,7 +162,7 @@
  <item id="interest_feedv2_send" added_in_milestone="83" hash_code="85742023" type="0" content_hash_code="49706671" os_list="linux,windows" file_path="components/feed/core/v2/feed_network_impl.cc"/>
  <item id="intranet_redirect_detector" added_in_milestone="62" hash_code="21785164" type="0" content_hash_code="62025595" os_list="linux,windows" file_path="chrome/browser/intranet_redirect_detector.cc"/>
  <item id="invalidation_service" added_in_milestone="62" hash_code="72354423" type="0" deprecated="2020-01-23" content_hash_code="78425687" file_path=""/>
- <item id="javascript_report_error" added_in_milestone="87" hash_code="109607776" type="0" content_hash_code="30837893" os_list="linux,windows" file_path="components/crash/content/browser/error_reporting/send_javascript_error_report.cc"/>
+ <item id="javascript_report_error" added_in_milestone="87" hash_code="109607776" type="0" content_hash_code="30837893" os_list="linux" file_path="chrome/browser/error_reporting/chrome_js_error_report_processor.cc"/>
  <item id="kaleidoscope_service" added_in_milestone="87" hash_code="49759694" type="0" content_hash_code="14307563" os_list="linux,windows" file_path="chrome/browser/media/kaleidoscope/kaleidoscope_service.cc"/>
  <item id="kids_chrome_management_client_classify_url" added_in_milestone="77" hash_code="109987793" type="0" deprecated="2019-07-30" content_hash_code="112740597" file_path=""/>
  <item id="lib_address_input" added_in_milestone="62" hash_code="50816767" type="0" content_hash_code="57977576" os_list="linux,windows" file_path="third_party/libaddressinput/chromium/chrome_metadata_source.cc"/>
diff --git a/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm b/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
index 5f3231a8..a850776 100644
--- a/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
+++ b/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
@@ -773,80 +773,99 @@
       CreateGLImage(gfx::Size(256, 256), gfx::BufferFormat::BGRA_8888, false);
 
   std::unique_ptr<ui::CARendererLayerTree> ca_layer_tree;
-  CALayer* content_layer1 = nil;
-  CALayer* content_layer2 = nil;
-  CALayer* content_layer3 = nil;
-  CALayer* content_layer4 = nil;
+  CALayer* content_layer_old = nil;
+  CALayer* content_layer_new = nil;
 
   // Validate the initial values.
   {
     UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-    content_layer1 = GetOnlyContentLayer();
-
-    // Validate the content layer.
-    EXPECT_FALSE([content_layer1
+    content_layer_new = GetOnlyContentLayer();
+    EXPECT_FALSE([content_layer_new
         isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
   }
+  content_layer_old = content_layer_new;
 
+  // Pass a YUV 420 frame. This will become an AVSampleBufferDisplayLayer
+  // because it is in fullscreen low power mode.
   properties.gl_image = CreateGLImage(
       gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR, false);
-
-  // Pass another frame. This will automatically create a CVPixelBuffer
-  // behind the scenes, because the underlying buffer is YUV 420.
   {
     UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-    content_layer2 = GetOnlyContentLayer();
-
-    // Validate the content layer.
-    EXPECT_TRUE([content_layer2
+    content_layer_new = GetOnlyContentLayer();
+    EXPECT_TRUE([content_layer_new
         isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
-    EXPECT_NE(content_layer2, content_layer1);
+    EXPECT_NE(content_layer_new, content_layer_old);
   }
+  content_layer_old = content_layer_new;
 
+  // Pass a similar frame. Nothing should change.
   properties.gl_image = CreateGLImage(
-      gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR, true);
-
-  // Pass a frame with a CVPixelBuffer.
+      gfx::Size(256, 128), gfx::BufferFormat::YUV_420_BIPLANAR, false);
   {
     UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-    content_layer3 = GetOnlyContentLayer();
-
-    // Validate the content layer.
-    EXPECT_TRUE([content_layer3
+    content_layer_new = GetOnlyContentLayer();
+    EXPECT_TRUE([content_layer_new
         isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
-    EXPECT_EQ(content_layer3, content_layer2);
+    EXPECT_EQ(content_layer_new, content_layer_old);
   }
+  content_layer_old = content_layer_new;
 
-  properties.gl_image = CreateGLImage(
-      gfx::Size(513, 512), gfx::BufferFormat::YUV_420_BIPLANAR, true);
+  // Break fullscreen low power mode by changing opacity. This should cause
+  // us to drop out of using AVSampleBufferDisplayLayer.
+  properties.opacity = 0.9;
+  {
+    UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+    content_layer_new = GetOnlyContentLayer();
+    EXPECT_FALSE([content_layer_new
+        isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
+    EXPECT_NE(content_layer_new, content_layer_old);
+  }
+  content_layer_old = content_layer_new;
+
+  // Now try a P010 frame. Because this may be HDR, we should jump back to
+  // having an AVSampleBufferDisplayLayer.
+  properties.gl_image =
+      CreateGLImage(gfx::Size(128, 256), gfx::BufferFormat::P010, false);
+  {
+    UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+    content_layer_new = GetOnlyContentLayer();
+    EXPECT_TRUE([content_layer_new
+        isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
+    EXPECT_NE(content_layer_new, content_layer_old);
+  }
+  content_layer_old = content_layer_new;
+
+  // Go back to testing AVSampleBufferLayer and fullscreen low power.
+  properties.opacity = 1.0;
 
   // Pass a frame with a CVPixelBuffer which, when scaled down, will have a
   // fractional dimension.
+  properties.gl_image = CreateGLImage(
+      gfx::Size(513, 512), gfx::BufferFormat::YUV_420_BIPLANAR, true);
   {
     UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-    content_layer3 = GetOnlyContentLayer();
+    content_layer_new = GetOnlyContentLayer();
 
     // Validate that the layer's size is adjusted to include the fractional
     // width, which works around a macOS bug (https://crbug.com/792632).
-    CGSize layer_size = content_layer3.bounds.size;
+    CGSize layer_size = content_layer_new.bounds.size;
     EXPECT_EQ(256.5, layer_size.width);
     EXPECT_EQ(256, layer_size.height);
   }
-
-  properties.gl_image = CreateGLImage(
-      gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR, false);
+  content_layer_old = content_layer_new;
 
   // Pass a frame that is clipped.
   properties.contents_rect = gfx::RectF(0, 0, 1, 0.9);
+  properties.gl_image = CreateGLImage(
+      gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR, false);
   {
     UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-    content_layer4 = GetOnlyContentLayer();
-
-    // Validate the content layer.
-    EXPECT_FALSE([content_layer4
+    content_layer_new = GetOnlyContentLayer();
+    EXPECT_FALSE([content_layer_new
         isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
-    EXPECT_NE(content_layer4, content_layer3);
+    EXPECT_NE(content_layer_new, content_layer_old);
   }
+  content_layer_old = content_layer_new;
 }
 
 // Ensure that blocklisting AVSampleBufferDisplayLayer works.
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
index 3a34811..60459a3 100644
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
@@ -90,9 +90,10 @@
     bool AddContentLayer(CARendererLayerTree* tree,
                          const CARendererLayerParams& params);
 
-    // Workaround for https://crbug.com/923427. Only allow any
-    // AVSampleBufferDisplayLayer if there is exactly one video quad.
-    void EnforceOnlyOneAVLayer();
+    // Downgrade all downgradeable AVSampleBufferDisplayLayers to be normal
+    // CALayers.
+    // https://crbug.com/923427, https://crbug.com/1143477
+    void DowngradeAVLayersToCALayers();
 
     // Allocate CALayers for this layer and its children, and set their
     // properties appropriately. Re-use the CALayers from |old_layer| if
@@ -200,6 +201,13 @@
     NSString* const ca_filter = nil;
 
     CALayerType type = CALayerType::kDefault;
+
+    // If |type| is CALayerType::kVideo and |video_type_can_downgrade| then
+    // |type| can be downgraded to kDefault. This can be set to false for
+    // HDR video (that cannot be displayed by a regular CALayer) or for
+    // protected content (see https://crbug.com/1026703).
+    bool video_type_can_downgrade = true;
+
     base::scoped_nsobject<CALayer> ca_layer;
 
     // If this layer's contents can be represented as an
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
index 2b3c354..d679412 100644
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
@@ -268,23 +268,14 @@
   return found_video_layer;
 }
 
-void CARendererLayerTree::RootLayer::EnforceOnlyOneAVLayer() {
-  size_t video_layer_count = 0;
+void CARendererLayerTree::RootLayer::DowngradeAVLayersToCALayers() {
   for (auto& clip_layer : clip_and_sorting_layers) {
     for (auto& transform_layer : clip_layer.transform_layers) {
       for (auto& content_layer : transform_layer.content_layers) {
-        if (content_layer.type == CALayerType::kVideo)
-          video_layer_count += 1;
-      }
-    }
-  }
-  if (video_layer_count <= 1)
-    return;
-  for (auto& clip_layer : clip_and_sorting_layers) {
-    for (auto& transform_layer : clip_layer.transform_layers) {
-      for (auto& content_layer : transform_layer.content_layers) {
-        if (content_layer.type == CALayerType::kVideo)
+        if (content_layer.type == CALayerType::kVideo &&
+            content_layer.video_type_can_downgrade) {
           content_layer.type = CALayerType::kDefault;
+        }
       }
     }
   }
@@ -443,18 +434,21 @@
   if (metal::ShouldUseHDRCopier(io_surface, io_surface_color_space)) {
     type = CALayerType::kHDRCopier;
   } else if (io_surface) {
-    switch (IOSurfaceGetPixelFormat(io_surface)) {
-      case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
-      case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
-        // Only allow 4:2:0 frames which fill the layer's contents to be
-        // promoted to AV layers.
-        if (tree->allow_av_sample_buffer_display_layer_ &&
-            contents_rect == gfx::RectF(0, 0, 1, 1)) {
+    // Only allow 4:2:0 frames which fill the layer's contents to be
+    // promoted to AV layers.
+    if (tree->allow_av_sample_buffer_display_layer_ &&
+        contents_rect == gfx::RectF(0, 0, 1, 1)) {
+      switch (IOSurfaceGetPixelFormat(io_surface)) {
+        case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
           type = CALayerType::kVideo;
-        }
-        break;
-      default:
-        break;
+          break;
+        case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
+          type = CALayerType::kVideo;
+          video_type_can_downgrade = false;
+          break;
+        default:
+          break;
+      }
     }
   }
 
@@ -498,6 +492,7 @@
       opacity(layer.opacity),
       ca_filter(layer.ca_filter),
       type(layer.type),
+      video_type_can_downgrade(layer.video_type_can_downgrade),
       ca_layer(std::move(layer.ca_layer)),
       av_layer(std::move(layer.av_layer)) {
   DCHECK(!layer.ca_layer);
@@ -609,9 +604,9 @@
     DLOG(ERROR) << "CARendererLayerTree root layer not attached to tree.";
   }
 
-  EnforceOnlyOneAVLayer();
-
   if (WantsFullcreenLowPowerBackdrop()) {
+    // In fullscreen low power mode there exists a single video layer on a
+    // solid black background.
     const gfx::RectF bg_rect(
         ScaleSize(gfx::SizeF(pixel_size), 1 / scale_factor));
     if (gfx::RectF([ca_layer frame]) != bg_rect)
@@ -623,6 +618,16 @@
       [ca_layer setFrame:CGRectZero];
     if ([ca_layer backgroundColor])
       [ca_layer setBackgroundColor:nil];
+    // We know that we are not in fullscreen low power mode, so there is no
+    // power savings (and a slight power cost) to using
+    // AVSampleBufferDisplayLayer.
+    // https://crbug.com/1143477
+    // We also want to minimize our use of AVSampleBufferDisplayLayer because we
+    // don't track which video element corresponded to which CALayer, and
+    // AVSampleBufferDisplayLayer is not updated with the CATransaction.
+    // Combined, these can result in result in videos jumping around.
+    // https://crbug.com/923427
+    DowngradeAVLayersToCALayers();
   }
 
   for (size_t i = 0; i < clip_and_sorting_layers.size(); ++i) {
diff --git a/ui/android/java/src/org/chromium/ui/base/Clipboard.java b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
index 477418d..1cc2880 100644
--- a/ui/android/java/src/org/chromium/ui/base/Clipboard.java
+++ b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
@@ -424,6 +424,7 @@
      * system. But on Android O, sharing images/files needs to grant permission to each app/packages
      * individually. Note: Don't forget to revoke the permission once the clipboard is updated.
      */
+    @SuppressWarnings("QueryPermissionsNeeded")
     private void grantUriPermission(@NonNull Uri uri) {
         if ((Build.VERSION.SDK_INT != Build.VERSION_CODES.O
                     && Build.VERSION.SDK_INT != Build.VERSION_CODES.O_MR1)
diff --git a/ui/base/page_transition_types.cc b/ui/base/page_transition_types.cc
index b055b4dc..45577be6 100644
--- a/ui/base/page_transition_types.cc
+++ b/ui/base/page_transition_types.cc
@@ -89,6 +89,8 @@
     case PAGE_TRANSITION_RELOAD: return "reload";
     case PAGE_TRANSITION_KEYWORD: return "keyword";
     case PAGE_TRANSITION_KEYWORD_GENERATED: return "keyword_generated";
+    case PAGE_TRANSITION_FROM_API_3:
+      return "api3";
   }
   return NULL;
 }
diff --git a/ui/base/page_transition_types.h b/ui/base/page_transition_types.h
index 01421cd4..5b8425cf 100644
--- a/ui/base/page_transition_types.h
+++ b/ui/base/page_transition_types.h
@@ -111,8 +111,13 @@
   // Any of the core values above can be augmented by one or more qualifiers.
   // These qualifiers further define the transition.
 
-  // TODO(https://crbug.com/1141501): this is for an experiment, and will be
+  // TODO(https://crbug.com/1141501): these are for an experiment, and will be
   // removed once data is collected from experiment.
+  // Both of these transition types are for experiments to exclude visits from
+  // appearing in the omnibox. PAGE_TRANSITION_FROM_API_3 also makes it so
+  // the visit does not surface in the history page. Neither transition type
+  // is used with TYPED.
+  PAGE_TRANSITION_FROM_API_3 = 0x00200000,
   PAGE_TRANSITION_FROM_API_2 = 0x00400000,
 
   // A managed user attempted to visit a URL but was blocked.
diff --git a/ui/base/x/x11_display_util.cc b/ui/base/x/x11_display_util.cc
index b6bfd2d..f5d93cf 100644
--- a/ui/base/x/x11_display_util.cc
+++ b/ui/base/x/x11_display_util.cc
@@ -137,11 +137,10 @@
 // Get the EDID data from the |output| and stores to |edid|.
 std::vector<uint8_t> GetEDIDProperty(x11::RandR* randr,
                                      x11::RandR::Output output) {
-  auto future = randr->GetOutputProperty({
+  auto future = randr->GetOutputProperty(x11::RandR::GetOutputPropertyRequest{
       .output = output,
       .property = gfx::GetAtom(kRandrEdidProperty),
-      .long_length = 128,
-  });
+      .long_length = 128});
   auto response = future.Sync();
   std::vector<uint8_t> edid;
   if (response && response->format == 8 && response->type != x11::Atom::None)
diff --git a/ui/base/x/x11_software_bitmap_presenter.cc b/ui/base/x/x11_software_bitmap_presenter.cc
index 473aa9a..2c0a8bf8 100644
--- a/ui/base/x/x11_software_bitmap_presenter.cc
+++ b/ui/base/x/x11_software_bitmap_presenter.cc
@@ -76,11 +76,11 @@
     connection->CreatePixmap({depth, pixmap_id, widget, width, height});
     ScopedPixmap pixmap(connection, pixmap_id);
 
-    connection->ChangeGC(
-        {.gc = gc, .subwindow_mode = x11::SubwindowMode::IncludeInferiors});
+    connection->ChangeGC(x11::ChangeGCRequest{
+        .gc = gc, .subwindow_mode = x11::SubwindowMode::IncludeInferiors});
     connection->CopyArea({widget, pixmap_id, gc, x, y, 0, 0, width, height});
-    connection->ChangeGC(
-        {.gc = gc, .subwindow_mode = x11::SubwindowMode::ClipByChildren});
+    connection->ChangeGC(x11::ChangeGCRequest{
+        .gc = gc, .subwindow_mode = x11::SubwindowMode::ClipByChildren});
 
     auto req = connection->GetImage({x11::ImageFormat::ZPixmap, pixmap_id, 0, 0,
                                      width, height, kAllPlanes});
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
index 247d833..80f2903 100644
--- a/ui/base/x/x11_util.cc
+++ b/ui/base/x/x11_util.cc
@@ -220,13 +220,13 @@
 }
 
 void RaiseWindow(x11::Window window) {
-  x11::Connection::Get()->ConfigureWindow(
-      {.window = window, .stack_mode = x11::StackMode::Above});
+  x11::Connection::Get()->ConfigureWindow(x11::ConfigureWindowRequest{
+      .window = window, .stack_mode = x11::StackMode::Above});
 }
 
 void LowerWindow(x11::Window window) {
-  x11::Connection::Get()->ConfigureWindow(
-      {.window = window, .stack_mode = x11::StackMode::Below});
+  x11::Connection::Get()->ConfigureWindow(x11::ConfigureWindowRequest{
+      .window = window, .stack_mode = x11::StackMode::Below});
 }
 
 void DefineCursor(x11::Window window, x11::Cursor cursor) {
@@ -235,14 +235,15 @@
   // timing on BookmarkBarViewTest8.DNDBackToOriginatingMenu on
   // linux-chromeos-rel, causing it to flake.
   x11::Connection::Get()
-      ->ChangeWindowAttributes({.window = window, .cursor = cursor})
+      ->ChangeWindowAttributes(x11::ChangeWindowAttributesRequest{
+          .window = window, .cursor = cursor})
       .Sync();
 }
 
 x11::Window CreateDummyWindow(const std::string& name) {
   auto* connection = x11::Connection::Get();
   auto window = connection->GenerateId<x11::Window>();
-  connection->CreateWindow({
+  connection->CreateWindow(x11::CreateWindowRequest{
       .wid = window,
       .parent = connection->default_root(),
       .x = -100,
@@ -560,7 +561,7 @@
 
 bool PropertyExists(x11::Window window, const std::string& property_name) {
   auto response = x11::Connection::Get()
-                      ->GetProperty({
+                      ->GetProperty(x11::GetPropertyRequest{
                           .window = static_cast<x11::Window>(window),
                           .property = gfx::GetAtom(property_name),
                           .long_length = 1,
@@ -573,7 +574,7 @@
                            x11::Atom property,
                            scoped_refptr<base::RefCountedMemory>* out_data,
                            x11::Atom* out_type) {
-  auto future = x11::Connection::Get()->GetProperty({
+  auto future = x11::Connection::Get()->GetProperty(x11::GetPropertyRequest{
       .window = static_cast<x11::Window>(window),
       .property = property,
       // Don't limit the amount of returned data.
diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h
index b5f74bb8..f3f4b48 100644
--- a/ui/base/x/x11_util.h
+++ b/ui/base/x/x11_util.h
@@ -143,11 +143,11 @@
   using lentype = decltype(x11::GetPropertyRequest::long_length);
   auto response =
       x11::Connection::Get()
-          ->GetProperty(
-              {.window = static_cast<x11::Window>(window),
-               .property = name,
-               .long_length =
-                   amount ? length : std::numeric_limits<lentype>::max()})
+          ->GetProperty(x11::GetPropertyRequest{
+              .window = static_cast<x11::Window>(window),
+              .property = name,
+              .long_length =
+                  amount ? length : std::numeric_limits<lentype>::max()})
           .Sync();
   if (!response || response->format != CHAR_BIT * sizeof(T))
     return false;
@@ -178,13 +178,13 @@
   static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "");
   std::vector<uint8_t> data(sizeof(T) * values.size());
   memcpy(data.data(), values.data(), sizeof(T) * values.size());
-  x11::Connection::Get()->ChangeProperty(
-      {.window = static_cast<x11::Window>(window),
-       .property = name,
-       .type = type,
-       .format = CHAR_BIT * sizeof(T),
-       .data_len = values.size(),
-       .data = base::RefCountedBytes::TakeVector(&data)});
+  x11::Connection::Get()->ChangeProperty(x11::ChangePropertyRequest{
+      .window = static_cast<x11::Window>(window),
+      .property = name,
+      .type = type,
+      .format = CHAR_BIT * sizeof(T),
+      .data_len = values.size(),
+      .data = base::RefCountedBytes::TakeVector(&data)});
 }
 
 template <typename T>
diff --git a/ui/base/x/x11_whole_screen_move_loop.cc b/ui/base/x/x11_whole_screen_move_loop.cc
index 1b8bc9f..09a0c5a 100644
--- a/ui/base/x/x11_whole_screen_move_loop.cc
+++ b/ui/base/x/x11_whole_screen_move_loop.cc
@@ -263,7 +263,7 @@
 void X11WholeScreenMoveLoop::CreateDragInputWindow(
     x11::Connection* connection) {
   grab_input_window_ = connection->GenerateId<x11::Window>();
-  connection->CreateWindow({
+  connection->CreateWindow(x11::CreateWindowRequest{
       .wid = grab_input_window_,
       .parent = connection->default_root(),
       .x = -100,
diff --git a/ui/base/x/x11_window.cc b/ui/base/x/x11_window.cc
index ca2f12f..988ffa9 100644
--- a/ui/base/x/x11_window.cc
+++ b/ui/base/x/x11_window.cc
@@ -718,7 +718,7 @@
 
   if (it_below_window != window_below_parents.rend() &&
       it_above_window != window_above_parents.rend()) {
-    connection_->ConfigureWindow({
+    connection_->ConfigureWindow(x11::ConfigureWindowRequest{
         .window = *it_above_window,
         .sibling = *it_below_window,
         .stack_mode = x11::StackMode::Above,
@@ -837,7 +837,7 @@
 }
 
 void XWindow::MoveCursorTo(const gfx::Point& location_in_pixels) {
-  connection_->WarpPointer({
+  connection_->WarpPointer(x11::WarpPointerRequest{
       .dst_window = x_root_window_,
       .dst_x = bounds_in_pixels_.x() + location_in_pixels.x(),
       .dst_y = bounds_in_pixels_.y() + location_in_pixels.y(),
@@ -1424,7 +1424,7 @@
   bool remap = window_mapped_in_client_;
   if (remap)
     Hide();
-  connection_->ChangeWindowAttributes({
+  connection_->ChangeWindowAttributes(x11::ChangeWindowAttributesRequest{
       .window = xwindow_,
       .override_redirect = x11::Bool32(override_redirect),
   });
@@ -1487,7 +1487,7 @@
 void XWindow::UpdateWindowRegion(
     std::unique_ptr<std::vector<x11::Rectangle>> region) {
   auto set_shape = [&](const std::vector<x11::Rectangle>& rectangles) {
-    connection_->shape().Rectangles({
+    connection_->shape().Rectangles(x11::Shape::RectanglesRequest{
         .operation = x11::Shape::So::Set,
         .destination_kind = x11::Shape::Sk::Bounding,
         .ordering = x11::ClipOrdering::YXBanded,
@@ -1515,7 +1515,7 @@
     // If the window has system borders, the mask must be set to null (not a
     // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will
     // not put borders on a window with a custom shape.
-    connection_->shape().Mask({
+    connection_->shape().Mask(x11::Shape::MaskRequest{
         .operation = x11::Shape::So::Set,
         .destination_kind = x11::Shape::Sk::Bounding,
         .destination_window = xwindow_,
diff --git a/ui/base/x/x11_workspace_handler.cc b/ui/base/x/x11_workspace_handler.cc
index 65a7b17..84ae470 100644
--- a/ui/base/x/x11_workspace_handler.cc
+++ b/ui/base/x/x11_workspace_handler.cc
@@ -17,7 +17,7 @@
 
 x11::Future<x11::GetPropertyReply> GetWorkspace() {
   auto* connection = x11::Connection::Get();
-  return connection->GetProperty({
+  return connection->GetProperty(x11::GetPropertyRequest{
       .window = connection->default_screen().root,
       .property = static_cast<x11::Atom>(gfx::GetAtom("_NET_CURRENT_DESKTOP")),
       .type = static_cast<x11::Atom>(gfx::GetAtom("CARDINAL")),
diff --git a/ui/file_manager/file_manager/foreground/elements/files_toast.js b/ui/file_manager/file_manager/foreground/elements/files_toast.js
index 0e2d7a3..80be34b 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_toast.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_toast.js
@@ -104,7 +104,7 @@
    * @private
    */
   onTransitionEnd_() {
-    const hide = !this.$.container.hasAttribute('open');
+    const hide = !this.$.container.open;
 
     if (hide && this.visible) {
       this._setVisible(false);
diff --git a/ui/file_manager/file_manager/foreground/elements/files_toast_unittest.js b/ui/file_manager/file_manager/foreground/elements/files_toast_unittest.js
index d951be5b..d814398a 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_toast_unittest.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_toast_unittest.js
@@ -16,11 +16,17 @@
       await new Promise(r => setTimeout(r, 0));
     }
   };
+  const getToastOpacity = () => {
+    return Number(
+        window.getComputedStyle(toast.shadowRoot.querySelector('cr-toast'))
+            .opacity);
+  };
 
   // Toast is hidden to start.
   assertFalse(toast.visible);
 
-  // Show toast1, verify visible, text and action text.
+  // Show toast1, wait for cr-toast to finish animating, and then verify all the
+  // properties and HTML is correct.
   let a1Called = false;
   toast.show('t1', {
     text: 'a1',
@@ -28,6 +34,7 @@
       a1Called = true;
     }
   });
+  await waitFor(() => getToastOpacity() === 1);
   assertTrue(toast.visible);
   assertEquals('t1', text.innerText);
   assertFalse(action.hidden);
@@ -44,28 +51,36 @@
   toast.show('t3');
   assertEquals('t1', text.innerText);
 
-  // Invoke toast1 action, callback will be called,
-  // and toast2 will show after animation.
+  // Invoke toast1 action, callback will be called.
   action.dispatchEvent(new MouseEvent('click'));
   assertTrue(a1Called);
-  await waitFor(() => text.innerText === 't2');
+
+  // Wait for toast1 to finish hiding and then wait for toast2 to finish
+  // showing.
+  await waitFor(() => getToastOpacity() === 0);
+  await waitFor(() => getToastOpacity() === 1);
+
   assertTrue(toast.visible);
   assertEquals('t2', text.innerText);
   assertFalse(action.hidden);
   assertEquals('a2', action.innerText);
 
-  // Invoke toast2 action, callback will be called,
-  // and toast3 will show after animation with no action.
+  // Invoke toast2 action, callback will be called.
   action.dispatchEvent(new MouseEvent('click'));
   assertTrue(a2Called);
-  await waitFor(() => text.innerText === 't3');
+
+  // Wait for toast2 to finish hiding and wait for toast3 to finish showing.
+  await waitFor(() => getToastOpacity() === 0);
+  await waitFor(() => getToastOpacity() === 1);
+
   assertTrue(toast.visible);
   assertEquals('t3', text.innerText);
   assertTrue(action.hidden);
 
   // Call hide(), toast should no longer be visible, no more toasts shown.
   toast.hide();
-  await waitFor(() => !toast.visible);
+  await waitFor(() => getToastOpacity() === 0);
+  assertFalse(toast.visible);
 
   done();
 }
diff --git a/ui/file_manager/gallery/js/gallery_scripts.js b/ui/file_manager/gallery/js/gallery_scripts.js
index 8cbb3fd..94d7d84 100644
--- a/ui/file_manager/gallery/js/gallery_scripts.js
+++ b/ui/file_manager/gallery/js/gallery_scripts.js
@@ -17,6 +17,7 @@
 // <include src="../../image_loader/image_loader_client.js">
 
 // <include src="../../../webui/resources/js/cr.js">
+// <include src="../../../webui/resources/js/assert.js">
 // <include src="../../../webui/resources/js/util.js">
 // <include src="../../../webui/resources/js/event_tracker.js">
 // <include src="../../../webui/resources/js/load_time_data.js">
diff --git a/ui/file_manager/video_player/js/video_player_scripts.js b/ui/file_manager/video_player/js/video_player_scripts.js
index 1a339792..d062ba1a 100644
--- a/ui/file_manager/video_player/js/video_player_scripts.js
+++ b/ui/file_manager/video_player/js/video_player_scripts.js
@@ -14,6 +14,7 @@
 // <include src="video_player_metrics.js">
 
 // <include src="../../../webui/resources/js/cr.js">
+// <include src="../../../webui/resources/js/assert.js">
 // <include src="../../../webui/resources/js/util.js">
 // <include src="../../../webui/resources/js/load_time_data.js">
 
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index a77a629..800e2d30 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -39,6 +39,8 @@
 component("geometry_skia") {
   sources = [
     "geometry_skia_export.h",
+    "mask_filter_info.cc",
+    "mask_filter_info.h",
     "rrect_f.cc",
     "rrect_f.h",
     "rrect_f_builder.cc",
diff --git a/ui/gfx/mask_filter_info.cc b/ui/gfx/mask_filter_info.cc
new file mode 100644
index 0000000..06ca28f
--- /dev/null
+++ b/ui/gfx/mask_filter_info.cc
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/mask_filter_info.h"
+
+#include <sstream>
+
+#include "ui/gfx/transform.h"
+
+namespace gfx {
+
+bool MaskFilterInfo::Transform(const gfx::Transform& transform) {
+  return rounded_corner_bounds_.IsEmpty()
+             ? false
+             : transform.TransformRRectF(&rounded_corner_bounds_);
+}
+
+std::string MaskFilterInfo::ToString() const {
+  return "MaskFilterInfo{" + rounded_corner_bounds_.ToString() + "}";
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/mask_filter_info.h b/ui/gfx/mask_filter_info.h
new file mode 100644
index 0000000..8ce56fc6
--- /dev/null
+++ b/ui/gfx/mask_filter_info.h
@@ -0,0 +1,64 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_MASK_FILTER_INFO_H_
+#define UI_GFX_MASK_FILTER_INFO_H_
+
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry_skia_export.h"
+#include "ui/gfx/rrect_f.h"
+
+namespace gfx {
+
+class Transform;
+
+// This class defines a mask filter to be applied to the given rect.
+class GEOMETRY_SKIA_EXPORT MaskFilterInfo {
+ public:
+  MaskFilterInfo() = default;
+  explicit MaskFilterInfo(const RRectF& rrect)
+      : rounded_corner_bounds_(rrect) {}
+  MaskFilterInfo(const RectF& bounds, const RoundedCornersF& radii)
+      : rounded_corner_bounds_(bounds, radii) {}
+  MaskFilterInfo(const MaskFilterInfo& copy) = default;
+  ~MaskFilterInfo() = default;
+
+  // The bounds the filter will be applied to.
+  RectF bounds() const { return rounded_corner_bounds_.rect(); }
+
+  // Defines the rounded corner bounds to clip.
+  const RRectF& rounded_corner_bounds() const { return rounded_corner_bounds_; }
+
+  // True if this contains a rounded corner mask.
+  bool HasRoundedCorners() const {
+    return rounded_corner_bounds_.GetType() != RRectF::Type::kEmpty &&
+           rounded_corner_bounds_.GetType() != RRectF::Type::kRect;
+  }
+
+  // True if this contains no effective mask information.
+  bool IsEmpty() const { return rounded_corner_bounds_.IsEmpty(); }
+
+  // Transform the mask information. Returns false if the transform
+  // cannot be applied.
+  bool Transform(const gfx::Transform& transform);
+
+  std::string ToString() const;
+
+ private:
+  // The rounded corner bounds. This also defines the bounds that the mask
+  // filter will be applied to.
+  RRectF rounded_corner_bounds_;
+};
+
+inline bool operator==(const MaskFilterInfo& lhs, const MaskFilterInfo& rhs) {
+  return lhs.rounded_corner_bounds() == rhs.rounded_corner_bounds();
+}
+
+inline bool operator!=(const MaskFilterInfo& lhs, const MaskFilterInfo& rhs) {
+  return !(lhs == rhs);
+}
+
+}  // namespace gfx
+
+#endif  // UI_GFX_MASK_FILTER_INFO_H_
diff --git a/ui/gfx/mojom/BUILD.gn b/ui/gfx/mojom/BUILD.gn
index 41796dc8a..5bb6fa7 100644
--- a/ui/gfx/mojom/BUILD.gn
+++ b/ui/gfx/mojom/BUILD.gn
@@ -15,6 +15,7 @@
     "font_render_params.mojom",
     "gpu_extra_info.mojom",
     "gpu_fence_handle.mojom",
+    "mask_filter_info.mojom",
     "overlay_transform.mojom",
     "presentation_feedback.mojom",
     "rrect_f.mojom",
@@ -226,6 +227,17 @@
       traits_headers = [ "swap_result_mojom_traits.h" ]
       traits_public_deps = [ "//ui/gfx" ]
     },
+    {
+      types = [
+        {
+          mojom = "gfx.mojom.MaskFilterInfo"
+          cpp = "::gfx::MaskFilterInfo"
+        },
+      ]
+      traits_sources = [ "mask_filter_info_mojom_traits.cc" ]
+      traits_headers = [ "mask_filter_info_mojom_traits.h" ]
+      traits_public_deps = [ "//ui/gfx" ]
+    },
   ]
 
   cpp_typemaps += shared_cpp_typemaps
diff --git a/ui/gfx/mojom/mask_filter_info.mojom b/ui/gfx/mojom/mask_filter_info.mojom
new file mode 100644
index 0000000..7e3b9ea
--- /dev/null
+++ b/ui/gfx/mojom/mask_filter_info.mojom
@@ -0,0 +1,12 @@
+// Copyright 2020 The Chromium 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 gfx.mojom;
+
+import "ui/gfx/mojom/rrect_f.mojom";
+
+// See ui/gfx/mask_filter_info.h.
+struct MaskFilterInfo {
+  gfx.mojom.RRectF rounded_corner_bounds;
+};
diff --git a/ui/gfx/mojom/mask_filter_info_mojom_traits.cc b/ui/gfx/mojom/mask_filter_info_mojom_traits.cc
new file mode 100644
index 0000000..683762ae
--- /dev/null
+++ b/ui/gfx/mojom/mask_filter_info_mojom_traits.cc
@@ -0,0 +1,19 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/mojom/mask_filter_info_mojom_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<gfx::mojom::MaskFilterInfoDataView, gfx::MaskFilterInfo>::
+    Read(gfx::mojom::MaskFilterInfoDataView data, gfx::MaskFilterInfo* out) {
+  gfx::RRectF bounds;
+  if (!data.ReadRoundedCornerBounds(&bounds))
+    return false;
+  *out = gfx::MaskFilterInfo(bounds);
+  return true;
+}
+
+}  // namespace mojo
diff --git a/ui/gfx/mojom/mask_filter_info_mojom_traits.h b/ui/gfx/mojom/mask_filter_info_mojom_traits.h
new file mode 100644
index 0000000..0cc30b3
--- /dev/null
+++ b/ui/gfx/mojom/mask_filter_info_mojom_traits.h
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_MOJOM_MASK_FILTER_INFO_MOJOM_TRAITS_H_
+#define UI_GFX_MOJOM_MASK_FILTER_INFO_MOJOM_TRAITS_H_
+
+#include "ui/gfx/mask_filter_info.h"
+#include "ui/gfx/mojom/mask_filter_info.mojom-shared.h"
+#include "ui/gfx/mojom/rrect_f_mojom_traits.h"
+
+namespace mojo {
+template <>
+struct StructTraits<gfx::mojom::MaskFilterInfoDataView, gfx::MaskFilterInfo> {
+  static const gfx::RRectF& rounded_corner_bounds(
+      const gfx::MaskFilterInfo& info) {
+    return info.rounded_corner_bounds();
+  }
+
+  static bool Read(gfx::mojom::MaskFilterInfoDataView data,
+                   gfx::MaskFilterInfo* out);
+};
+
+}  // namespace mojo
+#endif  // UI_GFX_MOJOM_LINEAR_GRADIENT_MOJOM_TRAITS_H_
diff --git a/ui/webui/resources/cr_elements/cr_toast/cr_toast.html b/ui/webui/resources/cr_elements/cr_toast/cr_toast.html
index 8b54718..4433d933 100644
--- a/ui/webui/resources/cr_elements/cr_toast/cr_toast.html
+++ b/ui/webui/resources/cr_elements/cr_toast/cr_toast.html
@@ -37,7 +37,7 @@
         padding: 0 24px;
         position: fixed;
         transform: translateY(100px);
-        transition: opacity 300ms, transform 300ms, visibility 300ms;
+        transition: opacity 300ms, transform 300ms;
         visibility: hidden;
         z-index: 1;
       }
diff --git a/ui/webui/resources/tools/generate_grd.py b/ui/webui/resources/tools/generate_grd.py
index 44d5de9b..d65706e 100644
--- a/ui/webui/resources/tools/generate_grd.py
+++ b/ui/webui/resources/tools/generate_grd.py
@@ -66,6 +66,10 @@
 GRD_INCLUDE_TEMPLATE = '      <include name="{name}" ' \
                        'file="{file}" resource_path="{path}" ' \
                        'use_base_dir="false" type="{type}" />\n'
+GRD_INCLUDE_TEMPLATE_PP = '      <include name="{name}" ' \
+                          'file="{file}" resource_path="{path}" ' \
+                          'use_base_dir="false" preprocess="true" '\
+                          'type="{type}" />\n'
 
 GRD_END_TEMPLATE = '    </includes>\n'\
                    '  </release>\n'\
@@ -91,6 +95,16 @@
   if resource_path_prefix != None:
     resource_path = resource_path_prefix + '/' + resource_path
 
+  # This is a temporary workaround, since Polymer 2 shared resource files are
+  # not preprocessed.
+  # TODO(rbpotter): Remove this once OS Settings has been migrated to Polymer 3.
+  if ('vulcanized' in pathname or 'crisper' in pathname):
+    return GRD_INCLUDE_TEMPLATE_PP.format(
+        file=pathname,
+        path=resource_path,
+        name=name,
+        type=type)
+
   return GRD_INCLUDE_TEMPLATE.format(
       file=pathname,
       path=resource_path,
diff --git a/url/origin.cc b/url/origin.cc
index 14d35e1..923360e 100644
--- a/url/origin.cc
+++ b/url/origin.cc
@@ -287,11 +287,20 @@
   DCHECK_EQ(0U, port());
 }
 
+base::Optional<std::string> Origin::SerializeWithNonce() const {
+  return SerializeWithNonceImpl();
+}
+
+base::Optional<std::string> Origin::SerializeWithNonceAndInitIfNeeded() {
+  GetNonceForSerialization();
+  return SerializeWithNonceImpl();
+}
+
 // The pickle is saved in the following format, in order:
 // string - tuple_.GetURL().spec().
 // uint64_t (if opaque) - high bits of nonce if opaque. 0 if not initialized.
 // uint64_t (if opaque) - low bits of nonce if opaque. 0 if not initialized.
-base::Optional<std::string> Origin::SerializeWithNonce() const {
+base::Optional<std::string> Origin::SerializeWithNonceImpl() const {
   if (!opaque() && !tuple_.IsValid())
     return base::nullopt;
 
diff --git a/url/origin.h b/url/origin.h
index d8ad572a..2257a1b 100644
--- a/url/origin.h
+++ b/url/origin.h
@@ -58,6 +58,7 @@
 namespace net {
 class NetworkIsolationKey;
 class OpaqueNonTransientNetworkIsolationKeyTest;
+class SchemefulSite;
 }  // namespace net
 
 namespace url {
@@ -299,6 +300,9 @@
  private:
   friend class blink::SecurityOrigin;
   friend class net::NetworkIsolationKey;
+  // SchemefulSite needs access to the serialization/deserialization logic which
+  // includes the nonce.
+  friend class net::SchemefulSite;
   friend class net::OpaqueNonTransientNetworkIsolationKeyTest;
   friend class OriginTest;
   friend struct mojo::UrlOriginAdapter;
@@ -395,11 +399,17 @@
   base::Optional<base::UnguessableToken> GetNonceForSerialization() const;
 
   // Serializes this Origin, including its nonce if it is opaque. If an opaque
-  // origin's |tuple_| is invalid or the nonce isn't initialized, nullopt is
-  // returned. Use of this method should be limited as an opaque origin will
-  // never be matchable in future browser sessions.
+  // origin's |tuple_| is invalid nullopt is returned. If the nonce is not
+  // initialized, a nonce of 0 is used. Use of this method should be limited as
+  // an opaque origin will never be matchable in future browser sessions.
   base::Optional<std::string> SerializeWithNonce() const;
 
+  // Like SerializeWithNonce(), but forces |nonce_| to be initialized prior to
+  // serializing.
+  base::Optional<std::string> SerializeWithNonceAndInitIfNeeded();
+
+  base::Optional<std::string> SerializeWithNonceImpl() const;
+
   // Deserializes an origin from |ToValueWithNonce|. Returns nullopt if the
   // value was invalid in any way.
   static base::Optional<Origin> Deserialize(const std::string& value);
diff --git a/url/origin_unittest.cc b/url/origin_unittest.cc
index dccb7ba..30c7c63 100644
--- a/url/origin_unittest.cc
+++ b/url/origin_unittest.cc
@@ -109,6 +109,11 @@
     return origin.SerializeWithNonce();
   }
 
+  base::Optional<std::string> SerializeWithNonceAndInitIfNeeded(
+      Origin& origin) {
+    return origin.SerializeWithNonceAndInitIfNeeded();
+  }
+
   base::Optional<Origin> Deserialize(const std::string& value) {
     return Origin::Deserialize(value);
   }
@@ -933,6 +938,19 @@
   // Can't use DoEqualityComparisons here since empty nonces are never == unless
   // they are the same object.
   EXPECT_EQ(opaque.GetDebugString(), deserialized.value().GetDebugString());
+
+  // Now force initialization of the nonce prior to serialization.
+  for (const GURL& url : invalid_urls) {
+    SCOPED_TRACE(url.spec());
+    Origin origin = Origin::Create(url);
+    base::Optional<std::string> serialized =
+        SerializeWithNonceAndInitIfNeeded(origin);
+    base::Optional<Origin> deserialized = Deserialize(std::move(*serialized));
+    ASSERT_TRUE(deserialized.has_value());
+
+    // The nonce should have been initialized prior to Serialization().
+    EXPECT_EQ(origin, deserialized.value());
+  }
 }
 
 TEST_F(OriginTest, DeserializeValidNonce) {
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/GeolocationTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/GeolocationTest.java
index d8bb8009..f3b22ec9 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/GeolocationTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/GeolocationTest.java
@@ -27,11 +27,11 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.InMemorySharedPreferencesContext;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.net.test.util.TestWebServer;
 import org.chromium.weblayer.Browser;
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/MediaRouterTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/MediaRouterTest.java
index d0a68230..888a910 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/MediaRouterTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/MediaRouterTest.java
@@ -5,6 +5,7 @@
 package org.chromium.weblayer.test;
 
 import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE;
+import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking;
 
 import android.support.test.InstrumentationRegistry;
 import android.view.View;
@@ -24,8 +25,11 @@
 import org.chromium.content_public.browser.test.util.ClickUtils;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
+import org.chromium.content_public.browser.test.util.TestTouchUtils;
 import org.chromium.content_public.common.ContentSwitches;
 import org.chromium.ui.test.util.UiRestriction;
+import org.chromium.weblayer.Browser;
+import org.chromium.weblayer.Tab;
 import org.chromium.weblayer.TestWebLayer;
 import org.chromium.weblayer.shell.InstrumentationActivity;
 
@@ -48,32 +52,63 @@
     private static final int SCRIPT_RETRY_MS = 150;
 
     private static final String TEST_SINK_NAME = "test-sink-1";
-    // The javascript snippets.
-    private static final String UNSET_RESULT_SCRIPT = "lastExecutionResult = null";
-    private static final String GET_RESULT_SCRIPT = "lastExecutionResult";
+
+    // Javascript snippets.
     private static final String WAIT_DEVICE_SCRIPT = "waitUntilDeviceAvailable();";
     private static final String START_PRESENTATION_SCRIPT = "startPresentation();";
-    private static final String CHECK_CONNECTION_SCRIPT = "checkConnection();";
     private static final String TERMINATE_CONNECTION_SCRIPT =
             "terminateConnectionAndWaitForStateChange();";
 
     @Before
-    public void setUp() throws Exception {
+    public void setUp() {
         mActivity = mActivityTestRule.launchShellWithUrl("about:blank");
-        TestWebLayer.getTestWebLayer(mActivity.getApplicationContext())
-                .initializeMockMediaRouteProvider();
     }
 
-    private void executeJavaScriptApi(String script) throws Exception {
-        mActivityTestRule.executeScriptSync(UNSET_RESULT_SCRIPT, false);
+    private TestWebLayer getTestWebLayer() {
+        return TestWebLayer.getTestWebLayer(mActivity.getApplicationContext());
+    }
+
+    private void executeScriptAndWaitForResult(String script) throws Exception {
+        mActivityTestRule.executeScriptSync("lastExecutionResult = null", false);
         mActivityTestRule.executeScriptSync(script, false);
         CriteriaHelper.pollInstrumentationThread(() -> {
             String result =
-                    mActivityTestRule.executeScriptAndExtractString(GET_RESULT_SCRIPT, false);
+                    mActivityTestRule.executeScriptAndExtractString("lastExecutionResult", false);
             Criteria.checkThat(result, Matchers.is("passed"));
         }, SCRIPT_TIMEOUT_MS, SCRIPT_RETRY_MS);
     }
 
+    private void startPresentationAndSelectRoute() throws Exception {
+        // Request a presentation.
+        mActivityTestRule.navigateAndWait(mActivityTestRule.getTestDataURL(TEST_PAGE));
+        executeScriptAndWaitForResult(WAIT_DEVICE_SCRIPT);
+        executeScriptAndWaitForResult(START_PRESENTATION_SCRIPT);
+
+        // Verify the route selection dialog is showing and make a selection.
+        View testRouteButton = getTestWebLayer().getMediaRouteButton(TEST_SINK_NAME);
+        Assert.assertNotNull(testRouteButton);
+        ClickUtils.mouseSingleClickView(
+                InstrumentationRegistry.getInstrumentation(), testRouteButton);
+    }
+
+    private String verifyPresentationStarted() throws Exception {
+        // Verify in javascript that a presentation has started.
+        executeScriptAndWaitForResult("checkConnection();");
+        String connectionId =
+                mActivityTestRule.executeScriptAndExtractString("startedConnection.id", false);
+        Assert.assertFalse(connectionId.isEmpty());
+        String defaultRequestConnectionId = mActivityTestRule.executeScriptAndExtractString(
+                "defaultRequestConnectionId", false);
+        Assert.assertEquals(connectionId, defaultRequestConnectionId);
+        return connectionId;
+    }
+
+    void checkStartFailed(String errorName, String errorMessageSubstring) throws Exception {
+        String script =
+                String.format("checkStartFailed('%s', '%s');", errorName, errorMessageSubstring);
+        executeScriptAndWaitForResult(script);
+    }
+
     /**
      * Basic test where the page requests a route, the user selects a route, and a connection is
      * started.
@@ -83,26 +118,155 @@
     @Feature({"MediaRouter"})
     @LargeTest
     public void testBasic() throws Exception {
+        getTestWebLayer().initializeMockMediaRouteProvider(/*closeRouteWithErrorOnSend=*/false,
+                /*disableIsSupportsSource=*/false, /*createRouteErrorMessage=*/null,
+                /*joinRouteErrorMessage=*/null);
+        startPresentationAndSelectRoute();
+        verifyPresentationStarted();
+
+        executeScriptAndWaitForResult(TERMINATE_CONNECTION_SCRIPT);
+    }
+
+    /** Test of PresentationConnection.onmessage. */
+    @Test
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    @Feature({"MediaRouter"})
+    @LargeTest
+    public void testSendAndOnMessage() throws Exception {
+        getTestWebLayer().initializeMockMediaRouteProvider(/*closeRouteWithErrorOnSend=*/false,
+                /*disableIsSupportsSource=*/false, /*createRouteErrorMessage=*/null,
+                /*joinRouteErrorMessage=*/null);
+        startPresentationAndSelectRoute();
+        verifyPresentationStarted();
+
+        executeScriptAndWaitForResult("sendMessageAndExpectResponse('foo');");
+    }
+
+    /** Test of PresentationConnection.onclose. */
+    @Test
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    @Feature({"MediaRouter"})
+    @LargeTest
+    public void testOnClose() throws Exception {
+        getTestWebLayer().initializeMockMediaRouteProvider(/*closeRouteWithErrorOnSend=*/true,
+                /*disableIsSupportsSource=*/false, /*createRouteErrorMessage=*/null,
+                /*joinRouteErrorMessage=*/null);
+        startPresentationAndSelectRoute();
+        verifyPresentationStarted();
+
+        executeScriptAndWaitForResult("sendMessageAndExpectConnectionCloseOnError()");
+    }
+
+    /**
+     * Test that starting the presentation fails when there are no providers that support the given
+     * source.
+     */
+    @Test
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    @Feature({"MediaRouter"})
+    @LargeTest
+    public void testFailNoProvider() throws Exception {
+        getTestWebLayer().initializeMockMediaRouteProvider(/*closeRouteWithErrorOnSend=*/false,
+                /*disableIsSupportsSource=*/true, /*createRouteErrorMessage=*/null,
+                /*joinRouteErrorMessage=*/null);
+
+        startPresentationAndSelectRoute();
+        checkStartFailed("UnknownError", "No provider supports createRoute with source");
+    }
+
+    /** Tests route creation failure. */
+    @Test
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    @Feature({"MediaRouter"})
+    @LargeTest
+    public void testFailCreateRoute() throws Exception {
+        getTestWebLayer().initializeMockMediaRouteProvider(/*closeRouteWithErrorOnSend=*/false,
+                /*disableIsSupportsSource=*/false, /*createRouteErrorMessage=*/"Unknown sink",
+                /*joinRouteErrorMessage=*/null);
+
+        startPresentationAndSelectRoute();
+        checkStartFailed("UnknownError", "Unknown sink");
+    }
+
+    /** Tests reconnecting to a presentation (joining a route) from a new tab. */
+    @Test
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    @Feature({"MediaRouter"})
+    @LargeTest
+    public void testJoinRoute() throws Exception {
+        getTestWebLayer().initializeMockMediaRouteProvider(/*closeRouteWithErrorOnSend=*/false,
+                /*disableIsSupportsSource=*/false, /*createRouteErrorMessage=*/null,
+                /*joinRouteErrorMessage=*/null);
+
+        startPresentationAndSelectRoute();
+        String connectionId = verifyPresentationStarted();
+
+        Tab firstTab = mActivity.getTab();
+        Tab secondTab = runOnUiThreadBlocking(() -> {
+            Browser browser = mActivity.getTab().getBrowser();
+            Tab tab = browser.createTab();
+            browser.setActiveTab(tab);
+            return tab;
+        });
+        mActivityTestRule.navigateAndWait(
+                secondTab, mActivityTestRule.getTestDataURL(TEST_PAGE), true);
+        executeScriptAndWaitForResult(String.format("reconnectConnection(\'%s\');", connectionId));
+        String reconnectedConnectionId =
+                mActivityTestRule.executeScriptAndExtractString("reconnectedConnection.id", false);
+        Assert.assertEquals(connectionId, reconnectedConnectionId);
+
+        runOnUiThreadBlocking(() -> { firstTab.getBrowser().setActiveTab(firstTab); });
+        executeScriptAndWaitForResult(TERMINATE_CONNECTION_SCRIPT);
+    }
+
+    /** Tests failure of reconnecting to a presentation (joining a route) from a new tab. */
+    @Test
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    @Feature({"MediaRouter"})
+    @LargeTest
+    public void testFailureToJoinRoute() throws Exception {
+        getTestWebLayer().initializeMockMediaRouteProvider(/*closeRouteWithErrorOnSend=*/false,
+                /*disableIsSupportsSource=*/false, /*createRouteErrorMessage=*/null,
+                /*joinRouteErrorMessage=*/"Unknown route");
+
+        startPresentationAndSelectRoute();
+        String connectionId = verifyPresentationStarted();
+
+        Tab secondTab = runOnUiThreadBlocking(() -> {
+            Browser browser = mActivity.getTab().getBrowser();
+            Tab tab = browser.createTab();
+            browser.setActiveTab(tab);
+            return tab;
+        });
+        mActivityTestRule.navigateAndWait(
+                secondTab, mActivityTestRule.getTestDataURL(TEST_PAGE), true);
+        executeScriptAndWaitForResult(
+                String.format("reconnectConnectionAndExpectFailure(\'%s\');", connectionId));
+    }
+
+    /** Tests the user cancelling the media route selection process. */
+    @Test
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    @Feature({"MediaRouter"})
+    @LargeTest
+    public void testFailStartCancelled() throws Exception {
+        getTestWebLayer().initializeMockMediaRouteProvider(/*closeRouteWithErrorOnSend=*/false,
+                /*disableIsSupportsSource=*/false, /*createRouteErrorMessage=*/null,
+                /*joinRouteErrorMessage=*/null);
+
         // Request a presentation.
         mActivityTestRule.navigateAndWait(mActivityTestRule.getTestDataURL(TEST_PAGE));
-        executeJavaScriptApi(WAIT_DEVICE_SCRIPT);
-        executeJavaScriptApi(START_PRESENTATION_SCRIPT);
+        executeScriptAndWaitForResult(WAIT_DEVICE_SCRIPT);
+        executeScriptAndWaitForResult(START_PRESENTATION_SCRIPT);
 
-        // Verify the route selection dialog is showing and make a selection.
-        View testRouteButton = TestWebLayer.getTestWebLayer(mActivity.getApplicationContext())
-                                       .getMediaRouteButton(TEST_SINK_NAME);
+        // Verify the route selection dialog is showing but then dismiss it.
+        View testRouteButton = getTestWebLayer().getMediaRouteButton(TEST_SINK_NAME);
         Assert.assertNotNull(testRouteButton);
-        ClickUtils.mouseSingleClickView(
-                InstrumentationRegistry.getInstrumentation(), testRouteButton);
 
-        // Verify in javascript that a presentation has started.
-        executeJavaScriptApi(CHECK_CONNECTION_SCRIPT);
-        String connectionId =
-                mActivityTestRule.executeScriptAndExtractString("startedConnection.id");
-        Assert.assertFalse(connectionId.isEmpty());
-        String defaultRequestConnectionId =
-                mActivityTestRule.executeScriptAndExtractString("defaultRequestConnectionId");
-        Assert.assertEquals(connectionId, defaultRequestConnectionId);
-        executeJavaScriptApi(TERMINATE_CONNECTION_SCRIPT);
+        // Click outside the dialog to dismiss it.
+        View topContents = mActivity.getTopContentsContainer();
+        TestTouchUtils.singleClick(
+                InstrumentationRegistry.getInstrumentation(), 1, topContents.getHeight() + 10);
+        checkStartFailed("NotAllowedError", "Dialog closed.");
     }
 }
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/PageInfoTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/PageInfoTest.java
index d4a2658..bec2ac8 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/PageInfoTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/PageInfoTest.java
@@ -19,8 +19,8 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.StrictModeContext;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.weblayer.TestWebLayer;
 import org.chromium.weblayer.shell.InstrumentationActivity;
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/SmokeTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/SmokeTest.java
index 56d19350..05b2772a 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/SmokeTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/SmokeTest.java
@@ -16,9 +16,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.weblayer.shell.InstrumentationActivity;
 
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/test/TestWebLayerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/test/TestWebLayerImpl.java
index cb9d38f2..32d8dbd 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/test/TestWebLayerImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/test/TestWebLayerImpl.java
@@ -199,8 +199,25 @@
     }
 
     @Override
-    public void initializeMockMediaRouteProvider() {
+    public void initializeMockMediaRouteProvider(boolean closeRouteWithErrorOnSend,
+            boolean disableIsSupportsSource, String createRouteErrorMessage,
+            String joinRouteErrorMessage) {
         BrowserMediaRouter.setRouteProviderFactoryForTest(new MockMediaRouteProvider.Factory());
+
+        if (closeRouteWithErrorOnSend) {
+            MockMediaRouteProvider.Factory.sProvider.setCloseRouteWithErrorOnSend(true);
+        }
+        if (disableIsSupportsSource) {
+            MockMediaRouteProvider.Factory.sProvider.setIsSupportsSource(false);
+        }
+        if (createRouteErrorMessage != null) {
+            MockMediaRouteProvider.Factory.sProvider.setCreateRouteErrorMessage(
+                    createRouteErrorMessage);
+        }
+        if (joinRouteErrorMessage != null) {
+            MockMediaRouteProvider.Factory.sProvider.setJoinRouteErrorMessage(
+                    joinRouteErrorMessage);
+        }
     }
 
     @Override
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl b/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl
index 59cd69e..ca301fe 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl
+++ b/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl
@@ -4,6 +4,7 @@
 
 package org.chromium.weblayer_private.test_interfaces;
 
+import android.os.Bundle;
 import org.chromium.weblayer_private.interfaces.IObjectWrapper;
 import org.chromium.weblayer_private.interfaces.ITab;
 
@@ -55,7 +56,9 @@
   boolean didShowFullscreenToast(in ITab tab) = 17;
 
   // Does setup for MediaRouter tests, mocking out Chromecast devices.
-  void initializeMockMediaRouteProvider() = 18;
+  void initializeMockMediaRouteProvider(
+      boolean closeRouteWithErrorOnSend, boolean disableIsSupportsSource,
+      in String createRouteErrorMessage, in String joinRouteErrorMessage) = 18;
 
   // Gets a button from the currently visible media route selection dialog. The button represents a
   // route and contains the text |name|. Returns null if no such dialog or button exists.
diff --git a/weblayer/public/javatestutil/org/chromium/weblayer/TestWebLayer.java b/weblayer/public/javatestutil/org/chromium/weblayer/TestWebLayer.java
index 63b2bee3..6656156 100644
--- a/weblayer/public/javatestutil/org/chromium/weblayer/TestWebLayer.java
+++ b/weblayer/public/javatestutil/org/chromium/weblayer/TestWebLayer.java
@@ -139,8 +139,11 @@
         return mITestWebLayer.didShowFullscreenToast(tab.getITab());
     }
 
-    public void initializeMockMediaRouteProvider() throws RemoteException {
-        mITestWebLayer.initializeMockMediaRouteProvider();
+    public void initializeMockMediaRouteProvider(boolean closeRouteWithErrorOnSend,
+            boolean disableIsSupportsSource, @Nullable String createRouteErrorMessage,
+            @Nullable String joinRouteErrorMessage) throws RemoteException {
+        mITestWebLayer.initializeMockMediaRouteProvider(closeRouteWithErrorOnSend,
+                disableIsSupportsSource, createRouteErrorMessage, joinRouteErrorMessage);
     }
 
     public View getMediaRouteButton(String name) throws RemoteException {
diff --git a/weblayer/test/data/media_router/common.js b/weblayer/test/data/media_router/common.js
index 114165ba..53f2215 100644
--- a/weblayer/test/data/media_router/common.js
+++ b/weblayer/test/data/media_router/common.js
@@ -290,11 +290,11 @@
 /**
  * Calls reconnect(connectionId) and verifies that it fails.
  * @param {!string} connectionId ID of connection to reconnect.
- * @param {!string} expectedErrorMessage
  */
 function reconnectConnectionAndExpectFailure(
-    connectionId, expectedErrorMessage) {
+    connectionId) {
   var reconnectConnectionRequest = new PresentationRequest(presentationUrl);
+  var expectedErrorMessage = 'Unknown route';
   reconnectConnectionRequest.reconnect(connectionId)
       .then(function(connection) {
         sendResult(false, 'reconnect() unexpectedly succeeded.');