diff --git a/DEPS b/DEPS
index 3820d963..295542ff 100644
--- a/DEPS
+++ b/DEPS
@@ -245,7 +245,7 @@
   # 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': '112f9f1273ef9505673c4a5154a2f9d8cc929d23',
+  'skia_revision': '87ced29082dba285f3c5f7f763bda906191cf354',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -320,7 +320,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'eba1a96f6793a1360b99f86597632af9e565b953',
+  'devtools_frontend_revision': '85c29e982d6574fcf9bd48875a70e720d195fea4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -722,7 +722,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/linux-amd64',
-          'version': '6Tedy7sNUuGxQonFLNS-cNqwCuei42vo8V4kHVA1VEYC',
+          'version': 'vYgH0GbTQNVjRMtt15gEkKoqlY0FhG33N87v_dmmbncC',
         },
       ],
       'dep_type': 'cipd',
@@ -733,7 +733,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': 'YeHsBYNVPaSD3APzBkAWSm87R40cALe68s52fVUvlTkC',
+          'version': '8U89GphSBwmWWUP7Cd_rd0X0S0E5QwXwyAZ6Qfhx3usC',
         },
       ],
       'dep_type': 'cipd',
@@ -744,7 +744,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/windows-amd64',
-          'version': 'cxcXx7pnzR_s9RsYCFVuHp7syDOa5VOx4lQvokSjk3IC',
+          'version': 'JbHSIdHFMOq3WzVVAqvQ9ECPOFSDUHkquSqY4jJbUscC',
         },
       ],
       'dep_type': 'cipd',
@@ -805,7 +805,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'ZFybfM9WA_ZDTzPoqqNyWkYnKhc-eKP-qu_wHennQ34C',
+          'version': 'HODW6m8VayryUJucacS9PY8PR4FM7dBYoYjG6f3eKukC',
       },
     ],
     'condition': 'checkout_android',
@@ -1044,7 +1044,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'db41eed6b7442273b54bac9695567d97b60718de',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '54c265ea2b2fc90ae29fc87366cffc0a5e57f7c4',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1583,7 +1583,7 @@
     Var('swiftshader_git') + '/SwiftShader.git' + '@' +  Var('swiftshader_revision'),
 
   'src/third_party/text-fragments-polyfill/src': {
-    'url': Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + '04c058c92fc5be41f91db654b9e903ade4fca27e',
+    'url': Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'ea30795d4a95a1850aff9f52f37ea3146260403e',
     'condition': 'checkout_ios',
   },
 
@@ -1648,7 +1648,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'c843f8d63c8c17acfbb7d48e09059a581ba779b9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'ce702dbbe4e86d5248a6ad4b13475cc166dd02a8',
+    Var('webrtc_git') + '/src.git' + '@' + '8d6cd55b60176da8f975da9f4ee1143e01a09db1',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1730,7 +1730,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0b962ed90d3d4a7a9b8561dd52e0910ed8a7ed2b',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3c3863829f5177f88561647211b56cae27ee6030',
     'condition': 'checkout_src_internal',
   },
 
@@ -1760,7 +1760,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'huP5FRrbgw-tHl9bdM4-qlL3hrfYHTOXmzc2xcJQQYMC',
+        'version': 'RzDWpfmi2CqSz2ZX8kwgQTvcycW3-Co8uCieXmHyzSgC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1771,7 +1771,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': '4RiezqEg5sHwAct7NoR1oxnGBRbhs8iTOjB3hI6uLdAC',
+        'version': '4pOvBAmmlVc7FirmYud1YCAv1qqLeMCxmwXh2bCNXjMC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index ff2447d..623876d 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -659,6 +659,8 @@
        '^chrome/services/sharing/nearby/',
        # gRPC provides some C++ libraries that use std::shared_ptr<>.
        '^chromeos/services/libassistant/grpc/',
+       '^chromecast/cast_core/grpc',
+       '^chromecast/cast_core/runtime/browser',
        # Fuchsia provides C++ libraries that use std::shared_ptr<>.
        '.*fuchsia.*test\.(cc|h)',
        _THIRD_PARTY_EXCEPT_BLINK],  # Not an error in third_party folders.
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index d0ad3195..f908042 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -825,6 +825,7 @@
     ui::PageTransition page_transition,
     bool has_user_gesture,
     const absl::optional<url::Origin>& initiating_origin,
+    content::RenderFrameHost* initiator_document,
     mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
   // Sandbox flags
   // =============
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index b11001f3..d0b57377 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -188,6 +188,7 @@
       ui::PageTransition page_transition,
       bool has_user_gesture,
       const absl::optional<url::Origin>& initiating_origin,
+      content::RenderFrameHost* initiator_document,
       mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory)
       override;
   void RegisterNonNetworkSubresourceURLLoaderFactories(
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index 8ef2bc3..5525049 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -205,6 +205,9 @@
                     "Force the Chrome major version number to 100 in the User-Agent string."),
             Flag.baseFeature(BlinkFeatures.FORCE_MINOR_VERSION100_IN_USER_AGENT,
                     "Force the Chrome minor version number to 100 in the User-Agent string."),
+            Flag.baseFeature(BlinkFeatures.FORCE_MAJOR_VERSION_IN_MINOR_POSITION_IN_USER_AGENT,
+                    "Force the Chrome major version number to 99 and put the major version"
+                            + " number in the minor version position in the User-Agent string."),
             Flag.baseFeature(NetworkServiceFeatures.URL_LOADER_SYNC_CLIENT,
                     "Optimizes communication between URLLoader and CorsURLLoader."),
             Flag.baseFeature(BlinkFeatures.SET_TIMEOUT_WITHOUT_CLAMP,
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
index 47f339c..ae561c9 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
@@ -50,7 +50,6 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.DisableIf;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.MetricsUtils;
@@ -918,7 +917,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisabledTest(message = "https://crbug.com/1279813")
     public void testTouchingFormWithAdjustResize() throws Throwable {
         PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
             mRule.getActivity().getWindow().setSoftInputMode(
@@ -1116,7 +1114,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisabledTest(message = "https://crbug.com/1153875")
     public void testAutofillTriggersAfterReload() throws Throwable {
         final String data = "<html><head></head><body><form action='a.html' name='formname'>"
                 + "<input type='text' id='text1' name='username'"
@@ -1147,7 +1144,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisabledTest(message = "https://crbug.com/1279813")
     public void testNotifyVirtualValueChanged() throws Throwable {
         final String data = "<html><head></head><body><form action='a.html' name='formname'>"
                 + "<input type='text' id='text1' name='username'"
@@ -1182,7 +1178,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisabledTest(message = "https://crbug.com/1279813")
     public void testJavascriptNotTriggerNotifyVirtualValueChanged() throws Throwable {
         final String data = "<html><head></head><body><form action='a.html' name='formname'>"
                 + "<input type='text' id='text1' name='username'"
@@ -1307,7 +1302,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisabledTest(message = "https://crbug.com/1279813")
     public void testSwitchFromIFrame() throws Throwable {
         // we intentionally load main frame and iframe from the same URL and make both have the
         // similar form, so the new session is triggered by frame change
@@ -1522,7 +1516,6 @@
     @Feature({"AndroidWebView"})
     @DisableIf.Build(sdk_is_less_than = Build.VERSION_CODES.P,
             message = "This test is disabled on Android O because of https://crbug.com/997362")
-    @DisabledTest(message = "https://crbug.com/1279813")
     public void
     testSelectControlChangeNotification() throws Throwable {
         int cnt = 0;
@@ -2058,7 +2051,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisabledTest(message = "https://crbug.com/1279813")
     public void testPageScrollTriggerViewExitAndEnter() throws Throwable {
         final String data = "<html><head></head><body><form action='a.html' name='formname'>"
                 + "<input type='text' id='text1' name='username'"
@@ -2678,7 +2670,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisabledTest(message = "https://crbug.com/1279813")
     public void testFirstFieldRemovedBeforeSuggestionSelected() throws Throwable {
         // This test verifies that form filling works even if an element of the form that was
         // supposed to be filled has been deleted between the time of decision to fill the form and
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/devui/util/ComponentsInfoLoaderTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/devui/util/ComponentsInfoLoaderTest.java
index 3316abc..94373d3 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/devui/util/ComponentsInfoLoaderTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/devui/util/ComponentsInfoLoaderTest.java
@@ -6,20 +6,19 @@
 
 import androidx.test.filters.SmallTest;
 
-import org.junit.After;
 import org.junit.Assert;
-import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 
 import org.chromium.android_webview.devui.util.ComponentInfo;
 import org.chromium.android_webview.devui.util.ComponentsInfoLoader;
-import org.chromium.android_webview.services.ComponentsProviderPathUtil;
 import org.chromium.android_webview.test.AwJUnit4ClassRunner;
-import org.chromium.base.FileUtils;
 import org.chromium.base.test.util.Batch;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 
 /**
@@ -28,37 +27,22 @@
 @RunWith(AwJUnit4ClassRunner.class)
 @Batch(Batch.UNIT_TESTS)
 public class ComponentsInfoLoaderTest {
-    private static File sComponentsDownloadDir =
-            new File(ComponentsProviderPathUtil.getComponentUpdateServiceDirectoryPath());
-
-    @BeforeClass
-    public static void deleteOriginalComponentsDownloadDir() {
-        if (sComponentsDownloadDir.exists()) {
-            Assert.assertTrue(FileUtils.recursivelyDeleteFile(sComponentsDownloadDir, null));
-        }
-    }
-
-    @After
-    public void tearDown() {
-        if (sComponentsDownloadDir.exists()) {
-            Assert.assertTrue(FileUtils.recursivelyDeleteFile(sComponentsDownloadDir, null));
-        }
-    }
+    @Rule
+    public TemporaryFolder mTempDir = new TemporaryFolder();
 
     @Test
     @SmallTest
-    public void testMultipleComponents_withOneVersionSubDirectory() {
+    public void testMultipleComponents_withOneVersionSubDirectory() throws IOException {
         ComponentInfo[] expectedList =
                 new ComponentInfo[] {new ComponentInfo("MockComponent A", "1.0.2.1"),
                         new ComponentInfo("MockComponent B", "2021.1.2.1")};
 
         for (ComponentInfo mockComponent : expectedList) {
-            new File(sComponentsDownloadDir,
-                    mockComponent.getComponentName() + "/" + mockComponent.getComponentVersion())
-                    .mkdirs();
+            mTempDir.newFolder(
+                    mockComponent.getComponentName(), mockComponent.getComponentVersion());
         }
 
-        ComponentsInfoLoader componentsInfoLoader = new ComponentsInfoLoader();
+        ComponentsInfoLoader componentsInfoLoader = new ComponentsInfoLoader(mTempDir.getRoot());
         ArrayList<ComponentInfo> retrievedComponentsInfoList =
                 componentsInfoLoader.getComponentsInfo();
 
@@ -67,10 +51,8 @@
 
     @Test
     @SmallTest
-    public void testComponentsDownloadDirectory_isEmpty() {
-        sComponentsDownloadDir.mkdirs();
-
-        ComponentsInfoLoader componentsInfoLoader = new ComponentsInfoLoader();
+    public void testComponentsDownloadDirectory_isEmpty() throws IOException {
+        ComponentsInfoLoader componentsInfoLoader = new ComponentsInfoLoader(mTempDir.getRoot());
         ArrayList<ComponentInfo> retrievedComponentsInfoList =
                 componentsInfoLoader.getComponentsInfo();
 
@@ -80,8 +62,9 @@
 
     @Test
     @SmallTest
-    public void testComponentsDownloadDirectory_doesNotExist() {
-        ComponentsInfoLoader componentsInfoLoader = new ComponentsInfoLoader();
+    public void testComponentsDownloadDirectory_doesNotExist() throws IOException {
+        ComponentsInfoLoader componentsInfoLoader =
+                new ComponentsInfoLoader(new File(mTempDir.getRoot(), "nonexistent"));
         ArrayList<ComponentInfo> retrievedComponentsInfoList =
                 componentsInfoLoader.getComponentsInfo();
 
@@ -91,10 +74,10 @@
 
     @Test
     @SmallTest
-    public void testVersionSubDirectory_doesNotExist() {
-        new File(sComponentsDownloadDir, "MockComponent A").mkdirs();
+    public void testVersionSubDirectory_doesNotExist() throws IOException {
+        mTempDir.newFolder("MockComponent A");
 
-        ComponentsInfoLoader componentsInfoLoader = new ComponentsInfoLoader();
+        ComponentsInfoLoader componentsInfoLoader = new ComponentsInfoLoader(mTempDir.getRoot());
         ArrayList<ComponentInfo> retrievedComponentsInfoList =
                 componentsInfoLoader.getComponentsInfo();
 
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/ComponentsListFragment.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/ComponentsListFragment.java
index a7e60ee0..f28406f 100644
--- a/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/ComponentsListFragment.java
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/ComponentsListFragment.java
@@ -28,10 +28,12 @@
 import org.chromium.android_webview.common.services.ServiceNames;
 import org.chromium.android_webview.devui.util.ComponentInfo;
 import org.chromium.android_webview.devui.util.ComponentsInfoLoader;
+import org.chromium.android_webview.services.ComponentsProviderPathUtil;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.task.AsyncTask;
 import org.chromium.ui.widget.Toast;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Locale;
 
@@ -134,7 +136,8 @@
             @Override
             @WorkerThread
             protected ArrayList<ComponentInfo> doInBackground() {
-                ComponentsInfoLoader componentInfoLoader = new ComponentsInfoLoader();
+                ComponentsInfoLoader componentInfoLoader = new ComponentsInfoLoader(new File(
+                        ComponentsProviderPathUtil.getComponentUpdateServiceDirectoryPath()));
                 ArrayList<ComponentInfo> retrievedComponentInfoList =
                         componentInfoLoader.getComponentsInfo();
 
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/util/ComponentsInfoLoader.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/util/ComponentsInfoLoader.java
index 46229db..f999ea2 100644
--- a/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/util/ComponentsInfoLoader.java
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/util/ComponentsInfoLoader.java
@@ -4,27 +4,32 @@
 
 package org.chromium.android_webview.devui.util;
 
-import org.chromium.android_webview.services.ComponentsProviderPathUtil;
-
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 
 /**
- * A Controller class which iterates over AwComponentUpdateService's download directory {@link
- * ComponentsProviderPathUtil#getComponentUpdateServiceDirectoryPath} to retrieve component name and
- * version for each component.
+ * A Controller class which iterates over the directory where components are downloaded to retrieve
+ * component name and version for each component.
  */
 public class ComponentsInfoLoader {
+    private final File mComponentsDir;
+
+    /**
+     * @param componentsDir the top directory where components are downloaded {@link
+     *         ComponentsProviderPathUtil#getComponentUpdateServiceDirectoryPath}.
+     */
+    public ComponentsInfoLoader(File componentsDir) {
+        mComponentsDir = componentsDir;
+    }
+
     /**
      * @return list of {@link ComponentInfo} for downloaded components sorted in lexicographical
      *         order.
      */
     public ArrayList<ComponentInfo> getComponentsInfo() {
         ArrayList<ComponentInfo> componentInfoList = new ArrayList<>();
-        File[] componentDirectories =
-                new File(ComponentsProviderPathUtil.getComponentUpdateServiceDirectoryPath())
-                        .listFiles();
+        File[] componentDirectories = mComponentsDir.listFiles();
 
         if (componentDirectories == null || componentDirectories.length == 0) {
             return componentInfoList;
diff --git a/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebPlatformTestsActivityTest.java b/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebPlatformTestsActivityTest.java
index f2a2d07..d7f7f72 100644
--- a/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebPlatformTestsActivityTest.java
+++ b/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebPlatformTestsActivityTest.java
@@ -101,6 +101,7 @@
 
     @Test
     @MediumTest
+    @FlakyTest(message = "https://crbug.com/1282164")
     public void testNestedOpensAndCloses() throws Exception {
         final BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
         final int depthToTest = 3;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index ad8767b..ff7d8bc 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -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("//ash/ambient/resources/resources.gni")
 import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/features.gni")
 import("//build/config/ui.gni")
@@ -163,6 +164,7 @@
     "ambient/model/ambient_photo_config.h",
     "ambient/model/ambient_slideshow_photo_config.cc",
     "ambient/model/ambient_slideshow_photo_config.h",
+    "ambient/resources/ambient_animation_static_resources.h",
     "ambient/ui/ambient_background_image_view.cc",
     "ambient/ui/ambient_background_image_view.h",
     "ambient/ui/ambient_container_view.cc",
@@ -1415,6 +1417,8 @@
     "system/privacy_screen/privacy_screen_toast_view.h",
     "system/rotation/rotation_lock_feature_pod_controller.cc",
     "system/rotation/rotation_lock_feature_pod_controller.h",
+    "system/scheduled_feature/scheduled_feature.cc",
+    "system/scheduled_feature/scheduled_feature.h",
     "system/screen_layout_observer.cc",
     "system/screen_layout_observer.h",
     "system/screen_security/screen_capture_observer.h",
@@ -2204,6 +2208,15 @@
 
     deps += [ "//chromeos/assistant/internal/ambient" ]
   }
+
+  if (include_ash_ambient_animation_resources) {
+    sources +=
+        [ "ambient/resources/ambient_animation_static_resources_impl.cc" ]
+    deps += [ "//ash/ambient/resources:lottie_resources" ]
+  } else {
+    sources +=
+        [ "ambient/resources/ambient_animation_static_resources_stub.cc" ]
+  }
 }
 
 action("dbus_service_files") {
@@ -2529,6 +2542,7 @@
     "system/network/sms_observer_unittest.cc",
     "system/network/vpn_list_unittest.cc",
     "system/network/wifi_toggle_notification_controller_unittest.cc",
+    "system/night_light/night_light_controller_unittest.cc",
     "system/overview/overview_button_tray_unittest.cc",
     "system/palette/mock_palette_tool_delegate.cc",
     "system/palette/mock_palette_tool_delegate.h",
@@ -2560,6 +2574,7 @@
     "system/power/power_status_unittest.cc",
     "system/power/video_activity_notifier_unittest.cc",
     "system/rotation/rotation_lock_feature_pod_controller_unittest.cc",
+    "system/scheduled_feature/scheduled_feature_unittest.cc",
     "system/screen_layout_observer_unittest.cc",
     "system/screen_security/screen_security_notification_controller_unittest.cc",
     "system/session/logout_button_tray_unittest.cc",
@@ -2873,6 +2888,12 @@
     "//content/public/browser",
     "//content/public/common",
   ]
+
+  if (include_ash_ambient_animation_resources) {
+    sources += [
+      "ambient/resources/ambient_animation_static_resources_impl_unittest.cc",
+    ]
+  }
 }
 
 # TODO(oshima): Remove or migrate to new ash_ui_perftests
diff --git a/ash/ambient/resources/BUILD.gn b/ash/ambient/resources/BUILD.gn
index 33d14b6..dfc8a38 100644
--- a/ash/ambient/resources/BUILD.gn
+++ b/ash/ambient/resources/BUILD.gn
@@ -3,11 +3,14 @@
 # found in the LICENSE file.
 
 import("//build/cipd/cipd.gni")
+import("//build/config/chrome_build.gni")
 import("//build/config/chromeos/ui_mode.gni")
 import("//tools/grit/grit_rule.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-assert(is_chromeos_ash)
+# See DEPS file. Both of these are prerequisites for downloading Lottie
+# ambient mode resources from CIPD.
+assert(is_chromeos_ash && is_chrome_branded)
 
 lottie_resources_grd_file = "$target_gen_dir/lottie_resources.grd"
 
diff --git a/ash/ambient/resources/ambient_animation_static_resources.h b/ash/ambient/resources/ambient_animation_static_resources.h
new file mode 100644
index 0000000..3532d383
--- /dev/null
+++ b/ash/ambient/resources/ambient_animation_static_resources.h
@@ -0,0 +1,58 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_AMBIENT_RESOURCES_AMBIENT_ANIMATION_STATIC_RESOURCES_H_
+#define ASH_AMBIENT_RESOURCES_AMBIENT_ANIMATION_STATIC_RESOURCES_H_
+
+#include <memory>
+
+#include "ash/ash_export.h"
+#include "ash/public/cpp/ambient/ambient_animation_theme.h"
+#include "base/containers/flat_map.h"
+#include "base/strings/string_piece.h"
+
+namespace gfx {
+class ImageSkia;
+}  // namespace gfx
+
+namespace ash {
+
+// Loads static resources for a given AmbientAnimationTheme. "Static" resources
+// are those that are fixed for the lifetime of the animation, as opposed to
+// dynamic ones that can change between animation cycles (photos from IMAX).
+// All resources are only loaded one time internally, so callers are free to
+// invoke these methods as many times as desired without having to worry about
+// caching the output themselves.
+//
+// This class is not thread-safe, but it may be bound to any sequence (including
+// the UI sequence). It does not do expensive blocking I/O.
+class ASH_EXPORT AmbientAnimationStaticResources {
+ public:
+  // Creates an AmbientAnimationStaticResources instance that loads resources
+  // for the given |theme|. Returns nullptr if |theme| is not supported.
+  static std::unique_ptr<AmbientAnimationStaticResources> Create(
+      AmbientAnimationTheme theme);
+
+  virtual ~AmbientAnimationStaticResources() = default;
+
+  // Returns the Lottie animation json data for this theme. The returned
+  // StringPiece points to data owned by the AmbientAnimationStaticResources
+  // instance. This method can never fail.
+  // TODO(esum): Add an argument where the caller specifies whether to load the
+  // "portrait" or "landscape" version of this animation theme.
+  virtual base::StringPiece GetLottieData() const = 0;
+
+  // Returns the image to use for a static asset in the animation, identified by
+  // the |asset_id|. The |asset_id| is a string identifier specified when the
+  // animation is built offline by UX and is embedded in the Lottie json file.
+  // Asset ids are unique within each Lottie file, but not across Lottie files.
+  //
+  // Returns an empty ImageSkia instance if the |asset_id| is unknown.
+  virtual gfx::ImageSkia GetStaticImageAsset(
+      base::StringPiece asset_id) const = 0;
+};
+
+}  // namespace ash
+
+#endif  // ASH_AMBIENT_RESOURCES_AMBIENT_ANIMATION_STATIC_RESOURCES_H_
diff --git a/ash/ambient/resources/ambient_animation_static_resources_impl.cc b/ash/ambient/resources/ambient_animation_static_resources_impl.cc
new file mode 100644
index 0000000..b283cd20
--- /dev/null
+++ b/ash/ambient/resources/ambient_animation_static_resources_impl.cc
@@ -0,0 +1,129 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/ambient/resources/ambient_animation_static_resources.h"
+
+#include <utility>
+
+#include "ash/ambient/resources/grit/ash_ambient_lottie_resources.h"
+#include "base/check.h"
+#include "base/logging.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace ash {
+namespace {
+
+using AnimationThemeToResourceIdMap =
+    base::flat_map<AmbientAnimationTheme, int>;
+using AssetIdToResourceIdMap = base::flat_map<base::StringPiece, int>;
+
+const AnimationThemeToResourceIdMap& GetAnimationThemeToLottieResourceIdMap() {
+  static const AnimationThemeToResourceIdMap* m =
+      new AnimationThemeToResourceIdMap(
+          {{AmbientAnimationTheme::kFeelTheBreeze,
+            IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_ANIMATION_JSON}});
+  return *m;
+}
+
+// TODO(esum): Look into auto-generating this map and the one above via a
+// build-time script.
+AssetIdToResourceIdMap GetAssetIdToResourceIdMapForTheme(
+    AmbientAnimationTheme theme) {
+  base::flat_map<AmbientAnimationTheme, AssetIdToResourceIdMap> m = {
+      // Themes
+      {
+          // Theme: Feel the Breeze
+          AmbientAnimationTheme::kFeelTheBreeze,
+          {
+              // Assets
+              {"bg.png", IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_BG_PNG},
+              {"clips_bottom.png",
+               IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_CLIPS_BOTTOM_PNG},
+              {"clips_top.png",
+               IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_CLIPS_TOP_PNG},
+              {"shadow_1.png",
+               IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_SHADOW_1_PNG},
+              {"shadow_2.png",
+               IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_SHADOW_2_PNG},
+              {"shadow_3.png",
+               IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_SHADOW_3_PNG},
+              {"shadow_4.png",
+               IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_SHADOW_4_PNG},
+              {"shadow_5.png",
+               IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_SHADOW_5_PNG},
+              {"shadow_6.png",
+               IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_SHADOW_6_PNG},
+              {"time_weather.png",
+               IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_TIME_WEATHER_PNG},
+              {"tree_shadow.png",
+               IDR_ASH_AMBIENT_LOTTIE_LOTTIE_FEEL_THE_BREEZE_TREE_SHADOW_PNG}
+              // End Assets
+          }
+          // End Theme: Feel the Breeze
+      }
+      // End Themes
+  };
+  DCHECK(m.contains(theme)) << "Asset/resource ids missing for " << theme;
+  return m.at(theme);
+}
+
+class AmbientAnimationStaticResourcesImpl
+    : public AmbientAnimationStaticResources {
+ public:
+  AmbientAnimationStaticResourcesImpl(
+      int lottie_json_resource_id,
+      base::flat_map<base::StringPiece, int> asset_id_to_resource_id)
+      : lottie_json_resource_id_(lottie_json_resource_id),
+        asset_id_to_resource_id_(std::move(asset_id_to_resource_id)) {}
+
+  AmbientAnimationStaticResourcesImpl(
+      const AmbientAnimationStaticResourcesImpl&) = delete;
+  AmbientAnimationStaticResourcesImpl& operator=(
+      const AmbientAnimationStaticResourcesImpl&) = delete;
+
+  ~AmbientAnimationStaticResourcesImpl() override = default;
+
+  base::StringPiece GetLottieData() const override {
+    base::StringPiece animation_json =
+        ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
+            lottie_json_resource_id_);
+    DCHECK(!animation_json.empty());
+    return animation_json;
+  }
+
+  gfx::ImageSkia GetStaticImageAsset(
+      base::StringPiece asset_id) const override {
+    if (!asset_id_to_resource_id_.contains(asset_id))
+      return gfx::ImageSkia();
+
+    const gfx::ImageSkia* image =
+        ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+            asset_id_to_resource_id_.at(asset_id));
+    DCHECK(image) << asset_id;
+    return *image;
+  }
+
+ private:
+  // Resource id for this animation theme's Lottie json data.
+  const int lottie_json_resource_id_;
+  // Map of all static image assets in this animation to their corresponding
+  // resource ids. Points to global memory with static duration.
+  const base::flat_map<base::StringPiece, int> asset_id_to_resource_id_;
+};
+
+}  // namespace
+
+// static
+std::unique_ptr<AmbientAnimationStaticResources>
+AmbientAnimationStaticResources::Create(AmbientAnimationTheme theme) {
+  if (!GetAnimationThemeToLottieResourceIdMap().contains(theme))
+    return nullptr;
+
+  return std::make_unique<AmbientAnimationStaticResourcesImpl>(
+      GetAnimationThemeToLottieResourceIdMap().at(theme),
+      GetAssetIdToResourceIdMapForTheme(theme));
+}
+
+}  // namespace ash
diff --git a/ash/ambient/resources/ambient_animation_static_resources_impl_unittest.cc b/ash/ambient/resources/ambient_animation_static_resources_impl_unittest.cc
new file mode 100644
index 0000000..f9545e6
--- /dev/null
+++ b/ash/ambient/resources/ambient_animation_static_resources_impl_unittest.cc
@@ -0,0 +1,64 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/ambient/resources/ambient_animation_static_resources.h"
+
+#include "ash/public/cpp/ambient/ambient_animation_theme.h"
+#include "base/json/json_reader.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace ash {
+
+using ::testing::IsEmpty;
+using ::testing::IsNull;
+using ::testing::Not;
+using ::testing::NotNull;
+
+// AmbientAnimationStaticResources actually has very little application logic
+// and is more a class to house static data. Thus, an animation theme is picked
+// as an example and the basics are tested with it. A test case does not need to
+// exist for every possible animation theme.
+
+TEST(AmbientAnimationStaticResourcesTest, LoadsLottieData) {
+  auto resources = AmbientAnimationStaticResources::Create(
+      AmbientAnimationTheme::kFeelTheBreeze);
+  ASSERT_THAT(resources, NotNull());
+  ASSERT_THAT(resources->GetLottieData(), Not(IsEmpty()));
+  EXPECT_TRUE(base::JSONReader::Read(resources->GetLottieData()));
+}
+
+TEST(AmbientAnimationStaticResourcesTest, LoadsStaticAssets) {
+  auto resources = AmbientAnimationStaticResources::Create(
+      AmbientAnimationTheme::kFeelTheBreeze);
+  ASSERT_THAT(resources, NotNull());
+  gfx::ImageSkia clips_bottom_original =
+      resources->GetStaticImageAsset("clips_bottom.png");
+  ASSERT_FALSE(clips_bottom_original.isNull());
+  gfx::ImageSkia clips_bottom_reloaded =
+      resources->GetStaticImageAsset("clips_bottom.png");
+  ASSERT_FALSE(clips_bottom_reloaded.isNull());
+  EXPECT_TRUE(
+      clips_bottom_reloaded.BackedBySameObjectAs(clips_bottom_original));
+
+  gfx::ImageSkia clips_top = resources->GetStaticImageAsset("clips_top.png");
+  EXPECT_FALSE(clips_top.isNull());
+}
+
+TEST(AmbientAnimationStaticResourcesTest, FailsForSlideshowTheme) {
+  EXPECT_THAT(AmbientAnimationStaticResources::Create(
+                  AmbientAnimationTheme::kSlideshow),
+              IsNull());
+}
+
+TEST(AmbientAnimationStaticResourcesTest, FailsForUnknownAssetId) {
+  auto resources = AmbientAnimationStaticResources::Create(
+      AmbientAnimationTheme::kFeelTheBreeze);
+  ASSERT_THAT(resources, NotNull());
+  gfx::ImageSkia image = resources->GetStaticImageAsset("unknown_asset_id");
+  EXPECT_TRUE(image.isNull());
+}
+
+}  // namespace ash
diff --git a/ash/ambient/resources/ambient_animation_static_resources_stub.cc b/ash/ambient/resources/ambient_animation_static_resources_stub.cc
new file mode 100644
index 0000000..6b6694d
--- /dev/null
+++ b/ash/ambient/resources/ambient_animation_static_resources_stub.cc
@@ -0,0 +1,29 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/ambient/resources/ambient_animation_static_resources.h"
+
+#include "base/logging.h"
+
+namespace ash {
+
+// This stub source file is only built on platforms that don't support the
+// ambient animation resources. 2 things are required currently for support:
+// 1) An internal chrome-branded checkout.
+// 2) The include_ash_ambient_animation_resources GN flag must be true.
+// Without these, the ambient animation code will still compile due to the
+// dummy definitions in this stub, but any resource loading will immediately
+// fail with a FATAL error.
+
+// static
+std::unique_ptr<AmbientAnimationStaticResources>
+AmbientAnimationStaticResources::Create(AmbientAnimationTheme theme) {
+  LOG(FATAL) << "Ambient animation resources are not available on this build. "
+                "To enable, an internal chrome-branded checkout is required, "
+                "and the include_ash_ambient_animation_resources GN flag must "
+                "be true.";
+  return nullptr;
+}
+
+}  // namespace ash
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 6e70c9e..7c6ef100 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -2914,6 +2914,12 @@
       <message name="IDS_ASH_LOGIN_PUBLIC_ACCOUNT_SIGNOUT_REMINDER" desc="Text shown in the public account user pod, reminding the user to log out.">
         Your internet session will be cleared when you sign out. <ph name="LEARN_MORE">$1<ex>Learn more</ex></ph>
       </message>
+      <message name="IDS_ASH_LOGIN_PUBLIC_ACCOUNT_KEYBOARD_MENU_ACCESSIBLE_NAME" desc="Text to be spoken when the focus is set to the button that opens the keyboard menu for the given public account.">
+        Enter keyboard menu
+      </message>
+      <message name="IDS_ASH_LOGIN_PUBLIC_ACCOUNT_LANGUAGE_MENU_ACCESSIBLE_NAME" desc="Text to be spoken when the focus is set to the button that opens the language menu for the given public account.">
+        Enter language menu
+      </message>
       <message name="IDS_ASH_LOGIN_PUBLIC_SESSION_LANGUAGE_AND_INPUT" desc="Link in managed session pod that shows a section which allows the user to change the UI language and keyboard layout.">
         Choose language and keyboard
       </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_LOGIN_PUBLIC_ACCOUNT_KEYBOARD_MENU_ACCESSIBLE_NAME.png.sha1 b/ash/ash_strings_grd/IDS_ASH_LOGIN_PUBLIC_ACCOUNT_KEYBOARD_MENU_ACCESSIBLE_NAME.png.sha1
new file mode 100644
index 0000000..64879a0b
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_LOGIN_PUBLIC_ACCOUNT_KEYBOARD_MENU_ACCESSIBLE_NAME.png.sha1
@@ -0,0 +1 @@
+0c765e9ca952f1ef90d361ed1621d4c36ea877a8
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_LOGIN_PUBLIC_ACCOUNT_LANGUAGE_MENU_ACCESSIBLE_NAME.png.sha1 b/ash/ash_strings_grd/IDS_ASH_LOGIN_PUBLIC_ACCOUNT_LANGUAGE_MENU_ACCESSIBLE_NAME.png.sha1
new file mode 100644
index 0000000..f36eda78
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_LOGIN_PUBLIC_ACCOUNT_LANGUAGE_MENU_ACCESSIBLE_NAME.png.sha1
@@ -0,0 +1 @@
+79334e470869b8793b6db55d2ac2672f8eb6653f
\ No newline at end of file
diff --git a/ash/capture_mode/capture_mode_advanced_settings_view.cc b/ash/capture_mode/capture_mode_advanced_settings_view.cc
index cfb3a54..699fb7c2 100644
--- a/ash/capture_mode/capture_mode_advanced_settings_view.cc
+++ b/ash/capture_mode/capture_mode_advanced_settings_view.cc
@@ -65,9 +65,11 @@
               this,
               kCaptureModeMicIcon,
               l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT)))) {
-  audio_input_menu_group_->AddOption(
-      l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_OFF),
-      kAudioOff);
+  if (!is_in_projector_mode) {
+    audio_input_menu_group_->AddOption(
+        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_OFF),
+        kAudioOff);
+  }
   audio_input_menu_group_->AddOption(
       l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_MICROPHONE),
       kAudioMicrophone);
diff --git a/ash/capture_mode/capture_mode_bar_view.cc b/ash/capture_mode/capture_mode_bar_view.cc
index be1194b..17941009 100644
--- a/ash/capture_mode/capture_mode_bar_view.cc
+++ b/ash/capture_mode/capture_mode_bar_view.cc
@@ -25,6 +25,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/compositor/layer.h"
+#include "ui/gfx/geometry/size.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/background.h"
@@ -36,7 +37,9 @@
 
 namespace {
 
-constexpr gfx::Size kBarSize{376, 64};
+// Full size of capture mode bar view, the width of which will be
+// adjusted in projector mode.
+constexpr gfx::Size kFullBarSize{376, 64};
 
 constexpr gfx::Insets kBarPadding{/*vertical=*/14, /*horizontal=*/16};
 
@@ -110,7 +113,8 @@
 CaptureModeBarView::~CaptureModeBarView() = default;
 
 // static
-gfx::Rect CaptureModeBarView::GetBounds(aura::Window* root) {
+gfx::Rect CaptureModeBarView::GetBounds(aura::Window* root,
+                                        bool is_in_projector_mode) {
   DCHECK(root);
 
   auto bounds = root->GetBoundsInScreen();
@@ -128,8 +132,14 @@
     bar_y = shelf_widget->GetWindowBoundsInScreen().y();
   }
 
-  bar_y -= (kDistanceFromShelfOrHotseatTopDp + kBarSize.height());
-  bounds.ClampToCenteredSize(kBarSize);
+  gfx::Size bar_size = kFullBarSize;
+  if (is_in_projector_mode) {
+    bar_size.set_width(kFullBarSize.width() -
+                       capture_mode::kButtonSize.width() -
+                       capture_mode::kSpaceBetweenCaptureModeTypeButtons);
+  }
+  bar_y -= (kDistanceFromShelfOrHotseatTopDp + bar_size.height());
+  bounds.ClampToCenteredSize(bar_size);
   bounds.set_y(bar_y);
   return bounds;
 }
diff --git a/ash/capture_mode/capture_mode_bar_view.h b/ash/capture_mode/capture_mode_bar_view.h
index e98feb0..f18d4c26 100644
--- a/ash/capture_mode/capture_mode_bar_view.h
+++ b/ash/capture_mode/capture_mode_bar_view.h
@@ -62,8 +62,10 @@
   CaptureModeButton* close_button() const { return close_button_; }
 
   // Gets the ideal bounds in screen coordinates of the bar of widget on the
-  // given |root| window.
-  static gfx::Rect GetBounds(aura::Window* root);
+  // given `root` window. The `image_toggle_button` will not be shown in the bar
+  // if `is_in_projector_mode` is true, which means the width of the bar will be
+  // different.
+  static gfx::Rect GetBounds(aura::Window* root, bool is_in_projector_mode);
 
   // Called when either the capture mode source or type changes.
   void OnCaptureSourceChanged(CaptureModeSource new_source);
diff --git a/ash/capture_mode/capture_mode_constants.h b/ash/capture_mode/capture_mode_constants.h
index c750632..adf05a68 100644
--- a/ash/capture_mode/capture_mode_constants.h
+++ b/ash/capture_mode/capture_mode_constants.h
@@ -32,6 +32,9 @@
 constexpr int kCaptureRegionBorderStrokePx = 1;
 constexpr SkColor kRegionBorderColor = SK_ColorWHITE;
 
+// The space between the `image_toggle_button_` and `video_toggle_button_`.
+constexpr int kSpaceBetweenCaptureModeTypeButtons = 2;
+
 }  // namespace capture_mode
 
 }  // namespace ash
diff --git a/ash/capture_mode/capture_mode_session.cc b/ash/capture_mode/capture_mode_session.cc
index b72e9ea..ee4d7af8 100644
--- a/ash/capture_mode/capture_mode_session.cc
+++ b/ash/capture_mode/capture_mode_session.cc
@@ -540,9 +540,10 @@
   // the region is not larger than the current display.
   ClampCaptureRegionToRootWindowSize();
 
-  capture_mode_bar_widget_->Init(
-      CreateWidgetParams(parent, CaptureModeBarView::GetBounds(current_root_),
-                         "CaptureModeBarWidget"));
+  capture_mode_bar_widget_->Init(CreateWidgetParams(
+      parent,
+      CaptureModeBarView::GetBounds(current_root_, is_in_projector_mode_),
+      "CaptureModeBarWidget"));
   capture_mode_bar_view_ = capture_mode_bar_widget_->SetContentsView(
       std::make_unique<CaptureModeBarView>(is_in_projector_mode_));
   capture_mode_bar_widget_->GetNativeWindow()->SetTitle(
@@ -1163,7 +1164,7 @@
 void CaptureModeSession::RefreshBarWidgetBounds() {
   DCHECK(capture_mode_bar_widget_);
   capture_mode_bar_widget_->SetBounds(
-      CaptureModeBarView::GetBounds(current_root_));
+      CaptureModeBarView::GetBounds(current_root_, is_in_projector_mode_));
   auto* parent = GetParentContainer(current_root_);
   parent->StackChildAtTop(capture_mode_bar_widget_->GetNativeWindow());
   if (user_nudge_controller_)
diff --git a/ash/capture_mode/capture_mode_session_focus_cycler.cc b/ash/capture_mode/capture_mode_session_focus_cycler.cc
index 2ea7e2b..35792d35 100644
--- a/ash/capture_mode/capture_mode_session_focus_cycler.cc
+++ b/ash/capture_mode/capture_mode_session_focus_cycler.cc
@@ -448,9 +448,10 @@
                source_view->fullscreen_toggle_button(),
                source_view->region_toggle_button(),
                source_view->window_toggle_button()};
+
       base::EraseIf(items,
                     [](CaptureModeSessionFocusCycler::HighlightableView* item) {
-                      return !item->GetView()->GetEnabled();
+                      return !item || !item->GetView()->GetEnabled();
                     });
       break;
     }
diff --git a/ash/capture_mode/capture_mode_type_view.cc b/ash/capture_mode/capture_mode_type_view.cc
index a7260c65..bacbd68 100644
--- a/ash/capture_mode/capture_mode_type_view.cc
+++ b/ash/capture_mode/capture_mode_type_view.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/capture_mode/capture_mode_constants.h"
 #include "ash/capture_mode/capture_mode_controller.h"
 #include "ash/capture_mode/capture_mode_metrics.h"
 #include "ash/capture_mode/capture_mode_toggle_button.h"
@@ -27,21 +28,23 @@
 
 constexpr gfx::Insets kViewInsets{2};
 
-constexpr int kButtonSpacing = 2;
-
 }  // namespace
 
 CaptureModeTypeView::CaptureModeTypeView(bool projector_mode)
-    : image_toggle_button_(
-          AddChildView(std::make_unique<CaptureModeToggleButton>(
-              base::BindRepeating(&CaptureModeTypeView::OnImageToggle,
-                                  base::Unretained(this)),
-              kCaptureModeImageIcon))),
-      video_toggle_button_(
+    : video_toggle_button_(
           AddChildView(std::make_unique<CaptureModeToggleButton>(
               base::BindRepeating(&CaptureModeTypeView::OnVideoToggle,
                                   base::Unretained(this)),
               kCaptureModeVideoIcon))) {
+  if (!projector_mode) {
+    image_toggle_button_ =
+        AddChildView(std::make_unique<CaptureModeToggleButton>(
+            base::BindRepeating(&CaptureModeTypeView::OnImageToggle,
+                                base::Unretained(this)),
+            kCaptureModeImageIcon));
+    image_toggle_button_->SetTooltipText(
+        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_TOOLTIP_SCREENSHOT));
+  }
   auto* color_provider = AshColorProvider::Get();
   const SkColor bg_color = color_provider->GetControlsLayerColor(
       AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive);
@@ -50,22 +53,18 @@
   SetBorder(views::CreateEmptyBorder(kViewInsets));
   auto* box_layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kHorizontal, gfx::Insets(0),
-      kButtonSpacing));
+      capture_mode::kSpaceBetweenCaptureModeTypeButtons));
   box_layout->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::kCenter);
   auto* controller = CaptureModeController::Get();
+
   if (controller->is_recording_in_progress()) {
     // We can't have more than one recording at the same time.
     video_toggle_button_->SetEnabled(false);
-  } else if (projector_mode) {
-    // Projector mode can only do video recording.
-    image_toggle_button_->SetEnabled(false);
   }
 
   OnCaptureTypeChanged(controller->type());
 
-  image_toggle_button_->SetTooltipText(
-      l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_TOOLTIP_SCREENSHOT));
   video_toggle_button_->SetTooltipText(
       l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_TOOLTIP_SCREENRECORD));
 }
@@ -75,10 +74,13 @@
 void CaptureModeTypeView::OnCaptureTypeChanged(CaptureModeType new_type) {
   DCHECK(!CaptureModeController::Get()->is_recording_in_progress() ||
       new_type == CaptureModeType::kImage);
-  image_toggle_button_->SetToggled(new_type == CaptureModeType::kImage);
+
   video_toggle_button_->SetToggled(new_type == CaptureModeType::kVideo);
-  DCHECK_NE(image_toggle_button_->GetToggled(),
-            video_toggle_button_->GetToggled());
+  if (image_toggle_button_) {
+    image_toggle_button_->SetToggled(new_type == CaptureModeType::kImage);
+    DCHECK_NE(image_toggle_button_->GetToggled(),
+              video_toggle_button_->GetToggled());
+  }
 }
 
 void CaptureModeTypeView::OnImageToggle() {
diff --git a/ash/capture_mode/capture_mode_type_view.h b/ash/capture_mode/capture_mode_type_view.h
index 91a4fc2..46678e42 100644
--- a/ash/capture_mode/capture_mode_type_view.h
+++ b/ash/capture_mode/capture_mode_type_view.h
@@ -42,8 +42,9 @@
   void OnImageToggle();
   void OnVideoToggle();
 
-  // Owned by the views hierarchy.
-  CaptureModeToggleButton* image_toggle_button_;
+  // Owned by the views hierarchy. Initialize `image_toggle_button_` to nullptr
+  // as it is never created in projector mode.
+  CaptureModeToggleButton* image_toggle_button_ = nullptr;
   CaptureModeToggleButton* video_toggle_button_;
 };
 
diff --git a/ash/capture_mode/capture_mode_unittests.cc b/ash/capture_mode/capture_mode_unittests.cc
index 95b6257..66acb9e2 100644
--- a/ash/capture_mode/capture_mode_unittests.cc
+++ b/ash/capture_mode/capture_mode_unittests.cc
@@ -4932,24 +4932,19 @@
   CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
   EXPECT_FALSE(save_to_menu_group);
 
-  // The audio-off option should be disabled, unchecked and not interactable
-  // (even when clicked).
-  views::View* audio_off_option = test_api.GetAudioOffOption();
-  EXPECT_FALSE(audio_off_option->GetEnabled());
+  // The audio-off option should never be added.
+  EXPECT_FALSE(test_api.GetAudioOffOption());
+
   CaptureModeMenuGroup* audio_input_menu_group =
       test_api.GetAudioInputMenuGroup();
   EXPECT_TRUE(audio_input_menu_group->IsOptionChecked(kAudioMicrophone));
-  EXPECT_FALSE(audio_input_menu_group->IsOptionChecked(kAudioOff));
-  ClickOnView(audio_off_option, event_generator);
-  EXPECT_TRUE(audio_input_menu_group->IsOptionChecked(kAudioMicrophone));
-  EXPECT_FALSE(audio_input_menu_group->IsOptionChecked(kAudioOff));
   EXPECT_TRUE(controller->enable_audio_recording());
 }
 
 // Tests the keyboard navigation for projector mode with advanced capture mode
 // settings enabled. The `image_toggle_button_` in `CaptureModeTypeView` and the
-// `Off` audio input option in `CaptureModeAdvancedSettingsView` are disabled in
-// projector mode, thus they should be skipped while tabbing though.
+// `Off` audio input option in `CaptureModeAdvancedSettingsView` are not
+// available in projector mode.
 TEST_F(ProjectorCaptureModeIntegrationTests,
        KeyboardNavigationWithAdvancedSettings) {
   base::test::ScopedFeatureList scoped_feature_list{
@@ -4964,9 +4959,8 @@
   using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
   CaptureModeSessionTestApi test_api(controller->capture_mode_session());
 
-  EXPECT_FALSE(GetImageToggleButton()->GetEnabled());
-  // Tab once, check the image toggle button is skipped and the current focused
-  // view is the video toggle button.
+  EXPECT_FALSE(GetImageToggleButton());
+  // Tab once, check the current focused view is the video toggle button.
   auto* event_generator = GetEventGenerator();
   SendKey(ui::VKEY_TAB, event_generator);
   EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(),
@@ -4982,10 +4976,10 @@
   ASSERT_TRUE(settings_menu);
 
   CaptureModeAdvancedSettingsTestApi advanced_settings_test_api;
-  // Tab twice, check the `Off` option is skipped and remains disabled. The
-  // current focused view is the `Microphone` option.
+  // The `Off` option should not be visible.
+  EXPECT_FALSE(advanced_settings_test_api.GetAudioOffOption());
+  // Tab twice, the current focused view is the `Microphone` option.
   SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/2);
-  EXPECT_FALSE(advanced_settings_test_api.GetAudioOffOption()->GetEnabled());
   EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(),
             advanced_settings_test_api.GetMicrophoneOption());
 }
@@ -4995,10 +4989,9 @@
   StartProjectorModeSession();
   EXPECT_TRUE(controller->IsActive());
 
-  // The image toggle button should be disabled, whereas the video toggle button
-  // should be enabled and active.
-  EXPECT_FALSE(GetImageToggleButton()->GetEnabled());
-  EXPECT_FALSE(GetImageToggleButton()->GetToggled());
+  // The image toggle button shouldn't be available, whereas the video toggle
+  // button should be enabled and active.
+  EXPECT_FALSE(GetImageToggleButton());
   EXPECT_TRUE(GetVideoToggleButton()->GetEnabled());
   EXPECT_TRUE(GetVideoToggleButton()->GetToggled());
 }
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 1a122f84..86ee1593 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -703,14 +703,14 @@
 // transfer or access it later.
 const base::Feature kHoldingSpaceInProgressDownloadsIntegration{
     "HoldingSpaceInProgressDownloadsIntegration",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+    base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables in-progress downloads notification suppression with the productivity
 // feature that aims to reduce context switching by enabling users to collect
 // content and transfer or access it later.
 const base::Feature kHoldingSpaceInProgressDownloadsNotificationSuppression{
     "HoldingSpaceInProgressNotificationSuppression",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+    base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables incognito profile integration with the productivity feature that
 // aims to reduce context switching by enabling users to collect content and
diff --git a/ash/login/login_screen_test_api.cc b/ash/login/login_screen_test_api.cc
index 63886ace..c3342fa 100644
--- a/ash/login/login_screen_test_api.cc
+++ b/ash/login/login_screen_test_api.cc
@@ -662,7 +662,7 @@
       lock_screen_test.contents_view());
   LoginExpandedPublicAccountView::TestApi expanded_test(
       lock_contents_test.expanded_view());
-  return expanded_test.selected_language_item().value;
+  return expanded_test.selected_language_item_value();
 }
 
 // static
@@ -672,7 +672,7 @@
       lock_screen_test.contents_view());
   LoginExpandedPublicAccountView::TestApi expanded_test(
       lock_contents_test.expanded_view());
-  return expanded_test.selected_keyboard_item().value;
+  return expanded_test.selected_keyboard_item_value();
 }
 
 // static
diff --git a/ash/login/ui/login_expanded_public_account_view.cc b/ash/login/ui/login_expanded_public_account_view.cc
index df8f780..3a2779b 100644
--- a/ash/login/ui/login_expanded_public_account_view.cc
+++ b/ash/login/ui/login_expanded_public_account_view.cc
@@ -37,6 +37,7 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
+#include "ui/views/mouse_constants.h"
 
 namespace ash {
 
@@ -52,19 +53,15 @@
 constexpr int kBorderThicknessDp = 1;
 constexpr int kHorizontalMarginPaneDp = 28;
 constexpr int kLabelMarginDp = 20;
-constexpr int kLeftMarginForSelectionButton = 8;
-constexpr int kRightMarginForSelectionButton = 3;
 
 constexpr int kDropDownIconSizeDp = 16;
 constexpr int kArrowButtonSizeDp = 48;
 constexpr int kAdvancedViewButtonWidthDp = 190;
 constexpr int kAdvancedViewButtonHeightDp = 16;
-constexpr int kSelectionBoxWidthDp = 192;
-constexpr int kSelectionBoxHeightDp = 28;
 constexpr int kTopSpacingForLabelInAdvancedViewDp = 7;
 constexpr int kTopSpacingForLabelInRegularViewDp = 65;
 constexpr int kSpacingBetweenLabelsDp = 17;
-constexpr int kSpacingBetweenSelectionMenusDp = 15;
+constexpr int kSpacingBetweenSelectionMenusDp = 7;
 constexpr int kSpacingBetweenSelectionTitleAndButtonDp = 3;
 constexpr int kSpacingBetweenLanguageMenuAndAdvancedViewButtonDp = 4;
 constexpr int kSpacingBetweenAdvancedViewButtonAndLabelDp = 32;
@@ -77,6 +74,10 @@
 constexpr int kSpacingBetweenMonitoringWarningIconAndLabelDp = 8;
 constexpr int kMonitoringWarningIconSizeDp = 20;
 
+constexpr char kRightPaneViewClassName[] = "RightPaneView";
+constexpr char kRightPaneLabelsViewClassName[] = "RightPaneLabelsView";
+constexpr char kRightPaneAdvancedViewClassName[] = "RightPaneAdvancedView";
+
 views::Label* CreateLabel(const std::u16string& text, SkColor color) {
   auto* label = new views::Label(text);
   label->SetSubpixelRenderingEnabled(false);
@@ -300,13 +301,14 @@
 // Implements the right part of the expanded public session view.
 class RightPaneView : public NonAccessibleView {
  public:
-  explicit RightPaneView(const base::RepeatingClosure& on_learn_more_tapped) {
+  explicit RightPaneView(const base::RepeatingClosure& on_learn_more_tapped)
+      : NonAccessibleView(kRightPaneViewClassName) {
     SetPreferredSize(
         gfx::Size(kExpandedViewWidthDp / 2, kExpandedViewHeightDp));
     SetBorder(views::CreateEmptyBorder(gfx::Insets(kHorizontalMarginPaneDp)));
 
     // Create labels view.
-    labels_view_ = new NonAccessibleView();
+    labels_view_ = new NonAccessibleView(kRightPaneLabelsViewClassName);
     labels_view_->SetLayoutManager(std::make_unique<views::BoxLayout>(
         views::BoxLayout::Orientation::kVertical, gfx::Insets(),
         kSpacingBetweenLabelsDp));
@@ -356,7 +358,7 @@
     AddChildView(advanced_view_button_);
 
     // Create advanced view.
-    advanced_view_ = new NonAccessibleView();
+    advanced_view_ = new NonAccessibleView(kRightPaneAdvancedViewClassName);
     advanced_view_->SetLayoutManager(std::make_unique<views::BoxLayout>(
         views::BoxLayout::Orientation::kVertical));
     AddChildView(advanced_view_);
@@ -365,55 +367,28 @@
         AshColorProvider::Get()->GetContentLayerColor(
             AshColorProvider::ContentLayerType::kTextColorSecondary);
 
-    // Creates button to open the menu.
-    auto create_menu_button =
-        [&](views::Button::PressedCallback callback,
-            const std::u16string& text) -> SelectionButtonView* {
-      auto* button = new SelectionButtonView(std::move(callback), text);
-      button->SetPreferredSize(
-          gfx::Size(kSelectionBoxWidthDp, kSelectionBoxHeightDp));
-      button->SetMargins(kLeftMarginForSelectionButton,
-                         kRightMarginForSelectionButton);
-      button->SetBorder(views::CreateRoundedRectBorder(
-          kBorderThicknessDp, kRoundRectCornerRadiusDp,
-          AshColorProvider::Get()->GetContentLayerColor(
-              AshColorProvider::ContentLayerType::kSeparatorColor)));
-      button->SetIcon(kLoginScreenMenuDropdownIcon, selection_menu_title_color);
-      return button;
-    };
-
     auto create_padding = [](int amount) -> views::View* {
       auto* padding = new NonAccessibleView();
       padding->SetPreferredSize(gfx::Size(kNonEmptyWidth, amount));
       return padding;
     };
 
-    views::Label* language_title = CreateLabel(
+    language_title_ = CreateLabel(
         l10n_util::GetStringUTF16(IDS_ASH_LOGIN_LANGUAGE_SELECTION_SELECT),
         selection_menu_title_color);
-    language_selection_ = create_menu_button(
-        base::BindRepeating(&RightPaneView::LanguageSelectionButtonPressed,
-                            base::Unretained(this)),
-        std::u16string());
 
-    views::Label* keyboard_title = CreateLabel(
+    keyboard_title_ = CreateLabel(
         l10n_util::GetStringUTF16(IDS_ASH_LOGIN_KEYBOARD_SELECTION_SELECT),
         selection_menu_title_color);
-    keyboard_selection_ = create_menu_button(
-        base::BindRepeating(&RightPaneView::KeyboardSelectionButtonPressed,
-                            base::Unretained(this)),
-        std::u16string());
 
-    advanced_view_->AddChildView(language_title);
+    advanced_view_->AddChildView(language_title_);
     advanced_view_->AddChildView(
         create_padding(kSpacingBetweenSelectionTitleAndButtonDp));
-    advanced_view_->AddChildView(language_selection_);
     advanced_view_->AddChildView(
         create_padding(kSpacingBetweenSelectionMenusDp));
-    advanced_view_->AddChildView(keyboard_title);
+    advanced_view_->AddChildView(keyboard_title_);
     advanced_view_->AddChildView(
         create_padding(kSpacingBetweenSelectionTitleAndButtonDp));
-    advanced_view_->AddChildView(keyboard_selection_);
 
     submit_button_ = new ArrowButtonView(
         base::BindRepeating(&RightPaneView::SubmitButtonPressed,
@@ -471,19 +446,13 @@
       monitoring_warning_view_->UpdateForUser(user);
     current_user_ = user;
     if (!language_changed_by_user_)
-      selected_language_item_.value = user.public_account_info->default_locale;
+      selected_language_item_value_ = user.public_account_info->default_locale;
 
     PopulateLanguageItems(user.public_account_info->available_locales);
 
     if (user.public_account_info->default_locale ==
-        selected_language_item_.value) {
+        selected_language_item_value_)
       PopulateKeyboardItems(user.public_account_info->keyboard_layouts);
-    }
-
-    language_selection_->SetText(
-        base::UTF8ToUTF16(selected_language_item_.title));
-    keyboard_selection_->SetText(
-        base::UTF8ToUTF16(selected_keyboard_item_.title));
 
     if (!show_advanced_changed_by_user_)
       show_advanced_view_ = user.public_account_info->show_advanced_view;
@@ -499,27 +468,26 @@
               : MonitoringWarningView::WarningType::kSoftWarning);
   }
 
-  void OnLanguageSelected(PublicAccountMenuView::Item item) {
+  void OnLanguageSelected(const std::string& value) {
     language_changed_by_user_ = true;
-    selected_language_item_ = item;
-    language_selection_->SetText(base::UTF8ToUTF16(item.title));
-    current_user_.public_account_info->default_locale = item.value;
+    selected_language_item_value_ = value;
+    current_user_.public_account_info->default_locale = value;
 
     // User changed the preferred locale, request to get corresponding keyboard
     // layouts.
     Shell::Get()
         ->login_screen_controller()
         ->RequestPublicSessionKeyboardLayouts(
-            current_user_.basic_user_info.account_id, item.value);
+            current_user_.basic_user_info.account_id, value);
   }
 
-  void OnKeyboardSelected(PublicAccountMenuView::Item item) {
-    selected_keyboard_item_ = item;
-    keyboard_selection_->SetText(base::UTF8ToUTF16(item.title));
+  void OnKeyboardSelected(const std::string& value) {
+    selected_keyboard_item_value_ = value;
   }
 
   void PopulateLanguageItems(const std::vector<LocaleItem>& locales) {
     language_items_.clear();
+    int selected_language_index = 0;
     for (const auto& locale : locales) {
       PublicAccountMenuView::Item item;
       if (locale.group_name) {
@@ -529,69 +497,74 @@
         item.title = locale.title;
         item.value = locale.language_code;
         item.is_group = false;
-        item.selected = selected_language_item_.value == locale.language_code;
+        item.selected = selected_language_item_value_ == locale.language_code;
       }
+      if (selected_language_item_value_ == locale.language_code)
+        selected_language_index = language_items_.size();
       language_items_.push_back(item);
-
-      if (selected_language_item_.value == locale.language_code)
-        selected_language_item_ = item;
     }
 
-    PublicAccountMenuView* old_language_menu_view = language_menu_view_;
-
+    if (language_menu_view_) {
+      advanced_view_->RemoveChildView(language_menu_view_);
+      delete language_menu_view_;
+    }
     language_menu_view_ = new PublicAccountMenuView(
-        language_items_, language_selection_ /*anchor_view*/,
-        language_selection_ /*bubble_opener*/,
+        language_items_, selected_language_index,
         base::BindRepeating(&RightPaneView::OnLanguageSelected,
                             weak_factory_.GetWeakPtr()));
-    login_views_utils::GetBubbleContainer(this)->AddChildView(
-        language_menu_view_);
+    language_menu_view_->SetTooltipTextAndAccessibleName(
+        l10n_util::GetStringUTF16(
+            IDS_ASH_LOGIN_PUBLIC_ACCOUNT_LANGUAGE_MENU_ACCESSIBLE_NAME));
 
-    if (old_language_menu_view)
-      delete old_language_menu_view;
+    int after_title_after_padding_index =
+        advanced_view_->GetIndexOf(language_title_) + 2;
+    advanced_view_->AddChildViewAt(language_menu_view_,
+                                   after_title_after_padding_index);
   }
 
   void PopulateKeyboardItems(
       const std::vector<InputMethodItem>& keyboard_layouts) {
     keyboard_items_.clear();
+    int selected_keyboard_index = 0;
     for (const auto& keyboard : keyboard_layouts) {
       PublicAccountMenuView::Item item;
       item.title = keyboard.title;
       item.value = keyboard.ime_id;
       item.is_group = false;
       item.selected = keyboard.selected;
+      if (keyboard.selected) {
+        selected_keyboard_index = keyboard_items_.size();
+        selected_keyboard_item_value_ = item.value;
+      }
       keyboard_items_.push_back(item);
-
-      if (keyboard.selected)
-        selected_keyboard_item_ = item;
     }
 
-    PublicAccountMenuView* old_keyboard_menu_view = keyboard_menu_view_;
-
+    if (keyboard_menu_view_) {
+      advanced_view_->RemoveChildView(keyboard_menu_view_);
+      delete keyboard_menu_view_;
+    }
     keyboard_menu_view_ = new PublicAccountMenuView(
-        keyboard_items_, keyboard_selection_ /*anchor_view*/,
-        keyboard_selection_ /*bubble_opener*/,
+        keyboard_items_, selected_keyboard_index,
         base::BindRepeating(&RightPaneView::OnKeyboardSelected,
                             weak_factory_.GetWeakPtr()));
-    login_views_utils::GetBubbleContainer(this)->AddChildView(
-        keyboard_menu_view_);
+    keyboard_menu_view_->SetTooltipTextAndAccessibleName(
+        l10n_util::GetStringUTF16(
+            IDS_ASH_LOGIN_PUBLIC_ACCOUNT_KEYBOARD_MENU_ACCESSIBLE_NAME));
 
-    if (old_keyboard_menu_view)
-      delete old_keyboard_menu_view;
+    int after_title_after_padding_index =
+        advanced_view_->GetIndexOf(keyboard_title_) + 2;
+    advanced_view_->AddChildViewAt(keyboard_menu_view_,
+                                   after_title_after_padding_index);
   }
 
-  LoginBaseBubbleView* GetLanguageMenuView() { return language_menu_view_; }
+  PublicAccountMenuView* GetLanguageMenuView() { return language_menu_view_; }
 
-  LoginBaseBubbleView* GetKeyboardMenuView() { return keyboard_menu_view_; }
+  PublicAccountMenuView* GetKeyboardMenuView() { return keyboard_menu_view_; }
 
-  // Close language and keyboard menus and reset local states.
+  // Reset local states.
   void Reset() {
     show_advanced_changed_by_user_ = false;
     language_changed_by_user_ = false;
-    if (language_menu_view_ && language_menu_view_->GetVisible())
-      language_menu_view_->Hide();
-    if (keyboard_menu_view_ && keyboard_menu_view_->GetVisible())
-      keyboard_menu_view_->Hide();
   }
 
  private:
@@ -605,42 +578,15 @@
 
   void SubmitButtonPressed() {
     // TODO(crbug.com/984021) change to LaunchSamlPublicSession which would
-    // take selected_language_item_.value, selected_keyboard_item_.value too.
+    // take |selected_language_item_value_| and |selected_keyboard_item_value_|
+    // too.
     if (current_user_.public_account_info->using_saml) {
       Shell::Get()->login_screen_controller()->ShowGaiaSignin(
           current_user_.basic_user_info.account_id);
     } else {
       Shell::Get()->login_screen_controller()->LaunchPublicSession(
           current_user_.basic_user_info.account_id,
-          selected_language_item_.value, selected_keyboard_item_.value);
-    }
-  }
-
-  void LanguageSelectionButtonPressed() {
-    DCHECK(language_menu_view_);
-    if (language_menu_view_->GetVisible()) {
-      language_menu_view_->Hide();
-    } else {
-      bool opener_had_focus = language_selection_->HasFocus();
-
-      language_menu_view_->Show();
-
-      if (opener_had_focus)
-        language_menu_view_->RequestFocus();
-    }
-  }
-
-  void KeyboardSelectionButtonPressed() {
-    DCHECK(keyboard_menu_view_);
-    if (keyboard_menu_view_->GetVisible()) {
-      keyboard_menu_view_->Hide();
-    } else {
-      bool opener_had_focus = keyboard_selection_->HasFocus();
-
-      keyboard_menu_view_->Show();
-
-      if (opener_had_focus)
-        keyboard_menu_view_->RequestFocus();
+          selected_language_item_value_, selected_keyboard_item_value_);
     }
   }
 
@@ -650,20 +596,17 @@
   views::View* labels_view_ = nullptr;
   SelectionButtonView* advanced_view_button_ = nullptr;
   views::View* advanced_view_ = nullptr;
-  SelectionButtonView* language_selection_ = nullptr;
-  SelectionButtonView* keyboard_selection_ = nullptr;
+  views::View* language_title_ = nullptr;
+  views::View* keyboard_title_ = nullptr;
   ArrowButtonView* submit_button_ = nullptr;
   views::StyledLabel* learn_more_label_ = nullptr;
   MonitoringWarningView* monitoring_warning_view_ = nullptr;
 
-  // |language_menu_view_| and |keyboard_menu_view_| are parented by the top
-  // level view, either LockContentsView or LockDebugView. This allows the menu
-  // items to be clicked outside the bounds of the right pane view.
   PublicAccountMenuView* language_menu_view_ = nullptr;
   PublicAccountMenuView* keyboard_menu_view_ = nullptr;
 
-  PublicAccountMenuView::Item selected_language_item_;
-  PublicAccountMenuView::Item selected_keyboard_item_;
+  std::string selected_language_item_value_;
+  std::string selected_keyboard_item_value_;
   std::vector<PublicAccountMenuView::Item> language_items_;
   std::vector<PublicAccountMenuView::Item> keyboard_items_;
 
@@ -711,16 +654,6 @@
   return view_->right_pane_->learn_more_label_;
 }
 
-views::View*
-LoginExpandedPublicAccountView::TestApi::language_selection_button() {
-  return view_->right_pane_->language_selection_;
-}
-
-views::View*
-LoginExpandedPublicAccountView::TestApi::keyboard_selection_button() {
-  return view_->right_pane_->keyboard_selection_;
-}
-
 PublicAccountMenuView*
 LoginExpandedPublicAccountView::TestApi::language_menu_view() {
   return view_->right_pane_->language_menu_view_;
@@ -731,14 +664,14 @@
   return view_->right_pane_->keyboard_menu_view_;
 }
 
-PublicAccountMenuView::Item
-LoginExpandedPublicAccountView::TestApi::selected_language_item() {
-  return view_->right_pane_->selected_language_item_;
+std::string
+LoginExpandedPublicAccountView::TestApi::selected_language_item_value() {
+  return view_->right_pane_->selected_language_item_value_;
 }
 
-PublicAccountMenuView::Item
-LoginExpandedPublicAccountView::TestApi::selected_keyboard_item() {
-  return view_->right_pane_->selected_keyboard_item_;
+std::string
+LoginExpandedPublicAccountView::TestApi::selected_keyboard_item_value() {
+  return view_->right_pane_->selected_keyboard_item_value_;
 }
 
 views::ImageView*
@@ -764,7 +697,7 @@
     const std::string& language_code) {
   for (PublicAccountMenuView::Item item : view_->right_pane_->language_items_) {
     if (item.value == language_code) {
-      view_->right_pane_->OnLanguageSelected(item);
+      view_->right_pane_->OnLanguageSelected(item.value);
       return true;
     }
   }
@@ -775,7 +708,7 @@
     const std::string& ime_id) {
   for (PublicAccountMenuView::Item item : view_->right_pane_->keyboard_items_) {
     if (item.value == ime_id) {
-      view_->right_pane_->OnKeyboardSelected(item);
+      view_->right_pane_->OnKeyboardSelected(item.value);
       return true;
     }
   }
@@ -853,16 +786,27 @@
   if (GetBoundsInScreen().Contains(event->root_location()))
     return;
 
-  // Ignore press event inside the language and keyboard menu.
-  LoginBaseBubbleView* language_menu_view = right_pane_->GetLanguageMenuView();
+  // Ignore press event if the language or keyboard menu is still running,
+  // or if it had just been closed. Note that when we checked closed time,
+  // if the menu has never been closed, closed time will be set to time 0 and
+  // the time delta between now and then will be more than 100 ms.
+  PublicAccountMenuView* language_menu_view =
+      right_pane_->GetLanguageMenuView();
   if (language_menu_view &&
-      language_menu_view->GetBoundsInScreen().Contains(event->root_location()))
+      (language_menu_view->IsMenuRunning() ||
+       (base::TimeTicks::Now() - language_menu_view->GetClosedTime()) <
+           views::kMinimumTimeBetweenButtonClicks)) {
     return;
+  }
 
-  LoginBaseBubbleView* keyboard_menu_view = right_pane_->GetKeyboardMenuView();
+  PublicAccountMenuView* keyboard_menu_view =
+      right_pane_->GetKeyboardMenuView();
   if (keyboard_menu_view &&
-      keyboard_menu_view->GetBoundsInScreen().Contains(event->root_location()))
+      (keyboard_menu_view->IsMenuRunning() ||
+       (base::TimeTicks::Now() - language_menu_view->GetClosedTime()) <
+           views::kMinimumTimeBetweenButtonClicks)) {
     return;
+  }
 
   Hide();
 }
diff --git a/ash/login/ui/login_expanded_public_account_view.h b/ash/login/ui/login_expanded_public_account_view.h
index f905b98..9e04875e 100644
--- a/ash/login/ui/login_expanded_public_account_view.h
+++ b/ash/login/ui/login_expanded_public_account_view.h
@@ -43,12 +43,10 @@
     views::View* advanced_view();
     PublicAccountMonitoringInfoDialog* learn_more_dialog();
     views::StyledLabel* learn_more_label();
-    views::View* language_selection_button();
-    views::View* keyboard_selection_button();
     PublicAccountMenuView* language_menu_view();
     PublicAccountMenuView* keyboard_menu_view();
-    PublicAccountMenuView::Item selected_language_item();
-    PublicAccountMenuView::Item selected_keyboard_item();
+    std::string selected_language_item_value();
+    std::string selected_keyboard_item_value();
     views::ImageView* monitoring_warning_icon();
     views::Label* monitoring_warning_label();
     void ResetUserForTest();
diff --git a/ash/login/ui/login_expanded_public_account_view_unittest.cc b/ash/login/ui/login_expanded_public_account_view_unittest.cc
index 5c52c56a..db7dd56 100644
--- a/ash/login/ui/login_expanded_public_account_view_unittest.cc
+++ b/ash/login/ui/login_expanded_public_account_view_unittest.cc
@@ -20,6 +20,7 @@
 #include "ui/events/test/event_generator.h"
 #include "ui/views/controls/link.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/test/combobox_test_api.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
@@ -203,16 +204,18 @@
   LoginExpandedPublicAccountView::TestApi test_api(public_account_);
 
   // Verify the language and keyboard information is populated correctly.
-  std::string selected_language = test_api.selected_language_item().value;
-  std::string selected_keyboard = test_api.selected_keyboard_item().value;
-  EXPECT_EQ(selected_language, kEnglishLanguageCode);
-  EXPECT_EQ(selected_keyboard, kKeyboardIdForItem2);
+  std::string selected_language_item_value =
+      test_api.selected_language_item_value();
+  EXPECT_EQ(selected_language_item_value, kEnglishLanguageCode);
+  std::string selected_keyboard_item_value =
+      test_api.selected_keyboard_item_value();
+  EXPECT_EQ(selected_keyboard_item_value, kKeyboardIdForItem2);
 
   // Expect LaunchPublicSession mojo call when the submit button is clicked.
   auto client = std::make_unique<MockLoginScreenClient>();
-  EXPECT_CALL(*client,
-              LaunchPublicSession(user_.basic_user_info.account_id,
-                                  selected_language, selected_keyboard));
+  EXPECT_CALL(*client, LaunchPublicSession(user_.basic_user_info.account_id,
+                                           selected_language_item_value,
+                                           selected_keyboard_item_value));
 
   // Click on the submit button.
   TapOnView(test_api.submit_button());
@@ -230,35 +233,41 @@
   public_account_->UpdateForUser(user_);
   EXPECT_TRUE(test_api.advanced_view()->GetVisible());
 
-  // Tap on language selection button should bring up the language menu.
-  TapOnView(test_api.language_selection_button());
-  EXPECT_TRUE(test_api.language_menu_view()->GetVisible());
+  // Open language menu.
+  PublicAccountMenuView* language_menu_view = test_api.language_menu_view();
+  EXPECT_FALSE(language_menu_view->IsMenuRunning());
+  TapOnView(language_menu_view);
+  EXPECT_TRUE(language_menu_view->IsMenuRunning());
 
-  // First language item is selected, and selected item should have focus.
-  EXPECT_EQ(test_api.selected_language_item().value, kEnglishLanguageCode);
-  PublicAccountMenuView::TestApi language_test_api(
-      test_api.language_menu_view());
-  ASSERT_EQ(2u, language_test_api.contents()->children().size());
-  EXPECT_TRUE(language_test_api.contents()->children()[0]->HasFocus());
+  // First language item is selected.
+  EXPECT_EQ(test_api.selected_language_item_value(), kEnglishLanguageCode);
+  ASSERT_EQ(2, language_menu_view->GetRowCount());
+  EXPECT_EQ(0, language_menu_view->GetSelectedRow());
 
-  // Select language item should close the language menu.
+  // Once the menu is open, the focus is set on the entire view.
+  // The first key press will set the focus on the language item, the second
+  // press will select it and should close the language menu.
   GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
-  EXPECT_FALSE(test_api.language_menu_view()->GetVisible());
-
-  // Tap on keyboard selection button should bring up the keyboard menu.
-  TapOnView(test_api.keyboard_selection_button());
-  EXPECT_TRUE(test_api.keyboard_menu_view()->GetVisible());
-
-  // Second keyboard item is selected, and selected item should have focus.
-  EXPECT_EQ(test_api.selected_keyboard_item().value, kKeyboardIdForItem2);
-  PublicAccountMenuView::TestApi keyboard_test_api(
-      test_api.keyboard_menu_view());
-  ASSERT_EQ(2u, keyboard_test_api.contents()->children().size());
-  EXPECT_TRUE(keyboard_test_api.contents()->children()[1]->HasFocus());
-
-  // Select keyboard item should close the keyboard menu.
   GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
-  EXPECT_FALSE(test_api.keyboard_menu_view()->GetVisible());
+  EXPECT_FALSE(language_menu_view->IsMenuRunning());
+
+  // Open keyboard menu.
+  PublicAccountMenuView* keyboard_menu_view = test_api.keyboard_menu_view();
+  EXPECT_FALSE(keyboard_menu_view->IsMenuRunning());
+  TapOnView(keyboard_menu_view);
+  EXPECT_TRUE(keyboard_menu_view->IsMenuRunning());
+
+  // Second keyboard item is selected.
+  EXPECT_EQ(test_api.selected_keyboard_item_value(), kKeyboardIdForItem2);
+  ASSERT_EQ(2, keyboard_menu_view->GetRowCount());
+  EXPECT_EQ(1, keyboard_menu_view->GetSelectedRow());
+
+  // Once the menu is open, the focus is set on the entire view.
+  // The first key press will set the focus on the keyboard item, the second
+  // press will select it and should close the keyboard menu.
+  GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
+  GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
+  EXPECT_FALSE(keyboard_menu_view->IsMenuRunning());
 }
 
 TEST_P(LoginExpandedPublicAccountViewTest, ChangeMenuSelection) {
@@ -267,43 +276,48 @@
   public_account_->UpdateForUser(user_);
   EXPECT_TRUE(test_api.advanced_view()->GetVisible());
 
-  // Try to change language selection.
   // Open language menu.
-  TapOnView(test_api.language_selection_button());
-  EXPECT_TRUE(test_api.language_menu_view()->GetVisible());
+  PublicAccountMenuView* language_menu_view = test_api.language_menu_view();
+  EXPECT_FALSE(language_menu_view->IsMenuRunning());
+  TapOnView(language_menu_view);
+  EXPECT_TRUE(language_menu_view->IsMenuRunning());
 
   // Select second language item:
-  // 1. Language menu will be closed automatically.
-  // 2. Selected language item will change.
-  // 3. Expect RequestPublicSessionKeyboardLayouts mojo call with the selected
+  // 1. Selected language will change.
+  // 2. Expect RequestPublicSessionKeyboardLayouts mojo call with the selected
   // language item.
   auto client = std::make_unique<MockLoginScreenClient>();
   EXPECT_CALL(*client,
               RequestPublicSessionKeyboardLayouts(
                   user_.basic_user_info.account_id, kFrenchLanguageCode));
 
-  EXPECT_EQ(test_api.selected_language_item().value, kEnglishLanguageCode);
-  PublicAccountMenuView::TestApi language_test_api(
-      test_api.language_menu_view());
-  TapOnView(language_test_api.contents()->children()[1]);
-  EXPECT_FALSE(test_api.language_menu_view()->GetVisible());
-  EXPECT_EQ(test_api.selected_language_item().value, kFrenchLanguageCode);
+  EXPECT_EQ(test_api.selected_language_item_value(), kEnglishLanguageCode);
+  std::unique_ptr<views::test::ComboboxTestApi> language_test_api =
+      std::make_unique<views::test::ComboboxTestApi>(language_menu_view);
+  // Note that we do not need to open the menu to make this test API call.
+  language_test_api->PerformActionAt(1);
+  EXPECT_EQ(test_api.selected_language_item_value(), kFrenchLanguageCode);
   base::RunLoop().RunUntilIdle();
 
-  // Try to change keyboard selection.
+  PublicAccountMenuView* keyboard_menu_view = test_api.keyboard_menu_view();
+  // Close language menu.
+  // `PerformActionAt` does not close the menu automatically, make a click
+  // outside of language menu boundaries to close the menu.
+  EXPECT_TRUE(language_menu_view->IsMenuRunning());
+  TapOnView(keyboard_menu_view);
+  EXPECT_FALSE(language_menu_view->IsMenuRunning());
   // Open keyboard menu.
-  TapOnView(test_api.keyboard_selection_button());
-  EXPECT_TRUE(test_api.keyboard_menu_view()->GetVisible());
+  EXPECT_FALSE(keyboard_menu_view->IsMenuRunning());
+  TapOnView(keyboard_menu_view);
+  EXPECT_TRUE(keyboard_menu_view->IsMenuRunning());
 
-  // Select first keyboard item:
-  // 1. Keyboard menu will be closed automatically.
-  // 2. Selected keyboard item will change.
-  EXPECT_EQ(test_api.selected_keyboard_item().value, kKeyboardIdForItem2);
-  PublicAccountMenuView::TestApi keyboard_test_api(
-      test_api.keyboard_menu_view());
-  TapOnView(keyboard_test_api.contents()->children()[0]);
-  EXPECT_FALSE(test_api.keyboard_menu_view()->GetVisible());
-  EXPECT_EQ(test_api.selected_keyboard_item().value, kKeyboardIdForItem1);
+  // Select first keyboard item, selected keyboard will change.
+  EXPECT_EQ(test_api.selected_keyboard_item_value(), kKeyboardIdForItem2);
+  std::unique_ptr<views::test::ComboboxTestApi> keyboard_test_api =
+      std::make_unique<views::test::ComboboxTestApi>(
+          test_api.keyboard_menu_view());
+  keyboard_test_api->PerformActionAt(0);
+  EXPECT_EQ(test_api.selected_keyboard_item_value(), kKeyboardIdForItem1);
 }
 
 TEST_P(LoginExpandedPublicAccountViewTest, ChangeWarningLabel) {
diff --git a/ash/login/ui/public_account_menu_view.cc b/ash/login/ui/public_account_menu_view.cc
index 74875815..11b51c53 100644
--- a/ash/login/ui/public_account_menu_view.cc
+++ b/ash/login/ui/public_account_menu_view.cc
@@ -4,227 +4,79 @@
 
 #include "ash/login/ui/public_account_menu_view.h"
 
-#include <algorithm>
-#include <iterator>
-#include <memory>
-#include <utility>
-
 #include "ash/login/ui/hover_notifier.h"
 #include "ash/login/ui/non_accessible_view.h"
 #include "ash/style/ash_color_provider.h"
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/controls/scroll_view.h"
-#include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
-#include "ui/views/layout/box_layout.h"
+#include "ui/base/models/combobox_model.h"
 
 namespace ash {
 
 constexpr int kMenuItemWidthDp = 192;
-constexpr int kMenuItemHeightDp = 28;
-constexpr int kRegularMenuItemLeftPaddingDp = 2;
-constexpr int kGroupMenuItemLeftPaddingDp = 10;
-constexpr int kNonEmptyHeight = 1;
 
 namespace {
 
-class MenuItemView : public views::Button {
+class PublicAccountComboboxModel : public ui::ComboboxModel {
  public:
-  MenuItemView(const PublicAccountMenuView::Item& item,
-               const PublicAccountMenuView::OnHighlight& on_highlight)
-      : views::Button(base::BindRepeating(&MenuItemView::ButtonPressed,
-                                          base::Unretained(this))),
-        item_(item),
-        on_highlight_(on_highlight) {
-    SetFocusBehavior(FocusBehavior::ALWAYS);
-    set_suppress_default_focus_handling();
-    SetLayoutManager(std::make_unique<views::BoxLayout>(
-        views::BoxLayout::Orientation::kHorizontal));
-    SetPreferredSize(gfx::Size(kMenuItemWidthDp, kMenuItemHeightDp));
+  PublicAccountComboboxModel(
+      const std::vector<PublicAccountMenuView::Item>& items,
+      const size_t default_index)
+      : items_(items), default_index_(default_index) {}
 
-    auto spacing = std::make_unique<NonAccessibleView>();
-    spacing->SetPreferredSize(gfx::Size(item.is_group
-                                            ? kRegularMenuItemLeftPaddingDp
-                                            : kGroupMenuItemLeftPaddingDp,
-                                        kNonEmptyHeight));
-    AddChildView(std::move(spacing));
+  PublicAccountComboboxModel(const PublicAccountComboboxModel&) = delete;
+  PublicAccountComboboxModel& operator=(const PublicAccountComboboxModel&) =
+      delete;
 
-    auto label = std::make_unique<views::Label>(base::UTF8ToUTF16(item.title));
-    label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
-        AshColorProvider::ContentLayerType::kTextColorPrimary));
-    label->SetSubpixelRenderingEnabled(false);
-    label->SetAutoColorReadabilityEnabled(false);
-    label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    AddChildView(std::move(label));
+  ~PublicAccountComboboxModel() override = default;
 
-    if (item.selected)
-      SetBackground(views::CreateSolidBackground(SK_ColorGRAY));
+  // ui::ComboboxModel:
+  int GetItemCount() const override { return items_.size(); }
 
-    hover_notifier_ = std::make_unique<HoverNotifier>(
-        this,
-        base::BindRepeating(&MenuItemView::OnHover, base::Unretained(this)));
-  }
-  MenuItemView(const MenuItemView&) = delete;
-  MenuItemView& operator=(const MenuItemView&) = delete;
-  ~MenuItemView() override = default;
-
-  // views::View:
-  int GetHeightForWidth(int w) const override {
-    // Make row height fixed avoiding layout manager adjustments.
-    return GetPreferredSize().height();
+  // ui::ComboboxModel:
+  std::u16string GetItemAt(int index) const override {
+    return base::UTF8ToUTF16(items_[index].title);
   }
 
-  void OnHover(bool has_hover) {
-    if (has_hover && !item_.is_group)
-      RequestFocus();
+  // ui::ComboboxModel:
+  // Alternatively, we could override `IsItemSeparatorAt`, especially since
+  // group items are considered as some sort of separators. We choose to
+  // represent them as disabled items because they were presented in a similar
+  // fashion before (i.e. the group name was visible but unclickable).
+  bool IsItemEnabledAt(int index) const override {
+    return !items_[index].is_group;
   }
 
-  void OnFocus() override {
-    ScrollViewToVisible();
-    on_highlight_.Run(false /*by_selection*/);
-  }
-
-  const PublicAccountMenuView::Item& item() const { return item_; }
+  // ui::ComboboxModel:
+  int GetDefaultIndex() const override { return default_index_; }
 
  private:
-  void ButtonPressed() {
-    if (!item_.is_group)
-      on_highlight_.Run(true /*by_selection*/);
-  }
-
-  const PublicAccountMenuView::Item item_;
-  const PublicAccountMenuView::OnHighlight on_highlight_;
-  std::unique_ptr<HoverNotifier> hover_notifier_;
-};
-
-class LoginScrollBar : public views::OverlayScrollBar {
- public:
-  LoginScrollBar() : OverlayScrollBar(false) {}
-  LoginScrollBar(const LoginScrollBar&) = delete;
-  LoginScrollBar& operator=(const LoginScrollBar&) = delete;
-  ~LoginScrollBar() override = default;
-
-  // OverlayScrollBar:
-  bool OnKeyPressed(const ui::KeyEvent& event) override {
-    // Let LoginMenuView to handle up/down keypress.
-    return false;
-  }
+  const std::vector<PublicAccountMenuView::Item>& items_;
+  const int default_index_;
 };
 
 }  // namespace
 
-PublicAccountMenuView::TestApi::TestApi(PublicAccountMenuView* view)
-    : view_(view) {}
-
-PublicAccountMenuView::TestApi::~TestApi() = default;
-
-views::View* PublicAccountMenuView::TestApi::contents() const {
-  return view_->contents_;
-}
-
 PublicAccountMenuView::Item::Item() = default;
 
 PublicAccountMenuView::PublicAccountMenuView(const std::vector<Item>& items,
-                                             views::View* anchor_view,
-                                             LoginButton* opener,
+                                             const size_t selected_index,
                                              const OnSelect& on_select)
-    : LoginBaseBubbleView(anchor_view), opener_(opener), on_select_(on_select) {
-  SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
-  set_suppress_default_focus_handling();
+    : views::Combobox(new PublicAccountComboboxModel(items, selected_index)),
+      items_(items),
+      on_select_(on_select) {
+  SetPreferredSize(
+      gfx::Size(kMenuItemWidthDp, GetHeightForWidth(kMenuItemWidthDp)));
 
-  scroller_ = new views::ScrollView();
-  scroller_->SetBackgroundColor(absl::nullopt);
-  scroller_->SetDrawOverflowIndicator(false);
-  scroller_->ClipHeightTo(kMenuItemHeightDp, kMenuItemHeightDp * 5);
-  AddChildView(scroller_);
-
-  views::BoxLayout* box_layout =
-      SetLayoutManager(std::make_unique<views::BoxLayout>(
-          views::BoxLayout::Orientation::kVertical));
-  box_layout->SetFlexForView(scroller_, 1);
-
-  auto contents = std::make_unique<NonAccessibleView>();
-  views::BoxLayout* layout =
-      contents->SetLayoutManager(std::make_unique<views::BoxLayout>(
-          views::BoxLayout::Orientation::kVertical));
-  layout->SetDefaultFlex(1);
-  layout->set_minimum_cross_axis_size(kMenuItemWidthDp);
-  layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kCenter);
-
-  for (size_t i = 0; i < items.size(); i++) {
-    const Item& item = items[i];
-    contents->AddChildView(new MenuItemView(
-        item, base::BindRepeating(&PublicAccountMenuView::OnHighlightChange,
-                                  base::Unretained(this), i)));
-
-    if (item.selected)
-      selected_index_ = i;
-  }
-  contents_ = scroller_->SetContents(std::move(contents));
-  scroller_->SetVerticalScrollBar(std::make_unique<LoginScrollBar>());
+  property_changed_subscription_ = AddSelectedIndexChangedCallback(
+      base::BindRepeating(&PublicAccountMenuView::OnSelectedIndexChanged,
+                          weak_factory_.GetWeakPtr()));
 }
 
 PublicAccountMenuView::~PublicAccountMenuView() = default;
 
-void PublicAccountMenuView::OnHighlightChange(size_t item_index,
-                                              bool by_selection) {
-  selected_index_ = item_index;
-  views::View* highlight_item = contents_->children()[item_index];
-  for (views::View* child : contents_->GetChildrenInZOrder()) {
-    child->SetBackground(views::CreateSolidBackground(
-        child == highlight_item ? SK_ColorGRAY : SK_ColorTRANSPARENT));
-  }
-
-  if (by_selection) {
-    SetVisible(false);
-    MenuItemView* menu_view = static_cast<MenuItemView*>(highlight_item);
-    on_select_.Run(menu_view->item());
-  }
-  contents_->SchedulePaint();
-}
-
-LoginButton* PublicAccountMenuView::GetBubbleOpener() const {
-  return opener_;
-}
-
-void PublicAccountMenuView::OnFocus() {
-  // Forward the focus to the selected child view.
-  contents_->children()[selected_index_]->RequestFocus();
-}
-
-bool PublicAccountMenuView::OnKeyPressed(const ui::KeyEvent& event) {
-  const ui::KeyboardCode key = event.key_code();
-  if (key == ui::VKEY_UP || key == ui::VKEY_DOWN) {
-    FindNextItem(key == ui::VKEY_UP)->RequestFocus();
-    return true;
-  }
-
-  return false;
-}
-
-void PublicAccountMenuView::VisibilityChanged(View* starting_from,
-                                              bool is_visible) {
-  if (is_visible)
-    contents_->children()[selected_index_]->RequestFocus();
-}
-
-views::View* PublicAccountMenuView::FindNextItem(bool reverse) {
-  const auto& children = contents_->children();
-  const auto is_item = [](views::View* v) {
-    return !static_cast<MenuItemView*>(v)->item().is_group;
-  };
-  const auto begin = std::next(children.begin(), selected_index_);
-  if (reverse) {
-    // Subtle: make_reverse_iterator() will result in an iterator that refers to
-    // the element before its argument, which is what we want.
-    const auto i = std::find_if(std::make_reverse_iterator(begin),
-                                children.rend(), is_item);
-    return (i == children.rend()) ? *begin : *i;
-  }
-  const auto i = std::find_if(std::next(begin), children.end(), is_item);
-  return (i == children.end()) ? *begin : *i;
+void PublicAccountMenuView::OnSelectedIndexChanged() {
+  on_select_.Run(items_[GetSelectedIndex()].value);
 }
 
 }  // namespace ash
diff --git a/ash/login/ui/public_account_menu_view.h b/ash/login/ui/public_account_menu_view.h
index db9885fe..adf94ad 100644
--- a/ash/login/ui/public_account_menu_view.h
+++ b/ash/login/ui/public_account_menu_view.h
@@ -6,33 +6,14 @@
 #define ASH_LOGIN_UI_PUBLIC_ACCOUNT_MENU_VIEW_H_
 
 #include "ash/ash_export.h"
-#include "ash/login/ui/login_base_bubble_view.h"
-#include "ash/login/ui/login_button.h"
-#include "base/callback.h"
-#include "ui/views/view.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/views/controls/combobox/combobox.h"
 
 namespace ash {
 
 // Implements a menu view for the login screen's expanded public account view.
-// This is used instead of views::Combobox because we want a more customisable
-// view for the menu items to support some sepcific styles like nested menu
-// entries which have different left margin (less than regular items) and are
-// not selectable. views::Combobox uses views::MenuItemView which is not very
-// straightforward to customize.
-class ASH_EXPORT PublicAccountMenuView : public LoginBaseBubbleView {
+class ASH_EXPORT PublicAccountMenuView : public views::Combobox {
  public:
-  // TestApi is used for tests to get internal implementation details.
-  class ASH_EXPORT TestApi {
-   public:
-    explicit TestApi(PublicAccountMenuView* view);
-    ~TestApi();
-
-    views::View* contents() const;
-
-   private:
-    PublicAccountMenuView* const view_;
-  };
-
   struct Item {
     Item();
 
@@ -42,40 +23,24 @@
     bool selected = false;
   };
 
-  using OnSelect = base::RepeatingCallback<void(Item item)>;
-  using OnHighlight = base::RepeatingCallback<void(bool by_selection)>;
+  using OnSelect = base::RepeatingCallback<void(const std::string& value)>;
 
   PublicAccountMenuView(const std::vector<Item>& items,
-                        views::View* anchor_view,
-                        LoginButton* opener_,
+                        const size_t selected_index,
                         const OnSelect& on_select);
   PublicAccountMenuView(const PublicAccountMenuView&) = delete;
   PublicAccountMenuView& operator=(const PublicAccountMenuView&) = delete;
   ~PublicAccountMenuView() override;
 
-  void OnHighlightChange(size_t item_index, bool by_selection);
-
-  // LoginBaseBubbleView:
-  LoginButton* GetBubbleOpener() const override;
-
-  // views::View:
-  void OnFocus() override;
-  bool OnKeyPressed(const ui::KeyEvent& event) override;
-  void VisibilityChanged(View* starting_from, bool is_visible) override;
+  void OnSelectedIndexChanged();
 
  private:
-  views::View* FindNextItem(bool reverse);
-
-  // Owned by this class.
-  views::ScrollView* scroller_ = nullptr;
-
-  // Owned by ScrollView.
-  views::View* contents_ = nullptr;
-
-  LoginButton* opener_ = nullptr;
-
+  const std::vector<Item>& items_;
   const OnSelect on_select_;
-  size_t selected_index_ = 0;
+
+  base::CallbackListSubscription property_changed_subscription_;
+
+  base::WeakPtrFactory<PublicAccountMenuView> weak_factory_{this};
 };
 
 }  // namespace ash
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 6267301..d637941 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -23,6 +23,8 @@
     "accessibility_focus_ring_controller.h",
     "accessibility_focus_ring_info.cc",
     "accessibility_focus_ring_info.h",
+    "ambient/ambient_animation_theme.cc",
+    "ambient/ambient_animation_theme.h",
     "ambient/ambient_backend_controller.cc",
     "ambient/ambient_backend_controller.h",
     "ambient/ambient_client.cc",
diff --git a/ash/public/cpp/ambient/ambient_animation_theme.cc b/ash/public/cpp/ambient/ambient_animation_theme.cc
new file mode 100644
index 0000000..558c2b1
--- /dev/null
+++ b/ash/public/cpp/ambient/ambient_animation_theme.cc
@@ -0,0 +1,18 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/public/cpp/ambient/ambient_animation_theme.h"
+
+namespace ash {
+
+std::ostream& operator<<(std::ostream& os, AmbientAnimationTheme theme) {
+  switch (theme) {
+    case AmbientAnimationTheme::kSlideshow:
+      return os << "SLIDESHOW";
+    case AmbientAnimationTheme::kFeelTheBreeze:
+      return os << "FEEL_THE_BREZE";
+  }
+}
+
+}  // namespace ash
diff --git a/ash/public/cpp/ambient/ambient_animation_theme.h b/ash/public/cpp/ambient/ambient_animation_theme.h
new file mode 100644
index 0000000..80ad8de3
--- /dev/null
+++ b/ash/public/cpp/ambient/ambient_animation_theme.h
@@ -0,0 +1,33 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PUBLIC_CPP_AMBIENT_AMBIENT_ANIMATION_THEME_H_
+#define ASH_PUBLIC_CPP_AMBIENT_AMBIENT_ANIMATION_THEME_H_
+
+#include <ostream>
+
+#include "ash/public/cpp/ash_public_export.h"
+
+namespace ash {
+
+// Each corresponds to an animation design for ambient mode that UX created and
+// has its own Lottie file.
+//
+// These values are persisted in user pref storage, so they should never be
+// renumbered or reused.
+enum class ASH_PUBLIC_EXPORT AmbientAnimationTheme {
+  // This is the one exception in the list, and it describes the mode where
+  // IMAX photos are displayed at full screen in a slideshow fashion. This is
+  // not currently implemented as an "animation" and doesn't have a Lottie file.
+  // It is currently implemented entirely as a native UI view.
+  kSlideshow = 0,
+  kFeelTheBreeze = 1,
+};
+
+ASH_PUBLIC_EXPORT std::ostream& operator<<(std::ostream& os,
+                                           AmbientAnimationTheme theme);
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_AMBIENT_AMBIENT_ANIMATION_THEME_H_
diff --git a/ash/resources/BUILD.gn b/ash/resources/BUILD.gn
index 4f4dc66..2cc4f721 100644
--- a/ash/resources/BUILD.gn
+++ b/ash/resources/BUILD.gn
@@ -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("//ash/ambient/resources/resources.gni")
 import("//build/config/chromeos/ui_mode.gni")
 import("//tools/grit/grit_rule.gni")
 import("//tools/grit/repack.gni")
@@ -16,6 +17,13 @@
     "$root_gen_dir/ash/public/cpp/resources/ash_public_unscaled_resources.pak",
   ]
   deps = [ "//ash/public/cpp/resources:ash_public_unscaled_resources" ]
+
+  if (include_ash_ambient_animation_resources) {
+    sources += [
+      "$root_gen_dir/ash/ambient/resources/ash_ambient_lottie_resources.pak",
+    ]
+    deps += [ "//ash/ambient/resources:lottie_resources" ]
+  }
 }
 
 # Repacks resources needed for ash_unittests, etc. at a given scale.
diff --git a/ash/system/geolocation/geolocation_controller.cc b/ash/system/geolocation/geolocation_controller.cc
index a3f0e28..12c941e 100644
--- a/ash/system/geolocation/geolocation_controller.cc
+++ b/ash/system/geolocation/geolocation_controller.cc
@@ -17,6 +17,8 @@
 
 namespace {
 
+GeolocationController* g_geolocation_controller = nullptr;
+
 // Delay to wait for a response to our geolocation request, if we get a response
 // after which, we will consider the request a failure.
 constexpr base::TimeDelta kGeolocationRequestTimeout = base::Seconds(60);
@@ -44,10 +46,19 @@
   auto* timezone_settings = chromeos::system::TimezoneSettings::GetInstance();
   current_timezone_id_ = timezone_settings->GetCurrentTimezoneID();
   timezone_settings->AddObserver(this);
+  g_geolocation_controller = this;
 }
 
 GeolocationController::~GeolocationController() {
   chromeos::system::TimezoneSettings::GetInstance()->RemoveObserver(this);
+  DCHECK_EQ(g_geolocation_controller, this);
+  g_geolocation_controller = nullptr;
+}
+
+// static
+GeolocationController* GeolocationController::Get() {
+  DCHECK(g_geolocation_controller);
+  return g_geolocation_controller;
 }
 
 void GeolocationController::AddObserver(Observer* observer) {
@@ -110,12 +121,30 @@
     return;
   }
 
-  last_successful_geo_request_time_ = GetNow();
+  absl::optional<base::Time> previous_sunset;
+  absl::optional<base::Time> previous_sunrise;
+  bool possible_change_in_timezone = !geoposition_;
+  if (geoposition_) {
+    previous_sunset = GetSunsetTime();
+    previous_sunrise = GetSunriseTime();
+  }
 
   geoposition_ = std::make_unique<SimpleGeoposition>();
   geoposition_->latitude = position.latitude;
   geoposition_->longitude = position.longitude;
-  NotifyWithCurrentGeoposition(*geoposition_);
+
+  if (previous_sunset && previous_sunrise) {
+    // If the change in geoposition results in an hour or more in either sunset
+    // or sunrise times indicates of a possible timezone change.
+    constexpr base::TimeDelta kOneHourDuration = base::Hours(1);
+    possible_change_in_timezone =
+        (GetSunsetTime() - previous_sunset.value()).magnitude() >
+            kOneHourDuration ||
+        (GetSunriseTime() - previous_sunrise.value()).magnitude() >
+            kOneHourDuration;
+  }
+
+  NotifyGeopositionChange(possible_change_in_timezone);
 
   // On success, reset the backoff delay to its minimum value, and schedule
   // another request.
@@ -132,10 +161,10 @@
                 &GeolocationController::RequestGeoposition);
 }
 
-void GeolocationController::NotifyWithCurrentGeoposition(
-    SimpleGeoposition position) {
+void GeolocationController::NotifyGeopositionChange(
+    bool possible_change_in_timezone) {
   for (Observer& observer : observers_)
-    observer.OnGeopositionChanged(position);
+    observer.OnGeopositionChanged(possible_change_in_timezone);
 }
 
 void GeolocationController::RequestGeoposition() {
diff --git a/ash/system/geolocation/geolocation_controller.h b/ash/system/geolocation/geolocation_controller.h
index 055504c..499b476 100644
--- a/ash/system/geolocation/geolocation_controller.h
+++ b/ash/system/geolocation/geolocation_controller.h
@@ -47,8 +47,10 @@
  public:
   class Observer : public base::CheckedObserver {
    public:
-    // Emitted when the Geoposition is updated.
-    virtual void OnGeopositionChanged(SimpleGeoposition position) {}
+    // Emitted when the Geoposition is updated with
+    // |possible_change_in_timezone| to indicate whether timezone might have
+    // changed as a result of the geoposition change.
+    virtual void OnGeopositionChanged(bool possible_change_in_timezone) {}
 
    protected:
     ~Observer() override = default;
@@ -60,6 +62,8 @@
   GeolocationController& operator=(const GeolocationController&) = delete;
   ~GeolocationController() override;
 
+  static GeolocationController* Get();
+
   const base::OneShotTimer& timer() const { return *timer_; }
 
   base::Time last_successful_geo_request_time() const {
@@ -107,8 +111,10 @@
   // Calls `RequestGeoposition()` after `delay`.
   void ScheduleNextRequest(base::TimeDelta delay);
 
-  // Broadcasts the new position obtained from the request to all observers.
-  void NotifyWithCurrentGeoposition(SimpleGeoposition position);
+  // Broadcasts the change in geoposition to all observers with
+  // |possible_change_in_timezone| to indicate whether timezone might have
+  // changed as a result of the geoposition change.
+  void NotifyGeopositionChange(bool possible_change_in_timezone);
 
   // Virtual so that it can be overridden by a fake implementation in unit tests
   // that doesn't request actual geopositions.
diff --git a/ash/system/geolocation/geolocation_controller_unittest.cc b/ash/system/geolocation/geolocation_controller_unittest.cc
index a5a3d37..b6cb8c52 100644
--- a/ash/system/geolocation/geolocation_controller_unittest.cc
+++ b/ash/system/geolocation/geolocation_controller_unittest.cc
@@ -41,7 +41,7 @@
 
   // TODO(crbug.com/1269915): Add `sunset_` and `sunrise_` and update their
   // values when receiving the new position.
-  void OnGeopositionChanged(SimpleGeoposition position) override {
+  void OnGeopositionChanged(bool possible_change_in_timezone) override {
     position_received_num_++;
   }
 
diff --git a/ash/system/message_center/notification_grouping_controller.cc b/ash/system/message_center/notification_grouping_controller.cc
index 56bbe59..b49cce3a 100644
--- a/ash/system/message_center/notification_grouping_controller.cc
+++ b/ash/system/message_center/notification_grouping_controller.cc
@@ -142,6 +142,10 @@
                  << notification_id;
     return;
   }
+
+  if (!parent_view->IsManuallyExpandedOrCollapsed())
+    parent_view->SetExpanded(false);
+
   std::vector<const Notification*> notifications;
   for (const auto* notification : MessageCenter::Get()->GetNotifications()) {
     if (notification->notifier_id() == parent_view->notifier_id() &&
diff --git a/ash/system/message_center/stacked_notification_bar.cc b/ash/system/message_center/stacked_notification_bar.cc
index 9371f5c4..dde6eb06 100644
--- a/ash/system/message_center/stacked_notification_bar.cc
+++ b/ash/system/message_center/stacked_notification_bar.cc
@@ -110,7 +110,10 @@
       return;
 
     SkColor accent_color =
-        color_provider->GetColor(ui::kColorNotificationHeaderForeground);
+        features::IsNotificationsRefreshEnabled()
+            ? AshColorProvider::Get()->GetContentLayerColor(
+                  AshColorProvider::ContentLayerType::kIconColorPrimary)
+            : color_provider->GetColor(ui::kColorNotificationHeaderForeground);
     gfx::Image masked_small_icon = notification->GenerateMaskedSmallIcon(
         kStackedNotificationIconSize, accent_color,
         color_provider->GetColor(ui::kColorNotificationIconBackground),
@@ -265,7 +268,12 @@
 
   message_center::MessageCenter::Get()->AddObserver(this);
 
-  count_label_->SetEnabledColor(message_center_style::kCountLabelColor);
+  SkColor label_color =
+      features::IsNotificationsRefreshEnabled()
+          ? AshColorProvider::Get()->GetContentLayerColor(
+                AshColorProvider::ContentLayerType::kIconColorPrimary)
+          : message_center_style::kCountLabelColor;
+  count_label_->SetEnabledColor(label_color);
   count_label_->SetFontList(views::Label::GetDefaultFontList().Derive(
       1, gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM));
 
diff --git a/ash/system/scheduled_feature/scheduled_feature.cc b/ash/system/scheduled_feature/scheduled_feature.cc
new file mode 100644
index 0000000..0ff37e4
--- /dev/null
+++ b/ash/system/scheduled_feature/scheduled_feature.cc
@@ -0,0 +1,407 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/scheduled_feature/scheduled_feature.h"
+
+#include <cmath>
+#include <memory>
+
+#include "ash/constants/ash_features.h"
+#include "ash/constants/ash_pref_names.h"
+#include "ash/public/cpp/notification_utils.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/shell.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ash/system/geolocation/geolocation_controller.h"
+#include "ash/system/model/system_tray_model.h"
+#include "base/bind.h"
+#include "base/cxx17_backports.h"
+#include "base/i18n/time_formatting.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "third_party/icu/source/i18n/astro.h"
+#include "ui/aura/env.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace ash {
+
+namespace {
+
+// Default start time at 6:00 PM as an offset from 00:00.
+constexpr int kDefaultStartTimeOffsetMinutes = 18 * 60;
+
+// Default end time at 6:00 AM as an offset from 00:00.
+constexpr int kDefaultEndTimeOffsetMinutes = 6 * 60;
+
+}  // namespace
+
+ScheduledFeature::ScheduledFeature(
+    const std::string prefs_path_enabled,
+    const std::string prefs_path_schedule_type,
+    const std::string prefs_path_custom_start_time,
+    const std::string prefs_path_custom_end_time)
+    : prefs_path_enabled_(prefs_path_enabled),
+      prefs_path_schedule_type_(prefs_path_schedule_type),
+      prefs_path_custom_start_time_(prefs_path_custom_start_time),
+      prefs_path_custom_end_time_(prefs_path_custom_end_time),
+      geolocation_controller_(ash::GeolocationController::Get()) {
+  Shell::Get()->session_controller()->AddObserver(this);
+  aura::Env::GetInstance()->AddObserver(this);
+  chromeos::PowerManagerClient::Get()->AddObserver(this);
+}
+
+ScheduledFeature::~ScheduledFeature() {
+  chromeos::PowerManagerClient::Get()->RemoveObserver(this);
+  aura::Env::GetInstance()->RemoveObserver(this);
+  Shell::Get()->session_controller()->RemoveObserver(this);
+}
+
+// static
+bool ScheduledFeature::GetEnabled() const {
+  return active_user_pref_service_ &&
+         active_user_pref_service_->GetBoolean(prefs_path_enabled_);
+}
+
+ScheduledFeature::ScheduleType ScheduledFeature::GetScheduleType() const {
+  if (active_user_pref_service_) {
+    return static_cast<ScheduleType>(
+        active_user_pref_service_->GetInteger(prefs_path_schedule_type_));
+  }
+
+  return ScheduleType::kNone;
+}
+
+TimeOfDay ScheduledFeature::GetCustomStartTime() const {
+  if (active_user_pref_service_) {
+    return TimeOfDay(
+        active_user_pref_service_->GetInteger(prefs_path_custom_start_time_));
+  }
+
+  return TimeOfDay(kDefaultStartTimeOffsetMinutes);
+}
+
+TimeOfDay ScheduledFeature::GetCustomEndTime() const {
+  if (active_user_pref_service_) {
+    return TimeOfDay(
+        active_user_pref_service_->GetInteger(prefs_path_custom_end_time_));
+  }
+
+  return TimeOfDay(kDefaultEndTimeOffsetMinutes);
+}
+
+bool ScheduledFeature::IsNowWithinSunsetSunrise() const {
+  // The times below are all on the same calendar day.
+  const base::Time now = GetNow();
+  return now < geolocation_controller_->GetSunriseTime() ||
+         now > geolocation_controller_->GetSunsetTime();
+}
+
+void ScheduledFeature::SetEnabled(bool enabled) {
+  if (active_user_pref_service_)
+    active_user_pref_service_->SetBoolean(prefs_path_enabled_, enabled);
+}
+
+void ScheduledFeature::SetScheduleType(ScheduleType type) {
+  if (active_user_pref_service_) {
+    active_user_pref_service_->SetInteger(prefs_path_schedule_type_,
+                                          static_cast<int>(type));
+  }
+}
+
+void ScheduledFeature::SetCustomStartTime(TimeOfDay start_time) {
+  if (active_user_pref_service_) {
+    active_user_pref_service_->SetInteger(
+        prefs_path_custom_start_time_,
+        start_time.offset_minutes_from_zero_hour());
+  }
+}
+
+void ScheduledFeature::SetCustomEndTime(TimeOfDay end_time) {
+  if (active_user_pref_service_) {
+    active_user_pref_service_->SetInteger(
+        prefs_path_custom_end_time_, end_time.offset_minutes_from_zero_hour());
+  }
+}
+
+void ScheduledFeature::OnActiveUserPrefServiceChanged(
+    PrefService* pref_service) {
+  if (pref_service == active_user_pref_service_)
+    return;
+
+  // Initial login and user switching in multi profiles.
+  active_user_pref_service_ = pref_service;
+  InitFromUserPrefs();
+}
+
+void ScheduledFeature::OnGeopositionChanged(bool possible_change_in_timezone) {
+  DCHECK(GetScheduleType() != ScheduleType::kNone);
+
+  VLOG(1) << "Received new geoposition.";
+
+  // We only keep manual toggles if there's no change in timezone.
+  const bool keep_manual_toggles_during_schedules =
+      !possible_change_in_timezone;
+
+  Refresh(/*did_schedule_change=*/true, keep_manual_toggles_during_schedules);
+}
+
+void ScheduledFeature::SuspendDone(base::TimeDelta sleep_duration) {
+  // Time changes while the device is suspended. We need to refresh the schedule
+  // upon device resume to know what the status should be now.
+  Refresh(/*did_schedule_change=*/true,
+          /*keep_manual_toggles_during_schedules=*/true);
+}
+
+void ScheduledFeature::SetClockForTesting(base::Clock* clock) {
+  clock_ = clock;
+}
+
+base::Time ScheduledFeature::GetNow() const {
+  return clock_ ? clock_->Now() : base::Time::Now();
+}
+
+bool ScheduledFeature::MaybeRestoreSchedule() {
+  DCHECK(active_user_pref_service_);
+  DCHECK_NE(GetScheduleType(), ScheduleType::kNone);
+
+  auto iter = per_user_schedule_target_state_.find(active_user_pref_service_);
+  if (iter == per_user_schedule_target_state_.end())
+    return false;
+
+  ScheduleTargetState& target_state = iter->second;
+  const base::Time now = GetNow();
+  // It may be that the device was suspended for a very long time that the
+  // target time is no longer valid.
+  if (target_state.target_time <= now)
+    return false;
+
+  VLOG(1) << "Restoring a previous schedule.";
+  DCHECK_NE(GetEnabled(), target_state.target_status);
+  ScheduleNextToggle(target_state.target_time - now);
+  return true;
+}
+
+void ScheduledFeature::StartWatchingPrefsChanges() {
+  DCHECK(active_user_pref_service_);
+
+  pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
+  pref_change_registrar_->Init(active_user_pref_service_);
+  pref_change_registrar_->Add(
+      prefs_path_enabled_,
+      base::BindRepeating(&ScheduledFeature::OnEnabledPrefChanged,
+                          base::Unretained(this)));
+  pref_change_registrar_->Add(
+      prefs_path_schedule_type_,
+      base::BindRepeating(&ScheduledFeature::OnScheduleTypePrefChanged,
+                          base::Unretained(this)));
+  pref_change_registrar_->Add(
+      prefs_path_custom_start_time_,
+      base::BindRepeating(&ScheduledFeature::OnCustomSchedulePrefsChanged,
+                          base::Unretained(this)));
+  pref_change_registrar_->Add(
+      prefs_path_custom_end_time_,
+      base::BindRepeating(&ScheduledFeature::OnCustomSchedulePrefsChanged,
+                          base::Unretained(this)));
+}
+
+void ScheduledFeature::InitFromUserPrefs() {
+  StartWatchingPrefsChanges();
+  Refresh(/*did_schedule_change=*/true,
+          /*keep_manual_toggles_during_schedules=*/true);
+  is_first_user_init_ = false;
+}
+
+void ScheduledFeature::OnEnabledPrefChanged() {
+  const bool enabled = GetEnabled();
+  VLOG(1) << "Enable state changed. New state: " << enabled << ".";
+  DCHECK(active_user_pref_service_);
+  Refresh(/*did_schedule_change=*/false,
+          /*keep_manual_toggles_during_schedules=*/false);
+}
+
+void ScheduledFeature::OnScheduleTypePrefChanged() {
+  const ScheduledFeature::ScheduleType schedule_type = GetScheduleType();
+  // To prevent adding (or removing) an observer twice in a row when switching
+  // between different users, we need to check `is_observing_geolocation_`.
+  if (schedule_type == ScheduledFeature::ScheduleType::kNone &&
+      is_observing_geolocation_) {
+    geolocation_controller_->RemoveObserver(this);
+    is_observing_geolocation_ = false;
+  } else if (schedule_type != ScheduledFeature::ScheduleType::kNone &&
+             !is_observing_geolocation_) {
+    geolocation_controller_->AddObserver(this);
+    is_observing_geolocation_ = true;
+  }
+  Refresh(/*did_schedule_change=*/true,
+          /*keep_manual_toggles_during_schedules=*/false);
+}
+
+void ScheduledFeature::OnCustomSchedulePrefsChanged() {
+  DCHECK(active_user_pref_service_);
+  Refresh(/*did_schedule_change=*/true,
+          /*keep_manual_toggles_during_schedules=*/false);
+}
+
+void ScheduledFeature::Refresh(bool did_schedule_change,
+                               bool keep_manual_toggles_during_schedules) {
+  switch (GetScheduleType()) {
+    case ScheduleType::kNone:
+      timer_.Stop();
+      RefreshFeatureState();
+      return;
+    case ScheduleType::kSunsetToSunrise:
+      RefreshScheduleTimer(geolocation_controller_->GetSunsetTime(),
+                           geolocation_controller_->GetSunriseTime(),
+                           did_schedule_change,
+                           keep_manual_toggles_during_schedules);
+      return;
+    case ScheduleType::kCustom:
+      RefreshScheduleTimer(
+          GetCustomStartTime().ToTimeToday(), GetCustomEndTime().ToTimeToday(),
+          did_schedule_change, keep_manual_toggles_during_schedules);
+      return;
+  }
+}
+
+void ScheduledFeature::RefreshScheduleTimer(
+    base::Time start_time,
+    base::Time end_time,
+    bool did_schedule_change,
+    bool keep_manual_toggles_during_schedules) {
+  DCHECK(GetScheduleType() != ScheduleType::kNone);
+
+  if (keep_manual_toggles_during_schedules && MaybeRestoreSchedule()) {
+    RefreshFeatureState();
+    return;
+  }
+
+  // NOTE: Users can set any weird combinations.
+  const base::Time now = GetNow();
+  if (end_time <= start_time) {
+    // Example:
+    // Start: 9:00 PM, End: 6:00 AM.
+    //
+    //       6:00                21:00
+    // <----- + ------------------ + ----->
+    //        |                    |
+    //       end                 start
+    //
+    // Note that the above times are times of day (today). It is important to
+    // know where "now" is with respect to these times to decide how to adjust
+    // them.
+    if (end_time >= now) {
+      // If the end time (today) is greater than the time now, this means "now"
+      // is within the feature schedule, and the start time is actually
+      // yesterday. The above timeline is interpreted as:
+      //
+      //   21:00 (-1day)              6:00
+      // <----- + ----------- + ------ + ----->
+      //        |             |        |
+      //      start          now      end
+      //
+      start_time -= base::Days(1);
+    } else {
+      // Two possibilities here:
+      // - Either "now" is greater than the end time, but less than start time.
+      //   This means the feature is outside the schedule, waiting for the next
+      //   start time. The end time is actually a day later.
+      // - Or "now" is greater than both the start and end times. This means
+      //   the feature is within the schedule, waiting to turn off at the next
+      //   end time, which is also a day later.
+      end_time += base::Days(1);
+    }
+  }
+
+  DCHECK_GE(end_time, start_time);
+
+  // The target status that we need to set the feature to now if a change of
+  // status is needed immediately.
+  bool enable_now = false;
+
+  // Where are we now with respect to the start and end times?
+  if (now < start_time) {
+    // Example:
+    // Start: 6:00 PM today, End: 6:00 AM tomorrow, Now: 4:00 PM.
+    //
+    // <----- + ----------- + ----------- + ----->
+    //        |             |             |
+    //       now          start          end
+    //
+    // In this case, we need to disable the feature immediately if it's enabled.
+    enable_now = false;
+  } else if (now >= start_time && now < end_time) {
+    // Example:
+    // Start: 6:00 PM today, End: 6:00 AM tomorrow, Now: 11:00 PM.
+    //
+    // <----- + ----------- + ----------- + ----->
+    //        |             |             |
+    //      start          now           end
+    //
+    // Turn the feature on right away. Our future start time is a day later than
+    // its current value.
+    enable_now = true;
+    start_time += base::Days(1);
+  } else {  // now >= end_time.
+    // Example:
+    // Start: 6:00 PM today, End: 10:00 PM today, Now: 11:00 PM.
+    //
+    // <----- + ----------- + ----------- + ----->
+    //        |             |             |
+    //      start          end           now
+    //
+    // In this case, our future start and end times are a day later from their
+    // current values. The feature needs to be off immediately if it's already
+    // enabled.
+    enable_now = false;
+    start_time += base::Days(1);
+    end_time += base::Days(1);
+  }
+
+  // After the above processing, the start and end time are all in the future.
+  DCHECK_GE(start_time, now);
+  DCHECK_GE(end_time, now);
+
+  if (did_schedule_change && enable_now != GetEnabled()) {
+    // If the change in the schedule introduces a change in the status, then
+    // calling SetEnabled() is all we need, since it will trigger a change in
+    // the user prefs to which we will respond by calling Refresh(). This will
+    // end up in this function again, adjusting all the needed schedules.
+    SetEnabled(enable_now);
+    return;
+  }
+
+  // We reach here in one of the following conditions:
+  // 1) If schedule changes don't result in changes in the status, we need to
+  // explicitly update the timer to re-schedule the next toggle to account for
+  // any changes.
+  // 2) The user has just manually toggled the status of the feature either from
+  // the System Menu or System Settings. In this case, we respect the user
+  // wish and maintain the current status that they desire, but we schedule the
+  // status to be toggled according to the time that corresponds with the
+  // opposite status of the current one.
+  ScheduleNextToggle(GetEnabled() ? end_time - now : start_time - now);
+  RefreshFeatureState();
+}
+
+void ScheduledFeature::ScheduleNextToggle(base::TimeDelta delay) {
+  DCHECK(active_user_pref_service_);
+
+  const bool new_status = !GetEnabled();
+  const base::Time target_time = GetNow() + delay;
+
+  per_user_schedule_target_state_[active_user_pref_service_] =
+      ScheduleTargetState{target_time, new_status};
+
+  VLOG(1) << "Setting " << GetFeatureName() << " to toggle to "
+          << (new_status ? "enabled" : "disabled") << " at "
+          << base::TimeFormatTimeOfDay(target_time);
+  timer_.Start(FROM_HERE, delay,
+               base::BindOnce(&ScheduledFeature::SetEnabled,
+                              base::Unretained(this), new_status));
+}
+
+}  // namespace ash
diff --git a/ash/system/scheduled_feature/scheduled_feature.h b/ash/system/scheduled_feature/scheduled_feature.h
new file mode 100644
index 0000000..8bed5c24
--- /dev/null
+++ b/ash/system/scheduled_feature/scheduled_feature.h
@@ -0,0 +1,193 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SYSTEM_SCHEDULED_FEATURE_SCHEDULED_FEATURE_H_
+#define ASH_SYSTEM_SCHEDULED_FEATURE_SCHEDULED_FEATURE_H_
+
+#include <memory>
+
+#include "ash/ash_export.h"
+#include "ash/public/cpp/session/session_observer.h"
+#include "ash/system/geolocation/geolocation_controller.h"
+#include "ash/system/time/time_of_day.h"
+#include "base/containers/flat_map.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "chromeos/dbus/power/power_manager_client.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "ui/aura/env_observer.h"
+
+class PrefService;
+
+namespace ash {
+
+class ASH_EXPORT ScheduledFeature
+    : public GeolocationController::Observer,
+      public aura::EnvObserver,
+      public SessionObserver,
+      public chromeos::PowerManagerClient::Observer {
+ public:
+  // These values are written to logs. New enum values can be added, but
+  // existing enums must never be renumbered or deleted and reused.
+  enum ScheduleType {
+    // Automatic toggling of ScheduledFeature is turned off.
+    kNone = 0,
+
+    // Turned automatically on at the user's local sunset time, and off at the
+    // user's local sunrise time.
+    kSunsetToSunrise = 1,
+
+    // Toggled automatically based on the custom set start and end times
+    // selected by the user from the system settings.
+    kCustom = 2,
+
+    // kMaxValue is required for UMA_HISTOGRAM_ENUMERATION.
+    kMaxValue = kCustom,
+  };
+
+  ScheduledFeature(const std::string prefs_path_enabled,
+                   const std::string prefs_path_schedule_type,
+                   const std::string prefs_path_custom_start_time,
+                   const std::string prefs_path_custom_end_time);
+
+  ScheduledFeature(const ScheduledFeature&) = delete;
+  ScheduledFeature& operator=(const ScheduledFeature&) = delete;
+  ~ScheduledFeature() override;
+
+  base::OneShotTimer* timer() { return &timer_; }
+
+  bool GetEnabled() const;
+  ScheduleType GetScheduleType() const;
+  TimeOfDay GetCustomStartTime() const;
+  TimeOfDay GetCustomEndTime() const;
+
+  // Get whether the current time is after sunset and before sunrise.
+  bool IsNowWithinSunsetSunrise() const;
+
+  // Set the desired ScheduledFeature settings in the current active user
+  // prefs.
+  void SetEnabled(bool enabled);
+  void SetScheduleType(ScheduleType type);
+  void SetCustomStartTime(TimeOfDay start_time);
+  void SetCustomEndTime(TimeOfDay end_time);
+
+  // SessionObserver:
+  void OnActiveUserPrefServiceChanged(PrefService* pref_service) override;
+
+  // GeolocationController::Observer:
+  void OnGeopositionChanged(bool possible_change_in_timezone) override;
+
+  // chromeos::PowerManagerClient::Observer:
+  void SuspendDone(base::TimeDelta sleep_duration) override;
+
+  void SetClockForTesting(base::Clock* clock);
+
+ protected:
+  // Called by `Refresh()` and `RefreshScheduleTimer()` to refresh the feature
+  // state such as display temperature in Night Light.
+  virtual void RefreshFeatureState() {}
+
+ private:
+  virtual const char* GetFeatureName() const = 0;
+
+  // Gets now time from the `clock_`, used for testing, or `base::Time::Now()`
+  // if `clock_` does not exist.
+  base::Time GetNow() const;
+
+  // Attempts restoring a previously stored schedule for the current user if
+  // possible and returns true if so, false otherwise.
+  bool MaybeRestoreSchedule();
+
+  void StartWatchingPrefsChanges();
+
+  void InitFromUserPrefs();
+
+  // Called when the user pref for the enabled status of ScheduledFeature is
+  // changed.
+  void OnEnabledPrefChanged();
+
+  // Called when the user pref for the schedule type is changed.
+  void OnScheduleTypePrefChanged();
+
+  // Called when either of the custom schedule prefs (custom start or end times)
+  // are changed.
+  void OnCustomSchedulePrefsChanged();
+
+  // Refreshes the state of ScheduledFeature according to the currently set
+  // parameters. `did_schedule_change` is true when Refresh() is called as a
+  // result of a change in one of the schedule related prefs, and false
+  // otherwise.
+  // If `keep_manual_toggles_during_schedules` is true, refreshing the schedule
+  // will not override a previous user's decision to toggle the
+  // ScheduledFeature status while the schedule is being used.
+  void Refresh(bool did_schedule_change,
+               bool keep_manual_toggles_during_schedules);
+
+  // Given the desired start and end times that determine the time interval
+  // during which the feature will be ON, depending on the time of "now", it
+  // refreshes the `timer_` to either schedule the future start or end of
+  // the feature, as well as update the current status if needed.
+  // For `did_schedule_change` and `keep_manual_toggles_during_schedules`, see
+  // Refresh() above.
+  // This function should never be called if the schedule type is `kNone`.
+  void RefreshScheduleTimer(base::Time start_time,
+                            base::Time end_time,
+                            bool did_schedule_change,
+                            bool keep_manual_toggles_during_schedules);
+
+  // Schedule the upcoming next toggle of the feature status.
+  void ScheduleNextToggle(base::TimeDelta delay);
+
+  // The pref service of the currently active user. Can be null in
+  // ash_unittests.
+  PrefService* active_user_pref_service_ = nullptr;
+
+  // Tracks the upcoming feature state changes per each user due to automatic
+  // schedules. This can be used to restore a manually toggled status while the
+  // schedule is being used. See MaybeRestoreSchedule().
+  struct ScheduleTargetState {
+    // The time at which the feature will switch to `target_status` defined
+    // below.
+    base::Time target_time;
+    bool target_status;
+  };
+  base::flat_map<PrefService*, ScheduleTargetState>
+      per_user_schedule_target_state_;
+
+  // The timer that schedules the start and end of this feature when the
+  // schedule type is either kSunsetToSunrise or kCustom.
+  base::OneShotTimer timer_;
+
+  // True only until this feature is initialized from the very first user
+  // session. After that, it is set to false.
+  bool is_first_user_init_ = true;
+
+  // The registrar used to watch prefs changes in the above
+  // `active_user_pref_service_` from outside ash.
+  // NOTE: Prefs are how Chrome communicates changes to the ScheduledFeature
+  // settings controlled by this class from the WebUI settings.
+  std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
+
+  const std::string prefs_path_enabled_;
+  const std::string prefs_path_schedule_type_;
+  const std::string prefs_path_custom_start_time_;
+  const std::string prefs_path_custom_end_time_;
+  const std::string prefs_path_latitude_;
+  const std::string prefs_path_longitude_;
+
+  GeolocationController* geolocation_controller_;
+
+  // Track if this is `GeolocationController::Observer` to make sure it is not
+  // added twice if it is already an observer.
+  bool is_observing_geolocation_ = false;
+
+  // Optional Used in tests to override the time of "Now".
+  base::Clock* clock_ = nullptr;  // Not owned.
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_SCHEDULED_FEATURE_SCHEDULED_FEATURE_H_
diff --git a/ash/system/scheduled_feature/scheduled_feature_unittest.cc b/ash/system/scheduled_feature/scheduled_feature_unittest.cc
new file mode 100644
index 0000000..0c23ebf
--- /dev/null
+++ b/ash/system/scheduled_feature/scheduled_feature_unittest.cc
@@ -0,0 +1,408 @@
+// Copyright 2021 The Chromium 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 <cmath>
+#include <limits>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include "ash/constants/ash_features.h"
+#include "ash/constants/ash_pref_names.h"
+#include "ash/public/cpp/session/session_types.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/session/test_session_controller_client.h"
+#include "ash/shell.h"
+#include "ash/system/geolocation/geolocation_controller.h"
+#include "ash/system/scheduled_feature/scheduled_feature.h"
+#include "ash/system/time/time_of_day.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/test/ash_test_helper.h"
+#include "ash/test_shell_delegate.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/pattern.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/time.h"
+#include "components/prefs/pref_service.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace ash {
+
+namespace {
+
+constexpr char kUser1Email[] = "user1@featuredschedule";
+constexpr char kUser2Email[] = "user2@featuredschedule";
+
+class TestScheduledFeature : public ScheduledFeature {
+ public:
+  TestScheduledFeature(const std::string prefs_path_enabled,
+                       const std::string prefs_path_schedule_type,
+                       const std::string prefs_path_custom_start_time,
+                       const std::string prefs_path_custom_end_time)
+      : ScheduledFeature(prefs_path_enabled,
+                         prefs_path_schedule_type,
+                         prefs_path_custom_start_time,
+                         prefs_path_custom_end_time) {}
+  TestScheduledFeature(const TestScheduledFeature& other) = delete;
+  TestScheduledFeature& operator=(const TestScheduledFeature& rhs) = delete;
+  ~TestScheduledFeature() override {}
+
+  const char* GetFeatureName() const override { return "TestFeature"; }
+};
+
+class ScheduledFeatureTest : public NoSessionAshTestBase {
+ public:
+  ScheduledFeatureTest() = default;
+  ScheduledFeatureTest(const ScheduledFeatureTest& other) = delete;
+  ScheduledFeatureTest& operator=(const ScheduledFeatureTest& rhs) = delete;
+  ~ScheduledFeatureTest() override = default;
+
+  PrefService* user1_pref_service() {
+    return Shell::Get()->session_controller()->GetUserPrefServiceForUser(
+        AccountId::FromUserEmail(kUser1Email));
+  }
+
+  PrefService* user2_pref_service() {
+    return Shell::Get()->session_controller()->GetUserPrefServiceForUser(
+        AccountId::FromUserEmail(kUser2Email));
+  }
+
+  ScheduledFeature* feature() { return feature_.get(); }
+
+  // AshTestBase:
+  void SetUp() override {
+    NoSessionAshTestBase::SetUp();
+
+    CreateTestUserSessions();
+
+    // Simulate user 1 login.
+    SimulateNewUserFirstLogin(kUser1Email);
+
+    geolocation_controller_ = std::make_unique<GeolocationController>(
+        /*url_context_getter=*/nullptr);
+
+    // Use user prefs of NightLight, which is an example of ScheduledFeature.
+    feature_ = std::make_unique<TestScheduledFeature>(
+        prefs::kNightLightEnabled, prefs::kNightLightScheduleType,
+        prefs::kNightLightCustomStartTime, prefs::kNightLightCustomEndTime);
+
+    feature_->SetClockForTesting(&test_clock_);
+    feature_->OnActiveUserPrefServiceChanged(
+        Shell::Get()->session_controller()->GetActivePrefService());
+  }
+
+  void TearDown() override {
+    geolocation_controller_.reset();
+    feature_.reset();
+    NoSessionAshTestBase::TearDown();
+  }
+
+  void CreateTestUserSessions() {
+    auto* session_controller_client = GetSessionControllerClient();
+    session_controller_client->Reset();
+    session_controller_client->AddUserSession(kUser1Email);
+    session_controller_client->AddUserSession(kUser2Email);
+  }
+
+  void SwitchActiveUser(const std::string& email) {
+    GetSessionControllerClient()->SwitchActiveUser(
+        AccountId::FromUserEmail(email));
+  }
+
+  bool GetEnabled() { return feature_->GetEnabled(); }
+  ScheduledFeature::ScheduleType GetScheduleType() {
+    return feature_->GetScheduleType();
+  }
+
+  void SetFeatureEnabled(bool enabled) { feature_->SetEnabled(enabled); }
+  void SetScheduleType(ScheduledFeature::ScheduleType type) {
+    feature_->SetScheduleType(type);
+  }
+
+ protected:
+  std::unique_ptr<TestScheduledFeature> feature_;
+  std::unique_ptr<GeolocationController> geolocation_controller_;
+  base::SimpleTestClock test_clock_;
+};
+
+// Tests that switching users retrieves the feature settings for the active
+// user's prefs.
+TEST_F(ScheduledFeatureTest, UserSwitchAndSettingsPersistence) {
+  // Start with user1 logged in and update to sunset-to-sunrise schedule type.
+  const std::string kScheduleTypePrefString = prefs::kNightLightScheduleType;
+  ScheduledFeature::ScheduleType user1_schedule_type =
+      ScheduledFeature::ScheduleType::kSunsetToSunrise;
+  feature()->SetScheduleType(user1_schedule_type);
+  EXPECT_EQ(user1_schedule_type, GetScheduleType());
+  EXPECT_EQ(user1_schedule_type,
+            user1_pref_service()->GetInteger(kScheduleTypePrefString));
+
+  // Switch to user 2, and set to custom schedule type.
+  SwitchActiveUser(kUser2Email);
+
+  ScheduledFeature::ScheduleType user2_schedule_type =
+      ScheduledFeature::ScheduleType::kCustom;
+  user2_pref_service()->SetInteger(kScheduleTypePrefString,
+                                   user2_schedule_type);
+  EXPECT_EQ(user2_schedule_type, GetScheduleType());
+  EXPECT_EQ(user1_schedule_type,
+            user1_pref_service()->GetInteger(kScheduleTypePrefString));
+
+  // Switch back to user 1, to find feature schedule type is restored to
+  // sunset-to-sunrise.
+  SwitchActiveUser(kUser1Email);
+  EXPECT_EQ(user1_schedule_type, GetScheduleType());
+}
+
+// Tests transitioning from kNone to kCustom and back to kNone schedule
+// types.
+TEST_F(ScheduledFeatureTest, ScheduleNoneToCustomTransition) {
+  // Now is 6:00 PM.
+  test_clock_.SetNow(TimeOfDay(18 * 60).ToTimeToday());
+  SetFeatureEnabled(false);
+  feature()->SetScheduleType(ScheduledFeature::ScheduleType::kNone);
+  // Start time is at 3:00 PM and end time is at 8:00 PM.
+  feature()->SetCustomStartTime(TimeOfDay(15 * 60));
+  feature()->SetCustomEndTime(TimeOfDay(20 * 60));
+
+  //      15:00         18:00         20:00
+  // <----- + ----------- + ----------- + ----->
+  //        |             |             |
+  //      start          now           end
+  //
+  // Even though "Now" is inside the feature interval, nothing should
+  // change, since the schedule type is "none".
+  EXPECT_FALSE(GetEnabled());
+
+  // Now change the schedule type to custom, the feature should turn on
+  // immediately, and the timer should be running with a delay of exactly 2
+  // hours scheduling the end.
+  feature()->SetScheduleType(ScheduledFeature::ScheduleType::kCustom);
+  EXPECT_TRUE(GetEnabled());
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  EXPECT_EQ(base::Hours(2), feature()->timer()->GetCurrentDelay());
+
+  // If the user changes the schedule type to "none", the feature status
+  // should not change, but the timer should not be running.
+  feature()->SetScheduleType(ScheduledFeature::ScheduleType::kNone);
+  EXPECT_TRUE(GetEnabled());
+  EXPECT_FALSE(feature()->timer()->IsRunning());
+}
+
+// Tests what happens when the time now reaches the end of the feature
+// interval when the feature mode is on.
+TEST_F(ScheduledFeatureTest, TestCustomScheduleReachingEndTime) {
+  test_clock_.SetNow(TimeOfDay(18 * 60).ToTimeToday());
+  feature()->SetCustomStartTime(TimeOfDay(15 * 60));
+  feature()->SetCustomEndTime(TimeOfDay(20 * 60));
+  feature()->SetScheduleType(ScheduledFeature::ScheduleType::kCustom);
+  EXPECT_TRUE(GetEnabled());
+
+  // Simulate reaching the end time by triggering the timer's user task. Make
+  // sure that the feature ended.
+  //
+  //      15:00                      20:00
+  // <----- + ------------------------ + ----->
+  //        |                          |
+  //      start                    end & now
+  //
+  // Now is 8:00 PM.
+  test_clock_.SetNow(TimeOfDay(20 * 60).ToTimeToday());
+  feature()->timer()->FireNow();
+  EXPECT_FALSE(GetEnabled());
+  // The timer should still be running, but now scheduling the start at 3:00 PM
+  // tomorrow which is 19 hours from "now" (8:00 PM).
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  EXPECT_EQ(base::Hours(19), feature()->timer()->GetCurrentDelay());
+}
+
+// Tests that user toggles from the system menu or system settings override any
+// status set by an automatic schedule.
+TEST_F(ScheduledFeatureTest, ExplicitUserTogglesWhileScheduleIsActive) {
+  // Start with the below custom schedule, where the feature is off.
+  //
+  //      15:00               20:00          23:00
+  // <----- + ----------------- + ------------ + ---->
+  //        |                   |              |
+  //      start                end            now
+  //
+  test_clock_.SetNow(TimeOfDay(23 * 60).ToTimeToday());
+  feature()->SetCustomStartTime(TimeOfDay(15 * 60));
+  feature()->SetCustomEndTime(TimeOfDay(20 * 60));
+  feature()->SetScheduleType(ScheduledFeature::ScheduleType::kCustom);
+  EXPECT_FALSE(GetEnabled());
+
+  // What happens if the user manually turns the feature on while the schedule
+  // type says it should be off?
+  // User toggles either from the system menu or the System Settings toggle
+  // button must override any automatic schedule.
+  SetFeatureEnabled(true);
+  EXPECT_TRUE(GetEnabled());
+  // The timer should still be running, but the feature should automatically
+  // turn off at 8:00 PM tomorrow, which is 21 hours from now (11:00 PM).
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  EXPECT_EQ(base::Hours(21), feature()->timer()->GetCurrentDelay());
+
+  // Manually turning it back off should also be respected, and this time the
+  // start is scheduled at 3:00 PM tomorrow after 19 hours from "now" (8:00
+  // PM).
+  SetFeatureEnabled(false);
+  EXPECT_FALSE(GetEnabled());
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  EXPECT_EQ(base::Hours(16), feature()->timer()->GetCurrentDelay());
+}
+
+// Tests that changing the custom start and end times, in such a way that
+// shouldn't change the current status, only updates the timer but doesn't
+// change the status.
+TEST_F(ScheduledFeatureTest, ChangingStartTimesThatDontChangeTheStatus) {
+  //       16:00        18:00         22:00
+  // <----- + ----------- + ----------- + ----->
+  //        |             |             |
+  //       now          start          end
+  //
+  test_clock_.SetNow(TimeOfDay(16 * 60).ToTimeToday());  // 4:00 PM.
+  SetFeatureEnabled(false);
+  feature()->SetScheduleType(ScheduledFeature::ScheduleType::kNone);
+  feature()->SetCustomStartTime(TimeOfDay(18 * 60));  // 6:00 PM.
+  feature()->SetCustomEndTime(TimeOfDay(22 * 60));    // 10:00 PM.
+
+  // Since now is outside the feature interval, changing the schedule type
+  // to kCustom, shouldn't affect the status. Validate the timer is running
+  // with a 2-hour delay.
+  feature()->SetScheduleType(ScheduledFeature::ScheduleType::kCustom);
+  EXPECT_FALSE(GetEnabled());
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  EXPECT_EQ(base::Hours(2), feature()->timer()->GetCurrentDelay());
+
+  // Change the start time in such a way that doesn't change the status, but
+  // despite that, confirm that schedule has been updated.
+  feature()->SetCustomStartTime(TimeOfDay(19 * 60));  // 7:00 PM.
+  EXPECT_FALSE(GetEnabled());
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  EXPECT_EQ(base::Hours(3), feature()->timer()->GetCurrentDelay());
+
+  // Changing the end time in a similar fashion to the above and expect no
+  // change.
+  feature()->SetCustomEndTime(TimeOfDay(23 * 60));  // 11:00 PM.
+  EXPECT_FALSE(GetEnabled());
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  EXPECT_EQ(base::Hours(3), feature()->timer()->GetCurrentDelay());
+}
+
+// Tests that the feature should turn on at sunset time and turn off at sunrise
+// time.
+TEST_F(ScheduledFeatureTest, SunsetSunrise) {
+  EXPECT_FALSE(GetEnabled());
+
+  // Set time now to 10:00 AM.
+  base::Time current_time = TimeOfDay(10 * 60).ToTimeToday();
+  test_clock_.SetNow(current_time);
+  EXPECT_FALSE(feature()->timer()->IsRunning());
+  feature()->SetScheduleType(ScheduledFeature::ScheduleType::kSunsetToSunrise);
+  EXPECT_FALSE(GetEnabled());
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  EXPECT_EQ(geolocation_controller_->GetSunsetTime() - current_time,
+            feature()->timer()->GetCurrentDelay());
+
+  // Firing a timer should to advance the time to sunset and automatically turn
+  // on the feature.
+  current_time = geolocation_controller_->GetSunsetTime();
+  test_clock_.SetNow(current_time);
+  feature()->timer()->FireNow();
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  EXPECT_TRUE(GetEnabled());
+  EXPECT_EQ(geolocation_controller_->GetSunriseTime() + base::Hours(24) -
+                current_time,
+            feature()->timer()->GetCurrentDelay());
+
+  // Firing a timer should advance the time to sunrise and automatically turn
+  // off the feature.
+  current_time = geolocation_controller_->GetSunriseTime();
+  test_clock_.SetNow(current_time);
+  feature()->timer()->FireNow();
+  EXPECT_FALSE(GetEnabled());
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  EXPECT_EQ(geolocation_controller_->GetSunsetTime() - current_time,
+            feature()->timer()->GetCurrentDelay());
+}
+
+// The following tests ensure that the feature schedule is correctly
+// refreshed when the start and end times are inverted (i.e. the "start time" as
+// a time of day today is in the future with respect to the "end time" also as a
+// time of day today).
+//
+// Case 1: "Now" is less than both "end" and "start".
+TEST_F(ScheduledFeatureTest, CustomScheduleInvertedStartAndEndTimesCase1) {
+  // Now is 4:00 AM.
+  test_clock_.SetNow(TimeOfDay(4 * 60).ToTimeToday());
+  SetFeatureEnabled(false);
+  // Start time is at 9:00 PM and end time is at 6:00 AM. "Now" is less than
+  // both. The feature should be on.
+  //       4:00          6:00         21:00
+  // <----- + ----------- + ----------- + ----->
+  //        |             |             |
+  //       now           end          start
+  //
+  feature()->SetCustomStartTime(TimeOfDay(21 * 60));
+  feature()->SetCustomEndTime(TimeOfDay(6 * 60));
+  feature()->SetScheduleType(ScheduledFeature::ScheduleType::kCustom);
+
+  EXPECT_TRUE(GetEnabled());
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  // The feature should end in two hours.
+  EXPECT_EQ(base::Hours(2), feature()->timer()->GetCurrentDelay());
+}
+
+// Case 2: "Now" is between "end" and "start".
+TEST_F(ScheduledFeatureTest, CustomScheduleInvertedStartAndEndTimesCase2) {
+  // Now is 6:00 AM.
+  test_clock_.SetNow(TimeOfDay(6 * 60).ToTimeToday());
+  SetFeatureEnabled(false);
+  // Start time is at 9:00 PM and end time is at 4:00 AM. "Now" is between both.
+  // The feature should be off.
+  //       4:00          6:00         21:00
+  // <----- + ----------- + ----------- + ----->
+  //        |             |             |
+  //       end           now          start
+  //
+  feature()->SetCustomStartTime(TimeOfDay(21 * 60));
+  feature()->SetCustomEndTime(TimeOfDay(4 * 60));
+  feature()->SetScheduleType(ScheduledFeature::ScheduleType::kCustom);
+
+  EXPECT_FALSE(GetEnabled());
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  // The feature should start in 15 hours.
+  EXPECT_EQ(base::Hours(15), feature()->timer()->GetCurrentDelay());
+}
+
+// Case 3: "Now" is greater than both "start" and "end".
+TEST_F(ScheduledFeatureTest, CustomScheduleInvertedStartAndEndTimesCase3) {
+  // Now is 11:00 PM.
+  test_clock_.SetNow(TimeOfDay(23 * 60).ToTimeToday());
+  SetFeatureEnabled(false);
+  // Start time is at 9:00 PM and end time is at 4:00 AM. "Now" is greater than
+  // both. NightLight should be on.
+  //       4:00         21:00         23:00
+  // <----- + ----------- + ----------- + ----->
+  //        |             |             |
+  //       end          start          now
+  //
+  feature()->SetCustomStartTime(TimeOfDay(21 * 60));
+  feature()->SetCustomEndTime(TimeOfDay(4 * 60));
+  feature()->SetScheduleType(ScheduledFeature::ScheduleType::kCustom);
+
+  EXPECT_TRUE(GetEnabled());
+  EXPECT_TRUE(feature()->timer()->IsRunning());
+  // The feature should end in 5 hours.
+  EXPECT_EQ(base::Hours(5), feature()->timer()->GetCurrentDelay());
+}
+
+}  // namespace
+
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/system/unified/notification_icons_controller.cc b/ash/system/unified/notification_icons_controller.cc
index 0ae81af0..6558f83 100644
--- a/ash/system/unified/notification_icons_controller.cc
+++ b/ash/system/unified/notification_icons_controller.cc
@@ -240,23 +240,28 @@
   const bool should_show_icons =
       icons_view_visible_ && ShouldShowNotificationItemsInTray();
 
-  auto it = tray_items_.begin();
-  for (message_center::Notification* notification :
-       message_center_utils::GetSortedNotificationsWithOwnView()) {
-    if (it == tray_items_.end())
+  // Iterates `tray_items_` and notifications in reverse order so new pinned
+  // notifications get shown on the left side.
+  auto notifications =
+      message_center_utils::GetSortedNotificationsWithOwnView();
+
+  auto tray_it = tray_items_.rbegin();
+  for (auto notification_it = notifications.rbegin();
+       notification_it != notifications.rend(); ++notification_it) {
+    if (tray_it == tray_items_.rend())
       break;
-    if (ShouldShowNotification(notification)) {
-      (*it)->SetNotification(notification);
-      (*it)->SetVisible(should_show_icons);
-      ++it;
+    if (ShouldShowNotification(*notification_it)) {
+      (*tray_it)->SetNotification(*notification_it);
+      (*tray_it)->SetVisible(should_show_icons);
+      ++tray_it;
     }
   }
 
-  first_unused_item_index_ = std::distance(tray_items_.begin(), it);
+  first_unused_item_index_ = std::distance(tray_items_.rbegin(), tray_it);
 
-  for (; it != tray_items_.end(); ++it) {
-    (*it)->Reset();
-    (*it)->SetVisible(false);
+  for (; tray_it != tray_items_.rend(); ++tray_it) {
+    (*tray_it)->Reset();
+    (*tray_it)->SetVisible(false);
   }
   separator_->SetVisible(should_show_icons && TrayItemHasNotification());
 }
diff --git a/ash/system/unified/notification_icons_controller_unittest.cc b/ash/system/unified/notification_icons_controller_unittest.cc
index cd90c5d..10160d4 100644
--- a/ash/system/unified/notification_icons_controller_unittest.cc
+++ b/ash/system/unified/notification_icons_controller_unittest.cc
@@ -94,37 +94,47 @@
   AddNotification(true /* is_pinned */, false /* is_critical_warning */);
   AddNotification(false /* is_pinned */, false /* is_critical_warning */);
 
+  // Icons get added from RTL, so we check the end of the vector first.
+
   // Notification icons should be shown in medium screen size.
   UpdateDisplay("800x700");
   EXPECT_EQ(IsScalableStatusAreaEnabled(),
-            notification_icons_controller_->tray_items().front()->GetVisible());
+            notification_icons_controller_->tray_items().back()->GetVisible());
   EXPECT_EQ(IsScalableStatusAreaEnabled(), separator()->GetVisible());
 
   // Notification icons should not be shown in small screen size.
   UpdateDisplay("600x500");
   EXPECT_FALSE(
-      notification_icons_controller_->tray_items().front()->GetVisible());
+      notification_icons_controller_->tray_items().back()->GetVisible());
   EXPECT_FALSE(separator()->GetVisible());
 
   // Notification icons should be shown in large screen size.
   UpdateDisplay("1680x800");
   EXPECT_EQ(IsScalableStatusAreaEnabled(),
-            notification_icons_controller_->tray_items().front()->GetVisible());
+            notification_icons_controller_->tray_items().back()->GetVisible());
   EXPECT_EQ(IsScalableStatusAreaEnabled(), separator()->GetVisible());
 }
 
 TEST_P(NotificationIconsControllerTest, ShowNotificationIcons) {
   UpdateDisplay("800x700");
 
+  // Icons get added from RTL, so we check the end of the vector first.
+  const int end = notification_icons_controller_->tray_items().size() - 1;
+
+  // Ensure that the indexes that will be accessed exist.
+  ASSERT_TRUE(notification_icons_controller_->tray_items().size() >= 2);
+
   // If there's no notification, no notification icons should be shown.
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[0]->GetVisible());
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[1]->GetVisible());
+  EXPECT_FALSE(notification_icons_controller_->tray_items()[end]->GetVisible());
+  EXPECT_FALSE(
+      notification_icons_controller_->tray_items()[end - 1]->GetVisible());
   EXPECT_FALSE(separator()->GetVisible());
 
   // Same case for non pinned or non critical warning notification.
   AddNotification(false /* is_pinned */, false /* is_critical_warning */);
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[0]->GetVisible());
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[1]->GetVisible());
+  EXPECT_FALSE(notification_icons_controller_->tray_items()[end]->GetVisible());
+  EXPECT_FALSE(
+      notification_icons_controller_->tray_items()[end - 1]->GetVisible());
   EXPECT_FALSE(separator()->GetVisible());
 
   // Notification icons should be shown when pinned or critical warning
@@ -132,16 +142,18 @@
   std::string id0 =
       AddNotification(true /* is_pinned */, false /* is_critical_warning */);
   EXPECT_EQ(IsScalableStatusAreaEnabled(),
-            notification_icons_controller_->tray_items()[0]->GetVisible());
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[1]->GetVisible());
+            notification_icons_controller_->tray_items()[end]->GetVisible());
+  EXPECT_FALSE(
+      notification_icons_controller_->tray_items()[end - 1]->GetVisible());
   EXPECT_EQ(IsScalableStatusAreaEnabled(), separator()->GetVisible());
 
   std::string id1 =
       AddNotification(false /* is_pinned */, true /* is_critical_warning */);
   EXPECT_EQ(IsScalableStatusAreaEnabled(),
-            notification_icons_controller_->tray_items()[0]->GetVisible());
-  EXPECT_EQ(IsScalableStatusAreaEnabled(),
-            notification_icons_controller_->tray_items()[1]->GetVisible());
+            notification_icons_controller_->tray_items()[end]->GetVisible());
+  EXPECT_EQ(
+      IsScalableStatusAreaEnabled(),
+      notification_icons_controller_->tray_items()[end - 1]->GetVisible());
   EXPECT_EQ(IsScalableStatusAreaEnabled(), separator()->GetVisible());
 
   // Remove the critical warning notification should make the tray show only one
@@ -149,27 +161,33 @@
   message_center::MessageCenter::Get()->RemoveNotification(id1,
                                                            false /* by_user */);
   EXPECT_EQ(IsScalableStatusAreaEnabled(),
-            notification_icons_controller_->tray_items()[0]->GetVisible());
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[1]->GetVisible());
+            notification_icons_controller_->tray_items()[end]->GetVisible());
+  EXPECT_FALSE(
+      notification_icons_controller_->tray_items()[end - 1]->GetVisible());
   EXPECT_EQ(IsScalableStatusAreaEnabled(), separator()->GetVisible());
 
   // Remove the pinned notification, no icon is shown.
   message_center::MessageCenter::Get()->RemoveNotification(id0,
                                                            false /* by_user */);
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[0]->GetVisible());
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[1]->GetVisible());
+  EXPECT_FALSE(notification_icons_controller_->tray_items()[end]->GetVisible());
+  EXPECT_FALSE(
+      notification_icons_controller_->tray_items()[end - 1]->GetVisible());
   EXPECT_FALSE(separator()->GetVisible());
 }
 
 TEST_P(NotificationIconsControllerTest, NotShowNotificationIcons) {
   UpdateDisplay("800x700");
 
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[0]->GetVisible());
+  // Icons get added from RTL, so we check the end of the vector first.
+
+  EXPECT_FALSE(
+      notification_icons_controller_->tray_items().back()->GetVisible());
 
   AddNotification(true /* is_pinned */, false /* is_critical_warning */,
                   kBatteryNotificationNotifierId);
   // Battery notification should not be shown.
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[0]->GetVisible());
+  EXPECT_FALSE(
+      notification_icons_controller_->tray_items().back()->GetVisible());
   EXPECT_FALSE(separator()->GetVisible());
   // Notification count does update for this notification.
   notification_icons_controller_->notification_counter_view()->Update();
@@ -179,7 +197,8 @@
   AddNotification(true /* is_pinned */, false /* is_critical_warning */,
                   kUsbNotificationNotifierId);
   // Usb charging notification should not be shown.
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[0]->GetVisible());
+  EXPECT_FALSE(
+      notification_icons_controller_->tray_items().back()->GetVisible());
   EXPECT_FALSE(separator()->GetVisible());
   // Notification count does update for this notification.
   notification_icons_controller_->notification_counter_view()->Update();
@@ -189,7 +208,8 @@
   AddNotification(true /* is_pinned */, false /* is_critical_warning */,
                   kVmCameraMicNotifierId);
   // VM camera/mic notification should not be shown.
-  EXPECT_FALSE(notification_icons_controller_->tray_items()[0]->GetVisible());
+  EXPECT_FALSE(
+      notification_icons_controller_->tray_items().back()->GetVisible());
   EXPECT_FALSE(separator()->GetVisible());
   // Notification count does not update for this notification (since there's
   // another tray item for this).
diff --git a/ash/wm/desks/templates/desks_templates_presenter.cc b/ash/wm/desks/templates/desks_templates_presenter.cc
index daffefeb..2fddd6c 100644
--- a/ash/wm/desks/templates/desks_templates_presenter.cc
+++ b/ash/wm/desks/templates/desks_templates_presenter.cc
@@ -25,6 +25,7 @@
 namespace ash {
 
 namespace {
+
 DesksTemplatesPresenter* g_instance = nullptr;
 
 // The amount of time for which the launch template toasts will remain
@@ -37,7 +38,6 @@
 
 // Helper to get the desk model from the shell delegate. Should always return a
 // usable desk model, either from chrome sync, or a local storage.
-// TODO(sammiequon): Investigate if we can cache this.
 desks_storage::DeskModel* GetDeskModel() {
   auto* desk_model = Shell::Get()->desks_templates_delegate()->GetDeskModel();
   DCHECK(desk_model);
@@ -181,12 +181,22 @@
                      weak_ptr_factory_.GetWeakPtr(), is_update));
 }
 
-void DesksTemplatesPresenter::DeskModelLoaded() {}
-
 void DesksTemplatesPresenter::OnDeskModelDestroying() {
   desk_model_observation_.Reset();
 }
 
+void DesksTemplatesPresenter::EntriesAddedOrUpdatedRemotely(
+    const std::vector<const DeskTemplate*>& new_entries) {
+  if (overview_session_->IsShowingDesksTemplatesGrid())
+    GetAllEntries();
+}
+
+void DesksTemplatesPresenter::EntriesRemovedRemotely(
+    const std::vector<std::string>& uuids) {
+  if (overview_session_->IsShowingDesksTemplatesGrid())
+    GetAllEntries();
+}
+
 void DesksTemplatesPresenter::OnGetAllEntries(
     desks_storage::DeskModel::GetAllEntriesStatus status,
     const std::vector<DeskTemplate*>& entries) {
@@ -218,8 +228,6 @@
 
   RecordDeleteTemplateHistogram();
   GetAllEntries();
-
-  UpdateDesksTemplatesUI();
 }
 
 void DesksTemplatesPresenter::OnGetTemplateForDeskLaunch(
@@ -250,18 +258,17 @@
   if (status != desks_storage::DeskModel::AddOrUpdateEntryStatus::kOk)
     return;
 
-  const auto& grid_list = overview_session_->grid_list();
-  DCHECK(!grid_list.empty());
-
   // If the templates grid is already shown, just update the entries.
-  if (grid_list[0]->IsShowingDesksTemplatesGrid()) {
+  if (overview_session_->IsShowingDesksTemplatesGrid()) {
     GetAllEntries();
     return;
   }
 
   // Update the button here in case it has been disabled.
+  const auto& grid_list = overview_session_->grid_list();
+  DCHECK(!grid_list.empty());
   overview_session_->ShowDesksTemplatesGrids(
-      grid_list[0]->desks_bar_view()->IsZeroState());
+      grid_list.front()->desks_bar_view()->IsZeroState());
   for (auto& overview_grid : grid_list)
     overview_grid->UpdateSaveDeskAsTemplateButton();
 
diff --git a/ash/wm/desks/templates/desks_templates_presenter.h b/ash/wm/desks/templates/desks_templates_presenter.h
index 2592b77..9fc3bd2 100644
--- a/ash/wm/desks/templates/desks_templates_presenter.h
+++ b/ash/wm/desks/templates/desks_templates_presenter.h
@@ -66,13 +66,11 @@
                                 std::unique_ptr<DeskTemplate> desk_template);
 
   // desks_storage::DeskModelObserver:
-  // TODO(sammiequon): Implement these once the model starts sending these
-  // messages.
-  void DeskModelLoaded() override;
+  void DeskModelLoaded() override {}
   void OnDeskModelDestroying() override;
   void EntriesAddedOrUpdatedRemotely(
-      const std::vector<const DeskTemplate*>& new_entries) override {}
-  void EntriesRemovedRemotely(const std::vector<std::string>& uuids) override {}
+      const std::vector<const DeskTemplate*>& new_entries) override;
+  void EntriesRemovedRemotely(const std::vector<std::string>& uuids) override;
   void EntriesAddedOrUpdatedLocally(
       const std::vector<const DeskTemplate*>& new_entries) override {}
   void EntriesRemovedLocally(const std::vector<std::string>& uuids) override {}
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc
index 7452172d..82e163b 100644
--- a/ash/wm/overview/overview_session.cc
+++ b/ash/wm/overview/overview_session.cc
@@ -1005,6 +1005,13 @@
     grid->HideDesksTemplatesGrid(/*exit_overview=*/false);
 }
 
+bool OverviewSession::IsShowingDesksTemplatesGrid() const {
+  // All the grids should show the templates grid at the same time so just check
+  // if the first grid is showing.
+  return grid_list_.empty() ? false
+                            : grid_list_.front()->IsShowingDesksTemplatesGrid();
+}
+
 void OverviewSession::OnDeskAdded(const Desk* desk) {}
 void OverviewSession::OnDeskRemoved(const Desk* desk) {}
 void OverviewSession::OnDeskReordered(int old_index, int new_index) {}
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h
index 30512b7c..464b61d6 100644
--- a/ash/wm/overview/overview_session.h
+++ b/ash/wm/overview/overview_session.h
@@ -282,6 +282,7 @@
   // true then we will expand the desks bars.
   void ShowDesksTemplatesGrids(bool was_zero_state);
   void HideDesksTemplatesGrids();
+  bool IsShowingDesksTemplatesGrid() const;
 
   // DesksController::Observer:
   void OnDeskAdded(const Desk* desk) override;
diff --git a/base/BUILD.gn b/base/BUILD.gn
index e393c80c..554604d 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -3830,6 +3830,7 @@
       "containers/buffer_iterator_unittest.nc",
       "containers/checked_iterators_unittest.nc",
       "containers/contains_unittest.nc",
+      "containers/enum_set_unittest.nc",
       "containers/span_unittest.nc",
       "debug/crash_logging_unittest.nc",
       "memory/raw_ptr_unittest.nc",
diff --git a/base/containers/enum_set.h b/base/containers/enum_set.h
index 30fbb36..28f79dd 100644
--- a/base/containers/enum_set.h
+++ b/base/containers/enum_set.h
@@ -296,7 +296,7 @@
   // some minor optimizations.
   explicit constexpr EnumSet(EnumBitSet enums) : enums_(enums) {
     static_assert(kValueCount <= 64,
-                  "Max number of enum values is 64 for constexpr ");
+                  "Max number of enum values is 64 for constexpr constructor");
   }
 
   // Converts a value to/from an index into |enums_|.
diff --git a/base/containers/enum_set_unittest.cc b/base/containers/enum_set_unittest.cc
index 4ecbe7d..489e1f4 100644
--- a/base/containers/enum_set_unittest.cc
+++ b/base/containers/enum_set_unittest.cc
@@ -420,6 +420,57 @@
       TestEnumSet::single_val_bitstring(TestEnum::TEST_7_OUT_OF_BOUNDS));
 }
 
+TEST_F(EnumSetTest, SparseEnum) {
+  enum class TestEnumSparse {
+    TEST_1 = 1,
+    TEST_MIN = 1,
+    TEST_50 = 50,
+    TEST_100 = 100,
+    TEST_MAX = TEST_100,
+  };
+  using TestEnumSparseSet = EnumSet<TestEnumSparse, TestEnumSparse::TEST_MIN,
+                                    TestEnumSparse::TEST_MAX>;
+  TestEnumSparseSet sparse;
+  sparse.Put(TestEnumSparse::TEST_MIN);
+  sparse.Put(TestEnumSparse::TEST_MAX);
+  EXPECT_EQ(sparse.Size(), 2u);
+
+  // TestEnumSparseSet::All() does not compile because there are more than 64
+  // possible values. See NCTEST_ALL_METHOD_DISALLOWED_ON_LARGE_SPARSE_ENUM in
+  // enum_set_unittest.nc.
+}
+
+TEST_F(EnumSetTest, SparseEnumSmall) {
+  enum class TestEnumSparse {
+    TEST_1 = 1,
+    TEST_MIN = 1,
+    TEST_50 = 50,
+    TEST_60 = 60,
+    TEST_MAX = TEST_60,
+  };
+  using TestEnumSparseSet = EnumSet<TestEnumSparse, TestEnumSparse::TEST_MIN,
+                                    TestEnumSparse::TEST_MAX>;
+  TestEnumSparseSet sparse;
+  sparse.Put(TestEnumSparse::TEST_MIN);
+  sparse.Put(TestEnumSparse::TEST_MAX);
+  EXPECT_EQ(sparse.Size(), 2u);
+
+  // This may seem a little surprising! There are only 3 distinct values in
+  // TestEnumSparse, so why does TestEnumSparseSet think it has 60 of them? This
+  // is an artifact of EnumSet's design, as it has no way of knowing which
+  // values between the min and max are actually named in the enum's definition.
+  EXPECT_EQ(TestEnumSparseSet::All().Size(), 60u);
+}
+
+TEST_F(EnumSetTest, SingleValBitstringCrashesOnOutOfRange) {
+  EXPECT_CHECK_DEATH(
+      TestEnumSet::single_val_bitstring(TestEnum::TEST_BELOW_MIN));
+  EXPECT_CHECK_DEATH(
+      TestEnumSet::single_val_bitstring(TestEnum::TEST_6_OUT_OF_BOUNDS));
+  EXPECT_CHECK_DEATH(
+      TestEnumSet::single_val_bitstring(TestEnum::TEST_7_OUT_OF_BOUNDS));
+}
+
 TEST_F(EnumSetDeathTest, SingleValBitstringEnumWithNegatives) {
   enum class TestEnumNeg {
     TEST_BELOW_MIN = -3,
diff --git a/base/containers/enum_set_unittest.nc b/base/containers/enum_set_unittest.nc
new file mode 100644
index 0000000..c3d7347
--- /dev/null
+++ b/base/containers/enum_set_unittest.nc
@@ -0,0 +1,34 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a "No Compile Test" suite.
+// https://dev.chromium.org/developers/testing/no-compile-tests
+
+#include "base/containers/enum_set.h"
+
+namespace base {
+namespace {
+
+#if defined(NCTEST_ALL_METHOD_DISALLOWED_ON_LARGE_SPARSE_ENUM) // [r"fatal error: static_assert failed due to requirement 'kValueCount <= 64' \"Max number of enum values is 64 for constexpr constructor\""]
+
+void WontCompile() {
+  enum class TestEnumSparse {
+    TEST_1 = 1,
+    TEST_MIN = 1,
+    TEST_50 = 50,
+    TEST_100 = 100,
+    TEST_MAX = TEST_100,
+  };
+  using TestEnumSparseSet = EnumSet<TestEnumSparse, TestEnumSparse::TEST_MIN,
+                                    TestEnumSparse::TEST_MAX>;
+
+  // TestEnumSparseSet::All() does not compile because there are more than 64
+  // possible values.
+  TestEnumSparseSet::All();
+}
+
+#endif
+
+}  // namespace
+}  // namespace base
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 7fa20e5..a170f0e5 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-7.20211222.1.1
+7.20211222.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 7fa20e5..a170f0e5 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-7.20211222.1.1
+7.20211222.2.1
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 2b8ad609..e8a6155a 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -769,8 +769,10 @@
   auto result =
       std::make_pair(node->mask_filter_info, node->is_fast_rounded_corner);
 
-  if (!result.first.Transform(to_target))
+  if (!result.first.Transform(to_target)) {
+    DCHECK(result.first.IsEmpty());
     return kEmptyMaskFilterInfoPair;
+  }
 
   return result;
 }
diff --git a/chrome/VERSION b/chrome/VERSION
index 88bf9e5..8abb8d7 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=99
 MINOR=0
-BUILD=4782
+BUILD=4783
 PATCH=0
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index 1824e362..220effc 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -531,7 +531,6 @@
   "java/res/drawable/material_tooltip_background.xml",
   "java/res/drawable/mir_card.xml",
   "java/res/drawable/outline_chevron_right_24dp.xml",
-  "java/res/drawable/pill_background.xml",
   "java/res/drawable/price_tracking_disabled.xml",
   "java/res/drawable/price_tracking_enabled_filled.xml",
   "java/res/drawable/price_tracking_enabled_outline.xml",
@@ -651,7 +650,6 @@
   "java/res/layout/fre_data_reduction_proxy_lite_mode.xml",
   "java/res/layout/fre_tos_privacy_disclaimer.xml",
   "java/res/layout/fre_tosanduma.xml",
-  "java/res/layout/fullscreen_notification.xml",
   "java/res/layout/history_clear_browsing_data_header.xml",
   "java/res/layout/history_item_view.xml",
   "java/res/layout/history_main.xml",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
index 6617051..af885369 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
@@ -23,8 +23,6 @@
  * sub-components and shutting down the Autofill Assistant.
  */
 public class AssistantCoordinator {
-    private final Activity mActivity;
-
     private final AssistantModel mModel;
     private AssistantBottomBarCoordinator mBottomBarCoordinator;
     private final AssistantKeyboardCoordinator mKeyboardCoordinator;
@@ -38,8 +36,6 @@
             @NonNull BrowserControlsManager browserControlsManager,
             @NonNull ApplicationViewportInsetSupplier applicationBottomInsetProvider,
             AccessibilityUtil accessibilityUtil, AssistantInfoPageUtil infoPageUtil) {
-        mActivity = activity;
-
         if (overlayCoordinator != null) {
             mModel = new AssistantModel(overlayCoordinator.getModel());
             mOverlayCoordinator = overlayCoordinator;
diff --git a/chrome/android/java/res/drawable/pill_background.xml b/chrome/android/java/res/drawable/pill_background.xml
deleted file mode 100644
index b9ed6ad..0000000
--- a/chrome/android/java/res/drawable/pill_background.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2021 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:dither="true"
-    android:shape="rectangle">
-    <corners android:radius="40dp" />
-    <solid android:color="@color/default_bg_color_dark"/>
-    <size
-        android:width="60dp"
-        android:height="20dp" />
-</shape>
diff --git a/chrome/android/java/res/layout/fullscreen_notification.xml b/chrome/android/java/res/layout/fullscreen_notification.xml
deleted file mode 100644
index 5687b66a..0000000
--- a/chrome/android/java/res/layout/fullscreen_notification.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2021 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:paddingTop="24dp">
-    <TextView
-        android:id="@+id/text"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:maxWidth="@dimen/fullscreen_notification_max_width"
-        android:layout_gravity="center"
-        android:background="@drawable/pill_background"
-        android:textAppearance="@style/TextAppearance.Toast"
-        android:paddingStart="20dp"
-        android:paddingEnd="20dp"
-        android:paddingTop="8dp"
-        android:paddingBottom="8dp"
-        android:textAlignment="center"
-        android:text="@string/immersive_fullscreen_api_notification"/>
-</LinearLayout>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index b2547931..6cbd92c 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -157,7 +157,6 @@
     <!-- Should match toolbar_height_no_shadow -->
     <dimen name="control_container_height">56dp</dimen>
     <dimen name="custom_tabs_control_container_height">56dp</dimen>
-    <dimen name="fullscreen_notification_max_width">320dp</dimen>
 
     <!-- The combined height of the tab strip and toolbar. -->
     <dimen name="tab_strip_and_toolbar_height">56dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRow.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRow.java
index dfbc97f5..10e936d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRow.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRow.java
@@ -157,8 +157,8 @@
             ApiCompatibilityUtils.setTextAppearance(
                     primaryText, R.styleable.ChipView_primaryTextAppearance);
             primaryText.setText(formattedCurrentPrice);
-            primaryText.setTextColor(
-                    ApiCompatibilityUtils.getColor(getResources(), R.color.default_green));
+            primaryText.setTextColor(ApiCompatibilityUtils.getColor(
+                    getResources(), R.color.price_drop_annotation_text_green));
 
             // Secondary text displays the original price with a strikethrough.
             TextView secondaryText = cv.getSecondaryTextView();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenHtmlApiHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenHtmlApiHandler.java
index 73e3b4f7..a31dfe9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenHtmlApiHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenHtmlApiHandler.java
@@ -11,10 +11,9 @@
 import android.app.Activity;
 import android.os.Handler;
 import android.os.Message;
-import android.view.LayoutInflater;
+import android.view.Gravity;
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
-import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
 
@@ -47,6 +46,7 @@
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.SelectionPopupController;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.widget.Toast;
 
 import java.lang.ref.WeakReference;
 
@@ -66,8 +66,6 @@
     // Delay to allow a frame to render between getting the fullscreen layout update and clearing
     // the SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN flag.
     private static final long CLEAR_LAYOUT_FULLSCREEN_DELAY_MS = 20;
-    // Fade in/out animation duration for fullscreen notification toast.
-    private static final int TOAST_FADE_MS = 500;
 
     private final Activity mActivity;
     private final Handler mHandler;
@@ -88,7 +86,7 @@
 
     // Toast at the top of the screen that is shown when user enters fullscreen for the
     // first time.
-    private View mNotificationToast;
+    private Toast mNotificationToast;
 
     private OnLayoutChangeListener mFullscreenOnLayoutChangeListener;
 
@@ -357,10 +355,13 @@
      * @param controlsHidden {@code true} if the controls are now hidden.
      */
     private void maybeEnterFullscreenFromPendingState(boolean controlsHidden) {
-        if (!controlsHidden) return;
-        if (mTab != null && mPendingFullscreenOptions != null) {
+        if (!controlsHidden || mTab == null) return;
+        if (mPendingFullscreenOptions != null) {
             enterFullscreen(mTab, mPendingFullscreenOptions);
             mPendingFullscreenOptions = null;
+        } else {
+            // Restore browser controls if the fullscreen process got canceled.
+            TabBrowserControlsConstraintsHelper.update(mTab, BrowserControlsState.SHOWN, true);
         }
     }
 
@@ -511,27 +512,23 @@
      * Create and show the fullscreen notification toast.
      */
     private void showNotificationToast() {
-        assert mTab != null && mTab.getContentView() != null;
-        ViewGroup parent = mTab.getContentView();
-        if (mNotificationToast != null) parent.removeView(mNotificationToast);
-        mNotificationToast =
-                LayoutInflater.from(mActivity).inflate(R.layout.fullscreen_notification, null);
-        mNotificationToast.setAlpha(0);
-        parent.addView(mNotificationToast);
-        mNotificationToast.animate().alpha(1).setDuration(TOAST_FADE_MS).start();
-        mHandler.postDelayed(this::hideNotificationToast, 5000);
+        if (mNotificationToast != null) {
+            mNotificationToast.cancel();
+        }
+        int resId = R.string.immersive_fullscreen_api_notification;
+        mNotificationToast = Toast.makeText(mActivity, resId, Toast.LENGTH_LONG);
+        mNotificationToast.setGravity(Gravity.TOP | Gravity.CENTER, 0, 0);
+        mNotificationToast.show();
     }
 
     /**
      * Hides the notification toast.
      */
     private void hideNotificationToast() {
-        if (mNotificationToast == null) return;
-        mNotificationToast.animate().alpha(0).setDuration(TOAST_FADE_MS).withEndAction(() -> {
-            assert mTab != null && mTab.getContentView() != null;
-            mTab.getContentView().removeView(mNotificationToast);
+        if (mNotificationToast != null) {
+            mNotificationToast.cancel();
             mNotificationToast = null;
-        });
+        }
     }
 
     // ActivityStateListener
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkTest.java
index 4be9638e..c71e2d5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkTest.java
@@ -14,7 +14,6 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import androidx.annotation.ColorInt;
 import androidx.test.filters.MediumTest;
 
 import org.junit.Rule;
@@ -39,6 +38,7 @@
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
+import org.chromium.components.browser_ui.styles.SemanticColorUtils;
 import org.chromium.components.image_fetcher.ImageFetcher;
 import org.chromium.components.payments.CurrencyFormatter;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -59,7 +59,6 @@
     private static List<ParameterSet> sClassParams = new NightModeParams().getParameters();
 
     private static final long CURRENCY_MUTLIPLIER = 1000000;
-    private final @ColorInt int mFakeBgColor;
 
     @Rule
     public ChromeRenderTestRule mRenderTestRule =
@@ -85,7 +84,6 @@
 
     public PowerBookmarkTest(boolean nightModeEnabled) {
         // Sets a fake background color to make the screenshots easier to compare with bare eyes.
-        mFakeBgColor = nightModeEnabled ? Color.BLACK : Color.WHITE;
         NightModeTestUtils.setUpNightModeForDummyUiActivity(nightModeEnabled);
         mRenderTestRule.setNightModeEnabled(nightModeEnabled);
     }
@@ -135,7 +133,8 @@
                             .getLayoutInflater()
                             .inflate(R.layout.power_bookmark_shopping_item_row, mContentView, true)
                             .findViewById(R.id.power_bookmark_shopping_row);
-            mPowerBookmarkShoppingItemRow.setBackgroundColor(mFakeBgColor);
+            mPowerBookmarkShoppingItemRow.setBackgroundColor(
+                    SemanticColorUtils.getDefaultBgColor(getActivity()));
             ((TextView) mPowerBookmarkShoppingItemRow.findViewById(R.id.title))
                     .setText("Test Bookmark");
             ((TextView) mPowerBookmarkShoppingItemRow.findViewById(R.id.description))
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
index aa6d6052..00acf05b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
@@ -184,7 +184,6 @@
     @Test
     @MediumTest
     @Feature({"Fullscreen"})
-    @DisabledTest(message = "crbug.com/1282137")
     public void testDelayedPersistentFullscreen() {
         mActivityTestRule.startMainActivityWithURL(LONG_HTML_TEST_PAGE);
 
@@ -216,7 +215,6 @@
     @Test
     @LargeTest
     @Feature({"Fullscreen"})
-    @DisabledTest(message = "crbug.com/1282137")
     public void testPersistentFullscreenChangingUiFlags() throws InterruptedException {
         // Exiting fullscreen via UI Flags is not supported in versions prior to MR2.
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return;
@@ -542,7 +540,6 @@
     @Test
     @LargeTest
     @Feature({"Fullscreen"})
-    @DisabledTest(message = "crbug.com/1282137")
     public void testEnterPendingPersistentFullscreen() {
         FullscreenManagerTestUtils.disableBrowserOverrides();
         mActivityTestRule.startMainActivityWithURL(LONG_FULLSCREEN_API_HTML_TEST_PAGE);
diff --git a/chrome/app/extensions_strings.grdp b/chrome/app/extensions_strings.grdp
index eeffbea5..5a4a804 100644
--- a/chrome/app/extensions_strings.grdp
+++ b/chrome/app/extensions_strings.grdp
@@ -277,18 +277,12 @@
   <message name="IDS_EXTENSIONS_ITEM_SITE_ACCESS" desc="The label above the list of the websites that the extension can access.">
     Site access
   </message>
-  <message name="IDS_EXTENSIONS_ITEM_SITE_ACCESS_NEW" desc="The label of the button to click to view the list of websites that the extension can access.">
-    Site permissions
-  </message>
   <message name="IDS_EXTENSIONS_ITEM_SITE_ACCESS_ADD_HOST" desc="The label of the option to add a new site that the extension should be allowed to access.">
     Add a new page
   </message>
   <message name="IDS_EXTENSIONS_ITEM_SITE_ACCESS_EMPTY" desc="The text to indicate that an extension does not have any site access.">
     This extension has no additional site access.
   </message>
-  <message name="IDS_EXTENSIONS_ITEM_SITE_ACCESS_SUBLABEL" desc="The sublabel of the button to click to view the list of websites that the extension can access.">
-    Choose when this extension can read and change your site data
-  </message>
   <message name="IDS_EXTENSIONS_ITEM_SOURCE" desc="The label above an extension's source, which indicates where the extension came from (webstore, third-party, local disk, etc).">
     Source
   </message>
diff --git a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_ITEM_SITE_ACCESS_NEW.png.sha1 b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_ITEM_SITE_ACCESS_NEW.png.sha1
deleted file mode 100644
index 203f3cb..0000000
--- a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_ITEM_SITE_ACCESS_NEW.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-9d4f527dbd30b304e5468c804dde1f5d51911fc3
\ No newline at end of file
diff --git a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_ITEM_SITE_ACCESS_SUBLABEL.png.sha1 b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_ITEM_SITE_ACCESS_SUBLABEL.png.sha1
deleted file mode 100644
index 203f3cb..0000000
--- a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_ITEM_SITE_ACCESS_SUBLABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-9d4f527dbd30b304e5468c804dde1f5d51911fc3
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ccdf7bee..b47217f 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -5107,8 +5107,7 @@
     {"enable-web-authentication-cable-v2-support",
      flag_descriptions::kEnableWebAuthenticationCableV2SupportName,
      flag_descriptions::kEnableWebAuthenticationCableV2SupportDescription,
-     kOsDesktop | kOsAndroid,
-     FEATURE_VALUE_TYPE(device::kWebAuthCableSecondFactor)},
+     kOsDesktop, FEATURE_VALUE_TYPE(device::kWebAuthPhoneSupport)},
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     {"enable-web-authentication-chromeos-authenticator",
@@ -7502,7 +7501,12 @@
      flag_descriptions::kU2FSecurityKeyAPIDescription, kOsAll,
      FEATURE_VALUE_TYPE(extensions_features::kU2FSecurityKeyAPI)},
 #endif  // ENABLE_EXTENSIONS
-
+    {"force-major-version-to-minor",
+     flag_descriptions::kForceMajorVersionInMinorPositionInUserAgentName,
+     flag_descriptions::kForceMajorVersionInMinorPositionInUserAgentDescription,
+     kOsAll,
+     FEATURE_VALUE_TYPE(
+         blink::features::kForceMajorVersionInMinorPositionInUserAgent)},
     {"force-major-version-to-100",
      flag_descriptions::kForceMajorVersion100InUserAgentName,
      flag_descriptions::kForceMajorVersion100InUserAgentDescription, kOsAll,
diff --git a/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc b/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc
index 50fd175..8b1ea1faf 100644
--- a/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc
+++ b/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc
@@ -13,8 +13,6 @@
 #include "chrome/browser/android/autofill_assistant/ui_controller_android.h"
 #include "chrome/browser/android/autofill_assistant/ui_controller_android_utils.h"
 #include "chrome/browser/autofill/android/personal_data_manager_android.h"
-#include "chrome/browser/autofill/personal_data_manager_factory.h"
-#include "chrome/browser/profiles/profile_manager.h"
 #include "components/autofill/core/browser/autofill_data_util.h"
 
 using base::android::AttachCurrentThread;
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index a63e256..e7b092ea 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -34,10 +34,6 @@
 #include "chrome/browser/android/autofill_assistant/generic_ui_root_controller_android.h"
 #include "chrome/browser/android/autofill_assistant/ui_controller_android_utils.h"
 #include "chrome/browser/autofill/android/personal_data_manager_android.h"
-#include "chrome/browser/autofill/personal_data_manager_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill_assistant/browser/bottom_sheet_state.h"
@@ -51,8 +47,6 @@
 #include "components/autofill_assistant/browser/user_data.h"
 #include "components/autofill_assistant/browser/user_data_util.h"
 #include "components/autofill_assistant/browser/user_model.h"
-#include "components/signin/public/identity_manager/account_info.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/version_info/channel.h"
 #include "content/public/browser/browser_task_traits.h"
diff --git a/chrome/browser/ash/crostini/crostini_shelf_utils.cc b/chrome/browser/ash/crostini/crostini_shelf_utils.cc
index c1dea43..8ba5b26 100644
--- a/chrome/browser/ash/crostini/crostini_shelf_utils.cc
+++ b/chrome/browser/ash/crostini/crostini_shelf_utils.cc
@@ -61,7 +61,7 @@
 enum class FindAppIdResult { NoMatch, UniqueMatch, NonUniqueMatch };
 // Looks for an app where prefs_key is set to search_value. Returns the apps id
 // if there was only one app matching, otherwise returns an empty string.
-FindAppIdResult FindAppId(const base::DictionaryValue* prefs,
+FindAppIdResult FindAppId(const base::Value* prefs,
                           base::StringPiece prefs_key,
                           base::StringPiece search_value,
                           std::string* result,
@@ -142,8 +142,8 @@
 std::string GetCrostiniShelfAppId(const Profile* profile,
                                   const std::string* window_app_id,
                                   const std::string* window_startup_id) {
-  const base::DictionaryValue* apps = &base::Value::AsDictionaryValue(
-      *profile->GetPrefs()->GetDictionary(guest_os::prefs::kGuestOsRegistry));
+  const base::Value* apps =
+      profile->GetPrefs()->GetDictionary(guest_os::prefs::kGuestOsRegistry);
   std::string app_id;
 
   if (window_startup_id) {
diff --git a/chrome/browser/ash/external_protocol_dialog.cc b/chrome/browser/ash/external_protocol_dialog.cc
index a023ff0..0f33ea95 100644
--- a/chrome/browser/ash/external_protocol_dialog.cc
+++ b/chrome/browser/ash/external_protocol_dialog.cc
@@ -15,6 +15,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/text_elider.h"
@@ -31,6 +32,7 @@
 
 void OnArcHandled(const GURL& url,
                   const absl::optional<url::Origin>& initiating_origin,
+                  content::WeakDocumentPtr initiator_document,
                   int render_process_host_id,
                   int routing_id,
                   bool handled) {
@@ -50,7 +52,7 @@
   if (registration) {
     new ExternalProtocolDialog(web_contents, url,
                                base::UTF8ToUTF16(registration->Name()),
-                               initiating_origin);
+                               initiating_origin, initiator_document);
   } else {
     new ash::ExternalProtocolNoHandlersDialog(web_contents, url);
   }
@@ -67,7 +69,8 @@
     WebContents* web_contents,
     ui::PageTransition page_transition,
     bool has_user_gesture,
-    const absl::optional<url::Origin>& initiating_origin) {
+    const absl::optional<url::Origin>& initiating_origin,
+    content::WeakDocumentPtr initiator_document) {
   // First, check if ARC version of the dialog is available and run ARC version
   // when possible.
   // TODO(ellyjones): Refactor arc::RunArcExternalProtocolDialog() to take a
@@ -80,7 +83,8 @@
       url, initiating_origin, render_process_host_id, routing_id,
       page_transition, has_user_gesture,
       base::BindOnce(&OnArcHandled, url, initiating_origin,
-                     render_process_host_id, routing_id));
+                     std::move(initiator_document), render_process_host_id,
+                     routing_id));
 }
 
 namespace ash {
diff --git a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc
index 934bac01..0cec6d7 100644
--- a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc
+++ b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc
@@ -125,8 +125,7 @@
                                     msg->get_scan_result());
       return;
     case device::mojom::FingerprintMessage::Tag::kFingerprintError:
-      base::UmaHistogramEnumeration("Fingerprint.Auth.Error",
-                                    msg->get_fingerprint_error());
+      // TODO(issuetracker.google.com/184843581): Add metrics for errors.
       return;
   }
   NOTREACHED();
diff --git a/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc b/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc
index 7972296e..0c5fef8 100644
--- a/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc
+++ b/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc
@@ -24,7 +24,6 @@
 namespace {
 
 const char* kUmaAuthScanResult = "Fingerprint.Auth.ScanResult";
-const char* kUmaAuthError = "Fingerprint.Auth.Error";
 
 class FingerprintStorageUnitTest : public testing::Test {
  public:
@@ -137,29 +136,6 @@
       histogram_tester.GetAllSamples(kUmaAuthScanResult),
       ElementsAre(base::Bucket(
           static_cast<int>(device::mojom::ScanResult::SUCCESS), /*count=*/1)));
-
-  EXPECT_TRUE(histogram_tester.GetAllSamples(kUmaAuthError).empty());
-}
-
-TEST_F(FingerprintStorageUnitTest, TestFingerprintErrorIsSentToUma) {
-  FingerprintStorage* fingerprint_storage =
-      QuickUnlockFactory::GetForProfile(profile_.get())->fingerprint_storage();
-  base::HistogramTester histogram_tester;
-  base::flat_map<std::string, std::vector<std::string>> empty_matches;
-  device::mojom::FingerprintMessagePtr msg =
-      device::mojom::FingerprintMessage::New();
-
-  msg->set_fingerprint_error(
-      device::mojom::FingerprintError::UNABLE_TO_PROCESS);
-  fingerprint_storage->OnAuthScanDone(std::move(msg), empty_matches);
-
-  EXPECT_TRUE(histogram_tester.GetAllSamples(kUmaAuthScanResult).empty());
-
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples(kUmaAuthError),
-      ElementsAre(base::Bucket(
-          static_cast<int>(device::mojom::FingerprintError::UNABLE_TO_PROCESS),
-          /*count=*/1)));
 }
 
 }  // namespace quick_unlock
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash.h b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash.h
index 0f4b8824..85e462da 100644
--- a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash.h
+++ b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash.h
@@ -308,9 +308,6 @@
 
   // List of the currently running screen shares.
   std::vector<ScreenShareInfo> running_screen_shares_;
-
-  // TODO(https://crbug.com/1278733): Remove this flag
-  const bool is_screen_share_warning_mode_enabled_ = false;
 };
 
 // Helper class to call SetDlpContentManagerAshForTesting and
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc
index 9c48203..560c459 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
+#include "base/values.h"
 #include "chrome/browser/ash/settings/device_settings_service.h"
 #include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
 #include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
@@ -158,9 +159,22 @@
         ::ash::kReportDeviceNetworkTelemetryEventCheckingRateMs,
         kNetworkHealthRateMs);
 
-    network_handler_test_helper_.device_test()->ClearDevices();
-    network_handler_test_helper_.device_test()->AddDevice(
-        "ethernet/path", shill::kTypeEthernet, "ethernet");
+    const std::string kEthernetPath = "ethernet/path";
+    const std::string kProfilePath = "/profile/path";
+    network_handler_test_helper_.profile_test()->AddProfile(kProfilePath,
+                                                            "user_hash");
+    auto* const device_client = network_handler_test_helper_.device_test();
+    auto* const service_client = network_handler_test_helper_.service_test();
+    base::RunLoop().RunUntilIdle();
+
+    device_client->ClearDevices();
+    service_client->ClearServices();
+    device_client->AddDevice(kEthernetPath, shill::kTypeEthernet, "ethernet");
+    service_client->AddService(kEthernetPath, "guid", "name",
+                               shill::kTypeEthernet, shill::kStateOnline,
+                               /*is_visible=*/true);
+    service_client->SetServiceProperty(kEthernetPath, shill::kProfileProperty,
+                                       base::Value(kProfilePath));
     base::RunLoop().RunUntilIdle();
   }
 
@@ -223,6 +237,11 @@
       ->set_verdict(test_case.latency_verdict);
   https_latency_sampler->SetMetricData(std::move(https_latency_data));
   fake_delegate->SetHttpsLatencySampler(std::move(https_latency_sampler));
+
+  int info_report_count = 0;
+  int telemetry_report_count = 0;
+  int telemetry_flush_count = 0;
+  int event_report_count = 0;
   auto info_queue = std::unique_ptr<MockReportQueue, base::OnTaskRunnerDeleter>(
       new ::testing::NiceMock<MockReportQueue>(),
       base::OnTaskRunnerDeleter(task_runner_));
@@ -234,45 +253,57 @@
       std::unique_ptr<MockReportQueue, base::OnTaskRunnerDeleter>(
           new ::testing::NiceMock<MockReportQueue>(),
           base::OnTaskRunnerDeleter(task_runner_));
-  auto* const info_queue_ptr = info_queue.get();
-  auto* const telemetry_queue_ptr = telemetry_queue.get();
-  auto* const event_queue_ptr = event_queue.get();
+  ON_CALL(*info_queue, AddRecord).WillByDefault([&]() { ++info_report_count; });
+  ON_CALL(*telemetry_queue, AddRecord).WillByDefault([&]() {
+    ++telemetry_report_count;
+  });
+  ON_CALL(*telemetry_queue, Flush).WillByDefault([&]() {
+    ++telemetry_flush_count;
+  });
+  ON_CALL(*event_queue, AddRecord).WillByDefault([&]() {
+    ++event_report_count;
+  });
 
   fake_delegate->SetInfoQueue(std::move(info_queue));
   fake_delegate->SetTelemetryQueue(std::move(telemetry_queue));
   fake_delegate->SetEventQueue(std::move(event_queue));
 
-  EXPECT_CALL(*info_queue_ptr, AddRecord).Times(test_case.expected_info_count);
   auto metric_reporting_manager = MetricReportingManager::CreateForTesting(
       std::move(fake_delegate), nullptr);
+  base::RunLoop run_loop;
+  base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                   run_loop.QuitClosure());
+  run_loop.Run();
+  EXPECT_EQ(info_report_count, test_case.expected_info_count);
 
-  EXPECT_CALL(*telemetry_queue_ptr, AddRecord).Times(0);
-  EXPECT_CALL(*telemetry_queue_ptr, Flush)
-      .Times(test_case.expected_flush_per_period);
-  EXPECT_CALL(*event_queue_ptr, AddRecord).Times(0);
   task_environment_.FastForwardBy(base::Milliseconds(kNetworkHealthRateMs));
+  EXPECT_EQ(telemetry_report_count, 0);
+  EXPECT_EQ(telemetry_flush_count, test_case.expected_flush_per_period);
+  EXPECT_EQ(event_report_count, 0);
 
   metric_reporting_manager->OnLogin(nullptr);
 
-  EXPECT_CALL(*telemetry_queue_ptr, AddRecord)
-      .Times(test_case.expected_telemetry_count);
-  EXPECT_CALL(*telemetry_queue_ptr, Flush)
-      .Times(test_case.expected_flush_per_period);
-  EXPECT_CALL(*event_queue_ptr, AddRecord)
-      .Times(test_case.expected_event_count);
+  // Reset flush count.
+  telemetry_flush_count = 0;
   task_environment_.FastForwardBy(base::Milliseconds(kNetworkHealthRateMs));
+  EXPECT_EQ(telemetry_report_count, test_case.expected_telemetry_count);
+  EXPECT_EQ(telemetry_flush_count, test_case.expected_flush_per_period);
+  EXPECT_EQ(event_report_count, test_case.expected_event_count);
 
   fake_delegate_ptr->SetIsDeprovisioned(true);
   metric_reporting_manager->DeviceSettingsUpdated();
 
-  // Device is deprovisioned, so no reporting.
-  EXPECT_CALL(*telemetry_queue_ptr, AddRecord).Times(0);
-  EXPECT_CALL(*telemetry_queue_ptr, Flush).Times(0);
-  EXPECT_CALL(*event_queue_ptr, AddRecord).Times(0);
+  // Device is deprovisioned, so no reporting, reset all counts.
+  telemetry_report_count = 0;
+  telemetry_flush_count = 0;
+  event_report_count = 0;
   task_environment_.FastForwardBy(base::Milliseconds(kNetworkHealthRateMs));
+  EXPECT_EQ(telemetry_report_count, 0);
+  EXPECT_EQ(telemetry_flush_count, 0);
+  EXPECT_EQ(event_report_count, 0);
 }
 
-TEST_F(NetworkHealthReportingTest, NetworkEventsOvserver) {
+TEST_F(NetworkHealthReportingTest, NetworkEventsObserver) {
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ::ash::kReportDeviceNetworkStatus, true);
 
@@ -282,23 +313,28 @@
 
   auto fake_delegate = std::make_unique<FakeDelegate>();
   fake_delegate->SetIsAffiliated(true);
+
+  int event_reported_count = 0;
   auto event_queue =
       std::unique_ptr<MockReportQueue, base::OnTaskRunnerDeleter>(
           new ::testing::NiceMock<MockReportQueue>(),
           base::OnTaskRunnerDeleter(task_runner_));
-  auto* const event_queue_ptr = event_queue.get();
+  ON_CALL(*event_queue, AddRecord).WillByDefault([&]() {
+    ++event_reported_count;
+  });
   fake_delegate->SetEventQueue(std::move(event_queue));
 
   auto metric_reporting_manager = MetricReportingManager::CreateForTesting(
       std::move(fake_delegate), nullptr);
 
   metric_reporting_manager->OnLogin(nullptr);
-  EXPECT_CALL(*event_queue_ptr, AddRecord).Times(1);
   base::RunLoop run_loop;
   EmitSignalStrengthEvent();
   base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
                                                    run_loop.QuitClosure());
   run_loop.Run();
+
+  EXPECT_EQ(event_reported_count, 1);
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/ash/printing/calculators_policies_binder.cc b/chrome/browser/ash/printing/calculators_policies_binder.cc
index 486b6158..e7732c9 100644
--- a/chrome/browser/ash/printing/calculators_policies_binder.cc
+++ b/chrome/browser/ash/printing/calculators_policies_binder.cc
@@ -35,9 +35,9 @@
   return BulkPrintersCalculator::ALL_ACCESS;
 }
 
-std::vector<std::string> ConvertToVector(const base::ListValue* list) {
+std::vector<std::string> ConvertToVector(const base::Value* list) {
   std::vector<std::string> string_list;
-  if (!list) {
+  if (!list || !list->is_list()) {
     return string_list;
   }
 
@@ -72,7 +72,7 @@
   }
 
   std::vector<std::string> GetStringList(const char* name) const override {
-    return ConvertToVector(&base::Value::AsListValue(*prefs_->GetList(name)));
+    return ConvertToVector(prefs_->GetList(name));
   }
 
  private:
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 76de414..bc79850 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -269,6 +269,7 @@
 #include "content/public/browser/tts_platform.h"
 #include "content/public/browser/url_loader_request_interceptor.h"
 #include "content/public/browser/vpn_service_proxy.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_ui_url_loader_factory.h"
@@ -1067,7 +1068,8 @@
                bool is_main_frame,
                network::mojom::WebSandboxFlags sandbox_flags,
                bool has_user_gesture,
-               const absl::optional<url::Origin>& initiating_origin) {
+               const absl::optional<url::Origin>& initiating_origin,
+               content::WeakDocumentPtr initiator_document) {
   // If there is no longer a WebContents, the request may have raced with tab
   // closing. Don't fire the external request. (It may have been a prerender.)
   content::WebContents* web_contents = web_contents_getter.Run();
@@ -1153,11 +1155,12 @@
   // without any additional security checks. Since the URL is allowlisted,
   // we assume it can be executed.
   if (is_allowlisted) {
-    ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url, web_contents);
+    ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
+        url, web_contents, std::move(initiator_document));
   } else {
-    ExternalProtocolHandler::LaunchUrl(url, std::move(web_contents_getter),
-                                       page_transition, has_user_gesture,
-                                       initiating_origin);
+    ExternalProtocolHandler::LaunchUrl(
+        url, std::move(web_contents_getter), page_transition, has_user_gesture,
+        initiating_origin, std::move(initiator_document));
   }
 }
 
@@ -5507,6 +5510,7 @@
     ui::PageTransition page_transition,
     bool has_user_gesture,
     const absl::optional<url::Origin>& initiating_origin,
+    content::RenderFrameHost* initiator_document,
     mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   // External protocols are disabled for guests. An exception is made for the
@@ -5529,11 +5533,16 @@
     return false;
 #endif  // defined(ANDROID)
 
+  auto weak_initiator_document = initiator_document
+                                     ? initiator_document->GetWeakDocumentPtr()
+                                     : content::WeakDocumentPtr();
+
   content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&LaunchURL, weak_factory_.GetWeakPtr(), url,
-                                std::move(web_contents_getter), page_transition,
-                                is_main_frame, sandbox_flags, has_user_gesture,
-                                initiating_origin));
+      FROM_HERE,
+      base::BindOnce(&LaunchURL, weak_factory_.GetWeakPtr(), url,
+                     std::move(web_contents_getter), page_transition,
+                     is_main_frame, sandbox_flags, has_user_gesture,
+                     initiating_origin, std::move(weak_initiator_document)));
   return true;
 }
 
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index b5b7ba4f3..3a8f7cf2 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -614,6 +614,7 @@
       ui::PageTransition page_transition,
       bool has_user_gesture,
       const absl::optional<url::Origin>& initiating_origin,
+      content::RenderFrameHost* initiator_document,
       mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory)
       override;
   std::unique_ptr<content::OverlayWindow> CreateWindowForPictureInPicture(
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
index e9961c7..8086d85 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
@@ -227,7 +227,7 @@
     std::move(callback).Run(false);
     return;
   }
-  if (IsWarn(info.restriction_info)) {
+  if (is_screen_share_warning_mode_enabled_ && IsWarn(info.restriction_info)) {
     // Check which of the contents were already allowed and don't warn for
     // those.
     RemoveAllowedContents(info.confidential_contents,
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
index 55797b95e..2921239 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
@@ -154,6 +154,9 @@
   DlpReportingManager* reporting_manager_;
 
   std::unique_ptr<DlpWarnNotifier> warn_notifier_;
+
+  // TODO(https://crbug.com/1278733): Remove this flag
+  const bool is_screen_share_warning_mode_enabled_ = false;
 };
 
 }  // namespace policy
diff --git a/chrome/browser/devtools/devtools_browsertest.cc b/chrome/browser/devtools/devtools_browsertest.cc
index 36cfae0..5616953 100644
--- a/chrome/browser/devtools/devtools_browsertest.cc
+++ b/chrome/browser/devtools/devtools_browsertest.cc
@@ -1891,9 +1891,9 @@
       std::string("window.location = \"") + url.spec() + "\""));
   observer.Wait();
 
-  ASSERT_TRUE(main_web_contents()->GetURL().
-                  SchemeIs(content::kChromeDevToolsScheme));
-  ASSERT_EQ(url, GetInspectedTab()->GetURL());
+  ASSERT_TRUE(main_web_contents()->GetLastCommittedURL().SchemeIs(
+      content::kChromeDevToolsScheme));
+  ASSERT_EQ(url, GetInspectedTab()->GetLastCommittedURL());
   CloseDevToolsWindow();
 }
 
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc
index 1ec973e9..8ffee4fb 100644
--- a/chrome/browser/devtools/devtools_file_helper.cc
+++ b/chrome/browser/devtools/devtools_file_helper.cc
@@ -154,7 +154,8 @@
 std::string RegisterFileSystem(WebContents* web_contents,
                                const base::FilePath& path) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  CHECK(web_contents->GetURL().SchemeIs(content::kChromeDevToolsScheme));
+  CHECK(web_contents->GetLastCommittedURL().SchemeIs(
+      content::kChromeDevToolsScheme));
   std::string root_name(kRootName);
   storage::IsolatedContext::ScopedFSHandle file_system =
       isolated_context()->RegisterFileSystemForPath(
@@ -183,7 +184,8 @@
     const std::string& type,
     const std::string& file_system_id,
     const std::string& file_system_path) {
-  const GURL origin = web_contents->GetURL().DeprecatedGetOriginAsURL();
+  const GURL origin =
+      web_contents->GetLastCommittedURL().DeprecatedGetOriginAsURL();
   std::string file_system_name =
       storage::GetIsolatedFileSystemName(origin, file_system_id);
   std::string root_url = storage::GetIsolatedFileSystemRootURIString(
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 7c61157..c6cce2f8 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -898,14 +898,14 @@
     // committed URL of that frame, and use the loader associated with that
     // frame to allow nested frames with different schemes to load files.
     if (allow_web_ui_scheme && target_tab &&
-        target_tab->GetURL().scheme() == gurl.scheme()) {
+        target_tab->GetLastCommittedURL().scheme() == gurl.scheme()) {
       std::vector<std::string> allowed_webui_hosts;
       content::RenderFrameHost* frame_host = web_contents()->GetMainFrame();
 
       mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote =
-          content::CreateWebUIURLLoaderFactory(frame_host,
-                                               target_tab->GetURL().scheme(),
-                                               std::move(allowed_webui_hosts));
+          content::CreateWebUIURLLoaderFactory(
+              frame_host, target_tab->GetLastCommittedURL().scheme(),
+              std::move(allowed_webui_hosts));
       url_loader_factory = network::SharedURLLoaderFactory::Create(
           std::make_unique<network::WrapperPendingSharedURLLoaderFactory>(
               std::move(pending_remote)));
@@ -941,7 +941,8 @@
 }
 
 void DevToolsUIBindings::ShowItemInFolder(const std::string& file_system_path) {
-  CHECK(IsValidFrontendURL(web_contents_->GetURL()) && frontend_host_);
+  CHECK(IsValidFrontendURL(web_contents_->GetLastCommittedURL()) &&
+        frontend_host_);
   file_helper_->ShowItemInFolder(file_system_path);
 }
 
@@ -963,7 +964,8 @@
 }
 
 void DevToolsUIBindings::RequestFileSystems() {
-  CHECK(IsValidFrontendURL(web_contents_->GetURL()) && frontend_host_);
+  CHECK(IsValidFrontendURL(web_contents_->GetLastCommittedURL()) &&
+        frontend_host_);
   base::ListValue file_systems_value;
   for (auto const& file_system : file_helper_->GetFileSystems())
     file_systems_value.Append(CreateFileSystemValue(file_system));
@@ -972,20 +974,23 @@
 }
 
 void DevToolsUIBindings::AddFileSystem(const std::string& type) {
-  CHECK(IsValidFrontendURL(web_contents_->GetURL()) && frontend_host_);
+  CHECK(IsValidFrontendURL(web_contents_->GetLastCommittedURL()) &&
+        frontend_host_);
   file_helper_->AddFileSystem(
       type, base::BindRepeating(&DevToolsUIBindings::ShowDevToolsInfoBar,
                                 weak_factory_.GetWeakPtr()));
 }
 
 void DevToolsUIBindings::RemoveFileSystem(const std::string& file_system_path) {
-  CHECK(IsValidFrontendURL(web_contents_->GetURL()) && frontend_host_);
+  CHECK(IsValidFrontendURL(web_contents_->GetLastCommittedURL()) &&
+        frontend_host_);
   file_helper_->RemoveFileSystem(file_system_path);
 }
 
 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions(
     const std::string& file_system_url) {
-  CHECK(IsValidFrontendURL(web_contents_->GetURL()) && frontend_host_);
+  CHECK(IsValidFrontendURL(web_contents_->GetLastCommittedURL()) &&
+        frontend_host_);
   file_helper_->UpgradeDraggedFileSystemPermissions(
       file_system_url,
       base::BindRepeating(&DevToolsUIBindings::ShowDevToolsInfoBar,
@@ -997,7 +1002,8 @@
     const std::string& file_system_path,
     const std::string& excluded_folders_message) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  CHECK(IsValidFrontendURL(web_contents_->GetURL()) && frontend_host_);
+  CHECK(IsValidFrontendURL(web_contents_->GetLastCommittedURL()) &&
+        frontend_host_);
   if (!file_helper_->IsFileSystemAdded(file_system_path)) {
     IndexingDone(index_request_id, file_system_path);
     return;
@@ -1042,7 +1048,8 @@
                                       const std::string& file_system_path,
                                       const std::string& query) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  CHECK(IsValidFrontendURL(web_contents_->GetURL()) && frontend_host_);
+  CHECK(IsValidFrontendURL(web_contents_->GetLastCommittedURL()) &&
+        frontend_host_);
   if (!file_helper_->IsFileSystemAdded(file_system_path)) {
     SearchCompleted(search_request_id,
                     file_system_path,
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc b/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
index 36c6966..c2e39e7 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
@@ -161,16 +161,15 @@
   // REMOVE_SITE_DATA in browsing_data_remover.h, the former for the unprotected
   // web, the latter for  protected web data. There is no UI control for
   // extension data.
-  std::unique_ptr<base::DictionaryValue> origin_types(
-      new base::DictionaryValue);
-  origin_types->SetBoolean(
+  base::Value origin_types(base::Value::Type::DICTIONARY);
+  origin_types.SetBoolKey(
       extension_browsing_data_api_constants::kUnprotectedWebKey,
       isDataTypeSelected(BrowsingDataType::COOKIES, tab));
-  origin_types->SetBoolean(
+  origin_types.SetBoolKey(
       extension_browsing_data_api_constants::kProtectedWebKey,
       isDataTypeSelected(BrowsingDataType::HOSTED_APPS_DATA, tab));
-  origin_types->SetBoolean(
-      extension_browsing_data_api_constants::kExtensionsKey, false);
+  origin_types.SetBoolKey(extension_browsing_data_api_constants::kExtensionsKey,
+                          false);
 
   // Fill deletion time period.
   int period_pref =
@@ -184,80 +183,77 @@
     since = time.ToJsTime();
   }
 
-  std::unique_ptr<base::DictionaryValue> options(new base::DictionaryValue);
-  options->Set(extension_browsing_data_api_constants::kOriginTypesKey,
-               std::move(origin_types));
-  options->SetDoubleKey(extension_browsing_data_api_constants::kSinceKey,
-                        since);
+  base::Value options(base::Value::Type::DICTIONARY);
+  options.SetKey(extension_browsing_data_api_constants::kOriginTypesKey,
+                 std::move(origin_types));
+  options.SetDoubleKey(extension_browsing_data_api_constants::kSinceKey, since);
 
   // Fill dataToRemove and dataRemovalPermitted.
-  std::unique_ptr<base::DictionaryValue> selected(new base::DictionaryValue);
-  std::unique_ptr<base::DictionaryValue> permitted(new base::DictionaryValue);
+  base::Value selected(base::Value::Type::DICTIONARY);
+  base::Value permitted(base::Value::Type::DICTIONARY);
 
   bool delete_site_data =
       isDataTypeSelected(BrowsingDataType::COOKIES, tab) ||
       isDataTypeSelected(BrowsingDataType::HOSTED_APPS_DATA, tab);
 
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kCookiesKey,
              delete_site_data);
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kFileSystemsKey,
              delete_site_data);
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kIndexedDBKey,
              delete_site_data);
-  SetDetails(selected.get(), permitted.get(),
-      extension_browsing_data_api_constants::kLocalStorageKey,
-      delete_site_data);
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
+             extension_browsing_data_api_constants::kLocalStorageKey,
+             delete_site_data);
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kWebSQLKey,
              delete_site_data);
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kServiceWorkersKey,
              delete_site_data);
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kCacheStorageKey,
              delete_site_data);
   // PluginData is not supported anymore. (crbug.com/1135791)
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kPluginDataKeyDeprecated,
              false);
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kHistoryKey,
              isDataTypeSelected(BrowsingDataType::HISTORY, tab));
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kDownloadsKey,
              isDataTypeSelected(BrowsingDataType::DOWNLOADS, tab));
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kCacheKey,
              isDataTypeSelected(BrowsingDataType::CACHE, tab));
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kFormDataKey,
              isDataTypeSelected(BrowsingDataType::FORM_DATA, tab));
-  SetDetails(selected.get(), permitted.get(),
+  SetDetails(&selected, &permitted,
              extension_browsing_data_api_constants::kPasswordsKey,
              isDataTypeSelected(BrowsingDataType::PASSWORDS, tab));
 
-  std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue);
-  result->Set(extension_browsing_data_api_constants::kOptionsKey,
-              std::move(options));
-  result->Set(extension_browsing_data_api_constants::kDataToRemoveKey,
-              std::move(selected));
-  result->Set(extension_browsing_data_api_constants::kDataRemovalPermittedKey,
-              std::move(permitted));
-  return RespondNow(
-      OneArgument(base::Value::FromUniquePtrValue(std::move(result))));
+  base::Value result(base::Value::Type::DICTIONARY);
+  result.SetKey(extension_browsing_data_api_constants::kOptionsKey,
+                std::move(options));
+  result.SetKey(extension_browsing_data_api_constants::kDataToRemoveKey,
+                std::move(selected));
+  result.SetKey(extension_browsing_data_api_constants::kDataRemovalPermittedKey,
+                std::move(permitted));
+  return RespondNow(OneArgument(std::move(result)));
 }
 
-void BrowsingDataSettingsFunction::SetDetails(
-    base::DictionaryValue* selected_dict,
-    base::DictionaryValue* permitted_dict,
-    const char* data_type,
-    bool is_selected) {
+void BrowsingDataSettingsFunction::SetDetails(base::Value* selected_dict,
+                                              base::Value* permitted_dict,
+                                              const char* data_type,
+                                              bool is_selected) {
   bool is_permitted = IsRemovalPermitted(MaskForKey(data_type), prefs_);
-  selected_dict->SetBoolean(data_type, is_selected && is_permitted);
-  permitted_dict->SetBoolean(data_type, is_permitted);
+  selected_dict->SetBoolKey(data_type, is_selected && is_permitted);
+  permitted_dict->SetBoolKey(data_type, is_permitted);
 }
 
 BrowsingDataRemoverFunction::BrowsingDataRemoverFunction() = default;
@@ -303,11 +299,9 @@
   EXTENSION_FUNCTION_VALIDATE(GetRemovalMask(&removal_mask_));
 
   const base::Value* origins =
-      options.FindKeyOfType(extension_browsing_data_api_constants::kOriginsKey,
-                            base::Value::Type::LIST);
-  const base::Value* exclude_origins = options.FindKeyOfType(
-      extension_browsing_data_api_constants::kExcludeOriginsKey,
-      base::Value::Type::LIST);
+      options.FindListKey(extension_browsing_data_api_constants::kOriginsKey);
+  const base::Value* exclude_origins = options.FindListKey(
+      extension_browsing_data_api_constants::kExcludeOriginsKey);
 
   // Check that only |origins| or |excludeOrigins| can be set.
   if (origins && exclude_origins) {
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_api.h b/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
index 8f7bfc6e..241d641 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
@@ -75,8 +75,8 @@
   // indicating whether the data type is both selected and permitted to be
   // removed; and a value in the |permitted_dict| with the |data_type| as a
   // key, indicating only whether the data type is permitted to be removed.
-  void SetDetails(base::DictionaryValue* selected_dict,
-                  base::DictionaryValue* permitted_dict,
+  void SetDetails(base::Value* selected_dict,
+                  base::Value* permitted_dict,
                   const char* data_type,
                   bool is_selected);
 
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_unittest.cc b/chrome/browser/extensions/api/browsing_data/browsing_data_unittest.cc
index d4c4494..c282cf47 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_unittest.cc
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_unittest.cc
@@ -82,12 +82,11 @@
     return remover_->GetLastUsedOriginTypeMaskForTesting();
   }
 
-  uint64_t GetAsMask(const base::DictionaryValue* dict,
+  uint64_t GetAsMask(const base::Value* dict,
                      std::string path,
                      uint64_t mask_value) {
-    absl::optional<bool> result = dict->FindBoolPath(path);
-    EXPECT_TRUE(result.has_value()) << "for " << path;
-    return result.value() ? mask_value : 0;
+    EXPECT_TRUE(dict->FindBoolKey(path));
+    return *dict->FindBoolKey(path) ? mask_value : 0;
   }
 
   void RunBrowsingDataRemoveFunctionAndCompareRemovalMask(
@@ -142,15 +141,12 @@
     scoped_refptr<BrowsingDataSettingsFunction> function =
         new BrowsingDataSettingsFunction();
     SCOPED_TRACE("settings");
-    std::unique_ptr<base::Value> result_value(RunFunctionAndReturnSingleResult(
-        function.get(), std::string("[]"), browser()));
+    std::unique_ptr<base::Value> result = RunFunctionAndReturnSingleResult(
+        function.get(), std::string("[]"), browser());
 
-    base::DictionaryValue* result;
-    EXPECT_TRUE(result_value->GetAsDictionary(&result));
-    base::DictionaryValue* options;
-    EXPECT_TRUE(result->GetDictionary("options", &options));
-    absl::optional<double> since = options->FindDoubleKey("since");
-    ASSERT_TRUE(since);
+    EXPECT_TRUE(result->is_dict());
+    EXPECT_TRUE(result->FindDoublePath("options.since"));
+    double since = *result->FindDoublePath("options.since");
 
     double expected_since = 0;
     if (since_pref != browsing_data::TimePeriod::ALL_TIME) {
@@ -162,7 +158,7 @@
     // second, so we'll make sure the requested start time is within 10 seconds.
     // Since the smallest selectable period is an hour, that should be
     // sufficient.
-    EXPECT_LE(expected_since, *since + 10.0 * 1000.0);
+    EXPECT_LE(expected_since, since + 10.0 * 1000.0);
   }
 
   void SetPrefsAndVerifySettings(int data_type_flags,
@@ -229,24 +225,21 @@
     scoped_refptr<BrowsingDataSettingsFunction> function =
         new BrowsingDataSettingsFunction();
     SCOPED_TRACE("settings");
-    std::unique_ptr<base::Value> result_value(RunFunctionAndReturnSingleResult(
+    std::unique_ptr<base::Value> result(RunFunctionAndReturnSingleResult(
         function.get(), std::string("[]"), browser()));
 
-    base::DictionaryValue* result;
-    EXPECT_TRUE(result_value->GetAsDictionary(&result));
+    EXPECT_TRUE(result->is_dict());
 
-    base::DictionaryValue* options;
-    EXPECT_TRUE(result->GetDictionary("options", &options));
-    base::DictionaryValue* origin_types;
-    EXPECT_TRUE(options->GetDictionary("originTypes", &origin_types));
+    base::Value* origin_types = result->FindDictPath("options.originTypes");
+    EXPECT_TRUE(origin_types);
     uint64_t origin_type_mask =
         GetAsMask(origin_types, "unprotectedWeb", UNPROTECTED_WEB) |
         GetAsMask(origin_types, "protectedWeb", PROTECTED_WEB) |
         GetAsMask(origin_types, "extension", EXTENSION);
     EXPECT_EQ(expected_origin_type_mask, origin_type_mask);
 
-    base::DictionaryValue* data_to_remove;
-    EXPECT_TRUE(result->GetDictionary("dataToRemove", &data_to_remove));
+    base::Value* data_to_remove = result->FindDictKey("dataToRemove");
+    EXPECT_TRUE(data_to_remove);
     uint64_t removal_mask =
         GetAsMask(data_to_remove, "cache",
                   content::BrowsingDataRemover::DATA_TYPE_CACHE) |
@@ -471,13 +464,12 @@
     scoped_refptr<BrowsingDataSettingsFunction> settings_function =
         new BrowsingDataSettingsFunction();
     SCOPED_TRACE("settings_json");
-    std::unique_ptr<base::Value> result_value(RunFunctionAndReturnSingleResult(
+    std::unique_ptr<base::Value> result(RunFunctionAndReturnSingleResult(
         settings_function.get(), std::string("[]"), browser()));
 
-    base::DictionaryValue* result;
-    EXPECT_TRUE(result_value->GetAsDictionary(&result));
-    base::DictionaryValue* data_to_remove;
-    EXPECT_TRUE(result->GetDictionary("dataToRemove", &data_to_remove));
+    EXPECT_TRUE(result->is_dict());
+    base::Value* data_to_remove = result->FindDictKey("dataToRemove");
+    EXPECT_TRUE(data_to_remove);
 
     JSONStringValueSerializer serializer(&json);
     EXPECT_TRUE(serializer.Serialize(*data_to_remove));
diff --git a/chrome/browser/external_protocol/external_protocol_handler.cc b/chrome/browser/external_protocol/external_protocol_handler.cc
index 16e07067..1681c8e 100644
--- a/chrome/browser/external_protocol/external_protocol_handler.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler.cc
@@ -25,7 +25,7 @@
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/url_matcher/url_matcher.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/web_contents.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "net/base/escape.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
@@ -85,6 +85,13 @@
     "mailto", "news", "snews",
 };
 
+void AddMessageToConsole(const content::WeakDocumentPtr& document,
+                         blink::mojom::ConsoleMessageLevel level,
+                         const std::string& message) {
+  if (content::RenderFrameHost* rfh = document.AsRenderFrameHostIfValid())
+    rfh->AddMessageToConsole(level, message);
+}
+
 // Functions enabling unit testing. Using a NULL delegate will use the default
 // behavior; if a delegate is provided it will be used instead.
 scoped_refptr<shell_integration::DefaultProtocolClientWorker> CreateShellWorker(
@@ -113,6 +120,7 @@
     ui::PageTransition page_transition,
     bool has_user_gesture,
     const absl::optional<url::Origin>& initiating_origin,
+    content::WeakDocumentPtr initiator_document,
     ExternalProtocolHandler::Delegate* delegate) {
   DCHECK(web_contents);
   if (delegate) {
@@ -125,8 +133,8 @@
   // If the Shell does not have a registered name for the protocol,
   // attempting to invoke the protocol will fail.
   if (shell_integration::GetApplicationNameForProtocol(url).empty()) {
-    web_contents->GetMainFrame()->AddMessageToConsole(
-        blink::mojom::ConsoleMessageLevel::kError,
+    AddMessageToConsole(
+        initiator_document, blink::mojom::ConsoleMessageLevel::kError,
         "Failed to launch '" + url.possibly_invalid_spec() +
             "' because the scheme does not have a registered handler.");
     return;
@@ -134,12 +142,14 @@
 #endif
 
   ExternalProtocolHandler::RunExternalProtocolDialog(
-      url, web_contents, page_transition, has_user_gesture, initiating_origin);
+      url, web_contents, page_transition, has_user_gesture, initiating_origin,
+      std::move(initiator_document));
 }
 
 void LaunchUrlWithoutSecurityCheckWithDelegate(
     const GURL& url,
     content::WebContents* web_contents,
+    content::WeakDocumentPtr initiator_document,
     ExternalProtocolHandler::Delegate* delegate) {
   if (delegate) {
     delegate->LaunchUrlWithoutSecurityCheck(url, web_contents);
@@ -151,8 +161,8 @@
   if (!web_contents)
     return;
 
-  web_contents->GetMainFrame()->AddMessageToConsole(
-      blink::mojom::ConsoleMessageLevel::kInfo,
+  AddMessageToConsole(
+      initiator_document, blink::mojom::ConsoleMessageLevel::kInfo,
       "Launched external handler for '" + url.possibly_invalid_spec() + "'.");
 
   platform_util::OpenExternal(
@@ -183,6 +193,7 @@
     ui::PageTransition page_transition,
     bool has_user_gesture,
     const absl::optional<url::Origin>& initiating_origin,
+    content::WeakDocumentPtr initiator_document,
     ExternalProtocolHandler::Delegate* delegate,
     shell_integration::DefaultWebClientState state) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -204,6 +215,7 @@
     // Handle tel links by opening the Click to Call dialog. This will call back
     // into LaunchUrlWithoutSecurityCheck if the user selects a system handler.
     ClickToCallUiController::ShowDialog(web_contents, initiating_origin,
+                                        std::move(initiator_document),
                                         escaped_url, chrome_is_default_handler);
     return;
   }
@@ -225,14 +237,14 @@
     // Ask the user if they want to allow the protocol. This will call
     // LaunchUrlWithoutSecurityCheck if the user decides to accept the
     // protocol.
-    RunExternalProtocolDialogWithDelegate(escaped_url, web_contents,
-                                          page_transition, has_user_gesture,
-                                          initiating_origin, delegate);
+    RunExternalProtocolDialogWithDelegate(
+        escaped_url, web_contents, page_transition, has_user_gesture,
+        initiating_origin, std::move(initiator_document), delegate);
     return;
   }
 
-  LaunchUrlWithoutSecurityCheckWithDelegate(escaped_url, web_contents,
-                                            delegate);
+  LaunchUrlWithoutSecurityCheckWithDelegate(
+      escaped_url, web_contents, std::move(initiator_document), delegate);
 }
 
 bool IsSchemeOriginPairAllowedByPolicy(const std::string& scheme,
@@ -395,7 +407,8 @@
     content::WebContents::Getter web_contents_getter,
     ui::PageTransition page_transition,
     bool has_user_gesture,
-    const absl::optional<url::Origin>& initiating_origin) {
+    const absl::optional<url::Origin>& initiating_origin,
+    content::WeakDocumentPtr initiator_document) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Disable anti-flood protection if the user is invoking a bookmark or
@@ -424,8 +437,8 @@
       escaped_url.scheme(), base::OptionalOrNullptr(initiating_origin),
       g_external_protocol_handler_delegate, profile);
   if (block_state == BLOCK) {
-    web_contents->GetMainFrame()->AddMessageToConsole(
-        blink::mojom::ConsoleMessageLevel::kError,
+    AddMessageToConsole(
+        initiator_document, blink::mojom::ConsoleMessageLevel::kError,
         "Not allowed to launch '" + url.possibly_invalid_spec() + "'" +
             (g_accept_requests ? "." : " because a user gesture is required."));
 
@@ -456,7 +469,7 @@
       &OnDefaultProtocolClientWorkerFinished, escaped_url,
       std::move(web_contents_getter), block_state == UNKNOWN, page_transition,
       has_user_gesture, initiating_origin_or_precursor,
-      g_external_protocol_handler_delegate);
+      std::move(initiator_document), g_external_protocol_handler_delegate);
 
   // Start the check process running. This will send tasks to a worker task
   // runner and when the answer is known will send the result back to
@@ -468,7 +481,8 @@
 // static
 void ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
     const GURL& url,
-    content::WebContents* web_contents) {
+    content::WebContents* web_contents,
+    content::WeakDocumentPtr initiator_document) {
   // Escape the input scheme to be sure that the command does not
   // have parameters unexpected by the external program. The url passed in the
   // |url| parameter might already be escaped but the EscapeExternalHandlerValue
@@ -480,7 +494,8 @@
   GURL escaped_url(escaped_url_string);
 
   LaunchUrlWithoutSecurityCheckWithDelegate(
-      escaped_url, web_contents, g_external_protocol_handler_delegate);
+      escaped_url, web_contents, std::move(initiator_document),
+      g_external_protocol_handler_delegate);
 }
 
 // static
diff --git a/chrome/browser/external_protocol/external_protocol_handler.h b/chrome/browser/external_protocol/external_protocol_handler.h
index 102b2f27..8818262 100644
--- a/chrome/browser/external_protocol/external_protocol_handler.h
+++ b/chrome/browser/external_protocol/external_protocol_handler.h
@@ -13,7 +13,7 @@
 #include "ui/base/page_transition_types.h"
 
 namespace content {
-class WebContents;
+class WeakDocumentPtr;
 }
 
 namespace url {
@@ -105,12 +105,15 @@
   // ExternalProtocolDialog is created asking the user. If the user accepts,
   // LaunchUrlWithoutSecurityCheck is called on the io thread and the
   // application is launched.
+  // If possible, |initiator_document| identifies the document that requested
+  // the external protocol launch.
   // Must run on the UI thread.
   static void LaunchUrl(const GURL& url,
                         content::WebContents::Getter web_contents_getter,
                         ui::PageTransition page_transition,
                         bool has_user_gesture,
-                        const absl::optional<url::Origin>& initiating_origin);
+                        const absl::optional<url::Origin>& initiating_origin,
+                        content::WeakDocumentPtr initiator_document);
 
   // Starts a url using the external protocol handler with the help
   // of shellexecute. Should only be called if the protocol is allowlisted
@@ -121,8 +124,10 @@
   // NOTE: You should NOT call this function directly unless you are sure the
   // url you have has been checked against the denylist.
   // All calls to this function should originate in some way from LaunchUrl.
-  static void LaunchUrlWithoutSecurityCheck(const GURL& url,
-                                            content::WebContents* web_contents);
+  static void LaunchUrlWithoutSecurityCheck(
+      const GURL& url,
+      content::WebContents* web_contents,
+      content::WeakDocumentPtr initiator_document);
 
   // Allows LaunchUrl to proceed with launching an external protocol handler.
   // This is typically triggered by a user gesture, but is also called for
@@ -161,7 +166,8 @@
       content::WebContents* web_contents,
       ui::PageTransition page_transition,
       bool has_user_gesture,
-      const absl::optional<url::Origin>& initiating_origin);
+      const absl::optional<url::Origin>& initiating_origin,
+      content::WeakDocumentPtr initiator_document);
 
   // Clears the external protocol handling data.
   static void ClearData(Profile* profile);
diff --git a/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc b/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc
index 0260e45..add515e2 100644
--- a/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc
@@ -5,10 +5,13 @@
 #include "base/test/bind.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_features.h"
+#include "chrome/browser/external_protocol/external_protocol_handler.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/shell_integration.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "components/policy/core/common/policy_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
@@ -246,3 +249,71 @@
                                "allow-top-navigation-by-user-activation';",
                                /*user-gesture=*/true));
 }
+
+namespace {
+
+class AlwaysBlockedExternalProtocolHandlerDelegate
+    : public ExternalProtocolHandler::Delegate {
+ public:
+  AlwaysBlockedExternalProtocolHandlerDelegate() {
+    ExternalProtocolHandler::SetDelegateForTesting(this);
+  }
+  ~AlwaysBlockedExternalProtocolHandlerDelegate() override {
+    ExternalProtocolHandler::SetDelegateForTesting(nullptr);
+  }
+
+  scoped_refptr<shell_integration::DefaultProtocolClientWorker>
+  CreateShellWorker(const std::string& protocol) override {
+    NOTREACHED();
+    return nullptr;
+  }
+  ExternalProtocolHandler::BlockState GetBlockState(const std::string& scheme,
+                                                    Profile* profile) override {
+    return ExternalProtocolHandler::BLOCK;
+  }
+  void BlockRequest() override {}
+  void RunExternalProtocolDialog(
+      const GURL& url,
+      content::WebContents* web_contents,
+      ui::PageTransition page_transition,
+      bool has_user_gesture,
+      const absl::optional<url::Origin>& initiating_origin) override {
+    NOTREACHED();
+  }
+  void LaunchUrlWithoutSecurityCheck(
+      const GURL& url,
+      content::WebContents* web_contents) override {
+    NOTREACHED();
+  }
+  void FinishedProcessingCheck() override {}
+};
+
+}  // namespace
+
+// Tests (by forcing a particular scheme to be blocked, regardless of platform)
+// that the console message is attributed to a subframe if one was responsible.
+IN_PROC_BROWSER_TEST_F(ExternalProtocolHandlerBrowserTest,
+                       ProtocolLaunchEmitsConsoleLogInCorrectFrame) {
+  AlwaysBlockedExternalProtocolHandlerDelegate always_blocked;
+  content::RenderFrameHost* main_rfh = ui_test_utils::NavigateToURL(
+      browser(), GURL("data:text/html,<iframe srcdoc=\"Hello!\"></iframe>"));
+  ASSERT_TRUE(main_rfh);
+  content::RenderFrameHost* originating_rfh = ChildFrameAt(main_rfh, 0);
+
+  content::WebContentsConsoleObserver observer(
+      content::WebContents::FromRenderFrameHost(originating_rfh));
+  observer.SetPattern("*aunch*'willfailtolaunch://foo'*");
+  observer.SetFilter(base::BindRepeating(
+      [](content::RenderFrameHost* expected_rfh,
+         const content::WebContentsConsoleObserver::Message& message) {
+        return message.source_frame == expected_rfh;
+      },
+      originating_rfh));
+
+  ASSERT_TRUE(
+      ExecJs(originating_rfh, "location.href = 'willfailtolaunch://foo';"));
+  observer.Wait();
+  ASSERT_EQ(1u, observer.messages().size());
+  EXPECT_EQ("Not allowed to launch 'willfailtolaunch://foo'.",
+            observer.GetMessageAt(0u));
+}
diff --git a/chrome/browser/external_protocol/external_protocol_handler_unittest.cc b/chrome/browser/external_protocol/external_protocol_handler_unittest.cc
index 15a57690..d7e0d158 100644
--- a/chrome/browser/external_protocol/external_protocol_handler_unittest.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler_unittest.cc
@@ -16,6 +16,7 @@
 #include "components/prefs/testing_pref_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
@@ -193,7 +194,8 @@
         url,
         base::BindRepeating(&ExternalProtocolHandlerTest::GetWebContents,
                             base::Unretained(this)),
-        ui::PAGE_TRANSITION_LINK, true, initiating_origin);
+        ui::PAGE_TRANSITION_LINK, true, initiating_origin,
+        content::WeakDocumentPtr());
     run_loop_.Run();
     ExternalProtocolHandler::SetDelegateForTesting(nullptr);
 
@@ -309,8 +311,8 @@
   delegate_.set_block_state(ExternalProtocolHandler::DONT_BLOCK);
   delegate_.set_os_state(shell_integration::NOT_DEFAULT);
   delegate_.set_complete_on_launch(true);
-  ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url,
-                                                         web_contents_.get());
+  ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
+      url, web_contents_.get(), content::WeakDocumentPtr());
   run_loop_.Run();
   ExternalProtocolHandler::SetDelegateForTesting(nullptr);
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 12550e9b..e7fc120f 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2865,7 +2865,7 @@
   {
     "name": "enable-web-authentication-cable-v2-support",
     "owners": [ "webauthn-team@google.com" ],
-    "expiry_milestone": 95
+    "expiry_milestone": 103
   },
   {
     "name": "enable-web-authentication-chromeos-authenticator",
@@ -3262,6 +3262,11 @@
     "expiry_milestone": 100
   },
   {
+    "name": "force-major-version-to-minor",
+    "owners": [ "brgoldstein", "potassium-katabolism@google.com" ],
+    "expiry_milestone": 110
+  },
+  {
     "name": "force-minor-version-to-100",
     "owners": [ "abeyad", "potassium-katabolism@google.com" ],
     "expiry_milestone": 100
@@ -5586,6 +5591,11 @@
     "expiry_milestone": 95
   },
   {
+    "name": "use-sf-symbols-samples",
+    "owners": [ "gambard", "bling-flags@google.com" ],
+    "expiry_milestone": 110
+  },
+  {
     "name": "use-stork-smds-server-address",
     "owners": [ "cros-connectivity@google.com", "hsuregan"],
     // This flag is required for dev testing via Stork profiles which can be quickly
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index f009c57..dde9322 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1231,10 +1231,9 @@
     "Allow subresource compression for data savings";
 
 const char kEnableWebAuthenticationCableV2SupportName[] =
-    "Web Authentication caBLE v2 support";
+    "Web Authentication caBLE v2 QR codes";
 const char kEnableWebAuthenticationCableV2SupportDescription[] =
-    "Enable use of phones that are signed into the same account, with Sync "
-    "enabled, to be used as 2nd-factor security keys.";
+    "Enable display of QR codes for using Android phones as security keys.";
 
 const char kEnableWebAuthenticationChromeOSAuthenticatorName[] =
     "ChromeOS platform Web Authentication support";
@@ -2809,12 +2808,22 @@
     "a common submenu.";
 #endif
 
+const char kForceMajorVersionInMinorPositionInUserAgentName[] =
+    "Put major version in minor version position in User-Agent";
+const char kForceMajorVersionInMinorPositionInUserAgentDescription[] =
+    "Lock the Chrome major version in the User-Agent string to 99, and "
+    "force the major version number to the minor version position. This "
+    "flag is a backup plan for unexpected site-compatibility breakage with "
+    "a three digit major version.";
+
 const char kForceMajorVersion100InUserAgentName[] =
     "Force major version to 100 in User-Agent";
 const char kForceMajorVersion100InUserAgentDescription[] =
     "Force the Chrome major version in the User-Agent string to 100, which "
     "allows testing the 3-digit major version number before the actual M100 "
-    "release. This flag is only available from M96-M99.";
+    "release. This flag is only available from M96-M99. "
+    "If force-major-version-in-minor is enabled this flag will "
+    "have no effect.";
 
 const char kForceMinorVersion100InUserAgentName[] =
     "Force the minor version to 100 in the User-Agent string";
@@ -2825,7 +2834,9 @@
     "upcoming major version 100, this flag allows us to test whether setting "
     "the major version in the minor version part of the User-Agent string "
     "would be an acceptable alternative. If force-major-version-to-100 is set, "
-    "then this flag has no effect. See crbug.com/1278459 for details.";
+    "then this flag has no effect. See crbug.com/1278459 for details."
+    "If force-major-version-in-minor is enabled this flag will "
+    "have no effect.";
 
 // Android ---------------------------------------------------------------------
 
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 8c0fa89..1d7ead0 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1623,6 +1623,9 @@
 extern const char kShareContextMenuDescription[];
 #endif
 
+extern const char kForceMajorVersionInMinorPositionInUserAgentName[];
+extern const char kForceMajorVersionInMinorPositionInUserAgentDescription[];
+
 extern const char kForceMajorVersion100InUserAgentName[];
 extern const char kForceMajorVersion100InUserAgentDescription[];
 
diff --git a/chrome/browser/metrics/power/power_metrics_reporter.cc b/chrome/browser/metrics/power/power_metrics_reporter.cc
index cc7497f64..aa3c341d 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter.cc
+++ b/chrome/browser/metrics/power/power_metrics_reporter.cc
@@ -11,7 +11,6 @@
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
-#include "build/build_config.h"
 #include "chrome/browser/lifetime/browser_shutdown.h"
 #include "chrome/browser/metrics/power/power_details_provider.h"
 #include "chrome/browser/performance_monitor/process_metrics_recorder_util.h"
@@ -105,6 +104,9 @@
 
 #if defined(OS_MAC)
   power_details_provider_ = PowerDetailsProvider::Create();
+  iopm_power_source_sampling_event_source_.Start(
+      base::BindRepeating(&PowerMetricsReporter::OnIOPMPowerSourceSamplingEvent,
+                          base::Unretained(this)));
 #endif
 }
 
@@ -405,3 +407,24 @@
     return {BatteryDischargeMode::kBatteryLevelIncreased, absl::nullopt};
   return {BatteryDischargeMode::kDischarging, discharge_rate};
 }
+
+#if defined(OS_MAC)
+void PowerMetricsReporter::OnIOPMPowerSourceSamplingEvent() {
+  base::TimeTicks now_ticks = base::TimeTicks::Now();
+
+  if (!last_event_time_ticks_) {
+    last_event_time_ticks_ = now_ticks;
+    return;
+  }
+
+  // The delta is expected to be almost always 60 seconds. Split the buckets for
+  // 0.2s granularity (10s interval with 50 buckets + 1 underflow bucket + 1
+  // overflow bucket) around that value.
+  base::HistogramBase* histogram = base::LinearHistogram::FactoryTimeGet(
+      "Power.IOPMPowerSource.SamplingEventDelta",
+      /*min=*/base::Seconds(55), /*max=*/base::Seconds(65), /*buckets=*/52,
+      base::HistogramBase::kUmaTargetedHistogramFlag);
+  histogram->AddTime(now_ticks - *last_event_time_ticks_);
+  *last_event_time_ticks_ = now_ticks;
+}
+#endif  // defined(OS_MAC)
diff --git a/chrome/browser/metrics/power/power_metrics_reporter.h b/chrome/browser/metrics/power/power_metrics_reporter.h
index 4adee4d..ebc5adb2 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter.h
+++ b/chrome/browser/metrics/power/power_metrics_reporter.h
@@ -10,12 +10,17 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "chrome/browser/metrics/power/battery_level_provider.h"
 #include "chrome/browser/metrics/power/power_details_provider.h"
 #include "chrome/browser/metrics/usage_scenario/usage_scenario_data_store.h"
 #include "chrome/browser/performance_monitor/process_monitor.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
+#if defined(OS_MAC)
+#include "components/power_metrics/iopm_power_source_sampling_event_source.h"
+#endif  // defined(OS_MAC)
+
 // Reports metrics related to power (battery discharge, cpu time, etc.) to
 // understand what impacts Chrome's power consumption over an interval of time.
 //
@@ -126,6 +131,10 @@
       const BatteryLevelProvider::BatteryState& new_battery_state,
       base::TimeDelta interval_duration);
 
+#if defined(OS_MAC)
+  void OnIOPMPowerSourceSamplingEvent();
+#endif  // defined(OS_MAC)
+
   // The data store used to get the usage scenario data, it needs to outlive
   // this class.
   base::WeakPtr<UsageScenarioDataStore> data_store_;
@@ -144,6 +153,14 @@
 
   base::OnceClosure on_battery_sampled_for_testing_;
 
+#if defined(OS_MAC)
+  power_metrics::IOPMPowerSourceSamplingEventSource
+      iopm_power_source_sampling_event_source_;
+
+  // The time ticks from when the last IOPMPowerSource event was received.
+  absl::optional<base::TimeTicks> last_event_time_ticks_;
+#endif  // defined(OS_MAC)
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtrFactory<PowerMetricsReporter> weak_factory_{this};
diff --git a/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc b/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc
index ce280e1..d8fd60d 100644
--- a/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc
+++ b/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc
@@ -381,7 +381,9 @@
 
       optimization_guide::proto::Hint* hint = get_hints_response.add_hints();
       hint->set_key_representation(optimization_guide::proto::HOST);
-      hint->set_key(https_url_.host());
+      hint->set_key(search_results_page_url_.host());
+      hint->add_allowlisted_optimizations()->set_optimization_type(
+          optimization_guide::proto::OptimizationType::NOSCRIPT);
       optimization_guide::proto::PageHint* page_hint = hint->add_page_hints();
       page_hint->set_page_pattern("page pattern");
 
@@ -477,6 +479,15 @@
   std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_;
 };
 
+IN_PROC_BROWSER_TEST_F(HintsFetcherDisabledBrowserTest, HintsFetcherDisabled) {
+  const base::HistogramTester* histogram_tester = GetHistogramTester();
+
+  // Expect that the histogram for HintsFetcher to be 0 because the OnePlatform
+  // is not enabled.
+  histogram_tester->ExpectTotalCount(
+      "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 0);
+}
+
 // This test class enables OnePlatform Hints.
 class HintsFetcherBrowserTest : public HintsFetcherDisabledBrowserTest {
  public:
@@ -506,11 +517,7 @@
   void SetUpOnMainThread() override {
     // Register an optimization type, so hints will be fetched at page
     // navigation.
-    OptimizationGuideKeyedServiceFactory::GetForProfile(
-        Profile::FromBrowserContext(browser()
-                                        ->tab_strip_model()
-                                        ->GetActiveWebContents()
-                                        ->GetBrowserContext()))
+    OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
         ->RegisterOptimizationTypes({optimization_guide::proto::NOSCRIPT});
 
     HintsFetcherDisabledBrowserTest::SetUpOnMainThread();
@@ -522,6 +529,18 @@
             browser()->profile());
     return keyed_service->GetTopHostProvider();
   }
+
+  void CanApplyOptimizationOnDemand(
+      const std::vector<GURL>& urls,
+      const std::vector<optimization_guide::proto::OptimizationType>&
+          optimization_types,
+      optimization_guide::OnDemandOptimizationGuideDecisionRepeatingCallback
+          callback) {
+    OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+        ->CanApplyOptimizationOnDemand(
+            urls, optimization_types,
+            optimization_guide::proto::CONTEXT_BOOKMARKS, callback);
+  }
 };
 
 // This test creates new browser with no profile and loads a random page with
@@ -557,15 +576,6 @@
       "OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
 }
 
-IN_PROC_BROWSER_TEST_F(HintsFetcherDisabledBrowserTest, HintsFetcherDisabled) {
-  const base::HistogramTester* histogram_tester = GetHistogramTester();
-
-  // Expect that the histogram for HintsFetcher to be 0 because the OnePlatform
-  // is not enabled.
-  histogram_tester->ExpectTotalCount(
-      "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 0);
-}
-
 IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
                        HintsFetcherFetchedHintsLoaded) {
   const base::HistogramTester* histogram_tester = GetHistogramTester();
@@ -859,6 +869,156 @@
       "OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
 }
 
+IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
+                       OnDemandFetchRepeatedlyWithCache) {
+  SetNetworkConnectionOnline();
+
+  SetResponseType(
+      optimization_guide::HintsFetcherRemoteResponseType::kSuccessful);
+
+  OptimizationGuideKeyedService* ogks =
+      OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
+  ogks->RegisterOptimizationTypes(
+      {optimization_guide::proto::OptimizationType::NOSCRIPT});
+
+  {
+    base::HistogramTester histogram_tester;
+    std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
+    CanApplyOptimizationOnDemand(
+        {search_results_page_url()},
+        {optimization_guide::proto::OptimizationType::NOSCRIPT},
+        base::BindRepeating(
+            [](base::RunLoop* run_loop, const GURL& url,
+               const base::flat_map<
+                   optimization_guide::proto::OptimizationType,
+                   optimization_guide::OptimizationGuideDecisionWithMetadata>&
+                   decisions) {
+              // Expect one decision per requested type.
+              EXPECT_EQ(decisions.size(), 1u);
+              auto it = decisions.find(
+                  optimization_guide::proto::OptimizationType::NOSCRIPT);
+              EXPECT_NE(it, decisions.end());
+              EXPECT_EQ(it->second.decision,
+                        optimization_guide::OptimizationGuideDecision::kTrue);
+
+              run_loop->Quit();
+            },
+            run_loop.get()));
+    run_loop->Run();
+
+    histogram_tester.ExpectUniqueSample(
+        "OptimizationGuide.HintsFetcher.RequestStatus.Bookmarks",
+        optimization_guide::HintsFetcherRequestStatus::kSuccess, 1);
+  }
+
+  {
+    base::HistogramTester histogram_tester;
+    std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
+    CanApplyOptimizationOnDemand(
+        {search_results_page_url()},
+        {optimization_guide::proto::OptimizationType::NOSCRIPT},
+        base::BindRepeating(
+            [](base::RunLoop* run_loop, const GURL& url,
+               const base::flat_map<
+                   optimization_guide::proto::OptimizationType,
+                   optimization_guide::OptimizationGuideDecisionWithMetadata>&
+                   decisions) {
+              // Expect one decision per requested type.
+              EXPECT_EQ(decisions.size(), 1u);
+              auto it = decisions.find(
+                  optimization_guide::proto::OptimizationType::NOSCRIPT);
+              EXPECT_NE(it, decisions.end());
+              EXPECT_EQ(it->second.decision,
+                        optimization_guide::OptimizationGuideDecision::kTrue);
+
+              run_loop->Quit();
+            },
+            run_loop.get()));
+    run_loop->Run();
+
+    // Second time should not refetch since have all the right info already.
+    histogram_tester.ExpectTotalCount(
+        "OptimizationGuide.HintsFetcher.RequestStatus.Bookmarks", 0);
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
+                       OnDemandFetchRepeatedlyNoCache) {
+  SetNetworkConnectionOnline();
+
+  SetResponseType(
+      optimization_guide::HintsFetcherRemoteResponseType::kSuccessful);
+
+  OptimizationGuideKeyedService* ogks =
+      OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
+  ogks->RegisterOptimizationTypes(
+      {optimization_guide::proto::OptimizationType::NOSCRIPT});
+
+  GURL url_with_no_hints("https://urlwithnohints.com/notcached");
+
+  {
+    base::HistogramTester histogram_tester;
+    std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
+    CanApplyOptimizationOnDemand(
+        {url_with_no_hints},
+        {optimization_guide::proto::OptimizationType::NOSCRIPT},
+        base::BindRepeating(
+            [](base::RunLoop* run_loop, const GURL& url,
+               const base::flat_map<
+                   optimization_guide::proto::OptimizationType,
+                   optimization_guide::OptimizationGuideDecisionWithMetadata>&
+                   decisions) {
+              // Expect one decision per requested type.
+              EXPECT_EQ(decisions.size(), 1u);
+              auto it = decisions.find(
+                  optimization_guide::proto::OptimizationType::NOSCRIPT);
+              EXPECT_NE(it, decisions.end());
+              EXPECT_EQ(it->second.decision,
+                        optimization_guide::OptimizationGuideDecision::kFalse);
+
+              run_loop->Quit();
+            },
+            run_loop.get()));
+    run_loop->Run();
+
+    histogram_tester.ExpectUniqueSample(
+        "OptimizationGuide.HintsFetcher.RequestStatus.Bookmarks",
+        optimization_guide::HintsFetcherRequestStatus::kSuccess, 1);
+  }
+
+  {
+    base::HistogramTester histogram_tester;
+    std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
+    CanApplyOptimizationOnDemand(
+        {url_with_no_hints},
+        {optimization_guide::proto::OptimizationType::NOSCRIPT},
+        base::BindRepeating(
+            [](base::RunLoop* run_loop, const GURL& url,
+               const base::flat_map<
+                   optimization_guide::proto::OptimizationType,
+                   optimization_guide::OptimizationGuideDecisionWithMetadata>&
+                   decisions) {
+              // Expect one decision per requested type.
+              EXPECT_EQ(decisions.size(), 1u);
+              auto it = decisions.find(
+                  optimization_guide::proto::OptimizationType::NOSCRIPT);
+              EXPECT_NE(it, decisions.end());
+              EXPECT_EQ(it->second.decision,
+                        optimization_guide::OptimizationGuideDecision::kFalse);
+
+              run_loop->Quit();
+            },
+            run_loop.get()));
+    run_loop->Run();
+
+    // Second time should not refetch since no hosts or urls match.
+    histogram_tester.ExpectUniqueSample(
+        "OptimizationGuide.HintsFetcher.RequestStatus.Bookmarks",
+        optimization_guide::HintsFetcherRequestStatus::kNoHostsOrURLsToFetch,
+        1);
+  }
+}
+
 // Test that the hints are fetched at the time of the navigation.
 IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
                        HintsFetcher_NavigationFetch_URLKeyedNotRefetched) {
diff --git a/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc b/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc
index 4371d31d..0fdba194 100644
--- a/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc
+++ b/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc
@@ -459,12 +459,11 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-// TODO(https://crbug.com/1225946): Test is flaky.
 IN_PROC_BROWSER_TEST_F(PageContentAnnotationsServiceNoHistoryTest,
-                       DISABLED_ModelExecutesButDoesntWriteToHistory) {
+                       ModelExecutesButDoesntWriteToHistory) {
   base::HistogramTester histogram_tester;
 
-  GURL url(embedded_test_server()->GetURL("a.com", "/hello-no-history.html"));
+  GURL url(embedded_test_server()->GetURL("a.com", "/hello.html"));
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
 
   RetryForHistogramUntilCountReached(
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc b/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
index bfa5f38..881555e8 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
@@ -513,6 +513,10 @@
             /*model_metadata=*/absl::nullopt, model_file_observer_.get());
   }
 
+  base::HistogramTester* test_harness_histogram_tester() {
+    return &histogram_tester_;
+  }
+
  private:
   void InitializeFeatureList() override {
     scoped_feature_list_.InitWithFeaturesAndParameters(
@@ -536,11 +540,11 @@
   }
 
   std::unique_ptr<ModelFileObserver> model_file_observer_;
+  base::HistogramTester histogram_tester_;
 };
 
-// Flaky on various bots. See https://crbug.com/1266318
 IN_PROC_BROWSER_TEST_F(PredictionManagerModelDownloadingBrowserTest,
-                       DISABLED_TestIncognitoUsesModelFromRegularProfile) {
+                       TestIncognitoUsesModelFromRegularProfile) {
   SetResponseType(
       PredictionModelsFetcherRemoteResponseType::kSuccessfulWithValidModelFile);
 
@@ -599,44 +603,51 @@
 
     run_loop->Run();
 
+    // Should have same model loaded as original profile.
+    otr_histogram_tester.ExpectUniqueSample(
+        "OptimizationGuide.PredictionModelLoadedVersion.PainfulPageLoad", 123,
+        1);
+    // Should not have fetched.
     otr_histogram_tester.ExpectTotalCount(
-        "OptimizationGuide.PredictionModelDownloadManager.DownloadStatus", 0);
-    otr_histogram_tester.ExpectTotalCount(
-        "OptimizationGuide.PredictionModelUpdateVersion.PainfulPageLoad", 0);
+        "OptimizationGuide.PredictionModelFetcher.GetModelsResponse.Status", 0);
   }
 }
-// Flaky on multiple ASAN bots. See https://crbug.com/1266318
-#if defined(ADDRESS_SANITIZER)
-#define MAYBE_TestIncognitoDoesntFetchModels \
-  DISABLED_TestIncognitoDoesntFetchModels
-#else
-#define MAYBE_TestIncognitoDoesntFetchModels TestIncognitoDoesntFetchModels
-#endif
-IN_PROC_BROWSER_TEST_F(PredictionManagerModelDownloadingBrowserTest,
-                       MAYBE_TestIncognitoDoesntFetchModels) {
-  base::HistogramTester histogram_tester;
 
+IN_PROC_BROWSER_TEST_F(PredictionManagerModelDownloadingBrowserTest,
+                       TestIncognitoDoesntFetchModels) {
   SetResponseType(PredictionModelsFetcherRemoteResponseType::
                       kSuccessfulWithInvalidModelFile);
+  // Wait until regular profile has finished its model initialization routine.
+  {
+    RetryForHistogramUntilCountReached(
+        test_harness_histogram_tester(),
+        "OptimizationGuide.PredictionManager.StoreInitialized", 1);
+    base::RunLoop().RunUntilIdle();
+  }
 
-  Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
+  {
+    base::HistogramTester otr_histogram_tester;
 
-  // Registering should not initiate the fetch and the model updated callback
-  // should not be triggered too.
-  RegisterModelFileObserverWithKeyedService(otr_browser->profile());
+    Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
 
-  model_file_observer()->set_model_file_received_callback(base::BindOnce(
-      [](proto::OptimizationTarget optimization_target,
-         const ModelInfo& model_info) { FAIL() << "Should not be called"; }));
+    // Registering should not initiate the fetch and the model updated callback
+    // should not be triggered either.
+    RegisterModelFileObserverWithKeyedService(otr_browser->profile());
 
-  RetryForHistogramUntilCountReached(
-      &histogram_tester,
-      "OptimizationGuide.PredictionManager.HostModelFeaturesMapSize", 1);
+    model_file_observer()->set_model_file_received_callback(base::BindOnce(
+        [](proto::OptimizationTarget optimization_target,
+           const ModelInfo& model_info) { FAIL() << "Should not be called"; }));
 
-  histogram_tester.ExpectTotalCount(
-      "OptimizationGuide.PredictionModelDownloadManager.DownloadStatus", 0);
-  histogram_tester.ExpectTotalCount(
-      "OptimizationGuide.PredictionModelUpdateVersion.PainfulPageLoad", 0);
+    RetryForHistogramUntilCountReached(
+        &otr_histogram_tester,
+        "OptimizationGuide.PredictionManager.StoreInitialized", 1);
+    // Wait until everything has stabilized before ensuring no fetches went out.
+    base::RunLoop().RunUntilIdle();
+
+    // Should not have fetched.
+    otr_histogram_tester.ExpectTotalCount(
+        "OptimizationGuide.PredictionModelFetcher.GetModelsResponse.Status", 0);
+  }
 }
 
 IN_PROC_BROWSER_TEST_F(PredictionManagerModelDownloadingBrowserTest,
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.cc b/chrome/browser/password_manager/android/password_store_android_backend.cc
index 55a5e19..ed19b9a6 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend.cc
@@ -317,10 +317,8 @@
 
 void PasswordStoreAndroidBackend::GetAllLoginsAsync(
     LoginsOrErrorReply callback) {
-  JobId job_id = bridge_->GetAllLogins(PasswordStoreOperationTarget::kDefault);
-  QueueNewJob(job_id, JobReturnHandler(
-                          std::move(callback),
-                          MetricsRecorder(MetricInfix("GetAllLoginsAsync"))));
+  GetAllLoginsForTarget(PasswordStoreOperationTarget::kDefault,
+                        std::move(callback));
 }
 
 void PasswordStoreAndroidBackend::GetAutofillableLoginsAsync(
@@ -385,11 +383,8 @@
 void PasswordStoreAndroidBackend::RemoveLoginAsync(
     const PasswordForm& form,
     PasswordStoreChangeListReply callback) {
-  JobId job_id =
-      bridge_->RemoveLogin(form, PasswordStoreOperationTarget::kDefault);
-  QueueNewJob(job_id, JobReturnHandler(
-                          std::move(callback),
-                          MetricsRecorder(MetricInfix("RemoveLoginAsync"))));
+  RemoveLoginForTarget(form, PasswordStoreOperationTarget::kDefault,
+                       std::move(callback));
 }
 
 void PasswordStoreAndroidBackend::FilterAndRemoveLogins(
@@ -523,6 +518,33 @@
           base::Unretained(this)));
 }
 
+void PasswordStoreAndroidBackend::ClearAllLocalPasswords() {
+  LoginsOrErrorReply cleaning_callback = base::BindOnce(
+      [](base::WeakPtr<PasswordStoreAndroidBackend> weak_self,
+         LoginsResultOrError logins_or_error) {
+        if (!weak_self ||
+            absl::holds_alternative<PasswordStoreBackendError>(logins_or_error))
+          return;
+
+        base::OnceClosure callbacks_chain = base::DoNothing();
+
+        for (const auto& login : absl::get<LoginsResult>(logins_or_error)) {
+          callbacks_chain = base::BindOnce(
+              &PasswordStoreAndroidBackend::RemoveLoginForTarget, weak_self,
+              std::move(*login), PasswordStoreOperationTarget::kLocalStorage,
+              IgnoreChangeListAndRunCallback(std::move(callbacks_chain)));
+        }
+
+        std::move(callbacks_chain).Run();
+      },
+      weak_ptr_factory_.GetWeakPtr());
+
+  // TODO(https://crbug.com/1278748) Record whether the operation was
+  // successful.
+  GetAllLoginsForTarget(PasswordStoreOperationTarget::kLocalStorage,
+                        std::move(cleaning_callback));
+}
+
 void PasswordStoreAndroidBackend::OnCompleteWithLogins(
     JobId job_id,
     std::vector<PasswordForm> passwords) {
@@ -676,4 +698,23 @@
       MetricsRecorder(metric_infix), std::move(callback));
 }
 
+void PasswordStoreAndroidBackend::GetAllLoginsForTarget(
+    PasswordStoreOperationTarget target,
+    LoginsOrErrorReply callback) {
+  JobId job_id = bridge_->GetAllLogins(target);
+  QueueNewJob(job_id, JobReturnHandler(
+                          std::move(callback),
+                          MetricsRecorder(MetricInfix("GetAllLoginsAsync"))));
+}
+
+void PasswordStoreAndroidBackend::RemoveLoginForTarget(
+    const PasswordForm& form,
+    PasswordStoreOperationTarget target,
+    PasswordStoreChangeListReply callback) {
+  JobId job_id = bridge_->RemoveLogin(form, target);
+  QueueNewJob(job_id, JobReturnHandler(
+                          std::move(callback),
+                          MetricsRecorder(MetricInfix("RemoveLoginAsync"))));
+}
+
 }  // namespace password_manager
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.h b/chrome/browser/password_manager/android/password_store_android_backend.h
index bff952d..f9b242a 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.h
+++ b/chrome/browser/password_manager/android/password_store_android_backend.h
@@ -189,6 +189,7 @@
   FieldInfoStore* GetFieldInfoStore() override;
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
+  void ClearAllLocalPasswords() override;
 
   // Implements PasswordStoreAndroidBackendBridge::Consumer interface.
   void OnCompleteWithLogins(PasswordStoreAndroidBackendBridge::JobId job_id,
@@ -241,6 +242,16 @@
       const MetricInfix& metric_infix,
       PasswordStoreChangeListReply callback);
 
+  // Returns the complete list of PasswordForms (regardless of their blocklist
+  // status) from specified storage.
+  void GetAllLoginsForTarget(PasswordStoreOperationTarget target,
+                             LoginsOrErrorReply callback);
+
+  // Removes |form| from specified storage.
+  void RemoveLoginForTarget(const PasswordForm& form,
+                            PasswordStoreOperationTarget target,
+                            PasswordStoreChangeListReply callback);
+
   // Observer to propagate remote form changes to.
   RemoteChangesReceived remote_form_changes_received_;
 
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc b/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
index 2f5d31e..0c01630 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
@@ -555,6 +555,30 @@
       1);
 }
 
+TEST_F(PasswordStoreAndroidBackendTest, RemoveAllLocalLogins) {
+  backend().InitBackend(PasswordStoreAndroidBackend::RemoteChangesReceived(),
+                        base::RepeatingClosure(), base::DoNothing());
+
+  base::MockCallback<LoginsReply> mock_logins_reply;
+  const JobId kGetLoginsJobId{13387};
+  EXPECT_CALL(*bridge(),
+              GetAllLogins(PasswordStoreOperationTarget::kLocalStorage))
+      .WillOnce(Return(kGetLoginsJobId));
+  backend().ClearAllLocalPasswords();
+
+  // Imitate login retrieval and check that it triggers the removal of forms.
+  const JobId kRemoveLoginJobId{13388};
+  PasswordForm form_to_delete = CreateTestLogin(
+      kTestUsername, kTestPassword, kTestUrl, base::Time::FromTimeT(1500));
+  EXPECT_CALL(
+      *bridge(),
+      RemoveLogin(form_to_delete, PasswordStoreOperationTarget::kLocalStorage))
+      .WillOnce(Return(kRemoveLoginJobId));
+
+  consumer().OnCompleteWithLogins(kGetLoginsJobId, {form_to_delete});
+  RunUntilIdle();
+}
+
 class PasswordStoreAndroidBackendTestForMetrics
     : public PasswordStoreAndroidBackendTest,
       public testing::WithParamInterface<bool> {
diff --git a/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_url_loader_interceptor.h b/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_url_loader_interceptor.h
index 209dd548..5423bb7 100644
--- a/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_url_loader_interceptor.h
+++ b/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_url_loader_interceptor.h
@@ -37,7 +37,7 @@
 
   ~PrefetchProxyURLLoaderInterceptor() override;
 
-  // content::URLLaoderRequestInterceptor:
+  // content::URLLoaderRequestInterceptor:
   void MaybeCreateLoader(
       const network::ResourceRequest& tentative_resource_request,
       content::BrowserContext* browser_context,
diff --git a/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.h b/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.h
index d20220d6..62929e31e 100644
--- a/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.h
+++ b/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.h
@@ -38,7 +38,7 @@
       const network::ResourceRequest& tentative_resource_request,
       int frame_tree_node_id);
 
-  // content::URLLaoderRequestInterceptor:
+  // content::URLLoaderRequestInterceptor:
   void MaybeCreateLoader(
       const network::ResourceRequest& tentative_resource_request,
       content::BrowserContext* browser_context,
diff --git a/chrome/browser/profiles/host_zoom_map_browsertest.cc b/chrome/browser/profiles/host_zoom_map_browsertest.cc
index 2e4bcac4..ca55c35 100644
--- a/chrome/browser/profiles/host_zoom_map_browsertest.cc
+++ b/chrome/browser/profiles/host_zoom_map_browsertest.cc
@@ -121,17 +121,15 @@
 
   std::vector<std::string> GetHostsWithZoomLevelsFromPrefs() {
     PrefService* prefs = browser()->profile()->GetPrefs();
-    const base::DictionaryValue* dictionaries = &base::Value::AsDictionaryValue(
-        *prefs->GetDictionary(prefs::kPartitionPerHostZoomLevels));
-    const base::DictionaryValue* values = NULL;
+    const base::Value* dictionaries =
+        prefs->GetDictionary(prefs::kPartitionPerHostZoomLevels);
     std::string partition_key =
         ChromeZoomLevelPrefs::GetPartitionKeyForTesting(base::FilePath());
-    dictionaries->GetDictionary(partition_key, &values);
+    const base::Value* values = dictionaries->FindDictPath(partition_key);
     std::vector<std::string> results;
     if (values) {
-      for (base::DictionaryValue::Iterator it(*values);
-           !it.IsAtEnd(); it.Advance())
-        results.push_back(it.key());
+      for (const auto it : values->DictItems())
+        results.push_back(it.first);
     }
     return results;
   }
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index dce671bb..e7d59e6 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -518,7 +518,7 @@
       const ProfileInfo* profile_info = path_and_profile_info.second.get();
 
       Profile* profile = profile_info->GetRawProfile();
-      if (profile && profile->IsSystemProfile())
+      if (profile && !profile->IsRegularProfile())
         continue;
 
       for (const auto& origin_and_count : profile_info->keep_alives) {
@@ -2109,7 +2109,8 @@
   ProfileInfo* info_raw = info.get();
   profiles_info_.insert(
       std::make_pair(profile_ptr->GetPath(), std::move(info)));
-  ever_loaded_profiles_.insert(profile_ptr->GetPath());
+  if (profile_ptr->IsRegularProfile())
+    ever_loaded_profiles_.insert(profile_ptr->GetPath());
   return info_raw;
 }
 
@@ -2120,7 +2121,8 @@
   auto info = ProfileInfo::FromUnownedProfile(profile);
   ProfileInfo* info_raw = info.get();
   profiles_info_.insert(std::make_pair(path, std::move(info)));
-  ever_loaded_profiles_.insert(path);
+  if (profile->IsRegularProfile())
+    ever_loaded_profiles_.insert(path);
   return info_raw;
 }
 
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h
index 32096da..6b23be2 100644
--- a/chrome/browser/profiles/profile_manager.h
+++ b/chrome/browser/profiles/profile_manager.h
@@ -589,6 +589,8 @@
   // Set of profile dirs that were loaded during this browsing session at some
   // point (or are currently loaded). This is used to measure memory savings
   // from DestroyProfileOnBrowserClose.
+  //
+  // Doesn't include the System and Guest profile paths.
   std::set<base::FilePath> ever_loaded_profiles_;
 
   // Runs a task every 30 minutes to record the number of zombie & non-zombie
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index aa466347..94dfd32f1 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -163,9 +163,6 @@
     if (enable_nacl) {
       deps += [ "about_nacl:closure_compile" ]
     }
-    if (enable_pdf) {
-      deps += [ "pdf:closure_compile" ]
-    }
     if (is_android) {
       deps += [
         "explore_sites_internals:closure_compile",
diff --git a/chrome/browser/resources/chromeos/login/screens/common/user_creation.html b/chrome/browser/resources/chromeos/login/screens/common/user_creation.html
index db766963..f8b2e09e 100644
--- a/chrome/browser/resources/chromeos/login/screens/common/user_creation.html
+++ b/chrome/browser/resources/chromeos/login/screens/common/user_creation.html
@@ -32,8 +32,8 @@
         margin-top: 16px;
       }
     </style>
-    <oobe-adaptive-dialog id="userCreationDialog" role="dialog"
-        aria-label$="[[i18nDynamic(locale, titleKey_)]]" for-step="create">
+    <oobe-adaptive-dialog id="userCreationDialog" for-step="create"
+        role="presentation">
       <iron-icon slot="icon" icon="oobe-32:googleg"></iron-icon>
       <h1 slot="title">
         [[i18nDynamic(locale, titleKey_)]]
diff --git a/chrome/browser/resources/extensions/BUILD.gn b/chrome/browser/resources/extensions/BUILD.gn
index 7762738f..81705a7 100644
--- a/chrome/browser/resources/extensions/BUILD.gn
+++ b/chrome/browser/resources/extensions/BUILD.gn
@@ -100,7 +100,6 @@
     "shared_vars.ts",
     "shortcut_input.ts",
     "sidebar.ts",
-    "site_access.ts",
     "toggle_row.ts",
     "toolbar.ts",
   ]
@@ -140,7 +139,6 @@
     "shared_vars.ts",
     "shortcut_input.ts",
     "sidebar.ts",
-    "site_access.ts",
     "toggle_row.ts",
     "toolbar.ts",
   ]
@@ -206,7 +204,6 @@
     "shortcut_input.ts",
     "shortcut_util.ts",
     "sidebar.ts",
-    "site_access.ts",
     "toggle_row.ts",
     "toolbar.ts",
   ]
diff --git a/chrome/browser/resources/extensions/detail_view.html b/chrome/browser/resources/extensions/detail_view.html
index 967e53f..65f5b040 100644
--- a/chrome/browser/resources/extensions/detail_view.html
+++ b/chrome/browser/resources/extensions/detail_view.html
@@ -314,46 +314,33 @@
         </ul>
       </div>
     </div>
-    <!-- TODO(crbug.com/1253673): Add a "learn more" question mark with link at
-        the end of the sublabel. -->
-    <cr-link-row class="hr"
-        id="extensionsSiteAccessLink"
-        hidden$="[[!showSiteAccessLink_(data.*)]]"
-        label="$i18n{newItemSiteAccessTitle}"
-        sub-label="$i18n{itemSiteAccessSublabel}"
-        on-click="onSiteAccessTap_"
-        role-description="$i18n{subpageArrowRoleDescription}">
-    </cr-link-row>
-    <template is="dom-if" if="[[!showSiteAccessLink_(data.*)]]">
-      <div class="section hr">
-        <div class="section-title" role="heading" aria-level="2">
-          [[getSiteAccessTitle_(useNewSiteAccessPage)]]
-        </div>
-        <div class="section-content">
-          <span id="no-site-access"
-              hidden$="[[showSiteAccessContent_(data.*)]]">
-            $i18n{itemSiteAccessEmpty}
-          </span>
-          <template is="dom-if"
-              if="[[showFreeformRuntimeHostPermissions_(data.*)]]">
-            <extensions-runtime-host-permissions
-                permissions="[[data.permissions.runtimeHostPermissions]]"
-                use-new-site-access-page="[[useNewSiteAccessPage]]"
-                delegate="[[delegate]]"
-                item-id="[[data.id]]">
-            </extensions-runtime-host-permissions>
-          </template>
-          <template is="dom-if"
-              if="[[showHostPermissionsToggleList_(data.*)]]">
-            <extensions-host-permissions-toggle-list
-                permissions="[[data.permissions.runtimeHostPermissions]]"
-                delegate="[[delegate]]"
-                item-id="[[data.id]]">
-            </extensions-host-permissions-toggle-list>
-          </template>
-        </div>
+    <div class="section hr">
+      <div class="section-title" role="heading" aria-level="2">
+        $i18n{itemSiteAccess}
       </div>
-    </template>
+      <div class="section-content">
+        <span id="no-site-access"
+            hidden$="[[showSiteAccessContent_(data.*)]]">
+          $i18n{itemSiteAccessEmpty}
+        </span>
+        <template is="dom-if"
+            if="[[showFreeformRuntimeHostPermissions_(data.*)]]">
+          <extensions-runtime-host-permissions
+              permissions="[[data.permissions.runtimeHostPermissions]]"
+              delegate="[[delegate]]"
+              item-id="[[data.id]]">
+          </extensions-runtime-host-permissions>
+        </template>
+        <template is="dom-if"
+            if="[[showHostPermissionsToggleList_(data.*)]]">
+          <extensions-host-permissions-toggle-list
+              permissions="[[data.permissions.runtimeHostPermissions]]"
+              delegate="[[delegate]]"
+              item-id="[[data.id]]">
+          </extensions-host-permissions-toggle-list>
+        </template>
+      </div>
+    </div>
     <template is="dom-if"
         if="[[hasDependentExtensions_(data.dependentExtensions.splices)]]">
       <div class="section hr">
diff --git a/chrome/browser/resources/extensions/detail_view.ts b/chrome/browser/resources/extensions/detail_view.ts
index f8088d1..949349a 100644
--- a/chrome/browser/resources/extensions/detail_view.ts
+++ b/chrome/browser/resources/extensions/detail_view.ts
@@ -78,9 +78,6 @@
       /** Whether the user has enabled the UI's developer mode. */
       inDevMode: Boolean,
 
-      /** Whether the extension's site access will be shown in a new page. */
-      useNewSiteAccessPage: Boolean,
-
       /** Whether "allow in incognito" option should be shown. */
       incognitoAvailable: Boolean,
 
@@ -99,7 +96,6 @@
   data: chrome.developerPrivate.ExtensionInfo;
   delegate: ItemDelegate;
   inDevMode: boolean;
-  useNewSiteAccessPage: boolean;
   incognitoAvailable: boolean;
   showActivityLog: boolean;
   fromActivityLog: boolean;
@@ -134,8 +130,6 @@
    * Focuses the back button when page is loaded.
    */
   private onViewEnterStart_() {
-    // TODO(crbug.com/1253673): Focus on the site access link if we returned to
-    // this view from that subpage.
     const elementToFocus = this.fromActivityLog ?
         this.$.extensionsActivityLogLink :
         this.$.closeButton;
@@ -156,11 +150,6 @@
     navigation.navigateTo({page: Page.ACTIVITY_LOG, extensionId: this.data.id});
   }
 
-  private onSiteAccessTap_() {
-    navigation.navigateTo(
-        {page: Page.EXTENSION_SITE_ACCESS, extensionId: this.data.id});
-  }
-
   private getDescription_(description: string, fallback: string): string {
     return description || fallback;
   }
@@ -301,12 +290,6 @@
         getItemSourceString(getItemSource(this.data));
   }
 
-  private getSiteAccessTitle_(): string {
-    return loadTimeData.getString(
-        this.useNewSiteAccessPage ? 'newItemSiteAccessTitle' :
-                                    'itemSiteAccess');
-  }
-
   private hasPermissions_(): boolean {
     return this.data.permissions.simplePermissions.length > 0 ||
         this.hasRuntimeHostPermissions_();
@@ -321,10 +304,6 @@
         this.showHostPermissionsToggleList_();
   }
 
-  private showSiteAccessLink_(): boolean {
-    return this.hasRuntimeHostPermissions_() && this.useNewSiteAccessPage;
-  }
-
   private showFreeformRuntimeHostPermissions_(): boolean {
     return this.hasRuntimeHostPermissions_() &&
         this.data.permissions.runtimeHostPermissions!.hasAllHosts;
diff --git a/chrome/browser/resources/extensions/manager.html b/chrome/browser/resources/extensions/manager.html
index 123e305..d8f993e 100644
--- a/chrome/browser/resources/extensions/manager.html
+++ b/chrome/browser/resources/extensions/manager.html
@@ -56,7 +56,6 @@
     <template>
       <extensions-detail-view delegate="[[delegate]]" slot="view"
           in-dev-mode="[[inDevMode]]"
-          use-new-site-access-page="[[useNewSiteAccessPage]]"
           from-activity-log="[[fromActivityLog_]]"
           show-activity-log="[[showActivityLog]]"
           incognito-available="[[incognitoAvailable_]]"
@@ -71,13 +70,6 @@
       </extensions-activity-log>
     </template>
   </cr-lazy-render>
-  <cr-lazy-render id="extension-site-access">
-    <template>
-      <extensions-site-access slot="view"
-          extension-info="[[extensionSiteAccessItem_]]">
-      </extensions-site-access>
-    </template>
-  </cr-lazy-render>
   <cr-lazy-render id="keyboard-shortcuts">
     <template>
       <extensions-keyboard-shortcuts delegate="[[delegate]]" slot="view"
diff --git a/chrome/browser/resources/extensions/manager.ts b/chrome/browser/resources/extensions/manager.ts
index 5846b68..ed24e15 100644
--- a/chrome/browser/resources/extensions/manager.ts
+++ b/chrome/browser/resources/extensions/manager.ts
@@ -20,16 +20,15 @@
 import './load_error.js';
 import './options_dialog.js';
 import './sidebar.js';
-import './site_access.js';
 import './toolbar.js';
 // <if expr="chromeos">
 import './kiosk_dialog.js';
 // </if>
 
-import {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js';
 import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js';
 
 import {ActivityLogExtensionPlaceholder} from './activity_log/activity_log.js';
 import {ExtensionsDetailViewElement} from './detail_view.js';
@@ -108,11 +107,6 @@
         value: () => loadTimeData.getBoolean('showActivityLog'),
       },
 
-      useNewSiteAccessPage: {
-        type: Boolean,
-        value: () => loadTimeData.getBoolean('useNewSiteAccessPage'),
-      },
-
       devModeControlledByPolicy: {
         type: Boolean,
         value: false,
@@ -154,12 +148,6 @@
        */
       activityLogItem_: Object,
 
-      /**
-       * The item that provides some information about the current extension
-       * for the extension site access view subpage. See also errorPageItem_.
-       */
-      extensionSiteAccessItem_: Object,
-
       extensions_: Array,
 
       apps_: Array,
@@ -206,7 +194,6 @@
   delegate: Service;
   inDevMode: boolean;
   showActivityLog: boolean;
-  useNewSiteAccessPage: boolean;
   devModeControlledByPolicy: boolean;
   private isChildAccount_: boolean;
   private incognitoAvailable_: boolean;
@@ -215,7 +202,6 @@
   private detailViewItem_?: chrome.developerPrivate.ExtensionInfo;
   private activityLogItem_?: chrome.developerPrivate.ExtensionInfo|
       ActivityLogExtensionPlaceholder;
-  private extensionSiteAccessItem_?: chrome.developerPrivate.ExtensionInfo;
   private extensions_: Array<chrome.developerPrivate.ExtensionInfo>;
   private apps_: Array<chrome.developerPrivate.ExtensionInfo>;
   private didInitPage_: boolean;
@@ -479,11 +465,6 @@
         this.activityLogItem_ && this.activityLogItem_.id === item.id &&
         this.currentPage_!.page === Page.ACTIVITY_LOG) {
       this.activityLogItem_ = item;
-    } else if (
-        this.extensionSiteAccessItem_ &&
-        this.extensionSiteAccessItem_.id === item.id &&
-        this.currentPage_!.page === Page.EXTENSION_SITE_ACCESS) {
-      this.extensionSiteAccessItem_ = item;
     }
   }
 
@@ -503,8 +484,7 @@
     // We should never try and remove a non-existent item.
     assert(index >= 0);
     this.splice(listId, index, 1);
-    if ((this.currentPage_!.page === Page.EXTENSION_SITE_ACCESS ||
-         this.currentPage_!.page === Page.ACTIVITY_LOG ||
+    if ((this.currentPage_!.page === Page.ACTIVITY_LOG ||
          this.currentPage_!.page === Page.DETAILS ||
          this.currentPage_!.page === Page.ERRORS) &&
         this.currentPage_!.extensionId === itemId) {
@@ -572,18 +552,6 @@
       }
 
       this.activityLogItem_ = data ? assert(data) : activityLogPlaceholder;
-    } else if (toPage === Page.EXTENSION_SITE_ACCESS) {
-      // TODO(crbug.com/1253673): Redirect back to details page if the extension
-      // does not have any runtime host permissions.
-      if (!this.useNewSiteAccessPage) {
-        // Redirect back to the details page if we try to view the new extension
-        // site access page of an extension but the flag is not set.
-        navigation.replaceWith(
-            {page: Page.DETAILS, extensionId: newPage.extensionId});
-        return;
-      }
-
-      this.extensionSiteAccessItem_ = assert(data);
     }
 
     if (fromPage !== toPage) {
@@ -647,8 +615,7 @@
     const viewType = (e.composedPath()[0] as HTMLElement).tagName;
     if (viewType === 'EXTENSIONS-ITEM-LIST' ||
         viewType === 'EXTENSIONS-KEYBOARD-SHORTCUTS' ||
-        viewType === 'EXTENSIONS-ACTIVITY-LOG' ||
-        viewType === 'EXTENSIONS-SITE-ACCESS') {
+        viewType === 'EXTENSIONS-ACTIVITY-LOG') {
       return;
     }
 
diff --git a/chrome/browser/resources/extensions/navigation_helper.ts b/chrome/browser/resources/extensions/navigation_helper.ts
index 36606f4..9ed4800 100644
--- a/chrome/browser/resources/extensions/navigation_helper.ts
+++ b/chrome/browser/resources/extensions/navigation_helper.ts
@@ -13,7 +13,6 @@
   LIST = 'items-list',
   DETAILS = 'details-view',
   ACTIVITY_LOG = 'activity-log',
-  EXTENSION_SITE_ACCESS = 'extension-site-access',
   SHORTCUTS = 'keyboard-shortcuts',
   ERRORS = 'error-page',
 }
@@ -92,10 +91,6 @@
     if (id) {
       return {page: Page.ACTIVITY_LOG, extensionId: id};
     }
-    id = search.get('siteAccess');
-    if (id) {
-      return {page: Page.EXTENSION_SITE_ACCESS, extensionId: id};
-    }
     id = search.get('options');
     if (id) {
       return {page: Page.DETAILS, extensionId: id, subpage: Dialog.OPTIONS};
@@ -187,9 +182,6 @@
           path = '/?id=' + entry.extensionId;
         }
         break;
-      case Page.EXTENSION_SITE_ACCESS:
-        path = '/?siteAccess=' + entry.extensionId;
-        break;
       case Page.SHORTCUTS:
         path = '/shortcuts';
         break;
diff --git a/chrome/browser/resources/extensions/runtime_host_permissions.html b/chrome/browser/resources/extensions/runtime_host_permissions.html
index ced1400..c972ce0 100644
--- a/chrome/browser/resources/extensions/runtime_host_permissions.html
+++ b/chrome/browser/resources/extensions/runtime_host_permissions.html
@@ -64,7 +64,7 @@
   <div id="section-heading">
     <div id="section-heading-heading">
       <span id="section-heading-text">
-        [[getHostPermissionsHeading_(useNewSiteAccessPage)]]
+        [[getHostPermissionsHeading_(extensionsMenuAccessControlEnabled_)]]
       </span>
       <a class="link-icon-button" aria-label="$i18n{learnMore}"
           href="$i18n{hostPermissionsLearnMoreLink}" target="_blank"
@@ -77,7 +77,7 @@
       <select id="host-access" class="md-select" on-change="onHostAccessChange_"
           value="[[permissions.hostAccess]]"
           aria-labelledby="section-heading-text">
-        <template is="dom-if" if="[[!useNewSiteAccessPage]]">
+        <template is="dom-if" if="[[!extensionsMenuAccessControlEnabled_]]">
           <option value="[[HostAccess_.ON_CLICK]]">
             $i18n{hostAccessOnClick}
           </option>
@@ -88,7 +88,7 @@
             $i18n{hostAccessOnAllSites}
           </option>
         </template>
-        <template is="dom-if" if="[[useNewSiteAccessPage]]">
+        <template is="dom-if" if="[[extensionsMenuAccessControlEnabled_]]">
           <option value="[[HostAccess_.ON_CLICK]]">
             $i18n{newHostAccessOnClick}
           </option>
diff --git a/chrome/browser/resources/extensions/runtime_host_permissions.ts b/chrome/browser/resources/extensions/runtime_host_permissions.ts
index 315efb6f..4710acb1 100644
--- a/chrome/browser/resources/extensions/runtime_host_permissions.ts
+++ b/chrome/browser/resources/extensions/runtime_host_permissions.ts
@@ -59,8 +59,6 @@
 
       delegate: Object,
 
-      useNewSiteAccessText: Boolean,
-
       /**
        * Whether the dialog to add a new host permission is shown.
        */
@@ -127,13 +125,21 @@
         type: Object,
         value: chrome.developerPrivate.HostAccess,
       },
+
+      /**
+       * Whether the new site access menu should be shown.
+       */
+      extensionsMenuAccessControlEnabled_: {
+        type: Boolean,
+        value: () =>
+            loadTimeData.getBoolean('extensionsMenuAccessControlEnabled'),
+      },
     };
   }
 
   permissions: chrome.developerPrivate.RuntimeHostPermissions;
   itemId: string;
   delegate: ItemDelegate;
-  useNewSiteAccessText: boolean;
   private showHostDialog_: boolean;
   private hostDialogModel_: string|null;
   private hostDialogAnchorElement_: HTMLElement|null;
@@ -141,6 +147,7 @@
   private actionMenuAnchorElement_: HTMLElement|null;
   private oldHostAccess_: string|null;
   private revertingHostAccess_: boolean;
+  private extensionsMenuAccessControlEnabled_: boolean;
 
   private onHostAccessChange_() {
     const selectMenu = this.$['host-access'];
@@ -185,14 +192,14 @@
 
   private getHostPermissionsHeading_(): string {
     return loadTimeData.getString(
-        this.useNewSiteAccessText ? 'newHostPermissionsHeading' :
-                                    'hostPermissionsHeading');
+        this.extensionsMenuAccessControlEnabled_ ? 'newHostPermissionsHeading' :
+                                                   'hostPermissionsHeading');
   }
 
   private showSpecificSites_(): boolean {
     // TODO(crbug.com/1253673): Show a different "customize for each site" menu
     // for the new site access menu.
-    return !this.useNewSiteAccessText &&
+    return !this.extensionsMenuAccessControlEnabled_ &&
         this.permissions.hostAccess ===
         chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES;
   }
diff --git a/chrome/browser/resources/extensions/site_access.html b/chrome/browser/resources/extensions/site_access.html
deleted file mode 100644
index e3e0f89a..0000000
--- a/chrome/browser/resources/extensions/site_access.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<style include="cr-icons cr-shared-style shared-style">
-  #icon {
-    height: 24px;
-    margin-inline-end: 12px;
-    margin-inline-start: 16px;
-    width: 24px;
-  }
-</style>
-<div class="page-container" id="container">
-  <div class="page-content">
-    <div class="page-header">
-      <cr-icon-button class="icon-arrow-back no-overlap" id="closeButton"
-          aria-label="$i18n{back}" on-click="onCloseButtonClick_">
-      </cr-icon-button>
-      <img id="icon" src="[[extensionInfo.iconUrl]]" alt=""
-          hidden="[[extensionInfo.isPlaceholder]]">
-      <div class="cr-title-text">[[extensionInfo.name]]</div>
-    </div>
-  </div>
-</div>
diff --git a/chrome/browser/resources/extensions/site_access.ts b/chrome/browser/resources/extensions/site_access.ts
deleted file mode 100644
index 18b1c1e2..0000000
--- a/chrome/browser/resources/extensions/site_access.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2021 The Chromium 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/cr_elements/cr_icon_button/cr_icon_button.m.js';
-import 'chrome://resources/cr_elements/cr_icons_css.m.js';
-import 'chrome://resources/cr_elements/shared_style_css.m.js';
-import 'chrome://resources/cr_elements/shared_vars_css.m.js';
-import './strings.m.js';
-import './shared_style.js';
-import './shared_vars.js';
-
-import {CrContainerShadowMixin} from 'chrome://resources/cr_elements/cr_container_shadow_mixin.js';
-import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
-import {I18nMixin, I18nMixinInterface} from 'chrome://resources/js/i18n_mixin.js';
-import {afterNextRender, html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {navigation, Page} from './navigation_helper.js';
-
-interface ExtensionsSiteAccessElement {
-  $: {
-    closeButton: HTMLElement,
-  };
-}
-
-const ExtensionsSiteAccessElementBase =
-    I18nMixin(CrContainerShadowMixin(PolymerElement)) as
-    {new (): PolymerElement & I18nMixinInterface};
-
-class ExtensionsSiteAccessElement extends ExtensionsSiteAccessElementBase {
-  static get is() {
-    return 'extensions-site-access';
-  }
-
-  static get template() {
-    return html`{__html_template__}`;
-  }
-
-  static get properties() {
-    return {
-      /**
-       * The underlying ExtensionInfo for the extension site access items being
-       * displayed.
-       */
-      extensionInfo: Object,
-    };
-  }
-
-  extensionInfo: chrome.developerPrivate.ExtensionInfo;
-
-  ready() {
-    super.ready();
-    this.addEventListener('view-enter-start', this.onViewEnterStart_);
-  }
-
-  /**
-   * Focuses the back button when page is loaded.
-   */
-  private onViewEnterStart_() {
-    afterNextRender(this, () => focusWithoutInk(this.$.closeButton));
-  }
-
-  private onCloseButtonClick_() {
-    navigation.navigateTo(
-        {page: Page.DETAILS, extensionId: this.extensionInfo.id});
-  }
-}
-
-customElements.define(
-    ExtensionsSiteAccessElement.is, ExtensionsSiteAccessElement);
diff --git a/chrome/browser/resources/history/history_clusters/top_visit.html b/chrome/browser/resources/history/history_clusters/top_visit.html
index 51d5d727..44aeffda 100644
--- a/chrome/browser/resources/history/history_clusters/top_visit.html
+++ b/chrome/browser/resources/history/history_clusters/top_visit.html
@@ -73,7 +73,7 @@
   }
 </style>
 <url-visit visit="[[visit]]" cluster-index="[[clusterIndex]]" index="0"
-    has-related-visits$="[[hasRelatedVisits_]]" is-top-visit>
+    is-top-visit>
 </url-visit>
 <template is="dom-repeat" items="[[visibleRelatedVisits_]]">
   <url-visit visit="[[item]]" cluster-index="[[clusterIndex]]"
diff --git a/chrome/browser/resources/history/history_clusters/top_visit.ts b/chrome/browser/resources/history/history_clusters/top_visit.ts
index cdbef03..d2aba93 100644
--- a/chrome/browser/resources/history/history_clusters/top_visit.ts
+++ b/chrome/browser/resources/history/history_clusters/top_visit.ts
@@ -68,14 +68,6 @@
       },
 
       /**
-       * Whether there are related visits.
-       */
-      hasRelatedVisits_: {
-        type: Boolean,
-        computed: 'computeHasRelatedVisits_(visit.relatedVisits.*)',
-      },
-
-      /**
        * The default-hidden related visits.
        */
       hiddenRelatedVisits_: {
@@ -100,7 +92,6 @@
   visit: URLVisit;
   private expanded_: boolean;
   private hiddenRelatedVisits_: Array<URLVisit>;
-  private relatedVisits_: Array<URLVisit>;
 
   //============================================================================
   // Event handlers
@@ -143,10 +134,6 @@
     return this.hiddenRelatedVisits_.length > 0;
   }
 
-  private computeHasRelatedVisits_(): boolean {
-    return this.visit.relatedVisits.length > 0;
-  }
-
   private computeHiddenRelatedVisits_(): Array<URLVisit> {
     return this.visit.relatedVisits.filter((visit: URLVisit) => {
       return visit.belowTheFold;
diff --git a/chrome/browser/resources/history/history_clusters/url_visit.html b/chrome/browser/resources/history/history_clusters/url_visit.html
index d5afe35..468dd82 100644
--- a/chrome/browser/resources/history/history_clusters/url_visit.html
+++ b/chrome/browser/resources/history/history_clusters/url_visit.html
@@ -121,11 +121,6 @@
   :host([is-top-visit]) #actionMenuButton {
     --cr-icon-button-icon-size: 24px;
   }
-
-  :host(:not([has-related-visits])) #removeAllButton,
-  :host(:not([has-related-visits])) #openAllButton {
-    display: none;
-  }
 </style>
 <div id="header" on-click="onClick_" on-auxclick="onAuxClick_"
     on-keydown="onKeydown_">
@@ -160,14 +155,16 @@
   <template>
     <cr-action-menu role-description="$i18n{actionMenuDescription}">
       <button id="openAllButton" class="dropdown-item"
-          on-click="onOpenAllButtonClick_">
+          on-click="onOpenAllButtonClick_"
+          hidden="[[!visit.relatedVisits.length]]">
         $i18n{openAllInTabGroup}
       </button>
       <button class="dropdown-item" on-click="onRemoveSelfButtonClick_">
         $i18n{removeFromHistory}
       </button>
       <button id="removeAllButton" class="dropdown-item"
-          on-click="onRemoveAllButtonClick_">
+          on-click="onRemoveAllButtonClick_"
+          hidden="[[!visit.relatedVisits.length]]">
         $i18n{removeAllFromHistory}
       </button>
     </cr-action-menu>
diff --git a/chrome/browser/resources/pdf/BUILD.gn b/chrome/browser/resources/pdf/BUILD.gn
index 99aecf0e8..0d68ac5 100644
--- a/chrome/browser/resources/pdf/BUILD.gn
+++ b/chrome/browser/resources/pdf/BUILD.gn
@@ -4,23 +4,21 @@
 
 import("//chrome/common/features.gni")
 import("//pdf/features.gni")
-import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
 import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
+import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 import("../tools/optimize_webui.gni")
 
-preprocess_folder = "preprocessed"
-preprocess_manifest = "preprocessed_manifest.json"
-preprocess_gen_manifest = "preprocessed_gen_manifest.json"
-
 assert(enable_pdf, "enable_pdf check failed")
 
+preprocess_folder = "preprocessed"
+tsc_folder = "tsc"
+
 preprocess_if_expr("preprocess") {
   in_folder = "./"
   out_folder = "$target_gen_dir/$preprocess_folder"
-  out_manifest = "$target_gen_dir/$preprocess_manifest"
   defines = [ "enable_ink=$enable_ink" ]
   in_files = [
     "bookmark_type.js",
@@ -50,7 +48,6 @@
   deps = [ ":web_components" ]
   in_folder = target_gen_dir
   out_folder = "$target_gen_dir/$preprocess_folder"
-  out_manifest = "$target_gen_dir/$preprocess_gen_manifest"
   defines = [ "enable_ink=$enable_ink" ]
   in_files = [
     "elements/icons.js",
@@ -92,14 +89,13 @@
 
   optimize_webui("build") {
     host = "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai"
-    input = rebase_path("$target_gen_dir/$preprocess_folder", root_build_dir)
+    input = rebase_path("$target_gen_dir/$tsc_folder", root_build_dir)
     js_out_files = [ "pdf_viewer_wrapper.rollup.js" ]
     js_module_in_files = [ "pdf_viewer_wrapper.js" ]
     out_manifest = "$target_gen_dir/$build_manifest"
 
     deps = [
-      ":preprocess",
-      ":preprocess_generated",
+      ":build_ts",
       "../../../../ui/webui/resources:preprocess",
     ]
     excludes = [
@@ -132,7 +128,6 @@
 
 generate_grd("build_grd") {
   input_files = [
-    "browser_api.js",
     "index.css",
     "index.html",
     "main.js",
@@ -146,19 +141,14 @@
   input_files_base_dir = rebase_path(".", "//")
 
   if (optimize_webui) {
+    input_files += [ "browser_api.js" ]
     deps = [ ":build" ]
     resource_path_rewrites =
         [ "pdf_viewer_wrapper.rollup.js|pdf_viewer_wrapper.js" ]
     manifest_files = [ "$target_gen_dir/$build_manifest" ]
   } else {
-    deps = [
-      ":preprocess",
-      ":preprocess_generated",
-    ]
-    manifest_files = [
-      "$target_gen_dir/$preprocess_manifest",
-      "$target_gen_dir/$preprocess_gen_manifest",
-    ]
+    deps = [ ":build_ts" ]
+    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
   }
 
   deps += [ ":build_internal_plugin" ]
@@ -202,234 +192,97 @@
   ]
 }
 
-group("closure_compile") {
-  deps = [
-    ":closure_compile_local",
-    "elements:closure_compile",
+copy("copy_files") {
+  sources = [ "browser_api.js" ]
+  outputs = [ "$target_gen_dir/$preprocess_folder/{{source_file_part}}" ]
+}
+
+# Copies transpiled JS files that are used by Print Preview to the expected
+# location used by Print Preview's build configuration.
+# TODO(crbug.com/1260303): Print Preview is implemented in TS, so figure out a
+# better way expose these files to Print Preview after the PDF viewer migrates
+# to TS.
+copy("copy_print_preview_files") {
+  sources = [
+    "$target_gen_dir/tsc/constants.js",
+    "$target_gen_dir/tsc/controller.js",
+    "$target_gen_dir/tsc/gesture_detector.js",
+    "$target_gen_dir/tsc/metrics.js",
+    "$target_gen_dir/tsc/open_pdf_params_parser.js",
+    "$target_gen_dir/tsc/pdf_scripting_api.js",
+    "$target_gen_dir/tsc/pdf_viewer_base.js",
+    "$target_gen_dir/tsc/pdf_viewer_utils.js",
+    "$target_gen_dir/tsc/viewport.js",
+    "$target_gen_dir/tsc/viewport_scroller.js",
+    "$target_gen_dir/tsc/zoom_manager.js",
   ]
+  outputs = [ "$target_gen_dir//{{source_file_part}}" ]
+  deps = [ ":build_ts" ]
+}
+
+ts_library("build_ts") {
+  root_dir = "$target_gen_dir/$preprocess_folder"
+  out_dir = "$target_gen_dir/$tsc_folder"
+  tsconfig_base = "tsconfig_base.json"
+
+  # TODO(crbug.com/1260303): Factor out these source files to a .gni file to
+  # reduce redundancy.
+  in_files = [
+    "bookmark_type.js",
+    "browser_api.js",
+    "constants.js",
+    "controller.js",
+    "elements/icons.js",
+    "elements/shared-css.js",
+    "elements/shared-vars.js",
+    "elements/viewer-bookmark.js",
+    "elements/viewer-document-outline.js",
+    "elements/viewer-download-controls.js",
+    "elements/viewer-error-dialog.js",
+    "elements/viewer-page-selector.js",
+    "elements/viewer-password-dialog.js",
+    "elements/viewer-pdf-sidenav.js",
+    "elements/viewer-properties-dialog.js",
+    "elements/viewer-thumbnail-bar.js",
+    "elements/viewer-thumbnail.js",
+    "elements/viewer-toolbar.js",
+    "gesture_detector.js",
+    "local_storage_proxy.js",
+    "metrics.js",
+    "navigator.js",
+    "open_pdf_params_parser.js",
+    "pdf_scripting_api.js",
+    "pdf_viewer_base.js",
+    "pdf_viewer.js",
+    "pdf_viewer_shared_style.js",
+    "pdf_viewer_utils.js",
+    "pdf_viewer_wrapper.js",
+    "viewport.js",
+    "viewport_scroller.js",
+    "zoom_manager.js",
+  ]
+
   if (enable_ink) {
-    deps += [ "ink:closure_compile" ]
+    in_files += [
+      "annotation_tool.js",
+      "ink_controller.js",
+      "ink/drawing_canvas_externs.js",
+      "ink/ink_api.js",
+      "elements/viewer-annotations-bar.js",
+      "elements/viewer-annotations-mode-dialog.js",
+      "elements/viewer-ink-host.js",
+      "elements/viewer-pen-options.js",
+      "elements/viewer-toolbar-dropdown.js",
+    ]
   }
-}
-
-js_library("annotation_tool") {
-}
-
-js_library("bookmark_type") {
-}
-
-js_library("browser_api") {
-  deps = [ "//ui/webui/resources/js:assert.m" ]
-  externs_list = [
-    "$externs_path/chrome_extensions.js",
-    "$externs_path/mime_handler_private.js",
-  ]
-}
-
-js_library("constants") {
-}
-
-js_library("gesture_detector") {
+  definitions = [ "//tools/typescript/definitions/metrics_private.d.ts" ]
   deps = [
-    ":constants",
-    "//ui/webui/resources/js/cr:event_target.m",
+    "//third_party/polymer/v3_0:library",
+    "//ui/webui/resources:library",
   ]
-}
-
-js_library("open_pdf_params_parser") {
-  deps = [ ":constants" ]
-  externs_list = [ "$externs_path/pending.js" ]
-}
-
-js_library("pdf_scripting_api") {
-}
-
-js_library("viewport_scroller") {
-}
-
-js_library("viewport") {
-  deps = [
-    ":constants",
-    ":gesture_detector",
-    ":internal_plugin",
-    ":zoom_manager",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:event_tracker.m",
-    "//ui/webui/resources/js:util.m",
-  ]
-  externs_list = [ "$externs_path/pending.js" ]
-}
-
-js_library("zoom_manager") {
-  deps = [
-    ":browser_api",
-    "//ui/webui/resources/js/cr:event_target.m",
-  ]
-}
-
-js_library("metrics") {
-  deps = [ ":constants" ]
-  externs_list = [ "$externs_path/metrics_private.js" ]
-}
-
-js_library("navigator") {
-  deps = [
-    ":browser_api",
-    ":open_pdf_params_parser",
-    ":viewport",
-  ]
-}
-
-js_library("toolbar_manager") {
-  deps = [
-    "elements:viewer-zoom-toolbar",
-    "//ui/webui/resources/js:util.m",
-  ]
-}
-
-js_library("ink_controller") {
-  deps = [
-    ":annotation_tool",
-    ":controller",
-    ":viewport",
-    "//ui/webui/resources/js/cr:event_target.m",
-  ]
-}
-
-js_library("local_storage_proxy") {
-}
-
-js_library("controller") {
-  deps = [
-    ":gesture_detector",
-    ":internal_plugin",
-    ":viewport",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:load_time_data.m",
-    "//ui/webui/resources/js:promise_resolver.m",
-    "//ui/webui/resources/js/cr:event_target.m",
-  ]
-}
-
-js_library("internal_plugin") {
-}
-
-js_library("pdf_internal_plugin_wrapper") {
-  deps = [ ":gesture_detector" ]
-}
-
-js_library("pdf_viewer_base") {
-  deps = [
-    ":browser_api",
-    ":constants",
-    ":controller",
-    ":metrics",
-    ":pdf_scripting_api",
-    ":pdf_viewer_utils",
-    ":viewport",
-    ":viewport_scroller",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:event_tracker.m",
-    "//ui/webui/resources/js:load_time_data.m",
-    "//ui/webui/resources/js:promise_resolver.m",
-    "//ui/webui/resources/js:util.m",
-  ]
-  externs_list = [ "$externs_path/resources_private.js" ]
-}
-
-js_library("pdf_viewer") {
-  deps = [
-    ":bookmark_type",
-    ":browser_api",
-    ":constants",
-    ":controller",
-    ":ink_controller",
-    ":local_storage_proxy",
-    ":metrics",
-    ":navigator",
-    ":pdf_scripting_api",
-    ":pdf_viewer_base",
-    ":pdf_viewer_utils",
-    "elements:viewer-bookmark",
-    "elements:viewer-error-dialog",
-    "elements:viewer-password-dialog",
-    "elements:viewer-pdf-sidenav",
-    "elements:viewer-properties-dialog",
-    "elements:viewer-toolbar",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:event_tracker.m",
-    "//ui/webui/resources/js:load_time_data.m",
-    "//ui/webui/resources/js:promise_resolver.m",
-    "//ui/webui/resources/js:util.m",
-  ]
-  externs_list = [ "$externs_path/resources_private.js" ]
-}
-
-js_library("pdf_viewer_wrapper") {
-  deps = [ ":pdf_viewer" ]
-}
-
-js_library("pdf_viewer_utils") {
-  deps = [
-    ":controller",
-    ":viewport",
-    "//ui/webui/resources/js:util.m",
-  ]
-}
-
-js_library("pdf_viewer_pp") {
-  deps = [
-    ":constants",
-    ":controller",
-    ":pdf_scripting_api",
-    ":pdf_viewer_base",
-    ":pdf_viewer_utils",
-    ":toolbar_manager",
-    ":viewport",
-    "elements:viewer-error-dialog",
-    "elements:viewer-page-indicator",
-    "elements:viewer-zoom-toolbar",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:event_tracker.m",
-    "//ui/webui/resources/js:load_time_data.m",
-    "//ui/webui/resources/js:promise_resolver.m",
-    "//ui/webui/resources/js:util.m",
-  ]
-  externs_list = [ "$externs_path/resources_private.js" ]
-}
-
-js_library("main") {
-  deps = [
-    ":browser_api",
-    ":pdf_viewer",
-  ]
-}
-
-js_type_check("closure_compile_local") {
-  is_polymer3 = true
-  deps = [
-    ":annotation_tool",
-    ":browser_api",
-    ":constants",
-    ":controller",
-    ":gesture_detector",
-    ":ink_controller",
-    ":local_storage_proxy",
-    ":main",
-    ":metrics",
-    ":navigator",
-    ":open_pdf_params_parser",
-    ":pdf_internal_plugin_wrapper",
-    ":pdf_scripting_api",
-    ":pdf_viewer",
-    ":pdf_viewer_base",
-    ":pdf_viewer_pp",
-    ":pdf_viewer_utils",
-    ":pdf_viewer_wrapper",
-    ":toolbar_manager",
-    ":viewport",
-    ":viewport_scroller",
-    ":zoom_manager",
+  extra_deps = [
+    ":copy_files",
+    ":preprocess",
+    ":preprocess_generated",
   ]
 }
diff --git a/chrome/browser/resources/pdf/elements/BUILD.gn b/chrome/browser/resources/pdf/elements/BUILD.gn
index 8c63a4e..7ab835c 100644
--- a/chrome/browser/resources/pdf/elements/BUILD.gn
+++ b/chrome/browser/resources/pdf/elements/BUILD.gn
@@ -3,177 +3,8 @@
 # found in the LICENSE file.
 
 import("//pdf/features.gni")
-import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/polymer/html_to_js.gni")
 
-js_type_check("closure_compile") {
-  is_polymer3 = true
-  deps = [
-    ":viewer-bookmark",
-    ":viewer-document-outline",
-    ":viewer-download-controls",
-    ":viewer-error-dialog",
-    ":viewer-page-indicator",
-    ":viewer-page-selector",
-    ":viewer-password-dialog",
-    ":viewer-pdf-sidenav",
-    ":viewer-properties-dialog",
-    ":viewer-thumbnail",
-    ":viewer-thumbnail-bar",
-    ":viewer-toolbar",
-    ":viewer-zoom-button",
-    ":viewer-zoom-toolbar",
-  ]
-  if (enable_ink) {
-    deps += [
-      ":viewer-annotations-bar",
-      ":viewer-annotations-mode-dialog",
-      ":viewer-ink-host",
-      ":viewer-pen-options",
-      ":viewer-toolbar-dropdown",
-    ]
-  }
-}
-
-js_library("viewer-bookmark") {
-  deps = [ "..:bookmark_type" ]
-}
-
-js_library("viewer-document-outline") {
-  deps = [
-    ":viewer-bookmark",
-    "..:bookmark_type",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
-js_library("viewer-download-controls") {
-  deps = [
-    "..:constants",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
-  ]
-}
-
-js_library("viewer-error-dialog") {
-  deps = [ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m" ]
-}
-
-js_library("viewer-annotations-bar") {
-  deps = [
-    ":viewer-pen-options",
-    ":viewer-toolbar-dropdown",
-    "..:annotation_tool",
-    "..:ink_controller",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:event_tracker.m",
-  ]
-}
-
-js_library("viewer-annotations-mode-dialog") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
-  ]
-}
-
-if (enable_ink) {
-  js_library("viewer-ink-host") {
-    deps = [
-      "..:metrics",
-      "..:viewport",
-      "../ink:ink_api",
-    ]
-  }
-}
-
-js_library("viewer-page-indicator") {
-  deps = [
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:util.m",
-  ]
-}
-
-js_library("viewer-page-selector") {
-}
-
-js_library("viewer-password-dialog") {
-  deps = [
-    "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
-    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
-    "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
-  ]
-}
-
-js_library("viewer-pdf-sidenav") {
-  deps = [
-    ":viewer-document-outline",
-    ":viewer-thumbnail-bar",
-    "..:metrics",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/cr_elements/cr_icon_button:cr_icon_button.m",
-  ]
-}
-
-js_library("viewer-pen-options") {
-}
-
-js_library("viewer-properties-dialog") {
-  deps = [
-    "..:constants",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
-  ]
-}
-
-js_library("viewer-thumbnail") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/js:assert.m",
-  ]
-}
-
-js_library("viewer-thumbnail-bar") {
-  deps = [
-    ":viewer-thumbnail",
-    "..:controller",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:event_tracker.m",
-    "//ui/webui/resources/js:load_time_data.m",
-    "//ui/webui/resources/js/cr/ui:focus_outline_manager.m",
-  ]
-}
-
-js_library("viewer-toolbar") {
-  deps = [
-    ":viewer-annotations-bar",
-    ":viewer-annotations-mode-dialog",
-    ":viewer-download-controls",
-    ":viewer-page-selector",
-    "..:metrics",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
-js_library("viewer-toolbar-dropdown") {
-  deps = []
-}
-
-js_library("viewer-zoom-toolbar") {
-  deps = [
-    ":viewer-zoom-button",
-    "..:constants",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:util.m",
-  ]
-}
-
-js_library("viewer-zoom-button") {
-  deps = []
-}
-
 html_to_js("web_components") {
   js_files = [
     "icons.js",
diff --git a/chrome/browser/resources/pdf/tsconfig_base.json b/chrome/browser/resources/pdf/tsconfig_base.json
new file mode 100644
index 0000000..3e71f763
--- /dev/null
+++ b/chrome/browser/resources/pdf/tsconfig_base.json
@@ -0,0 +1,9 @@
+{
+  "extends": "../../../../tools/typescript/tsconfig_base.json",
+  "compilerOptions": {
+    "allowJs": true,
+    "noUncheckedIndexedAccess": false,
+    "noUnusedLocals": false,
+    "strictPropertyInitialization": false
+  }
+}
diff --git a/chrome/browser/resources/print_preview/BUILD.gn b/chrome/browser/resources/print_preview/BUILD.gn
index e13962e..1cfbc26 100644
--- a/chrome/browser/resources/print_preview/BUILD.gn
+++ b/chrome/browser/resources/print_preview/BUILD.gn
@@ -93,39 +93,45 @@
   out_manifest = "$target_gen_dir/$preprocess_pdf_manifest"
   in_files = [
     "pdf/browser_api.js",
-    "pdf/constants.js",
-    "pdf/controller.js",
-    "pdf/gesture_detector.js",
     "pdf/index.css",
     "pdf/index_pp.html",
     "pdf/internal_plugin.js",
     "pdf/main.js",
-    "pdf/metrics.js",
-    "pdf/open_pdf_params_parser.js",
-    "pdf/pdf_scripting_api.js",
-    "pdf/pdf_viewer_utils.js",
-    "pdf/pdf_viewer_base.js",
     "pdf/toolbar_manager.js",
-    "pdf/viewport.js",
-    "pdf/viewport_scroller.js",
-    "pdf/zoom_manager.js",
   ]
 }
 
 preprocess_if_expr("preprocess_pdf_generated") {
-  deps = [ "../pdf:web_components" ]
+  deps = [
+    "../pdf:copy_print_preview_files",
+    "../pdf:web_components",
+  ]
   in_folder = get_path_info("..", "gen_dir")
   out_folder = "$target_gen_dir/$preprocess_folder"
   out_manifest = "$target_gen_dir/$preprocess_pdf_gen_manifest"
   in_files = [
+    # Files produced by :copy_print_preview_files.
+    "pdf/constants.js",
+    "pdf/controller.js",
     "pdf/elements/icons.js",
     "pdf/elements/shared-vars.js",
     "pdf/elements/viewer-error-dialog.js",
+    "pdf/gesture_detector.js",
+    "pdf/metrics.js",
+    "pdf/open_pdf_params_parser.js",
+    "pdf/pdf_scripting_api.js",
+    "pdf/pdf_viewer_pp.js",
+    "pdf/pdf_viewer_shared_style.js",
+    "pdf/pdf_viewer_utils.js",
+    "pdf/viewport.js",
+    "pdf/viewport_scroller.js",
+    "pdf/zoom_manager.js",
+
+    # Other files (not part of PDF Viewer's ts_library).
     "pdf/elements/viewer-page-indicator.js",
     "pdf/elements/viewer-zoom-button.js",
     "pdf/elements/viewer-zoom-toolbar.js",
-    "pdf/pdf_viewer_pp.js",
-    "pdf/pdf_viewer_shared_style.js",
+    "pdf/pdf_viewer_base.js",
   ]
 }
 
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index dc92c58..4a3838f 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -347,6 +347,7 @@
     "privacy_page/privacy_page_browser_proxy.js",
     "privacy_page/secure_dns_input.js",
     "privacy_page/secure_dns.js",
+    "relaunch_mixin.js",
     "setting_id_param_util.js",
     "settings_page_css.js",
     "settings_page/settings_animated_pages.js",
diff --git a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_change_device_name_dialog.html b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_change_device_name_dialog.html
index 0635d58..434d63e 100644
--- a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_change_device_name_dialog.html
+++ b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_change_device_name_dialog.html
@@ -6,7 +6,7 @@
   [slot='button-container'] {
     display: flex;
     justify-content: flex-end;
-    margin: 18px 0 6px 0;
+    margin: 40px 0 20px 0;
     padding-top: 0;
   }
 
@@ -14,6 +14,10 @@
     color: var(--cros-text-color-alert);
   }
 
+  #inputContainer {
+    margin-top: 24px;
+  }
+
   #inputInfo {
     background-color: var(--cros-bg-color);
     color: var(--cros-text-color-secondary);
@@ -24,7 +28,7 @@
     line-height: var(--cr-form-field-label-line-height);
     padding-top: 8px;
     position: absolute;
-    top: 100px;
+    top: 128px;
     width: 280px;
   }
 
diff --git a/chrome/browser/resources/settings/languages_page/languages_subpage.html b/chrome/browser/resources/settings/languages_page/languages_subpage.html
index 85ffb30..92489b5 100644
--- a/chrome/browser/resources/settings/languages_page/languages_subpage.html
+++ b/chrome/browser/resources/settings/languages_page/languages_subpage.html
@@ -227,3 +227,9 @@
       body="[[i18n('languageManagedDialogBody')]]">
   </managed-dialog>
 </template>
+<if expr="not chromeos_ash">
+  <template is="dom-if" if="[[shouldShowRelaunchDialog]]" restamp>
+    <relaunch-confirmation-dialog restart-type="[[restartTypeEnum.RESTART]]"
+        on-close="onRelaunchDialogClose"></relaunch-confirmation-dialog>
+  </template>
+</if>
diff --git a/chrome/browser/resources/settings/languages_page/languages_subpage.ts b/chrome/browser/resources/settings/languages_page/languages_subpage.ts
index 2c0718b..d7f21f5a7 100644
--- a/chrome/browser/resources/settings/languages_page/languages_subpage.ts
+++ b/chrome/browser/resources/settings/languages_page/languages_subpage.ts
@@ -25,6 +25,9 @@
 import './languages.js';
 import '../controls/settings_toggle_button.js';
 import '../icons.js';
+// <if expr="not chromeos_ash">
+import '../relaunch_confirmation_dialog.js';
+// </if>
 import '../settings_shared_css.js';
 import '../settings_vars_css.js';
 
@@ -43,10 +46,8 @@
 
 import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
 import {loadTimeData} from '../i18n_setup.js';
-// <if expr="is_win">
-import {LifetimeBrowserProxyImpl} from '../lifetime_browser_proxy.js';
-// </if>
 import {PrefsMixin} from '../prefs/prefs_mixin.js';
+import {RelaunchMixin, RestartType} from '../relaunch_mixin.js';
 
 import {LanguageSettingsActionType, LanguageSettingsMetricsProxy, LanguageSettingsMetricsProxyImpl, LanguageSettingsPageImpressionType} from './languages_settings_metrics_proxy.js';
 import {LanguageHelper, LanguagesModel, LanguageState} from './languages_types.js';
@@ -72,7 +73,7 @@
 }
 
 const SettingsLanguagesSubpageElementBase =
-    I18nMixin(PrefsMixin(PolymerElement));
+    RelaunchMixin(I18nMixin(PrefsMixin(PolymerElement)));
 
 export class SettingsLanguagesSubpageElement extends
     SettingsLanguagesSubpageElementBase {
@@ -437,7 +438,7 @@
    * Handler for the restart button.
    */
   private onRestartTap_() {
-    LifetimeBrowserProxyImpl.getInstance().restart();
+    this.performRestart(RestartType.RESTART);
   }
   // </if>
 
diff --git a/chrome/browser/resources/settings/privacy_page/personalization_options.html b/chrome/browser/resources/settings/privacy_page/personalization_options.html
index 4851699..66b09a6 100644
--- a/chrome/browser/resources/settings/privacy_page/personalization_options.html
+++ b/chrome/browser/resources/settings/privacy_page/personalization_options.html
@@ -103,9 +103,14 @@
       </settings-signout-dialog>
     </template>
 
-<if expr="not chromeos">
+<if expr="not chromeos_ash">
     <cr-toast id="toast">
       <div>$i18n{restartToApplyChanges}</div>
       <cr-button on-click="onRestartTap_">$i18n{restart}</cr-button>
     </cr-toast>
+
+    <template is="dom-if" if="[[shouldShowRelaunchDialog]]" restamp>
+      <relaunch-confirmation-dialog restart-type="[[restartTypeEnum.RESTART]]"
+          on-close="onRelaunchDialogClose"></relaunch-confirmation-dialog>
+    </template>
 </if>
diff --git a/chrome/browser/resources/settings/privacy_page/personalization_options.ts b/chrome/browser/resources/settings/privacy_page/personalization_options.ts
index dba5556..06f3989 100644
--- a/chrome/browser/resources/settings/privacy_page/personalization_options.ts
+++ b/chrome/browser/resources/settings/privacy_page/personalization_options.ts
@@ -12,8 +12,11 @@
 import '../controls/settings_toggle_button.js';
 import '../people_page/signout_dialog.js';
 import '../prefs/prefs.js';
+// <if expr="not chromeos_ash">
+import '../relaunch_confirmation_dialog.js';
+// </if>
 import '../settings_shared_css.js';
-// <if expr="not chromeos">
+// <if expr="not chromeos_ash">
 import '//resources/cr_elements/cr_toast/cr_toast.js';
 // </if>
 
@@ -23,11 +26,11 @@
 
 import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
 import {loadTimeData} from '../i18n_setup.js';
-import {LifetimeBrowserProxyImpl} from '../lifetime_browser_proxy.js';
 import {PrivacyPageVisibility} from '../page_visibility.js';
 import {SettingsSignoutDialogElement} from '../people_page/signout_dialog.js';
 import {StatusAction, SyncStatus} from '../people_page/sync_browser_proxy.js';
 import {PrefsMixin} from '../prefs/prefs_mixin.js';
+import {RelaunchMixin, RestartType} from '../relaunch_mixin.js';
 
 import {MetricsReporting, PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl} from './privacy_page_browser_proxy.js';
 
@@ -42,7 +45,7 @@
 }
 
 const SettingsPersonalizationOptionsElementBase =
-    WebUIListenerMixin(PrefsMixin(PolymerElement));
+    RelaunchMixin(WebUIListenerMixin(PrefsMixin(PolymerElement)));
 
 export class SettingsPersonalizationOptionsElement extends
     SettingsPersonalizationOptionsElementBase {
@@ -287,7 +290,7 @@
 
   private onRestartTap_(e: Event) {
     e.stopPropagation();
-    LifetimeBrowserProxyImpl.getInstance().restart();
+    this.performRestart(RestartType.RESTART);
   }
 }
 
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_updates_child.html b/chrome/browser/resources/settings/safety_check_page/safety_check_updates_child.html
index 8baba523..3154c78 100644
--- a/chrome/browser/resources/settings/safety_check_page/safety_check_updates_child.html
+++ b/chrome/browser/resources/settings/safety_check_page/safety_check_updates_child.html
@@ -10,3 +10,9 @@
     managed-icon="[[getManagedIcon_(status_)]]"
     role="presentation">
 </settings-safety-check-child>
+<if expr="not chromeos_ash">
+  <template is="dom-if" if="[[shouldShowRelaunchDialog]]" restamp>
+    <relaunch-confirmation-dialog restart-type="[[restartTypeEnum.RELAUNCH]]"
+        on-close="onRelaunchDialogClose"></relaunch-confirmation-dialog>
+    </template>
+</if>
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_updates_child.ts b/chrome/browser/resources/settings/safety_check_page/safety_check_updates_child.ts
index fcd3aa75..f7d1ee8 100644
--- a/chrome/browser/resources/settings/safety_check_page/safety_check_updates_child.ts
+++ b/chrome/browser/resources/settings/safety_check_page/safety_check_updates_child.ts
@@ -7,14 +7,18 @@
  * 'settings-safety-updates-child' is the settings page containing the safety
  * check child showing the browser's update status.
  */
+
+// <if expr="not chromeos_ash">
+import '../relaunch_confirmation_dialog.js';
+// </if>
+
 import {assertNotReached} from 'chrome://resources/js/assert.m.js';
 import {I18nMixin} from 'chrome://resources/js/i18n_mixin.js';
 import {WebUIListenerMixin} from 'chrome://resources/js/web_ui_listener_mixin.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {LifetimeBrowserProxyImpl} from '../lifetime_browser_proxy.js';
 import {MetricsBrowserProxy, MetricsBrowserProxyImpl, SafetyCheckInteractions} from '../metrics_browser_proxy.js';
-
+import {RelaunchMixin, RestartType} from '../relaunch_mixin.js';
 import {SafetyCheckCallbackConstants, SafetyCheckUpdatesStatus} from './safety_check_browser_proxy.js';
 import {SafetyCheckIconStatus} from './safety_check_child.js';
 
@@ -24,7 +28,7 @@
 };
 
 const SettingsSafetyCheckUpdatesChildElementBase =
-    WebUIListenerMixin(I18nMixin(PolymerElement));
+    RelaunchMixin(WebUIListenerMixin(I18nMixin(PolymerElement)));
 
 export class SettingsSafetyCheckUpdatesChildElement extends
     SettingsSafetyCheckUpdatesChildElementBase {
@@ -108,7 +112,7 @@
     this.metricsBrowserProxy_.recordAction(
         'Settings.SafetyCheck.RelaunchAfterUpdates');
 
-    LifetimeBrowserProxyImpl.getInstance().relaunch();
+    this.performRestart(RestartType.RELAUNCH);
   }
 
   private getManagedIcon_(): string|null {
diff --git a/chrome/browser/resources/settings/system_page/system_page.html b/chrome/browser/resources/settings/system_page/system_page.html
index 6bc65d2e..f62f11cb 100644
--- a/chrome/browser/resources/settings/system_page/system_page.html
+++ b/chrome/browser/resources/settings/system_page/system_page.html
@@ -49,3 +49,9 @@
         </extension-controlled-indicator>
       </div>
     </template>
+    <if expr="not chromeos_ash">
+      <template is="dom-if" if="[[shouldShowRelaunchDialog]]" restamp>
+        <relaunch-confirmation-dialog restart-type="[[restartTypeEnum.RESTART]]"
+            on-close="onRelaunchDialogClose"></relaunch-confirmation-dialog>
+      </template>
+    </if>
diff --git a/chrome/browser/resources/settings/system_page/system_page.ts b/chrome/browser/resources/settings/system_page/system_page.ts
index 895f75e9..4e5c6aa 100644
--- a/chrome/browser/resources/settings/system_page/system_page.ts
+++ b/chrome/browser/resources/settings/system_page/system_page.ts
@@ -14,12 +14,15 @@
 import '../controls/extension_controlled_indicator.js';
 import '../controls/settings_toggle_button.js';
 import '../prefs/prefs.js';
+// <if expr="not chromeos_ash">
+import '../relaunch_confirmation_dialog.js';
+// </if>
 import '../settings_shared_css.js';
 
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
-import {LifetimeBrowserProxyImpl} from '../lifetime_browser_proxy.js';
+import {RelaunchMixin, RestartType} from '../relaunch_mixin.js';
 
 import {SystemPageBrowserProxyImpl} from './system_page_browser_proxy.js';
 
@@ -31,7 +34,9 @@
   };
 }
 
-export class SettingsSystemPageElement extends PolymerElement {
+const SettingsSystemPageElementBase = RelaunchMixin(PolymerElement);
+
+export class SettingsSystemPageElement extends SettingsSystemPageElementBase {
   static get is() {
     return 'settings-system-page';
   }
@@ -90,8 +95,7 @@
   private onRestartTap_(e: Event) {
     // Prevent event from bubbling up to the toggle button.
     e.stopPropagation();
-    // TODO(dbeam): we should prompt before restarting the browser.
-    LifetimeBrowserProxyImpl.getInstance().restart();
+    this.performRestart(RestartType.RESTART);
   }
 
   /**
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsTabServiceTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsTabServiceTest.java
index 491acaea..01524ed 100644
--- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsTabServiceTest.java
+++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsTabServiceTest.java
@@ -18,6 +18,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Matchers;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -87,7 +88,10 @@
     @Test
     @MediumTest
     @Feature({"LongScreenshots"})
-    public void testCapturedFilesystem() throws Exception {
+    @DisableIf.Build(message = "Flaky on emulators; see https://crbug.com/1282258",
+            supported_abis_includes = "x86")
+    public void
+    testCapturedFilesystem() throws Exception {
         EmbeddedTestServer testServer = mActivityTestRule.getTestServer();
         final String url = testServer.getURL("/chrome/test/data/android/about.html");
 
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.cc b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.cc
index f472fa93..07031f52 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.cc
+++ b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.cc
@@ -19,6 +19,7 @@
 #include "chrome/grit/chromium_strings.h"
 #include "components/sync_device_info/device_info.h"
 #include "components/vector_icons/vector_icons.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/paint_vector_icon.h"
@@ -41,10 +42,12 @@
 void ClickToCallUiController::ShowDialog(
     content::WebContents* web_contents,
     const absl::optional<url::Origin>& initiating_origin,
+    content::WeakDocumentPtr initiator_document,
     const GURL& url,
     bool hide_default_handler) {
   auto* controller = GetOrCreateFromWebContents(web_contents);
   controller->phone_url_ = url;
+  controller->initiator_document_ = std::move(initiator_document);
   controller->hide_default_handler_ = hide_default_handler;
   controller->UpdateAndShowDialog(initiating_origin);
 }
@@ -140,8 +143,8 @@
   if (ukm_recorder_)
     std::move(ukm_recorder_).Run(SharingClickToCallSelection::kApp);
 
-  ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(phone_url_,
-                                                         web_contents());
+  ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
+      phone_url_, web_contents(), initiator_document_);
 }
 
 void ClickToCallUiController::OnDialogShown(bool has_devices, bool has_apps) {
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h
index 4ae4a38f..d67af75c 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h
+++ b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h
@@ -14,6 +14,7 @@
 #include "chrome/browser/sharing/sharing_service.h"
 #include "chrome/browser/sharing/sharing_ui_controller.h"
 #include "chrome/browser/ui/page_action/page_action_icon_type.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/gurl.h"
@@ -31,6 +32,7 @@
       content::WebContents* web_contents);
   static void ShowDialog(content::WebContents* web_contents,
                          const absl::optional<url::Origin>& initiating_origin,
+                         content::WeakDocumentPtr initiator_document,
                          const GURL& url,
                          bool hide_default_handler);
 
@@ -76,6 +78,7 @@
 
   UKMRecorderCallback ukm_recorder_;
   GURL phone_url_;
+  content::WeakDocumentPtr initiator_document_;
   bool hide_default_handler_ = false;
 
   base::WeakPtrFactory<ClickToCallUiController> weak_ptr_factory_{this};
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
index a88120b..7dd5d811 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
+++ b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
@@ -22,6 +22,7 @@
 #include "components/sync/protocol/device_info_specifics.pb.h"
 #include "components/sync_device_info/fake_device_info_tracker.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/web_contents_tester.h"
@@ -51,7 +52,9 @@
           return std::make_unique<testing::NiceMock<MockSharingService>>();
         }));
     ClickToCallUiController::ShowDialog(
-        web_contents_.get(), /*initiating_origin=*/absl::nullopt,
+        web_contents_.get(),
+        /*initiating_origin=*/absl::nullopt,
+        /*initiator_document=*/content::WeakDocumentPtr(),
         GURL(base::StrCat({"tel:", kPhoneNumber})), false);
     controller_ = ClickToCallUiController::GetOrCreateFromWebContents(
         web_contents_.get());
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index b946c2d..62748c0 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -96,7 +96,7 @@
 // changed default theme assets, if you need themes to recreate their generated
 // images (which are cached), if you changed how missing values are
 // generated, or if you changed any constants.
-const int kThemePackVersion = 77;
+const int kThemePackVersion = 78;
 
 // IDs that are in the DataPack won't clash with the positive integer
 // uint16_t. kHeaderID should always have the maximum value because we want the
@@ -207,12 +207,12 @@
 
 // Strings used by themes to identify tints in the JSON.
 const StringToIntTable kTintTable[] = {
+    {"background_tab", TP::TINT_BACKGROUND_TAB},
     {"buttons", TP::TINT_BUTTONS},
     {"frame", TP::TINT_FRAME},
     {"frame_inactive", TP::TINT_FRAME_INACTIVE},
     {"frame_incognito", TP::TINT_FRAME_INCOGNITO},
     {"frame_incognito_inactive", TP::TINT_FRAME_INCOGNITO_INACTIVE},
-    {"background_tab", TP::TINT_BACKGROUND_TAB},
 
     // /!\ If you make any changes here, you must also increment
     // kThemePackVersion above, or else themes will display incorrectly.
@@ -221,10 +221,6 @@
 
 // Strings used by themes to identify colors in the JSON.
 constexpr StringToIntTable kOverwritableColorTable[] = {
-    {"frame", TP::COLOR_FRAME_ACTIVE},
-    {"frame_inactive", TP::COLOR_FRAME_INACTIVE},
-    {"frame_incognito", TP::COLOR_FRAME_ACTIVE_INCOGNITO},
-    {"frame_incognito_inactive", TP::COLOR_FRAME_INACTIVE_INCOGNITO},
     {"background_tab", TP::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_ACTIVE},
     {"background_tab_inactive",
      TP::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE},
@@ -234,6 +230,16 @@
      TP::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE_INCOGNITO},
     {"bookmark_text", TP::COLOR_BOOKMARK_TEXT},
     {"button_background", TP::COLOR_CONTROL_BUTTON_BACKGROUND},
+    {"frame", TP::COLOR_FRAME_ACTIVE},
+    {"frame_inactive", TP::COLOR_FRAME_INACTIVE},
+    {"frame_incognito", TP::COLOR_FRAME_ACTIVE_INCOGNITO},
+    {"frame_incognito_inactive", TP::COLOR_FRAME_INACTIVE_INCOGNITO},
+    {"ntp_background", TP::COLOR_NTP_BACKGROUND},
+    {"ntp_header", TP::COLOR_NTP_HEADER},
+    {"ntp_link", TP::COLOR_NTP_LINK},
+    {"ntp_text", TP::COLOR_NTP_TEXT},
+    {"omnibox_background", TP::COLOR_OMNIBOX_BACKGROUND},
+    {"omnibox_text", TP::COLOR_OMNIBOX_TEXT},
     {"tab_background_text", TP::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE},
     {"tab_background_text_inactive",
      TP::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE},
@@ -244,12 +250,7 @@
     {"tab_text", TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE},
     {"toolbar", TP::COLOR_TOOLBAR},
     {"toolbar_button_icon", TP::COLOR_TOOLBAR_BUTTON_ICON},
-    {"omnibox_text", TP::COLOR_OMNIBOX_TEXT},
-    {"omnibox_background", TP::COLOR_OMNIBOX_BACKGROUND},
-    {"ntp_background", TP::COLOR_NTP_BACKGROUND},
-    {"ntp_header", TP::COLOR_NTP_HEADER},
-    {"ntp_link", TP::COLOR_NTP_LINK},
-    {"ntp_text", TP::COLOR_NTP_TEXT},
+    {"toolbar_text", TP::COLOR_TOOLBAR_TEXT},
 
     // /!\ If you make any changes here, you must also increment
     // kThemePackVersion above, or else themes will display incorrectly.
@@ -844,10 +845,8 @@
   // Toolbar and active tab (set in SetFrameAndToolbarRelatedColors) use active
   // tab color.
   pack->SetColor(TP::COLOR_TOOLBAR, colors.active_tab_color);
-  pack->SetColor(TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE,
-                 colors.active_tab_text_color);
+  pack->SetColor(TP::COLOR_TOOLBAR_TEXT, colors.active_tab_text_color);
   pack->SetColor(TP::COLOR_TOOLBAR_BUTTON_ICON, colors.active_tab_text_color);
-  pack->SetColor(TP::COLOR_BOOKMARK_TEXT, colors.active_tab_text_color);
 
   // NTP.
   pack->SetColor(TP::COLOR_NTP_BACKGROUND, colors.ntp_color);
@@ -1054,10 +1053,16 @@
     int property_id;
     int color_id;
   } kThemePropertiesMap[] = {
+      {TP::COLOR_BOOKMARK_TEXT, kColorBookmarkText},
       {TP::COLOR_DOWNLOAD_SHELF, kColorDownloadShelf},
-      {TP::COLOR_TOOLBAR, kColorToolbar},
       {TP::COLOR_OMNIBOX_TEXT, kColorOmniboxText},
       {TP::COLOR_OMNIBOX_BACKGROUND, kColorOmniboxBackground},
+      {TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE,
+       kColorTabForegroundActiveFrameActive},
+      {TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE,
+       kColorTabForegroundActiveFrameInactive},
+      {TP::COLOR_TOOLBAR, kColorToolbar},
+      {TP::COLOR_TOOLBAR_TEXT, kColorToolbarText},
   };
 
   ui::ColorSet::ColorMap theme_colors;
@@ -1507,6 +1512,12 @@
     SetColor(TP::COLOR_TOOLBAR_BUTTON_ICON_HOVERED, toolbar_button_icon_color);
     SetColor(TP::COLOR_TOOLBAR_BUTTON_ICON_PRESSED, toolbar_button_icon_color);
   }
+  SkColor toolbar_text_color;
+  if (GetColor(TP::COLOR_TOOLBAR_TEXT, &toolbar_text_color)) {
+    SetColorIfUnspecified(TP::COLOR_BOOKMARK_TEXT, toolbar_text_color);
+    SetColorIfUnspecified(TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE,
+                          toolbar_text_color);
+  }
   SkColor tab_foreground_color;
   if (GetColor(TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE,
                &tab_foreground_color)) {
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc
index 8875a09..5b934300 100644
--- a/chrome/browser/themes/browser_theme_pack_unittest.cc
+++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -1085,20 +1085,16 @@
     EXPECT_EQ(frame_color, background_tab);
     EXPECT_TRUE(has_readable_contrast(background_tab_text, background_tab));
 
-    SkColor toolbar_color, ntp_background, tab_text, bookmark_text,
-        toolbar_button_icon;
-    EXPECT_TRUE(pack->GetColor(TP::COLOR_TOOLBAR, &toolbar_color));
+    SkColor ntp_background, toolbar_color, toolbar_button_icon, toolbar_text;
     EXPECT_TRUE(pack->GetColor(TP::COLOR_NTP_BACKGROUND, &ntp_background));
-    EXPECT_TRUE(pack->GetColor(TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE,
-                               &tab_text));
+    EXPECT_TRUE(pack->GetColor(TP::COLOR_TOOLBAR, &toolbar_color));
     EXPECT_TRUE(
         pack->GetColor(TP::COLOR_TOOLBAR_BUTTON_ICON, &toolbar_button_icon));
-    EXPECT_TRUE(pack->GetColor(TP::COLOR_BOOKMARK_TEXT, &bookmark_text));
+    EXPECT_TRUE(pack->GetColor(TP::COLOR_TOOLBAR_TEXT, &toolbar_text));
 
     EXPECT_EQ(toolbar_color, ntp_background);
-    EXPECT_EQ(tab_text, toolbar_button_icon);
-    EXPECT_EQ(tab_text, bookmark_text);
-    EXPECT_TRUE(has_readable_contrast(tab_text, toolbar_color));
+    EXPECT_EQ(toolbar_text, toolbar_button_icon);
+    EXPECT_TRUE(has_readable_contrast(toolbar_text, toolbar_color));
 
     EXPECT_NE(frame_color, toolbar_color);
     EXPECT_GE(color_utils::GetContrastRatio(frame_color, toolbar_color),
diff --git a/chrome/browser/themes/increased_contrast_theme_supplier.cc b/chrome/browser/themes/increased_contrast_theme_supplier.cc
index 3f69dba..94d526e 100644
--- a/chrome/browser/themes/increased_contrast_theme_supplier.cc
+++ b/chrome/browser/themes/increased_contrast_theme_supplier.cc
@@ -23,10 +23,6 @@
   const SkColor foreground = is_dark_mode_ ? SK_ColorWHITE : SK_ColorBLACK;
   const SkColor background = is_dark_mode_ ? SK_ColorBLACK : SK_ColorWHITE;
   switch (id) {
-    case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE:
-    case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE:
-      *color = foreground;
-      return true;
     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE:
     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE_INCOGNITO:
       *color = SK_ColorWHITE;
@@ -52,10 +48,9 @@
     case ThemeProperties::COLOR_TOOLBAR_TOP_SEPARATOR:
       *color = is_dark_mode_ ? SK_ColorDKGRAY : SK_ColorLTGRAY;
       return true;
-    case ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR:
-      *color = foreground;
-      return true;
     case ThemeProperties::COLOR_LOCATION_BAR_BORDER:
+    case ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR:
+    case ThemeProperties::COLOR_TOOLBAR_TEXT:
       *color = foreground;
       return true;
   }
diff --git a/chrome/browser/themes/theme_helper.cc b/chrome/browser/themes/theme_helper.cc
index 238ce8f3..ad332d6 100644
--- a/chrome/browser/themes/theme_helper.cc
+++ b/chrome/browser/themes/theme_helper.cc
@@ -358,10 +358,14 @@
                     incognito, theme_supplier);
   };
   switch (id) {
-    case TP::COLOR_DOWNLOAD_SHELF_BUTTON_BACKGROUND: {
+    case TP::COLOR_BOOKMARK_TEXT:
+    case TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE:
+    case TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE:
+      return GetColor(TP::COLOR_TOOLBAR_TEXT, incognito, theme_supplier,
+                      nullptr);
+    case TP::COLOR_DOWNLOAD_SHELF_BUTTON_BACKGROUND:
       return GetColor(TP::COLOR_DOWNLOAD_SHELF, incognito, theme_supplier,
                       nullptr);
-    }
     case TP::COLOR_DOWNLOAD_SHELF_BUTTON_TEXT: {
       const SkColor download_shelf_color =
           GetColor(TP::COLOR_DOWNLOAD_SHELF_BUTTON_BACKGROUND, incognito,
diff --git a/chrome/browser/themes/theme_helper_win.cc b/chrome/browser/themes/theme_helper_win.cc
index 20caee0b..f90085d1 100644
--- a/chrome/browser/themes/theme_helper_win.cc
+++ b/chrome/browser/themes/theme_helper_win.cc
@@ -64,7 +64,7 @@
 
     // Button Text Foreground
     case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON:
-    case ThemeProperties::COLOR_BOOKMARK_TEXT:
+    case ThemeProperties::COLOR_TOOLBAR_TEXT:
     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE:
     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE_INCOGNITO:
     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE:
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc
index 3db36d09..62152f7 100644
--- a/chrome/browser/themes/theme_properties.cc
+++ b/chrome/browser/themes/theme_properties.cc
@@ -75,9 +75,7 @@
       return gfx::kGoogleGrey050;
     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE:
     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE:
-    case ThemeProperties::COLOR_BOOKMARK_TEXT:
-    case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE:
-    case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE:
+    case ThemeProperties::COLOR_TOOLBAR_TEXT:
       return gfx::kGoogleGrey800;
     case ThemeProperties::COLOR_NTP_BACKGROUND:
       return kDefaultColorNTPBackground;
@@ -160,9 +158,7 @@
     case ThemeProperties::COLOR_HOVER_CARD_NO_PREVIEW_BACKGROUND:
     case ThemeProperties::COLOR_NTP_SHORTCUT:
       return gfx::kGoogleGrey900;
-    case ThemeProperties::COLOR_BOOKMARK_TEXT:
-    case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE:
-    case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE:
+    case ThemeProperties::COLOR_TOOLBAR_TEXT:
       return SK_ColorWHITE;
     case ThemeProperties::COLOR_NTP_TEXT:
       return gfx::kGoogleGrey200;
diff --git a/chrome/browser/themes/theme_properties.h b/chrome/browser/themes/theme_properties.h
index 8e45df1..a5f03ec 100644
--- a/chrome/browser/themes/theme_properties.h
+++ b/chrome/browser/themes/theme_properties.h
@@ -26,40 +26,41 @@
   // incorrectly.
 
   enum OverwritableByUserThemeProperty {
-    COLOR_FRAME_ACTIVE,
-    COLOR_FRAME_INACTIVE,
     // Instead of using the INCOGNITO variants directly, most code should
     // use the original color ID in an incognito-aware context (such as
     // GetDefaultColor).  This comment applies to other properties tagged
     // INCOGNITO below as well.
-    COLOR_FRAME_ACTIVE_INCOGNITO,
-    COLOR_FRAME_INACTIVE_INCOGNITO,
-    COLOR_TAB_BACKGROUND_INACTIVE_FRAME_ACTIVE,
-    COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE,
-    COLOR_TAB_BACKGROUND_INACTIVE_FRAME_ACTIVE_INCOGNITO,
-    COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE_INCOGNITO,
-    COLOR_TOOLBAR,
-    COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE,
-    COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE,
-    COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE,
-    COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE_INCOGNITO,
-    COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE_INCOGNITO,
     COLOR_BOOKMARK_TEXT,
+    COLOR_CONTROL_BUTTON_BACKGROUND,
+    COLOR_FRAME_ACTIVE,
+    COLOR_FRAME_ACTIVE_INCOGNITO,
+    COLOR_FRAME_INACTIVE,
+    COLOR_FRAME_INACTIVE_INCOGNITO,
     COLOR_NTP_BACKGROUND,
-    COLOR_NTP_TEXT,
     COLOR_NTP_LINK,
     COLOR_NTP_HEADER,
-    COLOR_CONTROL_BUTTON_BACKGROUND,
-    COLOR_TOOLBAR_BUTTON_ICON,
-    COLOR_OMNIBOX_TEXT,
+    COLOR_NTP_TEXT,
     COLOR_OMNIBOX_BACKGROUND,
+    COLOR_OMNIBOX_TEXT,
+    COLOR_TAB_BACKGROUND_INACTIVE_FRAME_ACTIVE,
+    COLOR_TAB_BACKGROUND_INACTIVE_FRAME_ACTIVE_INCOGNITO,
+    COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE,
+    COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE_INCOGNITO,
+    COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE,
+    COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE,
+    COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE_INCOGNITO,
+    COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE,
+    COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE_INCOGNITO,
+    COLOR_TOOLBAR,
+    COLOR_TOOLBAR_BUTTON_ICON,
+    COLOR_TOOLBAR_TEXT,
 
+    TINT_BACKGROUND_TAB,
     TINT_BUTTONS,
     TINT_FRAME,
     TINT_FRAME_INACTIVE,
     TINT_FRAME_INCOGNITO,
     TINT_FRAME_INCOGNITO_INACTIVE,
-    TINT_BACKGROUND_TAB,
 
     NTP_BACKGROUND_ALIGNMENT,
     NTP_BACKGROUND_TILING,
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index 68feae7..479ccaa 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -84,6 +84,7 @@
 
 absl::optional<ui::ColorId> ThemeProviderColorIdToColorId(int color_id) {
   static constexpr const auto kMap = base::MakeFixedFlatMap<int, ui::ColorId>({
+      {TP::COLOR_BOOKMARK_TEXT, kColorBookmarkText},
       {TP::COLOR_DOWNLOAD_SHELF, kColorDownloadShelf},
       {TP::COLOR_DOWNLOAD_SHELF_BUTTON_BACKGROUND,
        kColorDownloadShelfButtonBackground},
@@ -116,7 +117,12 @@
       {TP::COLOR_OMNIBOX_SECURITY_CHIP_SECURE, kColorOmniboxSecurityChipSecure},
       {TP::COLOR_OMNIBOX_TEXT, kColorOmniboxText},
       {TP::COLOR_OMNIBOX_TEXT_DIMMED, kColorOmniboxTextDimmed},
+      {TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE,
+       kColorTabForegroundActiveFrameActive},
+      {TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE,
+       kColorTabForegroundActiveFrameInactive},
       {TP::COLOR_TOOLBAR, kColorToolbar},
+      {TP::COLOR_TOOLBAR_TEXT, kColorToolbarText},
   });
   auto* color_it = kMap.find(color_id);
   if (color_it != kMap.cend()) {
diff --git a/chrome/browser/ui/android/external_protocol_dialog_android.cc b/chrome/browser/ui/android/external_protocol_dialog_android.cc
index 25eab61b..aedb9ea 100644
--- a/chrome/browser/ui/android/external_protocol_dialog_android.cc
+++ b/chrome/browser/ui/android/external_protocol_dialog_android.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "components/navigation_interception/intercept_navigation_delegate.h"
 #include "components/navigation_interception/navigation_params.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/referrer.h"
 #include "ui/base/page_transition_types.h"
@@ -20,7 +21,8 @@
     WebContents* web_contents,
     ui::PageTransition page_transition,
     bool has_user_gesture,
-    const absl::optional<url::Origin>& initiating_origin) {
+    const absl::optional<url::Origin>& initiating_origin,
+    content::WeakDocumentPtr) {
   navigation_interception::InterceptNavigationDelegate* delegate =
       navigation_interception::InterceptNavigationDelegate::Get(web_contents);
   if (!delegate)
diff --git a/chrome/browser/ui/android/webid/account_selection_view_android.cc b/chrome/browser/ui/android/webid/account_selection_view_android.cc
index b885bd72..9959bab 100644
--- a/chrome/browser/ui/android/webid/account_selection_view_android.cc
+++ b/chrome/browser/ui/android/webid/account_selection_view_android.cc
@@ -19,6 +19,7 @@
 #include "ui/android/color_utils_android.h"
 #include "ui/android/view_android.h"
 #include "ui/android/window_android.h"
+#include "ui/gfx/android/java_bitmap.h"
 #include "url/android/gurl_android.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -45,9 +46,13 @@
 ScopedJavaLocalRef<jobject> ConvertToJavaIdentityProviderMetadata(
     JNIEnv* env,
     const content::IdentityProviderMetadata& metadata) {
+  base::android::ScopedJavaLocalRef<jobject> java_brand_icon;
+  if (!metadata.brand_icon.isNull())
+    java_brand_icon = gfx::ConvertToJavaBitmap(metadata.brand_icon);
   return Java_IdentityProviderMetadata_Constructor(
       env, ui::OptionalSkColorToJavaColor(metadata.brand_text_color),
-      ui::OptionalSkColorToJavaColor(metadata.brand_background_color));
+      ui::OptionalSkColorToJavaColor(metadata.brand_background_color),
+      java_brand_icon);
 }
 
 ScopedJavaLocalRef<jobject> ConvertToJavaClientIdMetadata(
@@ -177,3 +182,15 @@
     AccountSelectionView::Delegate* delegate) {
   return std::make_unique<AccountSelectionViewAndroid>(delegate);
 }
+
+// static
+int AccountSelectionView::GetBrandIconMinimumSize() {
+  return Java_AccountSelectionBridge_getBrandIconMinimumSize(
+      base::android::AttachCurrentThread());
+}
+
+// static
+int AccountSelectionView::GetBrandIconIdealSize() {
+  return Java_AccountSelectionBridge_getBrandIconIdealSize(
+      base::android::AttachCurrentThread());
+}
diff --git a/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_continue_button.xml b/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_continue_button.xml
index 22c6bbc..91a911f 100644
--- a/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_continue_button.xml
+++ b/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_continue_button.xml
@@ -11,7 +11,9 @@
     android:layout_height="wrap_content"
     android:layout_marginTop="@dimen/account_selection_sheet_button_margin"
     android:layout_marginBottom="@dimen/account_selection_sheet_button_margin"
-    android:text="@string/account_selection_continue"
+    android:drawablePadding="5dp"
+    android:paddingStart="10dp"
+    android:paddingEnd="@dimen/account_selection_continue_padding_end"
     android:ellipsize="end"
     android:singleLine="true"
     style="@style/FilledButton.Flat"/>
diff --git a/chrome/browser/ui/android/webid/internal/java/res/values/dimens.xml b/chrome/browser/ui/android/webid/internal/java/res/values/dimens.xml
index 60fe321..108f19e 100644
--- a/chrome/browser/ui/android/webid/internal/java/res/values/dimens.xml
+++ b/chrome/browser/ui/android/webid/internal/java/res/values/dimens.xml
@@ -14,4 +14,11 @@
   <dimen name="account_selection_favicon_border_size">1dp</dimen>
 
   <dimen name="account_selection_sheet_button_margin">2dp</dimen>
+
+  <dimen name="account_selection_continue_icon_size">24dp</dimen>
+  <!-- Value chosen so that the text is centered in the button.
+    paddingStart (10dp)
+    + icon account_selection_continue_icon_size (24dp)
+    + drawablePadding (5dp) -->
+  <dimen name="account_selection_continue_padding_end">39dp</dimen>
 </resources>
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java
index 6132254..97d5e81 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java
@@ -4,8 +4,11 @@
 
 package org.chromium.chrome.browser.ui.android.webid;
 
+import android.content.res.Resources;
+
 import androidx.annotation.Nullable;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.browser.ui.android.webid.data.Account;
@@ -35,6 +38,19 @@
     }
 
     @CalledByNative
+    private static int getBrandIconMinimumSize() {
+        // Icon needs to be big enough for the smallest screen density (1x).
+        Resources resources = ContextUtils.getApplicationContext().getResources();
+        return Math.round(getBrandIconIdealSize() / resources.getDisplayMetrics().density);
+    }
+
+    @CalledByNative
+    private static int getBrandIconIdealSize() {
+        Resources resources = ContextUtils.getApplicationContext().getResources();
+        return Math.round(resources.getDimension(R.dimen.account_selection_continue_icon_size));
+    }
+
+    @CalledByNative
     private static @Nullable AccountSelectionBridge create(
             long nativeView, WindowAndroid windowAndroid) {
         BottomSheetController bottomSheetController =
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java
index 89e33d9..4e03e14 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java
@@ -98,7 +98,7 @@
             "Sam E. Goto", "Sam", TEST_PROFILE_PIC, /*isSignIn=*/false);
 
     private static final IdentityProviderMetadata IDP_METADATA =
-            new IdentityProviderMetadata(Color.BLACK, Color.BLACK);
+            new IdentityProviderMetadata(Color.BLACK, Color.BLACK, null);
     private static final ClientIdMetadata CLIENT_ID_METADATA =
             new ClientIdMetadata(TEST_URL_TERMS_OF_SERVICE, TEST_URL_PRIVACY_POLICY);
 
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTest.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTest.java
index ffc8476a..c1e2f4d 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTest.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTest.java
@@ -98,7 +98,7 @@
     private static final Account BOB = new Account("Bob", "", "Bob", "", TEST_PROFILE_PIC, false);
 
     private static final IdentityProviderMetadata IDP_METADATA =
-            new IdentityProviderMetadata(Color.BLACK, Color.BLACK);
+            new IdentityProviderMetadata(Color.BLACK, Color.BLACK, null);
     private static final ClientIdMetadata CLIENT_ID_METADATA =
             new ClientIdMetadata(TEST_URL_TERMS_OF_SERVICE, TEST_URL_PRIVACY_POLICY);
 
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java
index 83021bd..6d40e5c 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java
@@ -237,6 +237,17 @@
                     }
                     button.setTextColor(textColor);
                 }
+
+                Bitmap brandIcon = idpMetadata.getBrandIcon();
+                if (brandIcon != null) {
+                    Resources resources = context.getResources();
+                    int avatarSize = resources.getDimensionPixelSize(
+                            R.dimen.account_selection_continue_icon_size);
+                    Drawable croppedBrandIcon =
+                            AvatarGenerator.makeRoundAvatar(resources, brandIcon, avatarSize);
+                    button.setCompoundDrawablesWithIntrinsicBounds(
+                            croppedBrandIcon, null, null, null);
+                }
             }
         } else if (key == ContinueButtonProperties.ACCOUNT) {
             Account account = model.get(ContinueButtonProperties.ACCOUNT);
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java
index f069dfd..0fccfdf 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java
@@ -6,6 +6,8 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
@@ -14,6 +16,10 @@
 
 import static java.util.Arrays.asList;
 
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.text.Spanned;
 import android.text.style.ClickableSpan;
 import android.view.View;
@@ -42,6 +48,7 @@
 import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.HeaderProperties;
 import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.HeaderProperties.HeaderType;
 import org.chromium.chrome.browser.ui.android.webid.data.Account;
+import org.chromium.chrome.browser.ui.android.webid.data.IdentityProviderMetadata;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.browser.test.util.TouchCommon;
@@ -175,7 +182,7 @@
                                     .with(AccountProperties.ON_CLICK_LISTENER, null)
                                     .build());
 
-            mSheetItems.addAll(asList(account_without_callback, buildContinueButton(ANA)));
+            mSheetItems.addAll(asList(account_without_callback, buildContinueButton(ANA, null)));
         });
         pollUiThread(() -> mContentView.getVisibility() == View.VISIBLE);
 
@@ -252,6 +259,46 @@
         assertEquals("Expected two clickable links", 2, spans.length);
     }
 
+    /**
+     * Tests that the brand foreground and the brand icon are used in the "Continue" button.
+     */
+    @Test
+    @MediumTest
+    public void testContinueButtonBranding() {
+        final int expectedTextColor = Color.BLUE;
+        final int expectedIconColor = Color.RED;
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            Bitmap brandIcon = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+            brandIcon.eraseColor(expectedIconColor);
+            IdentityProviderMetadata idpMetadata = new IdentityProviderMetadata(
+                    expectedTextColor, /*brandBackgroundColor*/ Color.GREEN, brandIcon);
+
+            mSheetItems.addAll(Collections.singletonList(buildContinueButton(ANA, idpMetadata)));
+        });
+
+        pollUiThread(() -> mContentView.getVisibility() == View.VISIBLE);
+
+        assertNotNull(getAccounts().getChildAt(0));
+        TextView continueButton = mContentView.findViewById(R.id.account_selection_continue_btn);
+
+        assertEquals(expectedTextColor, continueButton.getTextColors().getDefaultColor());
+
+        Drawable[] compoundDrawables = continueButton.getCompoundDrawables();
+        assertEquals(4, compoundDrawables.length);
+
+        assertTrue(compoundDrawables[0] instanceof BitmapDrawable);
+        Bitmap actualBrandIconBitmap = ((BitmapDrawable) compoundDrawables[0]).getBitmap();
+        // AccountSelectionViewBinder crops the brand icon in a circle. Test a pixel in the middle
+        // of the icon which is unaffected by the cropping.
+        int centerX = actualBrandIconBitmap.getWidth() / 2;
+        int centerY = actualBrandIconBitmap.getHeight() / 2;
+        assertEquals(expectedIconColor, actualBrandIconBitmap.getColor(centerX, centerY).toArgb());
+
+        assertNull(compoundDrawables[1]);
+        assertNull(compoundDrawables[2]);
+        assertNull(compoundDrawables[3]);
+    }
+
     private RecyclerView getAccounts() {
         return mContentView.findViewById(R.id.sheet_item_list);
     }
@@ -277,12 +324,18 @@
                         .build());
     }
 
-    private MVCListAdapter.ListItem buildContinueButton(Account account) {
-        return new MVCListAdapter.ListItem(AccountSelectionProperties.ItemType.CONTINUE_BUTTON,
+    private MVCListAdapter.ListItem buildContinueButton(
+            Account account, IdentityProviderMetadata idpMetadata) {
+        PropertyModel.Builder modelBuilder =
                 new PropertyModel.Builder(ContinueButtonProperties.ALL_KEYS)
                         .with(ContinueButtonProperties.ACCOUNT, account)
-                        .with(ContinueButtonProperties.ON_CLICK_LISTENER, mAccountCallback)
-                        .build());
+                        .with(ContinueButtonProperties.ON_CLICK_LISTENER, mAccountCallback);
+        if (idpMetadata != null) {
+            modelBuilder.with(ContinueButtonProperties.IDP_METADATA, idpMetadata);
+        }
+
+        return new MVCListAdapter.ListItem(
+                AccountSelectionProperties.ItemType.CONTINUE_BUTTON, modelBuilder.build());
     }
 
     private MVCListAdapter.ListItem buildCancelButton() {
diff --git a/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/data/IdentityProviderMetadata.java b/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/data/IdentityProviderMetadata.java
index da5be5c..86ac1f8 100644
--- a/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/data/IdentityProviderMetadata.java
+++ b/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/data/IdentityProviderMetadata.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.ui.android.webid.data;
 
+import android.graphics.Bitmap;
+
 import androidx.annotation.Nullable;
 
 import org.chromium.base.annotations.CalledByNative;
@@ -15,15 +17,18 @@
 public class IdentityProviderMetadata {
     private final Integer mBrandTextColor;
     private final Integer mBrandBackgroundColor;
+    private final Bitmap mBrandIcon;
 
     @CalledByNative
-    public IdentityProviderMetadata(long brandTextColor, long brandBackgroundColor) {
+    public IdentityProviderMetadata(
+            long brandTextColor, long brandBackgroundColor, Bitmap brandIcon) {
         // Parameters are longs because ColorUtils.INVALID_COLOR does not fit in an int.
         mBrandTextColor =
                 (brandTextColor == ColorUtils.INVALID_COLOR) ? null : (int) brandTextColor;
         mBrandBackgroundColor = (brandBackgroundColor == ColorUtils.INVALID_COLOR)
                 ? null
                 : (int) brandBackgroundColor;
+        mBrandIcon = brandIcon;
     }
 
     public @Nullable Integer getBrandTextColor() {
@@ -33,4 +38,8 @@
     public @Nullable Integer getBrandBackgroundColor() {
         return mBrandBackgroundColor;
     }
+
+    public Bitmap getBrandIcon() {
+        return mBrandIcon;
+    }
 }
diff --git a/chrome/browser/ui/app_list/search/ranking/ranker_delegate.h b/chrome/browser/ui/app_list/search/ranking/ranker_delegate.h
index 6c6bfc77..d9851a5 100644
--- a/chrome/browser/ui/app_list/search/ranking/ranker_delegate.h
+++ b/chrome/browser/ui/app_list/search/ranking/ranker_delegate.h
@@ -22,8 +22,7 @@
 // behavior.
 class RankerDelegate : public Ranker {
  public:
-  RankerDelegate(Profile* profile,
-                 SearchController* controller);
+  RankerDelegate(Profile* profile, SearchController* controller);
   ~RankerDelegate() override;
 
   RankerDelegate(const RankerDelegate&) = delete;
diff --git a/chrome/browser/ui/app_list/search/search_controller_impl_new.cc b/chrome/browser/ui/app_list/search/search_controller_impl_new.cc
index 4957c457..2a67b7f 100644
--- a/chrome/browser/ui/app_list/search/search_controller_impl_new.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_impl_new.cc
@@ -70,6 +70,9 @@
 
 void SearchControllerImplNew::StartZeroState(base::OnceClosure on_done,
                                              base::TimeDelta timeout) {
+  // Categories currently are not used by zero-state, but may be required for
+  // sorting in SetResults.
+  categories_ = CreateAllCategories();
   base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, std::move(on_done), timeout);
 }
@@ -161,7 +164,15 @@
   ranker_->UpdateResultRanks(results_, provider_type);
   ranker_->UpdateCategoryRanks(results_, categories_, provider_type);
 
-  // Compile a single list of results and sort by their relevance.
+  // Sort categories and create a vector of category enums in display order.
+  std::sort(categories_.begin(), categories_.end(),
+            [](const auto& a, const auto& b) { return a.score > b.score; });
+  std::vector<Category> category_enums;
+  for (const auto& category : categories_)
+    category_enums.push_back(category.category);
+
+  // Compile a single list of results and sort first by their category with best
+  // match first, and then by relevance.
   std::vector<ChromeSearchResult*> all_results;
   for (const auto& type_results : results_) {
     for (const auto& result : type_results.second) {
@@ -186,17 +197,32 @@
       all_results.push_back(result.get());
     }
   }
-  std::sort(all_results.begin(), all_results.end(),
-            [](const ChromeSearchResult* a, const ChromeSearchResult* b) {
-              return a->display_score() > b->display_score();
-            });
 
-  // Create a vector of categories in display order.
-  std::sort(categories_.begin(), categories_.end(),
-            [](const auto& a, const auto& b) { return a.score > b.score; });
-  std::vector<Category> category_enums;
-  for (const auto& category : categories_)
-    category_enums.push_back(category.category);
+  std::sort(all_results.begin(), all_results.end(),
+            [&](const ChromeSearchResult* a, const ChromeSearchResult* b) {
+              if (a->best_match() != b->best_match()) {
+                // First, sort best matches to the front of the list.
+                return a->best_match();
+              } else if (!a->best_match() && a->category() != b->category()) {
+                // Next, sort by categories, except for within best match.
+                // |categories_| has been sorted above so the first category in
+                // |categories_| should be ranked more highly.
+                for (const auto& category : categories_) {
+                  if (category.category == a->category()) {
+                    return true;
+                  } else if (category.category == b->category()) {
+                    return false;
+                  }
+                }
+                // Any category associated with a result should also be present
+                // in |categories_|.
+                NOTREACHED();
+                return false;
+              } else {
+                // Lastly, sort by display score.
+                return a->display_score() > b->display_score();
+              }
+            });
 
   if (!observer_list_.empty()) {
     std::vector<const ChromeSearchResult*> observer_results;
diff --git a/chrome/browser/ui/app_list/search/search_controller_impl_new.h b/chrome/browser/ui/app_list/search/search_controller_impl_new.h
index 7f6bb96c..b1206da 100644
--- a/chrome/browser/ui/app_list/search/search_controller_impl_new.h
+++ b/chrome/browser/ui/app_list/search/search_controller_impl_new.h
@@ -16,6 +16,7 @@
 #include "base/observer_list.h"
 #include "chrome/browser/ui/app_list/search/mixer.h"
 #include "chrome/browser/ui/app_list/search/ranking/launch_data.h"
+#include "chrome/browser/ui/app_list/search/ranking/ranker_delegate.h"
 #include "chrome/browser/ui/app_list/search/search_controller.h"
 
 class AppListControllerDelegate;
@@ -32,7 +33,6 @@
 
 class SearchMetricsObserver;
 class SearchProvider;
-class RankerDelegate;
 enum class RankingItemType;
 
 // TODO(crbug.com/1199206): This is the new implementation of the search
@@ -82,6 +82,11 @@
   std::u16string get_query() override;
   base::Time session_start() override;
 
+  void set_ranker_delegate_for_test(
+      std::unique_ptr<RankerDelegate> ranker_delegate) {
+    ranker_ = std::move(ranker_delegate);
+  }
+
  private:
   Profile* profile_;
 
diff --git a/chrome/browser/ui/app_list/search/search_controller_impl_new_unittest.cc b/chrome/browser/ui/app_list/search/search_controller_impl_new_unittest.cc
new file mode 100644
index 0000000..5c6241f
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/search_controller_impl_new_unittest.cc
@@ -0,0 +1,191 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/app_list/search/search_controller_impl_new.h"
+
+#include <memory>
+#include <vector>
+
+#include "ash/public/cpp/app_list/app_list_features.h"
+#include "ash/public/cpp/app_list/app_list_types.h"
+#include "ash/public/cpp/test/shell_test_api.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ui/app_list/search/chrome_search_result.h"
+#include "chrome/browser/ui/app_list/search/ranking/ranker_delegate.h"
+#include "chrome/browser/ui/app_list/search/search_controller.h"
+#include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h"
+#include "chrome/test/base/chrome_ash_test_base.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/browser_task_environment.h"
+
+namespace app_list {
+namespace {
+
+using Category = ash::AppListSearchResultCategory;
+
+class TestSearchResult : public ChromeSearchResult {
+ public:
+  TestSearchResult(const std::string& id,
+                   Category category,
+                   bool best_match,
+                   double relevance) {
+    set_id(id);
+    SetCategory(category);
+    SetBestMatch(best_match);
+    set_relevance(relevance);
+    scoring().normalized_relevance = relevance;
+  }
+
+  TestSearchResult(const TestSearchResult&) = delete;
+  TestSearchResult& operator=(const TestSearchResult&) = delete;
+  ~TestSearchResult() override = default;
+
+ private:
+  void Open(int event_flags) override { NOTIMPLEMENTED(); }
+};
+
+// A test ranker delegate that circumvents all result rankings, and hardcodes
+// category ranking.
+class TestRankerDelegate : public RankerDelegate {
+ public:
+  explicit TestRankerDelegate(Profile* profile)
+      : RankerDelegate(profile, nullptr) {}
+  ~TestRankerDelegate() override {}
+
+  TestRankerDelegate(const TestRankerDelegate&) = delete;
+  TestRankerDelegate& operator=(const TestRankerDelegate&) = delete;
+
+  void SetCategoryRanks(base::flat_map<Category, double> category_ranks) {
+    category_ranks_ = category_ranks;
+  }
+
+  // Ranker:
+  void UpdateResultRanks(ResultsMap& results, ProviderType provider) override {
+    // Noop.
+  }
+
+  // Ranker:
+  void UpdateCategoryRanks(const ResultsMap& results,
+                           CategoriesList& categories,
+                           ProviderType provider) override {
+    for (auto& category : categories) {
+      const auto it = category_ranks_.find(category.category);
+      if (it != category_ranks_.end())
+        category.score = it->second;
+    }
+  }
+
+  // Ranker:
+  void Start(const std::u16string& query,
+             ResultsMap& results,
+             CategoriesList& categories) override {}
+  void Train(const LaunchData& launch) override {}
+  void Remove(ChromeSearchResult* result) override {}
+
+ private:
+  base::flat_map<Category, double> category_ranks_;
+};
+
+std::vector<std::unique_ptr<ChromeSearchResult>> MakeResults(
+    std::vector<std::string> ids,
+    std::vector<Category> categories,
+    std::vector<bool> best_matches,
+    std::vector<double> scores) {
+  std::vector<std::unique_ptr<ChromeSearchResult>> results;
+  for (size_t i = 0; i < ids.size(); ++i) {
+    results.emplace_back(std::make_unique<TestSearchResult>(
+        ids[i], categories[i], best_matches[i], scores[i]));
+  }
+  return results;
+}
+
+}  // namespace
+
+class SearchControllerImplNewTest : public testing::Test {
+ public:
+  SearchControllerImplNewTest() = default;
+  SearchControllerImplNewTest(const SearchControllerImplNewTest&) = delete;
+  SearchControllerImplNewTest& operator=(const SearchControllerImplNewTest&) =
+      delete;
+  ~SearchControllerImplNewTest() override = default;
+
+  void SetUp() override {
+    // TODO(crbug.com/1258415): Feature list can be removed after launch.
+    scoped_feature_list_.InitWithFeatures(
+        {app_list_features::kCategoricalSearch}, {});
+
+    search_controller_ = std::make_unique<SearchControllerImplNew>(
+        /*model_updater=*/&model_updater_, /*list_controller=*/nullptr,
+        /*notifier=*/nullptr, &profile_);
+
+    auto ranker_delegate = std::make_unique<TestRankerDelegate>(&profile_);
+    ranker_delegate_ = ranker_delegate.get();
+    search_controller_->set_ranker_delegate_for_test(
+        std::move(ranker_delegate));
+  }
+
+  void ExpectIdOrder(std::vector<std::string> id_order) {
+    const auto& sorted_results = model_updater_.search_results();
+    ASSERT_EQ(sorted_results.size(), id_order.size());
+    for (size_t i = 0; i < sorted_results.size(); ++i)
+      EXPECT_EQ(sorted_results[i]->id(), id_order[i]);
+  }
+
+  void Wait() { task_environment_.RunUntilIdle(); }
+
+ protected:
+  content::BrowserTaskEnvironment task_environment_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+  TestingProfile profile_;
+  FakeAppListModelUpdater model_updater_{&profile_, /*order_delegate=*/nullptr};
+  std::unique_ptr<SearchControllerImplNew> search_controller_;
+  // Owned by |search_controller_|.
+  TestRankerDelegate* ranker_delegate_{nullptr};
+};
+
+// Tests that categories are ordered correctly, and their results are grouped
+// together and ordered by score.
+TEST_F(SearchControllerImplNewTest, CategoriesOrderedCorrectly) {
+  ranker_delegate_->SetCategoryRanks(
+      {{Category::kFiles, 0.3}, {Category::kWeb, 0.2}, {Category::kApps, 0.1}});
+  auto file_results = MakeResults({"a"}, {Category::kFiles}, {false}, {0.9});
+  auto web_results = MakeResults(
+      {"c", "d", "b"}, {Category::kWeb, Category::kWeb, Category::kWeb},
+      {false, false, false}, {0.2, 0.1, 0.4});
+  auto app_results = MakeResults({"e"}, {Category::kApps}, {false}, {0.1});
+
+  // Simulate starting a search.
+  search_controller_->StartSearch(u"abc");
+  // Simulate several providers returning results.
+  search_controller_->SetResults(ash::AppListSearchResultType::kOmnibox,
+                                 std::move(web_results));
+  search_controller_->SetResults(ash::AppListSearchResultType::kInstalledApp,
+                                 std::move(app_results));
+  search_controller_->SetResults(ash::AppListSearchResultType::kFileSearch,
+                                 std::move(file_results));
+
+  ExpectIdOrder({"a", "b", "c", "d", "e"});
+}
+
+// Tests that best matches are ordered first, and categories are ignored when
+// ranking within best match.
+TEST_F(SearchControllerImplNewTest, BestMatchesOrderedAboveOtherResults) {
+  auto results = MakeResults(
+      {"a", "b", "c", "d"},
+      {Category::kWeb, Category::kWeb, Category::kApps, Category::kWeb},
+      {true, false, true, false}, {0.4, 0.8, 0.2, 0.9});
+  ranker_delegate_->SetCategoryRanks(
+      {{Category::kApps, 0.4}, {Category::kWeb, 0.2}});
+
+  search_controller_->StartSearch(u"abc");
+  // Simulate a provider returning and containing all of the above results. A
+  // single provider wouldn't return many results like this, but that's
+  // unimportant for the test.
+  search_controller_->SetResults(ash::AppListSearchResultType::kOmnibox,
+                                 std::move(results));
+
+  ExpectIdOrder({"a", "c", "d", "b"});
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_controller_unittest.cc b/chrome/browser/ui/app_list/search/search_controller_impl_unittest.cc
similarity index 85%
rename from chrome/browser/ui/app_list/search/search_controller_unittest.cc
rename to chrome/browser/ui/app_list/search/search_controller_impl_unittest.cc
index 8fd490c..97cd453f 100644
--- a/chrome/browser/ui/app_list/search/search_controller_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_impl_unittest.cc
@@ -31,14 +31,15 @@
   void Open(int event_flags) override { NOTIMPLEMENTED(); }
 };
 
-// SearchControllerTest --------------------------------------------------------
+// SearchControllerImplTest
+// --------------------------------------------------------
 
-class SearchControllerTest : public ChromeAshTestBase {
+class SearchControllerImplTest : public ChromeAshTestBase {
  public:
-  SearchControllerTest() = default;
-  SearchControllerTest(const SearchControllerTest&) = delete;
-  SearchControllerTest& operator=(const SearchControllerTest&) = delete;
-  ~SearchControllerTest() override = default;
+  SearchControllerImplTest() = default;
+  SearchControllerImplTest(const SearchControllerImplTest&) = delete;
+  SearchControllerImplTest& operator=(const SearchControllerImplTest&) = delete;
+  ~SearchControllerImplTest() override = default;
 
   SearchController& search_controller() { return search_controller_; }
   TestAppListControllerDelegate& list_controller() { return list_controller_; }
@@ -52,7 +53,8 @@
 
 // Tests -----------------------------------------------------------------------
 
-TEST_F(SearchControllerTest, ShouldConditionallyDismissViewWhenOpeningResult) {
+TEST_F(SearchControllerImplTest,
+       ShouldConditionallyDismissViewWhenOpeningResult) {
   struct TestCase {
     bool is_tablet_mode = false;
     bool request_to_dismiss_view = false;
diff --git a/chrome/browser/ui/bluetooth/chrome_bluetooth_chooser_controller.cc b/chrome/browser/ui/bluetooth/chrome_bluetooth_chooser_controller.cc
index 9f08367..46718b7b 100644
--- a/chrome/browser/ui/bluetooth/chrome_bluetooth_chooser_controller.cc
+++ b/chrome/browser/ui/bluetooth/chrome_bluetooth_chooser_controller.cc
@@ -19,6 +19,7 @@
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/referrer.h"
 #include "ui/base/page_transition_types.h"
@@ -87,7 +88,8 @@
 #if defined(OS_MAC)
   if (web_contents_) {
     ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
-        GURL(kBluetoothSettingsUri), web_contents_.get());
+        GURL(kBluetoothSettingsUri), web_contents_.get(),
+        content::WeakDocumentPtr());
   }
 #else
   NOTREACHED();
diff --git a/chrome/browser/ui/cocoa/window_size_autosaver.mm b/chrome/browser/ui/cocoa/window_size_autosaver.mm
index 536484f..6938a16c 100644
--- a/chrome/browser/ui/cocoa/window_size_autosaver.mm
+++ b/chrome/browser/ui/cocoa/window_size_autosaver.mm
@@ -54,57 +54,62 @@
 
 - (void)save:(NSNotification*)notification {
   DictionaryPrefUpdate update(_prefService, _path);
-  base::DictionaryValue* windowPrefs = update.Get();
+  base::Value* windowPrefs = update.Get();
   NSRect frame = [_window frame];
   if ([_window styleMask] & NSResizableWindowMask) {
     // Save the origin of the window.
-    windowPrefs->SetInteger("left", NSMinX(frame));
-    windowPrefs->SetInteger("right", NSMaxX(frame));
+    windowPrefs->SetIntKey("left", NSMinX(frame));
+    windowPrefs->SetIntKey("right", NSMaxX(frame));
     // windows's and linux's profiles have top < bottom due to having their
     // screen origin in the upper left, while cocoa's is in the lower left. To
     // keep the top < bottom invariant, store top in bottom and vice versa.
-    windowPrefs->SetInteger("top", NSMinY(frame));
-    windowPrefs->SetInteger("bottom", NSMaxY(frame));
+    windowPrefs->SetIntKey("top", NSMinY(frame));
+    windowPrefs->SetIntKey("bottom", NSMaxY(frame));
   } else {
     // Save the origin of the window.
-    windowPrefs->SetInteger("x", frame.origin.x);
-    windowPrefs->SetInteger("y", frame.origin.y);
+    windowPrefs->SetIntKey("x", frame.origin.x);
+    windowPrefs->SetIntKey("y", frame.origin.y);
   }
 }
 
 - (void)restore {
   // Get the positioning information.
-  const base::DictionaryValue* windowPrefs =
-      &base::Value::AsDictionaryValue(*_prefService->GetDictionary(_path));
+  const base::Value* windowPrefs = _prefService->GetDictionary(_path);
   if ([_window styleMask] & NSResizableWindowMask) {
-    int x1, x2, y1, y2;
-    if (!windowPrefs->GetInteger("left", &x1) ||
-        !windowPrefs->GetInteger("right", &x2) ||
-        !windowPrefs->GetInteger("top", &y1) ||
-        !windowPrefs->GetInteger("bottom", &y2)) {
+    absl::optional<int> x1 = windowPrefs->FindIntKey("left");
+    absl::optional<int> x2 = windowPrefs->FindIntKey("right");
+    absl::optional<int> y1 = windowPrefs->FindIntKey("top");
+    absl::optional<int> y2 = windowPrefs->FindIntKey("bottom");
+    if (!x1.has_value() || !x2.has_value() || !y1.has_value() ||
+        !y2.has_value()) {
       return;
     }
-    if (x2 - x1 < kMinWindowWidth || y2 - y1 < kMinWindowHeight) {
+    if (x2.value() - x1.value() < kMinWindowWidth ||
+        y2.value() - y1.value() < kMinWindowHeight) {
       // Windows should never be very small.
       DictionaryPrefUpdate update(_prefService, _path);
-      base::DictionaryValue* mutableWindowPrefs = update.Get();
+      base::Value* mutableWindowPrefs = update.Get();
       mutableWindowPrefs->RemoveKey("left");
       mutableWindowPrefs->RemoveKey("right");
       mutableWindowPrefs->RemoveKey("top");
       mutableWindowPrefs->RemoveKey("bottom");
     } else {
-      [_window setFrame:NSMakeRect(x1, y1, x2 - x1, y2 - y1) display:YES];
+      [_window
+          setFrame:NSMakeRect(x1.value(), y1.value(), x2.value() - x1.value(),
+                              y2.value() - y1.value())
+           display:YES];
 
       // Make sure the window is on-screen.
       [_window cascadeTopLeftFromPoint:NSZeroPoint];
     }
   } else {
-    int x, y;
-    if (!windowPrefs->GetInteger("x", &x) ||
-        !windowPrefs->GetInteger("y", &y))
-       return;  // Nothing stored.
+    absl::optional<int> x = windowPrefs->FindIntKey("x");
+    absl::optional<int> y = windowPrefs->FindIntKey("y");
+    if (!x.has_value() || !y.has_value())
+      return;  // Nothing stored.
     // Turn the origin (lower-left) into an upper-left window point.
-    NSPoint upperLeft = NSMakePoint(x, y + NSHeight([_window frame]));
+    NSPoint upperLeft =
+        NSMakePoint(x.value(), y.value() + NSHeight([_window frame]));
     [_window cascadeTopLeftFromPoint:upperLeft];
   }
 }
diff --git a/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm b/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
index c247d81..365ff61 100644
--- a/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
+++ b/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
@@ -96,18 +96,18 @@
   }
 
   // ...and it should be in the profile, too.
-  EXPECT_TRUE(pref->GetDictionary(path_));
-  int x, y;
-  const base::DictionaryValue* windowPref =
-      &base::Value::AsDictionaryValue(*pref->GetDictionary(path_));
-  EXPECT_FALSE(windowPref->GetInteger("left", &x));
-  EXPECT_FALSE(windowPref->GetInteger("right", &x));
-  EXPECT_FALSE(windowPref->GetInteger("top", &x));
-  EXPECT_FALSE(windowPref->GetInteger("bottom", &x));
-  ASSERT_TRUE(windowPref->GetInteger("x", &x));
-  ASSERT_TRUE(windowPref->GetInteger("y", &y));
-  EXPECT_EQ(300, x);
-  EXPECT_EQ(310, y);
+  const base::Value* windowPref = pref->GetDictionary(path_);
+  ASSERT_TRUE(windowPref);
+  EXPECT_FALSE(windowPref->FindIntKey("left").has_value());
+  EXPECT_FALSE(windowPref->FindIntKey("right").has_value());
+  EXPECT_FALSE(windowPref->FindIntKey("top").has_value());
+  EXPECT_FALSE(windowPref->FindIntKey("bottom").has_value());
+  absl::optional<int> x = windowPref->FindIntKey("x");
+  absl::optional<int> y = windowPref->FindIntKey("y");
+  ASSERT_TRUE(x.has_value());
+  ASSERT_TRUE(y.has_value());
+  EXPECT_EQ(300, x.value());
+  EXPECT_EQ(310, y.value());
 }
 
 TEST_F(WindowSizeAutosaverTest, RestoresAndSavesRect) {
@@ -157,19 +157,22 @@
 
   // ...and it should be in the profile, too.
   EXPECT_TRUE(pref->GetDictionary(path_));
-  int x1, y1, x2, y2;
-  const base::DictionaryValue* windowPref =
-      &base::Value::AsDictionaryValue(*pref->GetDictionary(path_));
-  EXPECT_FALSE(windowPref->GetInteger("x", &x1));
-  EXPECT_FALSE(windowPref->GetInteger("y", &x1));
-  ASSERT_TRUE(windowPref->GetInteger("left", &x1));
-  ASSERT_TRUE(windowPref->GetInteger("right", &x2));
-  ASSERT_TRUE(windowPref->GetInteger("top", &y1));
-  ASSERT_TRUE(windowPref->GetInteger("bottom", &y2));
-  EXPECT_EQ(300, x1);
-  EXPECT_EQ(310, y1);
-  EXPECT_EQ(300 + 250, x2);
-  EXPECT_EQ(310 + 252, y2);
+  const base::Value* windowPref = pref->GetDictionary(path_);
+  ASSERT_TRUE(windowPref);
+  EXPECT_FALSE(windowPref->FindIntKey("x").has_value());
+  EXPECT_FALSE(windowPref->FindIntKey("y").has_value());
+  absl::optional<int> x1 = windowPref->FindIntKey("left");
+  absl::optional<int> x2 = windowPref->FindIntKey("right");
+  absl::optional<int> y1 = windowPref->FindIntKey("top");
+  absl::optional<int> y2 = windowPref->FindIntKey("bottom");
+  ASSERT_TRUE(x1.has_value());
+  ASSERT_TRUE(x2.has_value());
+  ASSERT_TRUE(y1.has_value());
+  ASSERT_TRUE(y2.has_value());
+  EXPECT_EQ(300, x1.value());
+  EXPECT_EQ(310, y1.value());
+  EXPECT_EQ(300 + 250, x2.value());
+  EXPECT_EQ(310 + 252, y2.value());
 }
 
 // http://crbug.com/39625
@@ -178,11 +181,11 @@
   ASSERT_TRUE(pref);
 
   DictionaryPrefUpdate update(pref, path_);
-  base::DictionaryValue* windowPref = update.Get();
-  windowPref->SetInteger("left", 50);
-  windowPref->SetInteger("right", 50);
-  windowPref->SetInteger("top", 60);
-  windowPref->SetInteger("bottom", 60);
+  base::Value* windowPref = update.Get();
+  windowPref->SetIntKey("left", 50);
+  windowPref->SetIntKey("right", 50);
+  windowPref->SetIntKey("top", 60);
+  windowPref->SetIntKey("bottom", 60);
 
   {
     // Window rect shouldn't change...
@@ -199,13 +202,12 @@
 
   // ...and it should be gone from the profile, too.
   EXPECT_TRUE(pref->GetDictionary(path_));
-  int x1, y1, x2, y2;
-  EXPECT_FALSE(windowPref->GetInteger("x", &x1));
-  EXPECT_FALSE(windowPref->GetInteger("y", &x1));
-  ASSERT_FALSE(windowPref->GetInteger("left", &x1));
-  ASSERT_FALSE(windowPref->GetInteger("right", &x2));
-  ASSERT_FALSE(windowPref->GetInteger("top", &y1));
-  ASSERT_FALSE(windowPref->GetInteger("bottom", &y2));
+  EXPECT_FALSE(windowPref->FindIntKey("x").has_value());
+  EXPECT_FALSE(windowPref->FindIntKey("y").has_value());
+  ASSERT_FALSE(windowPref->FindIntKey("left").has_value());
+  ASSERT_FALSE(windowPref->FindIntKey("right").has_value());
+  ASSERT_FALSE(windowPref->FindIntKey("top").has_value());
+  ASSERT_FALSE(windowPref->FindIntKey("bottom").has_value());
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/color/BUILD.gn b/chrome/browser/ui/color/BUILD.gn
index 0eccf93..08e8c46 100644
--- a/chrome/browser/ui/color/BUILD.gn
+++ b/chrome/browser/ui/color/BUILD.gn
@@ -18,6 +18,8 @@
     "chrome_color_mixers.h",
     "chrome_color_provider_utils.cc",
     "chrome_color_provider_utils.h",
+    "native_chrome_color_mixer.cc",
+    "native_chrome_color_mixer.h",
     "omnibox_color_mixer.cc",
     "omnibox_color_mixer.h",
   ]
@@ -27,6 +29,10 @@
     "//ui/color:color",
     "//ui/color:mixers",
   ]
+
+  if (is_win) {
+    sources += [ "win/native_chrome_color_mixer_win.cc" ]
+  }
 }
 
 if (!is_ios && !is_android && !is_chromecast && !is_fuchsia) {
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h
index 5d60ba16..2212fd6 100644
--- a/chrome/browser/ui/color/chrome_color_id.h
+++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -56,11 +56,17 @@
     ThemeProperties::COLOR_OMNIBOX_SECURITY_CHIP_SECURE) \
   E(kColorOmniboxText, ThemeProperties::COLOR_OMNIBOX_TEXT) \
   E(kColorOmniboxTextDimmed, ThemeProperties::COLOR_OMNIBOX_TEXT_DIMMED) \
+  /* Tab output colors. */ \
+  E(kColorTabForegroundActiveFrameActive, \
+    ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE) \
+  E(kColorTabForegroundActiveFrameInactive, \
+    ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE) \
   /* Toolbar output colors. */ \
   E(kColorToolbar, ThemeProperties::COLOR_TOOLBAR) \
   E(kColorToolbarButtonIcon, ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON) \
   E(kColorToolbarContentAreaSeparator, \
-    ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR)
+    ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR) \
+  E(kColorToolbarText, ThemeProperties::COLOR_TOOLBAR_TEXT)
 
 #include "ui/color/color_id_macros.inc"
 
diff --git a/chrome/browser/ui/color/chrome_color_mixer.cc b/chrome/browser/ui/color/chrome_color_mixer.cc
index 7eea2018..0bf1481 100644
--- a/chrome/browser/ui/color/chrome_color_mixer.cc
+++ b/chrome/browser/ui/color/chrome_color_mixer.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/ui/color/chrome_color_mixer.h"
 
-#include "base/bind.h"
-#include "build/build_config.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/color/color_id.h"
@@ -22,13 +20,13 @@
   if (dark_mode) {
     mixer[kColorOmniboxBackground] = {gfx::kGoogleGrey900};
     mixer[kColorOmniboxText] = {SK_ColorWHITE};
-
     mixer[kColorToolbar] = {SkColorSetRGB(0x35, 0x36, 0x3A)};
+    mixer[kColorToolbarText] = {SK_ColorWHITE};
   } else {
     mixer[kColorOmniboxBackground] = {gfx::kGoogleGrey100};
     mixer[kColorOmniboxText] = {gfx::kGoogleGrey900};
-
     mixer[kColorToolbar] = {SK_ColorWHITE};
+    mixer[kColorToolbarText] = {gfx::kGoogleGrey800};
   }
 }
 
@@ -40,27 +38,16 @@
       key.color_mode == ui::ColorProviderManager::ColorMode::kDark;
   ui::ColorMixer& mixer = provider->AddMixer();
 
-#if defined(OS_WIN)
-  const bool high_contrast_mode =
-      key.contrast_mode == ui::ColorProviderManager::ContrastMode::kHigh;
-  if (high_contrast_mode) {
-    // High contrast uses system colors.
-    mixer[kColorOmniboxBackground] = {ui::kColorNativeBtnFace};
-    mixer[kColorOmniboxText] = {ui::kColorNativeBtnText};
-
-    mixer[kColorToolbar] = {ui::kColorNativeWindow};
-  } else {
-    AddBaseColors(dark_mode, mixer);
-  }
-#else
   AddBaseColors(dark_mode, mixer);
-#endif
 
-  // Download shelf colors.
+  mixer[kColorBookmarkText] = {kColorToolbarText};
   mixer[kColorDownloadShelf] = {kColorToolbar};
   mixer[kColorDownloadShelfButtonBackground] = {kColorDownloadShelf};
   mixer[kColorDownloadShelfButtonText] =
       ui::PickGoogleColor(ui::kColorAccent, kColorDownloadShelf,
                           color_utils::kMinimumReadableContrastRatio);
+  mixer[kColorTabForegroundActiveFrameActive] = {kColorToolbarText};
+  mixer[kColorTabForegroundActiveFrameInactive] = {
+      kColorTabForegroundActiveFrameActive};
   mixer[kColorToolbarContentAreaSeparator] = {ui::kColorSeparator};
 }
diff --git a/chrome/browser/ui/color/chrome_color_mixers.cc b/chrome/browser/ui/color/chrome_color_mixers.cc
index 14d1ba6..f3549552 100644
--- a/chrome/browser/ui/color/chrome_color_mixers.cc
+++ b/chrome/browser/ui/color/chrome_color_mixers.cc
@@ -5,11 +5,13 @@
 #include "chrome/browser/ui/color/chrome_color_mixers.h"
 
 #include "chrome/browser/ui/color/chrome_color_mixer.h"
+#include "chrome/browser/ui/color/native_chrome_color_mixer.h"
 #include "chrome/browser/ui/color/omnibox_color_mixer.h"
 
 void AddChromeColorMixers(ui::ColorProvider* provider,
                           const ui::ColorProviderManager::Key& key) {
   AddChromeColorMixer(provider, key);
+  AddNativeChromeColorMixer(provider, key);
   AddOmniboxColorMixer(provider, key);
 
   if (key.custom_theme) {
diff --git a/chrome/browser/ui/color/native_chrome_color_mixer.cc b/chrome/browser/ui/color/native_chrome_color_mixer.cc
new file mode 100644
index 0000000..4eb7302
--- /dev/null
+++ b/chrome/browser/ui/color/native_chrome_color_mixer.cc
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/color/native_chrome_color_mixer.h"
+
+#include "build/build_config.h"
+
+#if !defined(OS_WIN)
+void AddNativeChromeColorMixer(ui::ColorProvider* provider,
+                               const ui::ColorProviderManager::Key& key) {}
+#endif
diff --git a/chrome/browser/ui/color/native_chrome_color_mixer.h b/chrome/browser/ui/color/native_chrome_color_mixer.h
new file mode 100644
index 0000000..fef722b7
--- /dev/null
+++ b/chrome/browser/ui/color/native_chrome_color_mixer.h
@@ -0,0 +1,20 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_COLOR_NATIVE_CHROME_COLOR_MIXER_H_
+#define CHROME_BROWSER_UI_COLOR_NATIVE_CHROME_COLOR_MIXER_H_
+
+#include "ui/color/color_provider_manager.h"
+
+namespace ui {
+class ColorProvider;
+}
+
+// Adds a color mixer to |provider| that can override the default chrome colors.
+// This function should be implemented on a per-platform basis in relevant
+// subdirectories.
+void AddNativeChromeColorMixer(ui::ColorProvider* provider,
+                               const ui::ColorProviderManager::Key& key);
+
+#endif  // CHROME_BROWSER_UI_COLOR_NATIVE_CHROME_COLOR_MIXER_H_
diff --git a/chrome/browser/ui/color/win/native_chrome_color_mixer_win.cc b/chrome/browser/ui/color/win/native_chrome_color_mixer_win.cc
new file mode 100644
index 0000000..fbaca64
--- /dev/null
+++ b/chrome/browser/ui/color/win/native_chrome_color_mixer_win.cc
@@ -0,0 +1,27 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/color/native_chrome_color_mixer.h"
+
+#include "chrome/browser/ui/color/chrome_color_id.h"
+#include "ui/color/color_id.h"
+#include "ui/color/color_mixer.h"
+#include "ui/color/color_provider.h"
+#include "ui/color/color_provider_manager.h"
+#include "ui/color/color_recipe.h"
+
+void AddNativeChromeColorMixer(ui::ColorProvider* provider,
+                               const ui::ColorProviderManager::Key& key) {
+  if (key.contrast_mode != ui::ColorProviderManager::ContrastMode::kHigh)
+    return;
+
+  ui::ColorMixer& mixer = provider->AddMixer();
+
+  // High contrast uses system colors.
+  mixer[kColorOmniboxBackground] = {ui::kColorNativeBtnFace};
+  mixer[kColorOmniboxText] = {ui::kColorNativeBtnText};
+  mixer[kColorToolbar] = {ui::kColorNativeWindow};
+  mixer[kColorToolbarText] = {ui::kColorNativeBtnText};
+  mixer[kColorTabForegroundActiveFrameActive] = {ui::kColorNativeHighlightText};
+}
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index df80cdd..6d47b2c 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -67,6 +67,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
@@ -887,10 +888,10 @@
 
     if (CameraAccessed()) {
       ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
-          GURL(kCameraSettingsURI), web_contents());
+          GURL(kCameraSettingsURI), web_contents(), content::WeakDocumentPtr());
     } else if (MicrophoneAccessed()) {
       ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
-          GURL(kMicSettingsURI), web_contents());
+          GURL(kMicSettingsURI), web_contents(), content::WeakDocumentPtr());
     }
     return;
 #endif  // defined(OS_MAC)
@@ -1268,7 +1269,7 @@
     }
 
     ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
-        GURL(kLocationSettingsURI), web_contents());
+        GURL(kLocationSettingsURI), web_contents(), content::WeakDocumentPtr());
     return;
 #endif  // defined(OS_MAC)
   }
diff --git a/chrome/browser/ui/profile_picker.h b/chrome/browser/ui/profile_picker.h
index 6d48eb1e..0c11b39 100644
--- a/chrome/browser/ui/profile_picker.h
+++ b/chrome/browser/ui/profile_picker.h
@@ -7,6 +7,7 @@
 
 #include "base/callback_forward.h"
 #include "base/feature_list.h"
+#include "base/files/file_path.h"
 #include "base/time/time.h"
 #include "chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h"
 #include "components/signin/public/base/signin_buildflags.h"
@@ -16,11 +17,6 @@
 
 class GURL;
 class Profile;
-
-namespace base {
-class FilePath;
-}  // namespace base
-
 namespace content {
 class BrowserContext;
 }
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
index 50ce688..27300cb 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -391,6 +391,9 @@
       inner_labels_.push_back(label);
   }
 
+  // Returns the string to be set as the name of the ui::AXNodeData.
+  std::u16string GetVoiceOverString();
+
  private:
   // Returns a vector of optional labels to be displayed beneath value.
   virtual std::vector<std::unique_ptr<views::View>> CreateSubtextViews();
@@ -585,38 +588,8 @@
 void AutofillPopupItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
   base::WeakPtr<AutofillPopupController> controller =
       popup_view()->controller();
-  std::vector<std::u16string> text;
 
-  auto suggestion = controller->GetSuggestionAt(GetLineNumber());
-  std::u16string icon_name = GetIconAccessibleName(suggestion.icon);
-  if (!icon_name.empty())
-    text.push_back(icon_name);
-
-  auto main_text = controller->GetSuggestionMainTextAt(GetLineNumber());
-  text.push_back(main_text);
-
-  auto minor_text = controller->GetSuggestionMinorTextAt(GetLineNumber());
-  if (!minor_text.empty())
-    text.push_back(minor_text);
-
-  auto label_text = controller->GetSuggestionLabelAt(GetLineNumber());
-  if (!label_text.empty()) {
-    // |label| is not populated for footers or autocomplete entries.
-    text.push_back(label_text);
-  }
-
-  // TODO(siyua): GetSuggestionLabelAt should return a vector of strings.
-  if (!suggestion.offer_label.empty()) {
-    // |offer_label| is only populated for credit card suggestions.
-    text.push_back(suggestion.offer_label);
-  }
-
-  if (!suggestion.additional_label.empty()) {
-    // |additional_label| is only populated in a passwords context.
-    text.push_back(suggestion.additional_label);
-  }
-
-  node_data->SetName(base::JoinString(text, u" "));
+  node_data->SetName(GetVoiceOverString());
 
   // Options are selectable.
   node_data->role = ax::mojom::Role::kListBoxOption;
@@ -903,6 +876,47 @@
                          /*use_min_size=*/true);
 }
 
+std::u16string AutofillPopupItemView::GetVoiceOverString() {
+  base::WeakPtr<AutofillPopupController> controller =
+      popup_view()->controller();
+
+  auto suggestion = controller->GetSuggestionAt(GetLineNumber());
+
+  if (suggestion.voice_over)
+    return *suggestion.voice_over;
+
+  std::vector<std::u16string> text;
+  std::u16string icon_name = GetIconAccessibleName(suggestion.icon);
+  if (!icon_name.empty())
+    text.push_back(icon_name);
+
+  auto main_text = controller->GetSuggestionMainTextAt(GetLineNumber());
+  text.push_back(main_text);
+
+  auto minor_text = controller->GetSuggestionMinorTextAt(GetLineNumber());
+  if (!minor_text.empty())
+    text.push_back(minor_text);
+
+  auto label_text = controller->GetSuggestionLabelAt(GetLineNumber());
+  if (!label_text.empty()) {
+    // |label| is not populated for footers or autocomplete entries.
+    text.push_back(label_text);
+  }
+
+  // TODO(siyua): GetSuggestionLabelAt should return a vector of strings.
+  if (!suggestion.offer_label.empty()) {
+    // |offer_label| is only populated for credit card suggestions.
+    text.push_back(suggestion.offer_label);
+  }
+
+  if (!suggestion.additional_label.empty()) {
+    // |additional_label| is only populated in a passwords context.
+    text.push_back(suggestion.additional_label);
+  }
+
+  return base::JoinString(text, u" ");
+}
+
 /************** AutofillPopupSuggestionView **************/
 
 // static
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
index d5c14405..34951245 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
@@ -292,6 +292,33 @@
   widget_->OnMouseEvent(&click_mouse_event);
 }
 
+// Ensure that the voice_over value of suggestions is presented to the
+// accessibility layer.
+TEST_F(AutofillPopupViewNativeViewsTest, VoiceOverTest) {
+  const std::u16string voice_over_value = u"Password for user@gmail.com";
+  // Create a realistic suggestion for a password.
+  autofill::Suggestion suggestion(u"user@gmail.com");
+  suggestion.is_value_secondary = false;
+  suggestion.label = u"example.com";
+  suggestion.voice_over = voice_over_value;
+  suggestion.additional_label = u"\u2022\u2022\u2022\u2022";
+  suggestion.frontend_id = autofill::POPUP_ITEM_ID_USERNAME_ENTRY;
+
+  // Create autofill menu.
+  autofill_popup_controller_.set_suggestions({suggestion});
+  view_ = std::make_unique<autofill::AutofillPopupViewNativeViews>(
+      autofill_popup_controller_.GetWeakPtr(), widget_.get());
+  widget_->SetContentsView(view_.get());
+  widget_->Show();
+  view_->Show();
+
+  // Verify that the accessibility layer gets the right string to read out.
+  ui::AXNodeData node_data;
+  view_->GetRowsForTesting()[0]->GetAccessibleNodeData(&node_data);
+  EXPECT_EQ(voice_over_value,
+            node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
+}
+
 // Tests that (only) clickable items trigger an AcceptSuggestion event.
 TEST_P(AutofillPopupViewNativeViewsTestWithAnyPopupItemId, ShowClickTest) {
   CreateAndShowView({popup_item_id()});
diff --git a/chrome/browser/ui/views/chrome_typography_provider.cc b/chrome/browser/ui/views/chrome_typography_provider.cc
index 1e07f94..c7121bc7 100644
--- a/chrome/browser/ui/views/chrome_typography_provider.cc
+++ b/chrome/browser/ui/views/chrome_typography_provider.cc
@@ -129,13 +129,11 @@
   if (context == CONTEXT_DOWNLOAD_SHELF ||
       (context == CONTEXT_DOWNLOAD_SHELF_STATUS &&
        style == views::style::STYLE_DISABLED)) {
-    // TODO(pkasting): Instead of reusing COLOR_BOOKMARK_TEXT, use dedicated
-    // values.
     const auto* theme_provider = view.GetThemeProvider();
     if (!theme_provider)
       return gfx::kPlaceholderColor;
     const SkColor base_color =
-        theme_provider->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT);
+        theme_provider->GetColor(ThemeProperties::COLOR_TOOLBAR_TEXT);
     // TODO(pkasting): Should use some way of dimming text that's as analogous
     // as possible to e.g. enabled vs. disabled labels.
     const SkColor dimmed_color = SkColorSetA(base_color, 0xC7);
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc
index 4394b52..88cf0de 100644
--- a/chrome/browser/ui/views/download/download_item_view.cc
+++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -320,6 +320,7 @@
   file_name_label_ = AddChildView(std::make_unique<views::Label>());
   file_name_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   file_name_label_->SetTextContext(CONTEXT_DOWNLOAD_SHELF);
+  file_name_label_->SetAutoColorReadabilityEnabled(false);
   file_name_label_->GetViewAccessibility().OverrideIsIgnored(true);
   const std::u16string filename = ElidedFilename(*file_name_label_);
   file_name_label_->SetText(filename);
@@ -329,13 +330,16 @@
   status_label_ = AddChildView(std::make_unique<views::Label>(
       std::u16string(), CONTEXT_DOWNLOAD_SHELF_STATUS));
   status_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  status_label_->SetAutoColorReadabilityEnabled(false);
 
   warning_label_ = AddChildView(std::make_unique<views::StyledLabel>());
   warning_label_->SetTextContext(CONTEXT_DOWNLOAD_SHELF);
+  warning_label_->SetAutoColorReadabilityEnabled(false);
   warning_label_->SetCanProcessEventsWithinSubtree(false);
 
   deep_scanning_label_ = AddChildView(std::make_unique<views::StyledLabel>());
   deep_scanning_label_->SetTextContext(CONTEXT_DOWNLOAD_SHELF);
+  deep_scanning_label_->SetAutoColorReadabilityEnabled(false);
   deep_scanning_label_->SetCanProcessEventsWithinSubtree(false);
 
   open_now_button_ = AddChildView(std::make_unique<views::MdTextButton>(
@@ -697,10 +701,6 @@
   const SkColor background_color =
       GetThemeProvider()->GetColor(ThemeProperties::COLOR_DOWNLOAD_SHELF);
   SetBackground(views::CreateSolidBackground(background_color));
-  file_name_label_->SetBackgroundColor(background_color);
-  status_label_->SetBackgroundColor(background_color);
-  warning_label_->SetDisplayedOnBackgroundColor(background_color);
-  deep_scanning_label_->SetDisplayedOnBackgroundColor(background_color);
 
   shelf_->ConfigureButtonForTheme(open_now_button_);
   shelf_->ConfigureButtonForTheme(save_button_);
@@ -1282,7 +1282,7 @@
       dropdown_button_,
       dropdown_pressed_ ? vector_icons::kCaretDownIcon
                         : vector_icons::kCaretUpIcon,
-      GetThemeProvider()->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT));
+      GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR_TEXT));
   dropdown_button_->SizeToPreferredSize();
 }
 
diff --git a/chrome/browser/ui/views/download/download_shelf_view.cc b/chrome/browser/ui/views/download/download_shelf_view.cc
index 4b0c339a..76fdee3c 100644
--- a/chrome/browser/ui/views/download/download_shelf_view.cc
+++ b/chrome/browser/ui/views/download/download_shelf_view.cc
@@ -368,7 +368,7 @@
 
   views::SetImageFromVectorIcon(
       close_button_, vector_icons::kCloseRoundedIcon,
-      GetThemeProvider()->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT));
+      GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR_TEXT));
 }
 
 views::View* DownloadShelfView::GetDefaultFocusableChild() {
diff --git a/chrome/browser/ui/views/external_protocol_dialog.cc b/chrome/browser/ui/views/external_protocol_dialog.cc
index cf4fc1b..80216b5 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog.cc
@@ -23,6 +23,7 @@
 #include "components/constrained_window/constrained_window_views.h"
 #include "components/prefs/pref_service.h"
 #include "components/url_formatter/elide_url.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
@@ -54,7 +55,8 @@
     WebContents* web_contents,
     ui::PageTransition ignored_page_transition,
     bool ignored_has_user_gesture,
-    const absl::optional<url::Origin>& initiating_origin) {
+    const absl::optional<url::Origin>& initiating_origin,
+    content::WeakDocumentPtr initiator_document) {
   DCHECK(web_contents);
 
   std::u16string program_name =
@@ -65,8 +67,8 @@
   }
 
   // Windowing system takes ownership.
-  new ExternalProtocolDialog(web_contents, url, program_name,
-                             initiating_origin);
+  new ExternalProtocolDialog(web_contents, url, program_name, initiating_origin,
+                             std::move(initiator_document));
 }
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
@@ -74,11 +76,13 @@
     WebContents* web_contents,
     const GURL& url,
     const std::u16string& program_name,
-    const absl::optional<url::Origin>& initiating_origin)
+    const absl::optional<url::Origin>& initiating_origin,
+    content::WeakDocumentPtr initiator_document)
     : web_contents_(web_contents->GetWeakPtr()),
       url_(url),
       program_name_(program_name),
-      initiating_origin_(initiating_origin) {
+      initiating_origin_(initiating_origin),
+      initiator_document_(std::move(initiator_document)) {
   SetDefaultButton(ui::DIALOG_BUTTON_CANCEL);
   SetButtonLabel(ui::DIALOG_BUTTON_OK,
                  l10n_util::GetStringFUTF16(
@@ -171,8 +175,8 @@
                                            profile);
   }
 
-  ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url_,
-                                                         web_contents_.get());
+  ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
+      url_, web_contents_.get(), initiator_document_);
 }
 
 views::View* ExternalProtocolDialog::GetContentsView() {
diff --git a/chrome/browser/ui/views/external_protocol_dialog.h b/chrome/browser/ui/views/external_protocol_dialog.h
index edc83dd7..1e21bd8d 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.h
+++ b/chrome/browser/ui/views/external_protocol_dialog.h
@@ -8,6 +8,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/window/dialog_delegate.h"
 #include "url/gurl.h"
@@ -32,7 +33,8 @@
   ExternalProtocolDialog(content::WebContents* web_contents,
                          const GURL& url,
                          const std::u16string& program_name,
-                         const absl::optional<url::Origin>& initiating_origin);
+                         const absl::optional<url::Origin>& initiating_origin,
+                         content::WeakDocumentPtr initiator_document);
   ExternalProtocolDialog(const ExternalProtocolDialog&) = delete;
   ExternalProtocolDialog& operator=(const ExternalProtocolDialog&) = delete;
   ~ExternalProtocolDialog() override;
@@ -51,11 +53,12 @@
   void SetRememberSelectionCheckboxCheckedForTesting(bool checked);
   void OnDialogAccepted();
 
-  base::WeakPtr<content::WebContents> web_contents_;
+  const base::WeakPtr<content::WebContents> web_contents_;
 
   const GURL url_;
   const std::u16string program_name_;
   const absl::optional<url::Origin> initiating_origin_;
+  const content::WeakDocumentPtr initiator_document_;
 
   // The message box whose commands we handle.
   raw_ptr<views::MessageBoxView> message_box_view_ = nullptr;
diff --git a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
index 53b382a..dcec56c 100644
--- a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "net/dns/mock_host_resolver.h"
@@ -100,7 +101,8 @@
         browser()->tab_strip_model()->GetActiveWebContents();
     dialog_ = new ExternalProtocolDialog(
         web_contents, GURL("telnet://12345"), u"/usr/bin/telnet",
-        url::Origin::Create(GURL(initiating_origin)));
+        url::Origin::Create(GURL(initiating_origin)),
+        web_contents->GetMainFrame()->GetWeakDocumentPtr());
   }
 
   void SetChecked(bool checked) {
diff --git a/chrome/browser/ui/views/infobars/infobar_view.cc b/chrome/browser/ui/views/infobars/infobar_view.cc
index 223ad75..cabd9ef 100644
--- a/chrome/browser/ui/views/infobars/infobar_view.cc
+++ b/chrome/browser/ui/views/infobars/infobar_view.cc
@@ -62,7 +62,7 @@
 
 // IDs of the colors to use for infobar elements.
 constexpr int kInfoBarLabelBackgroundColor = ThemeProperties::COLOR_INFOBAR;
-constexpr int kInfoBarLabelTextColor = ThemeProperties::COLOR_BOOKMARK_TEXT;
+constexpr int kInfoBarLabelTextColor = ThemeProperties::COLOR_TOOLBAR_TEXT;
 
 constexpr int kSeparatorHeightDip = 1;
 
@@ -243,8 +243,10 @@
     if (label_type != LabelType::kNone) {
       auto* label = static_cast<views::Label*>(child);
       label->SetBackgroundColor(background_color);
-      if (label_type == LabelType::kLabel)
+      if (label_type == LabelType::kLabel) {
         label->SetEnabledColor(text_color);
+        label->SetAutoColorReadabilityEnabled(false);
+      }
     }
   }
 
diff --git a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc
index 4d621da..8509b023 100644
--- a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc
+++ b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc
@@ -61,14 +61,15 @@
   return CreateDialogWebView(
       browser, GURL(chrome::kChromeUISyncConfirmationURL),
       GetSyncConfirmationDialogPreferredHeight(browser->profile()),
-      kSyncConfirmationDialogWidth);
+      kSyncConfirmationDialogWidth, InitializeSigninWebDialogUI(true));
 }
 
 // static
 std::unique_ptr<views::WebView>
 SigninViewControllerDelegateViews::CreateSigninErrorWebView(Browser* browser) {
   return CreateDialogWebView(browser, GURL(chrome::kChromeUISigninErrorURL),
-                             kSigninErrorDialogHeight, absl::nullopt);
+                             kSigninErrorDialogHeight, absl::nullopt,
+                             InitializeSigninWebDialogUI(true));
 }
 
 // static
@@ -78,7 +79,8 @@
     signin_metrics::ReauthAccessPoint access_point) {
   return CreateDialogWebView(browser,
                              signin::GetReauthConfirmationURL(access_point),
-                             kReauthDialogHeight, kReauthDialogWidth);
+                             kReauthDialogHeight, kReauthDialogWidth,
+                             InitializeSigninWebDialogUI(false));
 }
 
 #if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
@@ -92,7 +94,8 @@
     base::OnceCallback<void(bool)> callback) {
   std::unique_ptr<views::WebView> web_view = CreateDialogWebView(
       browser, GURL(chrome::kChromeUIEnterpriseProfileWelcomeURL),
-      kSyncConfirmationDialogHeight, kSyncConfirmationDialogWidth);
+      kSyncConfirmationDialogHeight, kSyncConfirmationDialogWidth,
+      InitializeSigninWebDialogUI(false));
 
   EnterpriseProfileWelcomeUI* web_dialog_ui =
       web_view->GetWebContents()
@@ -244,14 +247,17 @@
     Browser* browser,
     const GURL& url,
     int dialog_height,
-    absl::optional<int> opt_width) {
+    absl::optional<int> opt_width,
+    InitializeSigninWebDialogUI initialize_signin_web_dialog_ui) {
   int dialog_width = opt_width.value_or(kModalDialogWidth);
   views::WebView* web_view = new views::WebView(browser->profile());
   web_view->LoadInitialURL(url);
 
-  SigninWebDialogUI* web_dialog_ui = static_cast<SigninWebDialogUI*>(
-      web_view->GetWebContents()->GetWebUI()->GetController());
-  web_dialog_ui->InitializeMessageHandlerWithBrowser(browser);
+  if (initialize_signin_web_dialog_ui) {
+    SigninWebDialogUI* web_dialog_ui = static_cast<SigninWebDialogUI*>(
+        web_view->GetWebContents()->GetWebUI()->GetController());
+    web_dialog_ui->InitializeMessageHandlerWithBrowser(browser);
+  }
 
   int max_height = browser->window()
                        ->GetWebContentsModalDialogHost()
diff --git a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h
index 7f5150f..9450218 100644
--- a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h
+++ b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h
@@ -7,6 +7,7 @@
 
 #include "base/callback.h"
 #include "base/memory/raw_ptr.h"
+#include "base/types/strong_alias.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
@@ -106,6 +107,9 @@
   friend SigninViewControllerDelegate;
   friend class SigninViewControllerDelegateViewsBrowserTest;
 
+  using InitializeSigninWebDialogUI =
+      base::StrongAlias<class InitializeSigninWebDialogUITag, bool>;
+
   // Creates and displays a constrained window containing |web_contents|. If
   // |wait_for_size| is true, the delegate will wait for ResizeNativeView() to
   // be called by the base class before displaying the constrained window.
@@ -122,7 +126,8 @@
       Browser* browser,
       const GURL& url,
       int dialog_height,
-      absl::optional<int> dialog_width);
+      absl::optional<int> dialog_width,
+      InitializeSigninWebDialogUI initialize_signin_web_dialog_ui);
 
   // Displays the modal dialog.
   void DisplayModal();
diff --git a/chrome/browser/ui/views/toolbar/reload_button_browsertest.cc b/chrome/browser/ui/views/toolbar/reload_button_browsertest.cc
index abee95f..93fad30 100644
--- a/chrome/browser/ui/views/toolbar/reload_button_browsertest.cc
+++ b/chrome/browser/ui/views/toolbar/reload_button_browsertest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/test/browser_test.h"
 
 class ReloadButtonBrowserTest : public InProcessBrowserTest {
@@ -29,7 +30,8 @@
       url,
       base::BindRepeating(&ReloadButtonBrowserTest::GetWebContents,
                           base::Unretained(this)),
-      ui::PAGE_TRANSITION_LINK, true, url::Origin::Create(url));
+      ui::PAGE_TRANSITION_LINK, true, url::Origin::Create(url),
+      content::WeakDocumentPtr());
   ASSERT_EQ(ExternalProtocolHandler::BLOCK,
             ExternalProtocolHandler::GetBlockState(fake_protocol, nullptr,
                                                    browser()->profile()));
diff --git a/chrome/browser/ui/views/webid/webid_account_selection_views.cc b/chrome/browser/ui/views/webid/webid_account_selection_views.cc
index 93cb8904..7d3a7fad 100644
--- a/chrome/browser/ui/views/webid/webid_account_selection_views.cc
+++ b/chrome/browser/ui/views/webid/webid_account_selection_views.cc
@@ -9,3 +9,12 @@
     AccountSelectionView::Delegate* delegate) {
   return nullptr;
 }
+
+// static
+int AccountSelectionView::GetBrandIconMinimumSize() {
+  return 0;
+}
+
+int AccountSelectionView::GetBrandIconIdealSize() {
+  return 0;
+}
diff --git a/chrome/browser/ui/webid/account_selection_view.h b/chrome/browser/ui/webid/account_selection_view.h
index 14990fb..d8cfde8 100644
--- a/chrome/browser/ui/webid/account_selection_view.h
+++ b/chrome/browser/ui/webid/account_selection_view.h
@@ -31,6 +31,8 @@
   };
 
   static std::unique_ptr<AccountSelectionView> Create(Delegate* delegate);
+  static int GetBrandIconMinimumSize();
+  static int GetBrandIconIdealSize();
 
   explicit AccountSelectionView(Delegate* delegate) : delegate_(delegate) {}
   AccountSelectionView(const AccountSelectionView&) = delete;
diff --git a/chrome/browser/ui/webid/identity_dialog_controller.cc b/chrome/browser/ui/webid/identity_dialog_controller.cc
index 7840dc7..b91fa3f 100644
--- a/chrome/browser/ui/webid/identity_dialog_controller.cc
+++ b/chrome/browser/ui/webid/identity_dialog_controller.cc
@@ -19,6 +19,14 @@
 
 IdentityDialogController::~IdentityDialogController() = default;
 
+int IdentityDialogController::GetBrandIconMinimumSize() {
+  return AccountSelectionView::GetBrandIconMinimumSize();
+}
+
+int IdentityDialogController::GetBrandIconIdealSize() {
+  return AccountSelectionView::GetBrandIconIdealSize();
+}
+
 void IdentityDialogController::ShowInitialPermissionDialog(
     content::WebContents* rp_web_contents,
     const GURL& idp_url,
@@ -125,7 +133,10 @@
 }
 
 void IdentityDialogController::OnDismiss() {
-  std::move(on_account_selection_).Run(std::string());
+  // |OnDismiss| can be called after |OnAccountSelected| which sets the callback
+  // to null.
+  if (on_account_selection_)
+    std::move(on_account_selection_).Run(std::string());
 }
 
 gfx::NativeView IdentityDialogController::GetNativeView() {
diff --git a/chrome/browser/ui/webid/identity_dialog_controller.h b/chrome/browser/ui/webid/identity_dialog_controller.h
index 403a9eb..bab4796 100644
--- a/chrome/browser/ui/webid/identity_dialog_controller.h
+++ b/chrome/browser/ui/webid/identity_dialog_controller.h
@@ -43,6 +43,9 @@
   ~IdentityDialogController() override;
 
   // content::IdentityRequestDelegate
+  int GetBrandIconMinimumSize() override;
+  int GetBrandIconIdealSize() override;
+
   void ShowInitialPermissionDialog(
       content::WebContents* rp_web_contents,
       const GURL& idp_url,
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 19570ad..32f9805 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -59,7 +59,8 @@
 constexpr char kInDevModeKey[] = "inDevMode";
 constexpr char kShowActivityLogKey[] = "showActivityLog";
 constexpr char kLoadTimeClassesKey[] = "loadTimeClasses";
-constexpr char kUseNewSiteAccessPage[] = "useNewSiteAccessPage";
+constexpr char kExtensionsMenuAccessControlEnabled[] =
+    "extensionsMenuAccessControlEnabled";
 
 std::string GetLoadTimeClasses(bool in_dev_mode) {
   return in_dev_mode ? "in-dev-mode" : std::string();
@@ -195,7 +196,6 @@
     {"itemPermissionsEmpty", IDS_EXTENSIONS_ITEM_PERMISSIONS_EMPTY},
     {"itemRemoveExtension", IDS_EXTENSIONS_ITEM_REMOVE_EXTENSION},
     {"itemSiteAccess", IDS_EXTENSIONS_ITEM_SITE_ACCESS},
-    {"itemSiteAccessSublabel", IDS_EXTENSIONS_ITEM_SITE_ACCESS_SUBLABEL},
     {"itemSiteAccessAddHost", IDS_EXTENSIONS_ITEM_SITE_ACCESS_ADD_HOST},
     {"itemSiteAccessEmpty", IDS_EXTENSIONS_ITEM_SITE_ACCESS_EMPTY},
     {"itemSource", IDS_EXTENSIONS_ITEM_SOURCE},
@@ -225,7 +225,6 @@
     {"loadErrorRetry", IDS_EXTENSIONS_LOAD_ERROR_RETRY},
     {"loadingActivities", IDS_EXTENSIONS_LOADING_ACTIVITIES},
     {"missingOrUninstalledExtension", IDS_MISSING_OR_UNINSTALLED_EXTENSION},
-    {"newItemSiteAccessTitle", IDS_EXTENSIONS_ITEM_SITE_ACCESS_NEW},
     {"noActivities", IDS_EXTENSIONS_NO_ACTIVITIES},
     {"noErrorsToShow", IDS_EXTENSIONS_ERROR_NO_ERRORS_CODE_MESSAGE},
     {"runtimeHostsDialogInputError",
@@ -336,7 +335,7 @@
   source->AddString(kLoadTimeClassesKey, GetLoadTimeClasses(in_dev_mode));
 
   source->AddBoolean(
-      kUseNewSiteAccessPage,
+      kExtensionsMenuAccessControlEnabled,
       base::FeatureList::IsEnabled(features::kExtensionsMenuAccessControl));
 
   return source;
diff --git a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc
index 47022bef..765807b 100644
--- a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc
+++ b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc
@@ -21,7 +21,7 @@
 #include "ui/resources/grit/webui_generated_resources.h"
 
 EnterpriseProfileWelcomeUI::EnterpriseProfileWelcomeUI(content::WebUI* web_ui)
-    : SigninWebDialogUI(web_ui) {
+    : content::WebUIController(web_ui) {
   content::WebUIDataSource* source = content::WebUIDataSource::Create(
       chrome::kChromeUIEnterpriseProfileWelcomeHost);
   webui::SetJSModuleDefaults(source);
@@ -81,7 +81,4 @@
   return handler_;
 }
 
-void EnterpriseProfileWelcomeUI::InitializeMessageHandlerWithBrowser(
-    Browser* browser) {}
-
 WEB_UI_CONTROLLER_TYPE_IMPL(EnterpriseProfileWelcomeUI)
diff --git a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h
index 493f2b9..3fa43da8 100644
--- a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h
+++ b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h
@@ -7,7 +7,7 @@
 
 #include "base/callback.h"
 #include "base/memory/raw_ptr.h"
-#include "chrome/browser/ui/webui/signin/signin_web_dialog_ui.h"
+#include "content/public/browser/web_ui_controller.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/skia/include/core/SkColor.h"
 
@@ -19,7 +19,7 @@
 class WebUI;
 }
 
-class EnterpriseProfileWelcomeUI : public SigninWebDialogUI {
+class EnterpriseProfileWelcomeUI : public content::WebUIController {
  public:
   // Type of a welcome screen for the enterprise flow.
   enum class ScreenType {
@@ -46,9 +46,6 @@
   // Allows tests to trigger page events.
   EnterpriseProfileWelcomeHandler* GetHandlerForTesting();
 
-  // SigninWebDialogUI:
-  void InitializeMessageHandlerWithBrowser(Browser* browser) override;
-
  private:
   // Stored for tests.
   raw_ptr<EnterpriseProfileWelcomeHandler> handler_ = nullptr;
diff --git a/chrome/browser/ui/webui/signin/signin_reauth_ui.cc b/chrome/browser/ui/webui/signin/signin_reauth_ui.cc
index 6dcb530..60794d0 100644
--- a/chrome/browser/ui/webui/signin/signin_reauth_ui.cc
+++ b/chrome/browser/ui/webui/signin/signin_reauth_ui.cc
@@ -23,6 +23,7 @@
 #include "components/signin/public/base/signin_metrics.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "google_apis/gaia/core_account_id.h"
@@ -89,7 +90,7 @@
 }  // namespace
 
 SigninReauthUI::SigninReauthUI(content::WebUI* web_ui)
-    : SigninWebDialogUI(web_ui) {
+    : content::WebUIController(web_ui) {
   Profile* profile = Profile::FromWebUI(web_ui);
   content::WebUIDataSource* source =
       content::WebUIDataSource::Create(chrome::kChromeUISigninReauthHost);
@@ -137,8 +138,6 @@
       base::flat_map<std::string, int>(js_localized_string_to_ids_)));
 }
 
-void SigninReauthUI::InitializeMessageHandlerWithBrowser(Browser* browser) {}
-
 void SigninReauthUI::AddStringResource(content::WebUIDataSource* source,
                                        base::StringPiece name,
                                        int ids) {
diff --git a/chrome/browser/ui/webui/signin/signin_reauth_ui.h b/chrome/browser/ui/webui/signin/signin_reauth_ui.h
index a4f2bfbc..12ae2da 100644
--- a/chrome/browser/ui/webui/signin/signin_reauth_ui.h
+++ b/chrome/browser/ui/webui/signin/signin_reauth_ui.h
@@ -8,10 +8,8 @@
 #include <string>
 #include <vector>
 
-#include "chrome/browser/ui/webui/signin/signin_web_dialog_ui.h"
 #include "content/public/browser/web_ui_controller.h"
 
-class Browser;
 class SigninReauthViewController;
 
 namespace content {
@@ -32,7 +30,7 @@
 //
 // Contact chrome-signin@chromium.org if you want to reuse this dialog for other
 // reauth use-cases.
-class SigninReauthUI : public SigninWebDialogUI {
+class SigninReauthUI : public content::WebUIController {
  public:
   explicit SigninReauthUI(content::WebUI* web_ui);
   ~SigninReauthUI() override;
@@ -45,11 +43,6 @@
   void InitializeMessageHandlerWithReauthController(
       SigninReauthViewController* controller);
 
-  // SigninWebDialogUI:
-  // This class relies on InitializeMessageHandlerWithReauthController() so this
-  // method does nothing.
-  void InitializeMessageHandlerWithBrowser(Browser* browser) override;
-
  private:
   // Adds a string resource with the given GRD |ids| to the WebUI data |source|
   // named as |name|. Also stores a reverse mapping from the localized version
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index e072d18..8130e17 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1640152356-7110f7b9e061caa182e80e91922d963a27259c43.profdata
+chrome-linux-main-1640195998-5f12738e91a40fba7c9211c94fa17b72687b2c7c.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index d1cae67..15c9fb83 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1640152356-8f297e453cce0188cadd2b4256a99a8b72186a5a.profdata
+chrome-mac-main-1640195998-b46144647da22c393082a759c08824a0c2dd2e1e.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 4e81953..830e0d6 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1640162853-e127f09e7d28173b7f76e48ecb02c54042744ba6.profdata
+chrome-win32-main-1640195998-914d5c9e0aa5241537ef3445167069f5128293f9.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 72066b2..aa7b377 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1640162853-3c4bf97ec3b654f6ce6b7df852105d11837a41cc.profdata
+chrome-win64-main-1640184867-a096f2b75bb14eb11cd3987363ed828b310a80f5.profdata
diff --git a/chrome/installer/util/initial_preferences.cc b/chrome/installer/util/initial_preferences.cc
index 1184098f..cd55f22d 100644
--- a/chrome/installer/util/initial_preferences.cc
+++ b/chrome/installer/util/initial_preferences.cc
@@ -33,10 +33,6 @@
 base::LazyInstance<installer::InitialPreferences>::DestructorAtExit
     g_initial_preferences = LAZY_INSTANCE_INITIALIZER;
 
-bool GetURLFromValue(const base::Value* in_value, std::string* out_value) {
-  return in_value && out_value && in_value->GetAsString(out_value);
-}
-
 std::vector<std::string> GetNamedList(const char* name,
                                       const base::DictionaryValue* prefs) {
   std::vector<std::string> list;
@@ -49,12 +45,11 @@
 
   list.reserve(value_list->GetList().size());
   for (const base::Value& entry : value_list->GetList()) {
-    std::string url_entry;
-    if (!GetURLFromValue(&entry, &url_entry)) {
+    if (!entry.is_string()) {
       NOTREACHED();
       break;
     }
-    list.push_back(url_entry);
+    list.push_back(entry.GetString());
   }
   return list;
 }
@@ -325,7 +320,9 @@
   absl::optional<base::Value> pref_value =
       initial_dictionary_->ExtractKey(name);
   if (pref_value.has_value()) {
-    if (!pref_value->GetAsString(&result))
+    if (pref_value->is_string())
+      result = pref_value->GetString();
+    else
       NOTREACHED();
   }
   return result;
diff --git a/chrome/renderer/resources/plugins/plugin_poster.html b/chrome/renderer/resources/plugins/plugin_poster.html
deleted file mode 100644
index ec97d91..0000000
--- a/chrome/renderer/resources/plugins/plugin_poster.html
+++ /dev/null
@@ -1,107 +0,0 @@
-<!doctype html>
-<html>
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, user-scalable=no">
-<script>
-  window.onload = function() {
-    if (plugin.didFinishLoading)
-      plugin.didFinishLoading();
-  };
-
-  window.onkeydown = function(e) {
-    if (e.key == 'Enter' || e.key == ' ') {
-      plugin.load();
-      e.preventDefault();
-    }
-  };
-</script>
-<link rel="stylesheet" href="plugin_placeholders.css"></link>
-<style>
-#outer {
-  border: none;
-  flex-direction: row;
-  cursor: pointer;
-}
-
-#shielding {
-  background-color: rgba(0, 0, 0, 0.5);
-  height: 100%;
-  left: 0px;
-  position: absolute;
-  top: 0px;
-  width: 100%;
-  z-index: 2;
-}
-
-#plugin-icon {
-  opacity: 0.8;
-  max-height: 100%;
-  max-width: 100%;
-  min-width: 0;
-  min-height: 0;
-}
-
-#plugin-icon:hover {
-  opacity: 0.95;
-}
-
-#poster {
-  height: 100%;
-  object-fit: contain;
-  width: 100%;
-  z-index: 1;
-}
-
-#inner-container {
-  align-items: center;
-  display: flex;
-  height: 100%;
-  justify-content: center;
-  left: 0px;
-  max-height: 100%;
-  max-width: 100%;
-  position: absolute;
-  top: 0px;
-  width: 100%;
-  z-index: 2;
-}
-</style>
-<base href="$i18n{baseurl}">
-</head>
-
-<body>
-  <div title="$i18n{name}" id="outer">
-    <img id="poster" srcset="$i18n{poster}">
-    <div id="shielding"></div>
-    <div id="inner-container"
-         style="width:$i18n{visibleWidth};height:$i18n{visibleHeight}">
-      <img id="plugin-icon" src="plugin_power_saver_play.png" />
-    </div>
-  </div>
-  <script>
-    document.getElementById('poster').onerror = function() {
-      this.hidden = true;
-    };
-
-    document.getElementById('outer').onclick = function() {
-      plugin.load();
-    };
-
-    window.resizePoster = function(marginLeft, marginTop, width, height) {
-      var container = document.getElementById('inner-container');
-      container.style.marginLeft = marginLeft;
-      container.style.marginTop = marginTop;
-      container.style.width = width;
-      container.style.height = height;
-
-      if (plugin.notifyPlaceholderReadyForTesting) {
-        // Defer until reflow complete.
-        window.setTimeout(function() {
-          plugin.notifyPlaceholderReadyForTesting();
-        });
-      }
-    };
-  </script>
-</body>
-</html>
diff --git a/chrome/renderer/resources/plugins/plugin_power_saver_play.png b/chrome/renderer/resources/plugins/plugin_power_saver_play.png
deleted file mode 100644
index f713caf4..0000000
--- a/chrome/renderer/resources/plugins/plugin_power_saver_play.png
+++ /dev/null
Binary files differ
diff --git a/chrome/renderer/resources/renderer_resources.grd b/chrome/renderer/resources/renderer_resources.grd
index c75a7d2..9cc7c42 100644
--- a/chrome/renderer/resources/renderer_resources.grd
+++ b/chrome/renderer/resources/renderer_resources.grd
@@ -13,7 +13,6 @@
       <include name="IDR_BLOCKED_PLUGIN_HTML" file="plugins/blocked_plugin.html" flattenhtml="true" type="BINDATA" />
       <include name="IDR_DISABLED_PLUGIN_HTML" file="plugins/disabled_plugin.html" flattenhtml="true" type="BINDATA" />
       <include name="IDR_PDF_PLUGIN_HTML" file="plugins/pdf_plugin.html" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_PLUGIN_POSTER_HTML" file="plugins/plugin_poster.html" flattenhtml="true" type="BINDATA" />
       <include name="IDR_CART_PRODUCT_EXTRACTION_JS" file="cart/cart-product-extraction.js" type="BINDATA"/>
       <include name="IDR_CART_DOMAIN_PRODUCT_ID_REGEX_JSON" file="cart/cart_domain_product_id_regex.json" type="BINDATA"/>
       <include name="IDR_CART_DOMAIN_CART_URL_REGEX_JSON" file="cart/cart_domain_cart_url_regex.json" type="BINDATA"/>
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index bd62f0b..0c936b98 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3451,6 +3451,8 @@
         "../browser/chromeos/policy/dlp/mock_dlp_content_observer.h",
         "../browser/chromeos/policy/dlp/mock_dlp_rules_manager.cc",
         "../browser/chromeos/policy/dlp/mock_dlp_rules_manager.h",
+        "../browser/chromeos/policy/dlp/mock_dlp_warn_notifier.cc",
+        "../browser/chromeos/policy/dlp/mock_dlp_warn_notifier.h",
         "../browser/device_api/device_attribute_api_browsertest.cc",
         "../browser/drive/drive_notification_manager_factory_browsertest.cc",
         "../browser/metrics/chromeos_metrics_provider_browsertest.cc",
@@ -6630,7 +6632,8 @@
       "../browser/ui/app_list/search/ranking/category_item_ranker_unittest.cc",
       "../browser/ui/app_list/search/ranking/category_usage_ranker_unittest.cc",
       "../browser/ui/app_list/search/ranking/removed_results_ranker_unittest.cc",
-      "../browser/ui/app_list/search/search_controller_unittest.cc",
+      "../browser/ui/app_list/search/search_controller_impl_new_unittest.cc",
+      "../browser/ui/app_list/search/search_controller_impl_unittest.cc",
       "../browser/ui/app_list/search/search_result_ranker/app_launch_event_logger_unittest.cc",
       "../browser/ui/app_list/search/search_result_ranker/app_launch_predictor_test_util.h",
       "../browser/ui/app_list/search/search_result_ranker/app_launch_predictor_unittest.cc",
diff --git a/chrome/test/chromedriver/element_commands.cc b/chrome/test/chromedriver/element_commands.cc
index 366ef2c..62a52bd 100644
--- a/chrome/test/chromedriver/element_commands.cc
+++ b/chrome/test/chromedriver/element_commands.cc
@@ -1148,10 +1148,12 @@
   double device_pixel_ratio =
          browser_info->FindKey("device_pixel_ratio")->GetDouble();
 
-  std::unique_ptr<base::DictionaryValue> clip_dict =
-      base::DictionaryValue::From(std::move(clip));
-  if (!clip_dict)
+  if (!clip->is_dict())
     return Status(kUnknownError, "Element Rect is not a dictionary");
+
+  base::DictionaryValue screenshot_params;
+  base::Value* clip_dict = screenshot_params.SetKey(
+      "clip", base::Value::FromUniquePtrValue(std::move(clip)));
   // |clip_dict| already contains the right width and height of the target
   // element, but its x and y are relative to containing frame. We replace them
   // with the x and y relative to top-level document origin, as expected by
@@ -1166,8 +1168,6 @@
   clip_dict->SetDoubleKey("width",
                           std::min(viewport_width - location.x,
                                    clip_dict->FindKey("width")->GetDouble()));
-  base::DictionaryValue screenshot_params;
-  screenshot_params.SetDictionary("clip", std::move(clip_dict));
 
   std::string screenshot;
   status = web_view->CaptureScreenshot(&screenshot, screenshot_params);
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index b940f9f0..db0e4b3 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -1329,11 +1329,11 @@
 
   base::DictionaryValue body_params;
   if (status.IsError()){
-    std::unique_ptr<base::DictionaryValue> inner_params(
-        new base::DictionaryValue());
-    inner_params->SetString("error", StatusCodeToString(status.code()));
-    inner_params->SetString("message", status.message());
-    inner_params->SetString("stacktrace", status.stack_trace());
+    base::Value* inner_params =
+        body_params.SetKey("value", base::Value(base::Value::Type::DICTIONARY));
+    inner_params->SetStringKey("error", StatusCodeToString(status.code()));
+    inner_params->SetStringKey("message", status.message());
+    inner_params->SetStringKey("stacktrace", status.stack_trace());
     // According to
     // https://www.w3.org/TR/2018/REC-webdriver1-20180605/#dfn-annotated-unexpected-alert-open-error
     // error UnexpectedAlertOpen should contain 'data.text' with alert text
@@ -1342,18 +1342,18 @@
       auto first = message.find("{");
       auto last = message.find_last_of("}");
       if (first == std::string::npos || last == std::string::npos) {
-        inner_params->SetString("data.text", "");
+        inner_params->SetStringPath("data.text", "");
       } else {
         std::string alertText = message.substr(first, last - first);
         auto colon = alertText.find(":");
         if (colon != std::string::npos && alertText.size() > (colon + 2))
           alertText = alertText.substr(colon + 2);
-        inner_params->SetString("data.text", alertText);
+        inner_params->SetStringPath("data.text", alertText);
       }
     }
-    body_params.SetDictionary("value", std::move(inner_params));
   } else {
-    body_params.Set("value", std::move(value));
+    body_params.SetKey("value",
+                       base::Value::FromUniquePtrValue(std::move(value)));
   }
 
   std::string body;
diff --git a/chrome/test/chromedriver/session_commands_unittest.cc b/chrome/test/chromedriver/session_commands_unittest.cc
index 28a1458d..3e2a245 100644
--- a/chrome/test/chromedriver/session_commands_unittest.cc
+++ b/chrome/test/chromedriver/session_commands_unittest.cc
@@ -118,8 +118,7 @@
   ASSERT_EQ(kInvalidArgument, status.code());
 
   // Empty "capabilities" is OK
-  params.SetDictionary("capabilities",
-                       std::make_unique<base::DictionaryValue>());
+  params.SetKey("capabilities", base::Value(base::Value::Type::DICTIONARY));
   status = ProcessCapabilities(params, &result);
   ASSERT_EQ(kOk, status.code()) << status.message();
   ASSERT_TRUE(result.DictEmpty());
@@ -136,8 +135,8 @@
   ASSERT_EQ(kInvalidArgument, status.code());
 
   // Empty "alwaysMatch" is OK
-  params.SetDictionary("capabilities.alwaysMatch",
-                       std::make_unique<base::DictionaryValue>());
+  params.SetPath("capabilities.alwaysMatch",
+                 base::Value(base::Value::Type::DICTIONARY));
   status = ProcessCapabilities(params, &result);
   ASSERT_EQ(kOk, status.code()) << status.message();
   ASSERT_TRUE(result.DictEmpty());
@@ -168,8 +167,8 @@
   base::DictionaryValue result;
 
   // "firstMatch" must be a JSON list
-  params.SetDictionary("capabilities.firstMatch",
-                       std::make_unique<base::DictionaryValue>());
+  params.SetPath("capabilities.firstMatch",
+                 base::Value(base::Value::Type::DICTIONARY));
   Status status = ProcessCapabilities(params, &result);
   ASSERT_EQ(kInvalidArgument, status.code());
 
@@ -490,8 +489,8 @@
   caps.SetPath({"goog:chromeOptions", "args"}, base::Value(args));
 
   base::DictionaryValue prefs;
-  prefs.SetKey("download.default_directory",
-               base::Value("/examples/python/downloads"));
+  prefs.SetPath("download.default_directory",
+                base::Value("/examples/python/downloads"));
   caps.SetPath({"goog:chromeOptions", "prefs"}, prefs.Clone());
 
   Status status = capabilities.Parse(caps);
@@ -514,11 +513,11 @@
   args.emplace_back("headless");
   caps.SetPath({"goog:chromeOptions", "args"}, base::Value(args));
 
-  base::DictionaryValue prefs;
-  std::unique_ptr<base::DictionaryValue> download(new base::DictionaryValue());
-  download->SetStringPath("default_directory", "/examples/python/downloads");
-  prefs.SetDictionary("download", std::move(download));
-  caps.SetPath({"goog:chromeOptions", "prefs"}, prefs.Clone());
+  base::Value* prefs = caps.SetPath({"goog:chromeOptions", "prefs"},
+                                    base::Value(base::Value::Type::DICTIONARY));
+  base::Value* download =
+      prefs->SetKey("download", base::Value(base::Value::Type::DICTIONARY));
+  download->SetStringKey("default_directory", "/examples/python/downloads");
 
   Status status = capabilities.Parse(caps);
   BrowserInfo binfo;
@@ -555,11 +554,11 @@
 TEST(SessionCommandsTest, ConfigureHeadlessSession_notHeadless) {
   Capabilities capabilities;
   base::DictionaryValue caps;
-  base::DictionaryValue prefs;
-  std::unique_ptr<base::DictionaryValue> download(new base::DictionaryValue());
-  download->SetStringPath("default_directory", "/examples/python/downloads");
-  prefs.SetDictionary("download", std::move(download));
-  caps.SetPath({"goog:chromeOptions", "prefs"}, prefs.Clone());
+  base::Value* prefs = caps.SetPath({"goog:chromeOptions", "prefs"},
+                                    base::Value(base::Value::Type::DICTIONARY));
+  base::Value* download =
+      prefs->SetKey("download", base::Value(base::Value::Type::DICTIONARY));
+  download->SetStringKey("default_directory", "/examples/python/downloads");
 
   Status status = capabilities.Parse(caps);
   BrowserInfo binfo;
diff --git a/chrome/test/chromedriver/util_unittest.cc b/chrome/test/chromedriver/util_unittest.cc
index 6d08fa2..156fbddd8 100644
--- a/chrome/test/chromedriver/util_unittest.cc
+++ b/chrome/test/chromedriver/util_unittest.cc
@@ -272,10 +272,8 @@
   base::DictionaryValue dv2;
   dv2.SetString("dv", "2");
 
-  std::unique_ptr<base::DictionaryValue> params(dv1.DeepCopy());
-
   base::DictionaryValue dict;
-  dict.SetDictionary(key, std::move(params));
+  dict.SetKey(key, dv1.Clone());
   const base::DictionaryValue* res = &dv2;
   bool has_value;
   bool has_dict = GetOptionalDictionary(&dict, key, &res, &has_value);
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index 71e101d..d8592ada 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -1315,30 +1315,28 @@
 
     session->active_input_sources.Append(std::move(tmp_source));
 
-    base::DictionaryValue tmp_state;
-    tmp_state.SetString("id", id);
+    base::Value* tmp_state = session->input_state_table.SetPath(
+        id, base::Value(base::Value::Type::DICTIONARY));
+    tmp_state->SetStringKey("id", id);
     if (type == "key") {
       // Initialize a key input state object
       // (https://w3c.github.io/webdriver/#dfn-key-input-state).
-      tmp_state.SetDictionary("pressed",
-                              std::make_unique<base::DictionaryValue>());
+      tmp_state->SetKey("pressed", base::Value(base::Value::Type::DICTIONARY));
       // For convenience, we use one integer property to encode four Boolean
       // properties (alt, shift, ctrl, meta) from the spec, using values from
       // enum KeyModifierMask.
-      tmp_state.SetInteger("modifiers", 0);
+      tmp_state->SetIntKey("modifiers", 0);
     } else if (type == "pointer") {
       int x = 0;
       int y = 0;
 
       // "pressed" is stored as a bitmask of pointer buttons.
-      tmp_state.SetInteger("pressed", 0);
-      tmp_state.SetString("subtype", pointer_type);
+      tmp_state->SetIntKey("pressed", 0);
+      tmp_state->SetStringKey("subtype", pointer_type);
 
-      tmp_state.SetInteger("x", x);
-      tmp_state.SetInteger("y", y);
+      tmp_state->SetIntKey("x", x);
+      tmp_state->SetIntKey("y", y);
     }
-    session->input_state_table.SetDictionary(
-        id, std::make_unique<base::DictionaryValue>(std::move(tmp_state)));
   }
 
   const base::ListValue* actions;
@@ -1463,10 +1461,9 @@
             std::string element_id;
             if (!origin_dict->GetString(GetElementKey(), &element_id))
               return Status(kInvalidArgument, "'element' is missing");
-            std::unique_ptr<base::DictionaryValue> origin_result =
-                std::make_unique<base::DictionaryValue>();
-            origin_result->SetString(GetElementKey(), element_id);
-            action->SetDictionary("origin", std::move(origin_result));
+            base::Value* origin_result = action->SetKey(
+                "origin", base::Value(base::Value::Type::DICTIONARY));
+            origin_result->SetStringPath(GetElementKey(), element_id);
           } else {
             if (origin != "viewport" && origin != "pointer")
               return Status(kInvalidArgument,
diff --git a/chrome/test/chromedriver/window_commands_unittest.cc b/chrome/test/chromedriver/window_commands_unittest.cc
index 5933b582..fe55ba8 100644
--- a/chrome/test/chromedriver/window_commands_unittest.cc
+++ b/chrome/test/chromedriver/window_commands_unittest.cc
@@ -88,7 +88,7 @@
 
 TEST(WindowCommandsTest, ExecuteSendCommandAndGetResult_NoCmd) {
   base::DictionaryValue params;
-  params.SetDictionary("params", std::make_unique<base::DictionaryValue>());
+  params.SetKey("params", base::Value(base::Value::Type::DICTIONARY));
   Status status = CallWindowCommand(ExecuteSendCommandAndGetResult, params);
   ASSERT_EQ(kInvalidArgument, status.code());
   ASSERT_NE(status.message().find("command not passed"), std::string::npos);
@@ -96,7 +96,7 @@
 
 TEST(WindowCommandsTest, ExecuteSendCommandAndGetResult_NoParams) {
   base::DictionaryValue params;
-  params.SetString("cmd", "CSS.enable");
+  params.SetStringKey("cmd", "CSS.enable");
   Status status = CallWindowCommand(ExecuteSendCommandAndGetResult, params);
   ASSERT_EQ(kInvalidArgument, status.code());
   ASSERT_NE(status.message().find("params not passed"), std::string::npos);
@@ -108,27 +108,26 @@
   std::unique_ptr<base::DictionaryValue> action_sequence(
       new base::DictionaryValue());
   std::unique_ptr<base::ListValue> actions(new base::ListValue());
-  std::unique_ptr<base::DictionaryValue> action(new base::DictionaryValue());
-  std::unique_ptr<base::DictionaryValue> parameters(
-      new base::DictionaryValue());
-  parameters->SetString("pointerType", "mouse");
-  action->SetString("type", "pointerMove");
-  action->SetInteger("x", 30);
-  action->SetInteger("y", 60);
+  base::Value action(base::Value::Type::DICTIONARY);
+  base::Value* parameters = action_sequence->SetKey(
+      "parameters", base::Value(base::Value::Type::DICTIONARY));
+  parameters->SetStringKey("pointerType", "mouse");
+  action.SetStringKey("type", "pointerMove");
+  action.SetIntKey("x", 30);
+  action.SetIntKey("y", 60);
   actions->Append(std::move(action));
-  action = std::make_unique<base::DictionaryValue>();
-  action->SetString("type", "pointerDown");
-  action->SetInteger("button", 0);
+  action = base::Value(base::Value::Type::DICTIONARY);
+  action.SetStringKey("type", "pointerDown");
+  action.SetIntKey("button", 0);
   actions->Append(std::move(action));
-  action = std::make_unique<base::DictionaryValue>();
-  action->SetString("type", "pointerUp");
-  action->SetInteger("button", 0);
+  action = base::Value(base::Value::Type::DICTIONARY);
+  action.SetStringKey("type", "pointerUp");
+  action.SetIntKey("button", 0);
   actions->Append(std::move(action));
 
   // pointer properties
   action_sequence->SetString("type", "pointer");
   action_sequence->SetString("id", "pointer1");
-  action_sequence->SetDictionary("parameters", std::move(parameters));
   action_sequence->SetList("actions", std::move(actions));
   const base::DictionaryValue* input_action_sequence = action_sequence.get();
   Status status =
@@ -189,25 +188,24 @@
   std::unique_ptr<base::DictionaryValue> action_sequence(
       new base::DictionaryValue());
   std::unique_ptr<base::ListValue> actions(new base::ListValue());
-  std::unique_ptr<base::DictionaryValue> action(new base::DictionaryValue());
-  std::unique_ptr<base::DictionaryValue> parameters(
-      new base::DictionaryValue());
-  parameters->SetString("pointerType", "touch");
-  action->SetString("type", "pointerMove");
-  action->SetInteger("x", 30);
-  action->SetInteger("y", 60);
+  base::Value action(base::Value::Type::DICTIONARY);
+  base::Value* parameters = action_sequence->SetKey(
+      "parameters", base::Value(base::Value::Type::DICTIONARY));
+  parameters->SetStringKey("pointerType", "touch");
+  action.SetStringKey("type", "pointerMove");
+  action.SetIntKey("x", 30);
+  action.SetIntKey("y", 60);
   actions->Append(std::move(action));
-  action = std::make_unique<base::DictionaryValue>();
-  action->SetString("type", "pointerDown");
+  action = base::Value(base::Value::Type::DICTIONARY);
+  action.SetStringKey("type", "pointerDown");
   actions->Append(std::move(action));
-  action = std::make_unique<base::DictionaryValue>();
-  action->SetString("type", "pointerUp");
+  action = base::Value(base::Value::Type::DICTIONARY);
+  action.SetStringKey("type", "pointerUp");
   actions->Append(std::move(action));
 
   // pointer properties
   action_sequence->SetString("type", "pointer");
   action_sequence->SetString("id", "pointer1");
-  action_sequence->SetDictionary("parameters", std::move(parameters));
   action_sequence->SetList("actions", std::move(actions));
   const base::DictionaryValue* input_action_sequence = action_sequence.get();
   Status status =
@@ -284,12 +282,11 @@
 TEST(WindowCommandsTest, ExecuteAddCookie_Valid) {
   AddCookieWebView webview = AddCookieWebView("http://chromium.org");
   base::DictionaryValue params;
-  std::unique_ptr<base::DictionaryValue> cookie_params =
-      std::make_unique<base::DictionaryValue>();
-  cookie_params->SetString("name", "testcookie");
-  cookie_params->SetString("value", "cookievalue");
-  cookie_params->SetString("sameSite", "Strict");
-  params.SetDictionary("cookie", std::move(cookie_params));
+  base::Value* cookie_params =
+      params.SetKey("cookie", base::Value(base::Value::Type::DICTIONARY));
+  cookie_params->SetStringKey("name", "testcookie");
+  cookie_params->SetStringKey("value", "cookievalue");
+  cookie_params->SetStringKey("sameSite", "Strict");
   std::unique_ptr<base::Value> result_value;
   Status status =
       CallWindowCommand(ExecuteAddCookie, &webview, params, &result_value);
@@ -299,11 +296,10 @@
 TEST(WindowCommandsTest, ExecuteAddCookie_NameMissing) {
   AddCookieWebView webview = AddCookieWebView("http://chromium.org");
   base::DictionaryValue params;
-  std::unique_ptr<base::DictionaryValue> cookie_params =
-      std::make_unique<base::DictionaryValue>();
-  cookie_params->SetString("value", "cookievalue");
-  cookie_params->SetString("sameSite", "invalid");
-  params.SetDictionary("cookie", std::move(cookie_params));
+  base::Value* cookie_params =
+      params.SetKey("cookie", base::Value(base::Value::Type::DICTIONARY));
+  cookie_params->SetStringKey("value", "cookievalue");
+  cookie_params->SetStringKey("sameSite", "invalid");
   std::unique_ptr<base::Value> result_value;
   Status status =
       CallWindowCommand(ExecuteAddCookie, &webview, params, &result_value);
@@ -315,11 +311,10 @@
 TEST(WindowCommandsTest, ExecuteAddCookie_MissingValue) {
   AddCookieWebView webview = AddCookieWebView("http://chromium.org");
   base::DictionaryValue params;
-  std::unique_ptr<base::DictionaryValue> cookie_params =
-      std::make_unique<base::DictionaryValue>();
-  cookie_params->SetString("name", "testcookie");
-  cookie_params->SetString("sameSite", "Strict");
-  params.SetDictionary("cookie", std::move(cookie_params));
+  base::Value* cookie_params =
+      params.SetKey("cookie", base::Value(base::Value::Type::DICTIONARY));
+  cookie_params->SetStringKey("name", "testcookie");
+  cookie_params->SetStringKey("sameSite", "Strict");
   std::unique_ptr<base::Value> result_value;
   Status status =
       CallWindowCommand(ExecuteAddCookie, &webview, params, &result_value);
@@ -331,12 +326,11 @@
 TEST(WindowCommandsTest, ExecuteAddCookie_DomainInvalid) {
   AddCookieWebView webview = AddCookieWebView("file://chromium.org");
   base::DictionaryValue params;
-  std::unique_ptr<base::DictionaryValue> cookie_params =
-      std::make_unique<base::DictionaryValue>();
-  cookie_params->SetString("name", "testcookie");
-  cookie_params->SetString("value", "cookievalue");
-  cookie_params->SetString("sameSite", "Strict");
-  params.SetDictionary("cookie", std::move(cookie_params));
+  base::Value* cookie_params =
+      params.SetKey("cookie", base::Value(base::Value::Type::DICTIONARY));
+  cookie_params->SetStringKey("name", "testcookie");
+  cookie_params->SetStringKey("value", "cookievalue");
+  cookie_params->SetStringKey("sameSite", "Strict");
   std::unique_ptr<base::Value> result_value;
   Status status =
       CallWindowCommand(ExecuteAddCookie, &webview, params, &result_value);
@@ -346,12 +340,11 @@
 TEST(WindowCommandsTest, ExecuteAddCookie_SameSiteEmpty) {
   AddCookieWebView webview = AddCookieWebView("https://chromium.org");
   base::DictionaryValue params;
-  std::unique_ptr<base::DictionaryValue> cookie_params =
-      std::make_unique<base::DictionaryValue>();
-  cookie_params->SetString("name", "testcookie");
-  cookie_params->SetString("value", "cookievalue");
-  cookie_params->SetString("sameSite", "");
-  params.SetDictionary("cookie", std::move(cookie_params));
+  base::Value* cookie_params =
+      params.SetKey("cookie", base::Value(base::Value::Type::DICTIONARY));
+  cookie_params->SetStringKey("name", "testcookie");
+  cookie_params->SetStringKey("value", "cookievalue");
+  cookie_params->SetStringKey("sameSite", "");
   std::unique_ptr<base::Value> result_value;
   Status status =
       CallWindowCommand(ExecuteAddCookie, &webview, params, &result_value);
@@ -361,11 +354,10 @@
 TEST(WindowCommandsTest, ExecuteAddCookie_SameSiteNotSet) {
   AddCookieWebView webview = AddCookieWebView("ftp://chromium.org");
   base::DictionaryValue params;
-  std::unique_ptr<base::DictionaryValue> cookie_params =
-      std::make_unique<base::DictionaryValue>();
-  cookie_params->SetString("name", "testcookie");
-  cookie_params->SetString("value", "cookievalue");
-  params.SetDictionary("cookie", std::move(cookie_params));
+  base::Value* cookie_params =
+      params.SetKey("cookie", base::Value(base::Value::Type::DICTIONARY));
+  cookie_params->SetStringKey("name", "testcookie");
+  cookie_params->SetStringKey("value", "cookievalue");
   std::unique_ptr<base::Value> result_value;
   Status status =
       CallWindowCommand(ExecuteAddCookie, &webview, params, &result_value);
@@ -601,71 +593,63 @@
   base::DictionaryValue params;
   std::unique_ptr<base::Value> result_value;
 
-  std::unique_ptr<base::DictionaryValue> dv(new base::DictionaryValue());
-  params.SetDictionary("page", std::move(dv));
+  base::Value* dv =
+      params.SetKey("page", base::Value(base::Value::Type::DICTIONARY));
   Status status =
       CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   base::DictionaryValue printParams = getDefaultPrintParams();
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("page", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("width", 21.59);
-  params.SetDictionary("page", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("paperWidth", ConvertCentimeterToInch(21.59));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("page", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("width", 33);
-  params.SetDictionary("page", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("paperWidth", ConvertCentimeterToInch(33));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
-  dv->SetString("width", "10");
-  params.SetDictionary("page", std::move(dv));
+  dv = params.SetKey("page", base::Value(base::Value::Type::DICTIONARY));
+  dv->SetStringKey("width", "10");
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("page", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("width", -3.0);
-  params.SetDictionary("page", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("page", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("height", 20);
-  params.SetDictionary("page", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("paperHeight", ConvertCentimeterToInch(20));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("page", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("height", 27.94);
-  params.SetDictionary("page", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("paperHeight", ConvertCentimeterToInch(27.94));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
-  dv->SetString("height", "10");
-  params.SetDictionary("page", std::move(dv));
+  dv = params.SetKey("page", base::Value(base::Value::Type::DICTIONARY));
+  dv->SetStringKey("height", "10");
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("page", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("height", -3.0);
-  params.SetDictionary("page", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 }
@@ -675,131 +659,115 @@
   base::DictionaryValue params;
   std::unique_ptr<base::Value> result_value;
 
-  std::unique_ptr<base::DictionaryValue> dv(new base::DictionaryValue());
-  params.SetDictionary("margin", std::move(dv));
+  base::Value* dv =
+      params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   Status status =
       CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   base::DictionaryValue printParams = getDefaultPrintParams();
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("top", 1.0);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("marginTop", ConvertCentimeterToInch(1.0));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("top", 10.2);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("marginTop", ConvertCentimeterToInch(10.2));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
-  dv->SetString("top", "10.2");
-  params.SetDictionary("margin", std::move(dv));
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
+  dv->SetStringKey("top", "10.2");
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("top", -0.1);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("bottom", 1.0);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("marginBottom", ConvertCentimeterToInch(1.0));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("bottom", 5.3);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("marginBottom", ConvertCentimeterToInch(5.3));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
-  dv->SetString("bottom", "10.2");
-  params.SetDictionary("margin", std::move(dv));
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
+  dv->SetStringKey("bottom", "10.2");
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("bottom", -0.1);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("left", 1.0);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("marginLeft", ConvertCentimeterToInch(1.0));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("left", 9.1);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("marginLeft", ConvertCentimeterToInch(9.1));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
-  dv->SetString("left", "10.2");
-  params.SetDictionary("margin", std::move(dv));
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
+  dv->SetStringKey("left", "10.2");
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("left", -0.1);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("right", 1.0);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("marginRight", ConvertCentimeterToInch(1.0));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("right", 8.1);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kOk, status.code()) << status.message();
   printParams = getDefaultPrintParams();
   printParams.SetDoubleKey("marginRight", ConvertCentimeterToInch(8.1));
   ASSERT_EQ(static_cast<const base::Value&>(printParams), webview.getParams());
 
-  dv = std::make_unique<base::DictionaryValue>();
-  dv->SetString("right", "10.2");
-  params.SetDictionary("margin", std::move(dv));
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
+  dv->SetStringKey("right", "10.2");
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 
-  dv = std::make_unique<base::DictionaryValue>();
+  dv = params.SetKey("margin", base::Value(base::Value::Type::DICTIONARY));
   dv->SetDoubleKey("right", -0.1);
-  params.SetDictionary("margin", std::move(dv));
   status = CallWindowCommand(ExecutePrint, &webview, params, &result_value);
   ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
 }
@@ -825,11 +793,10 @@
     if (cmd == "Page.getLayoutMetrics") {
       std::unique_ptr<base::DictionaryValue> res =
           std::make_unique<base::DictionaryValue>();
-      std::unique_ptr<base::DictionaryValue> d =
-          std::make_unique<base::DictionaryValue>();
+      base::Value* d = res->SetKey("contentSize",
+                                   base::Value(base::Value::Type::DICTIONARY));
       d->SetDoubleKey("width", wd);
       d->SetDoubleKey("height", hd);
-      res->SetDictionary("contentSize", std::move(d));
       *value = std::move(res);
     } else if (cmd == "Emulation.setDeviceMetricsOverride") {
       base::DictionaryValue expect;
diff --git a/chrome/test/data/BUILD.gn b/chrome/test/data/BUILD.gn
index b554785..435dded 100644
--- a/chrome/test/data/BUILD.gn
+++ b/chrome/test/data/BUILD.gn
@@ -4,7 +4,6 @@
 
 import("//chrome/common/features.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
-import("//pdf/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
 
@@ -51,9 +50,6 @@
     "cast:closure_compile",
   ]
 
-  if (enable_pdf) {
-    deps += [ "pdf:closure_compile" ]
-  }
   if (!is_android) {
     deps += [ "webui:closure_compile" ]
   }
diff --git a/chrome/test/data/pdf/BUILD.gn b/chrome/test/data/pdf/BUILD.gn
deleted file mode 100644
index b0efa80..0000000
--- a/chrome/test/data/pdf/BUILD.gn
+++ /dev/null
@@ -1,260 +0,0 @@
-# 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.
-
-import("//pdf/features.gni")
-import("//third_party/closure_compiler/compile_js.gni")
-
-js_type_check("closure_compile") {
-  is_polymer3 = true
-  closure_flags = default_closure_args + [
-                    "browser_resolver_prefix_replacements=\"chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/_test_resources/=../../chrome/test/data/\"",
-                    "browser_resolver_prefix_replacements=\"chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/=../../chrome/browser/resources/pdf/\"",
-                    "js_module_root=../../chrome/test/data/webui/",
-                    "js_module_root=./gen/chrome/test/data/webui/",
-                  ]
-  deps = [
-    #":annotations_feature_enabled_test",
-    ":basic_plugin_test",
-    ":basic_test",
-    ":beep_test",
-    ":bookmarks_test",
-    ":download_controls_test",
-    ":fullscreen_test",
-    ":gesture_detector_test",
-    ":layout_test",
-    ":material_elements_test",
-
-    #":metrics_test",
-    ":navigator_test",
-    ":nobeep_test",
-    ":page_change_test",
-    ":params_parser_test",
-    ":post_message_proxy_test",
-    ":printing_icon_test",
-
-    #":redirects_fail_test",
-    ":scroll_with_form_field_focused_test",
-    ":test_util",
-    ":title_test",
-
-    #":toolbar_manager_test",
-    #":touch_handling_test",
-    ":viewer_password_dialog_test",
-    ":viewer_pdf_sidenav_test",
-    ":viewer_properties_dialog_test",
-    ":viewer_thumbnail_bar_test",
-    ":viewer_thumbnail_test",
-    ":viewer_toolbar_test",
-    ":viewport_test",
-    ":whitespace_title_test",
-
-    #":zoom_manager_test",
-  ]
-
-  if (enable_ink) {
-    deps += [ ":viewer_toolbar_dropdown_test" ]
-  }
-}
-
-js_library("basic_plugin_test") {
-  deps = [ "//chrome/browser/resources/pdf:pdf_viewer_wrapper" ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("basic_test") {
-  deps = [ "//chrome/browser/resources/pdf:pdf_viewer_wrapper" ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("beep_test") {
-  deps = [ "//chrome/browser/resources/pdf:pdf_viewer_wrapper" ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("bookmarks_test") {
-  deps = [
-    ":test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("gesture_detector_test") {
-  deps = [
-    ":test_util",
-    "//chrome/browser/resources/pdf:gesture_detector",
-    "//ui/webui/resources/js/cr:event_target.m",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("layout_test") {
-  deps = [ "//chrome/browser/resources/pdf:pdf_viewer_wrapper" ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("material_elements_test") {
-  deps = [
-    ":test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/cr_elements/cr_icon_button:cr_icon_button.m",
-    "//ui/webui/resources/js:cr.m",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-if (enable_ink) {
-  js_library("viewer_toolbar_dropdown_test") {
-    deps = [ "//chrome/browser/resources/pdf:pdf_viewer_wrapper" ]
-    externs_list = [ "$externs_path/test.js" ]
-  }
-}
-
-js_library("download_controls_test") {
-  deps = [
-    "../webui:test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
-    "//ui/webui/resources/cr_elements/cr_icon_button:cr_icon_button.m",
-    "//ui/webui/resources/js:util.m",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("fullscreen_test") {
-  deps = [
-    ":test_util",
-    "../webui:test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-    "//third_party/polymer/v3_0/components-chromium/iron-test-helpers:mock-interactions",
-    "//ui/webui/resources/js:cr.m",
-    "//ui/webui/resources/js:util.m",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("navigator_test") {
-  deps = [
-    ":test_util",
-    "../webui:test_browser_proxy",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("nobeep_test") {
-  deps = [ "//chrome/browser/resources/pdf:pdf_viewer_wrapper" ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("page_change_test") {
-  deps = [
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-    "//third_party/polymer/v3_0/components-chromium/iron-test-helpers:mock-interactions",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("post_message_proxy_test") {
-  deps = [
-    "../webui:test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("printing_icon_test") {
-  deps = [ "//chrome/browser/resources/pdf:pdf_viewer_wrapper" ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("params_parser_test") {
-  deps = [ "//chrome/browser/resources/pdf:pdf_viewer_wrapper" ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("scroll_with_form_field_focused_test") {
-  deps = [
-    "../webui:test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("test_util") {
-  deps = [
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
-js_library("title_test") {
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("viewer_password_dialog_test") {
-  deps = [
-    "../webui:test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-    "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
-    "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("viewer_pdf_sidenav_test") {
-  deps = [ "//chrome/browser/resources/pdf:pdf_viewer_wrapper" ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("viewer_properties_dialog_test") {
-  deps = [
-    "../webui:test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("viewer_thumbnail_bar_test") {
-  deps = [
-    "../webui:test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-    "//third_party/polymer/v3_0/components-chromium/iron-test-helpers:mock-interactions",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/js/cr/ui:focus_outline_manager.m",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("viewer_thumbnail_test") {
-  deps = [
-    "../webui:test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("viewer_toolbar_test") {
-  deps = [
-    "../webui:test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("viewport_test") {
-  deps = [
-    ":test_util",
-    "//chrome/browser/resources/pdf:pdf_viewer_wrapper",
-  ]
-  externs_list = [ "$externs_path/test.js" ]
-}
-
-js_library("whitespace_title_test") {
-  externs_list = [ "$externs_path/test.js" ]
-}
diff --git a/chrome/test/data/pdf/download_controls_test.js b/chrome/test/data/pdf/download_controls_test.js
index f7d1aa5..7aa0d63 100644
--- a/chrome/test/data/pdf/download_controls_test.js
+++ b/chrome/test/data/pdf/download_controls_test.js
@@ -3,9 +3,8 @@
 // found in the LICENSE file.
 
 import {eventToPromise} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/_test_resources/webui/test_util.js';
-import {CrActionMenuElement, SaveRequestType, ViewerDownloadControlsElement} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js';
+import {SaveRequestType, ViewerDownloadControlsElement} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js';
 import {listenOnce} from 'chrome://resources/js/util.m.js';
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 const tests = [
   /**
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index 36d9d29..744236ea 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -9,7 +9,6 @@
 
 GEN('#include "chrome/browser/ui/webui/extensions/' +
     'extension_settings_browsertest.h"');
-GEN('#include "chrome/browser/ui/ui_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
 GEN('#include "build/chromeos_buildflags.h"');
 
@@ -291,20 +290,6 @@
 });
 
 ////////////////////////////////////////////////////////////////////////////////
-// Extension Site Access Tests
-
-var CrExtensionsSiteAccessTest = class extends CrExtensionsBrowserTest {
-  /** @override */
-  get browsePreload() {
-    return 'chrome://extensions/test_loader.html?module=extensions/site_access_test.js';
-  }
-};
-
-TEST_F('CrExtensionsSiteAccessTest', 'All', () => {
-  mocha.run();
-});
-
-////////////////////////////////////////////////////////////////////////////////
 // Extension Item List Tests
 
 var CrExtensionsItemListTest = class extends CrExtensionsBrowserTest {
@@ -521,13 +506,6 @@
           extension_manager_tests.TestNames.UrlNavigationToActivityLogFail);
     });
 
-TEST_F(
-    'CrExtensionsManagerTestWithIdQueryParam', 'UrlNavigationToSiteAccessFail',
-    function() {
-      this.runMochaTest(
-          extension_manager_tests.TestNames.UrlNavigationToSiteAccessFail);
-    });
-
 CrExtensionsManagerTestWithActivityLogFlag =
     class extends CrExtensionsManagerTestWithIdQueryParam {
   /** @override */
@@ -550,26 +528,6 @@
           extension_manager_tests.TestNames.UrlNavigationToActivityLogSuccess);
     });
 
-CrExtensionsManagerTestWithNewSiteAccess =
-    class extends CrExtensionsManagerTestWithIdQueryParam {
-  /** @override */
-  get browsePreload() {
-    return 'chrome://extensions/test_loader.html?module=extensions/manager_test_with_new_site_access.js';
-  }
-
-  /** @override */
-  get featureList() {
-    return {enabled: ['features::kExtensionsMenuAccessControl']};
-  }
-};
-
-TEST_F(
-    'CrExtensionsManagerTestWithNewSiteAccess',
-    'UrlNavigationToSiteAccessSuccess', function() {
-      this.runMochaTest(
-          extension_manager_tests.TestNames.UrlNavigationToSiteAccessSuccess);
-    });
-
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Keyboard Shortcuts Tests
 
diff --git a/chrome/test/data/webui/extensions/detail_view_test.js b/chrome/test/data/webui/extensions/detail_view_test.js
index 5f67cac..29227b92 100644
--- a/chrome/test/data/webui/extensions/detail_view_test.js
+++ b/chrome/test/data/webui/extensions/detail_view_test.js
@@ -55,11 +55,9 @@
     item.set('inDevMode', false);
     item.set('incognitoAvailable', true);
     item.set('showActivityLog', false);
-    item.set('useNewSiteAccessPage', false);
     document.body.appendChild(item);
   });
 
-  // TODO(crbug.com/1253673): Break this test up into smaller subtests.
   test(assert(extension_detail_view_tests.TestNames.Layout), function() {
     flush();
 
@@ -127,36 +125,6 @@
     item.set('data.permissions', {simplePermissions: []});
     flush();
 
-    expectFalse(testIsVisible('#extensionsSiteAccessLink'));
-    expectTrue(testIsVisible('#no-site-access'));
-    item.set('useNewSiteAccessPage', true);
-    flush();
-
-    // Since there are no site permissions, there shouldn't be a link to the
-    // site access page.
-    expectFalse(testIsVisible('#extensionsSiteAccessLink'));
-    expectTrue(testIsVisible('#no-site-access'));
-
-    // Adding any runtime host permissions should result in the runtime host
-    // controls becoming visible.
-    const allSitesPermissions = {
-      simplePermissions: [],
-      runtimeHostPermissions: {
-        hosts: [{granted: false, host: '<all_urls>'}],
-        hasAllHosts: true,
-        hostAccess: chrome.developerPrivate.HostAccess.ON_CLICK,
-      },
-    };
-    item.set('data.permissions', allSitesPermissions);
-    flush();
-
-    expectTrue(testIsVisible('#extensionsSiteAccessLink'));
-    expectFalse(testIsVisible('#no-site-access'));
-
-    item.set('useNewSiteAccessPage', false);
-    item.set('data.permissions', {simplePermissions: []});
-    flush();
-
     const optionsUrl =
         'chrome-extension://' + extensionData.id + '/options.html';
     item.set('data.optionsPage', {openInTab: true, url: optionsUrl});
@@ -238,6 +206,14 @@
 
     // Adding any runtime host permissions should result in the runtime host
     // controls becoming visible.
+    const allSitesPermissions = {
+      simplePermissions: [],
+      runtimeHostPermissions: {
+        hosts: [{granted: false, host: '<all_urls>'}],
+        hasAllHosts: true,
+        hostAccess: chrome.developerPrivate.HostAccess.ON_CLICK,
+      },
+    };
     item.set('data.permissions', allSitesPermissions);
     flush();
     expectFalse(testIsVisible('#no-site-access'));
@@ -351,13 +327,6 @@
             currentPage,
             {page: Page.ACTIVITY_LOG, extensionId: extensionData.id});
 
-        // Ditto for the site access page, which is hidden behind a feature
-        // flag.
-        item.shadowRoot.querySelector('#extensionsSiteAccessLink').click();
-        expectDeepEquals(
-            currentPage,
-            {page: Page.EXTENSION_SITE_ACCESS, extensionId: extensionData.id});
-
         // Reset current page and test delegate calls.
         navigation.navigateTo(
             {page: Page.DETAILS, extensionId: extensionData.id});
diff --git a/chrome/test/data/webui/extensions/manager_test_with_id_query_param.js b/chrome/test/data/webui/extensions/manager_test_with_id_query_param.js
index 27369888..98966a1 100644
--- a/chrome/test/data/webui/extensions/manager_test_with_id_query_param.js
+++ b/chrome/test/data/webui/extensions/manager_test_with_id_query_param.js
@@ -15,8 +15,6 @@
   UrlNavigationToDetails: 'url navigation to details',
   UrlNavigationToActivityLogFail:
       'url navigation to activity log without flag set',
-  UrlNavigationToSiteAccessFail:
-      'url navigation to site access page without flag set',
 };
 
 function getDataByName(list, name) {
@@ -99,31 +97,4 @@
         // Should be re-routed to the main page.
         assertViewActive('extensions-item-list');
       });
-
-  test(
-      assert(extension_manager_tests.TestNames.UrlNavigationToSiteAccessFail),
-      function() {
-        expectFalse(manager.useNewSiteAccessPage);
-
-        // Try to open the extensions site access page with a valid ID.
-        navigation.navigateTo({
-          page: Page.EXTENSION_SITE_ACCESS,
-          extensionId: 'ldnnhddmnhbkjipkidpdiheffobcpfmf'
-        });
-        flush();
-
-        // Should be re-routed to details page with useNewSiteAccessPage set to
-        // false.
-        assertViewActive('extensions-detail-view');
-        const detailsView =
-            manager.shadowRoot.querySelector('extensions-detail-view');
-        expectFalse(detailsView.useNewSiteAccessPage);
-
-        // Try to open the extensions site access page with an invalid ID.
-        navigation.navigateTo(
-            {page: Page.EXTENSION_SITE_ACCESS, extensionId: 'z'.repeat(32)});
-        flush();
-        // Should be re-routed to the main page.
-        assertViewActive('extensions-item-list');
-      });
 });
diff --git a/chrome/test/data/webui/extensions/manager_test_with_new_site_access.js b/chrome/test/data/webui/extensions/manager_test_with_new_site_access.js
deleted file mode 100644
index 5a7c72346..0000000
--- a/chrome/test/data/webui/extensions/manager_test_with_new_site_access.js
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2021 The Chromium 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 {navigation, Page} from 'chrome://extensions/extensions.js';
-
-import {assert} from 'chrome://resources/js/assert.m.js';
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {eventToPromise} from '../test_util.js';
-
-
-window.extension_manager_tests = {};
-extension_manager_tests.suiteName = 'ExtensionManagerTest';
-/** @enum {string} */
-extension_manager_tests.TestNames = {
-  UrlNavigationToSiteAccessSuccess:
-      'url navigation to site access page with flag set',
-};
-
-suite(extension_manager_tests.suiteName, function() {
-  /** @type {ExtensionsManagerElement} */
-  let manager;
-
-  /** @param {string} tagName */
-  function assertViewActive(tagName) {
-    assertTrue(!!manager.$.viewManager.querySelector(`${tagName}.active`));
-  }
-
-  setup(function() {
-    document.body.innerHTML = '';
-    window.history.replaceState(
-        {}, '', '/?id=ldnnhddmnhbkjipkidpdiheffobcpfmf');
-
-    manager = document.createElement('extensions-manager');
-    document.body.appendChild(manager);
-
-    // Wait for the first view to be active before starting tests.
-    return eventToPromise('view-enter-start', manager);
-  });
-
-
-  test(
-      assert(
-          extension_manager_tests.TestNames.UrlNavigationToSiteAccessSuccess),
-      function() {
-        expectTrue(manager.useNewSiteAccessPage);
-
-        // Try to open the extensions site access page with a valid ID.
-        navigation.navigateTo({
-          page: Page.EXTENSION_SITE_ACCESS,
-          extensionId: 'ldnnhddmnhbkjipkidpdiheffobcpfmf'
-        });
-
-        flush();
-        assertViewActive('extensions-site-access');
-
-        // Try to open extensions site access page with an invalid ID.
-        navigation.navigateTo(
-            {page: Page.EXTENSION_SITE_ACCESS, extensionId: 'z'.repeat(32)});
-        flush();
-        // Should be redirected to the list page.
-        assertViewActive('extensions-item-list');
-      });
-});
diff --git a/chrome/test/data/webui/extensions/runtime_host_permissions_test.js b/chrome/test/data/webui/extensions/runtime_host_permissions_test.js
index 440efab..9dfbd64 100644
--- a/chrome/test/data/webui/extensions/runtime_host_permissions_test.js
+++ b/chrome/test/data/webui/extensions/runtime_host_permissions_test.js
@@ -21,12 +21,12 @@
   const ITEM_ID = 'a'.repeat(32);
 
   setup(function() {
+    loadTimeData.overrideValues({extensionsMenuAccessControlEnabled: false});
     document.body.innerHTML = '';
     element = document.createElement('extensions-runtime-host-permissions');
     delegate = new TestService();
     element.delegate = delegate;
     element.itemId = ITEM_ID;
-    element.useNewSiteAccessPage = false;
 
     document.body.appendChild(element);
 
@@ -85,7 +85,7 @@
   });
 
   test('permissions display new site access menu', function() {
-    element.set('useNewSiteAccessPage', true);
+    loadTimeData.overrideValues({extensionsMenuAccessControlEnabled: true});
     const permissions = {
       hostAccess: HostAccess.ON_CLICK,
       hasAllHosts: true,
diff --git a/chrome/test/data/webui/extensions/site_access_test.js b/chrome/test/data/webui/extensions/site_access_test.js
deleted file mode 100644
index 11989deb..0000000
--- a/chrome/test/data/webui/extensions/site_access_test.js
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2021 The Chromium 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 {navigation, Page} from 'chrome://extensions/extensions.js';
-
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {createExtensionInfo} from './test_util.js';
-
-/** @fileoverview Suite of tests for extensions-site-access. */
-suite('ExtensionsSiteAccessTest', function() {
-  /**
-   * Backing extension id, same id as the one in
-   * createExtensionInfo
-   * @type {string}
-   */
-  const EXTENSION_ID = 'a'.repeat(32);
-
-  /**
-   * Extension site access element created before each test.
-   * @type {ExtensionsSiteAccess}
-   */
-  let extensionsSiteAccess;
-
-  /**
-   * Backing extension info for the site access page.
-   * @type {chrome.developerPrivate.ExtensionInfo}
-   */
-  let extensionInfo;
-
-  /**
-   * ID of a navigation listener. Cleared after every test.
-   * @type {Number}
-   */
-  let listenerId = 0;
-
-  // Initialize an extension site access element before each test.
-  setup(function() {
-    document.body.innerHTML = '';
-
-    extensionsSiteAccess = document.createElement('extensions-site-access');
-
-    extensionInfo = createExtensionInfo({
-      id: EXTENSION_ID,
-    });
-    extensionsSiteAccess.extensionInfo = extensionInfo;
-
-    document.body.appendChild(extensionsSiteAccess);
-
-    extensionsSiteAccess.dispatchEvent(
-        new CustomEvent('view-enter-start', {bubbles: true}));
-  });
-
-  teardown(function() {
-    navigation.removeListener(listenerId);
-  });
-
-  test('clicking on back button navigates to the details page', function() {
-    flush();
-
-    let currentPage = null;
-    listenerId = navigation.addListener(newPage => {
-      currentPage = newPage;
-    });
-
-    extensionsSiteAccess.shadowRoot.querySelector('#closeButton').click();
-    expectDeepEquals(
-        currentPage, {page: Page.DETAILS, extensionId: EXTENSION_ID});
-  });
-});
diff --git a/chromecast/browser/test/cast_navigation_browsertest.cc b/chromecast/browser/test/cast_navigation_browsertest.cc
index 2f714ec..dbf95e1 100644
--- a/chromecast/browser/test/cast_navigation_browsertest.cc
+++ b/chromecast/browser/test/cast_navigation_browsertest.cc
@@ -40,10 +40,9 @@
   void LoadAboutBlank() {
     content::WebContents* web_contents =
         NavigateToURL(GURL(url::kAboutBlankURL));
-    content::TitleWatcher title_watcher(
-        web_contents, base::ASCIIToUTF16(url::kAboutBlankURL));
+    content::TitleWatcher title_watcher(web_contents, url::kAboutBlankURL16);
     std::u16string result = title_watcher.WaitAndGetTitle();
-    EXPECT_EQ(url::kAboutBlankURL, base::UTF16ToASCII(result));
+    EXPECT_EQ(url::kAboutBlankURL16, result);
   }
   void PlayAudio(const std::string& media_file) {
     PlayMedia("audio", media_file);
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 57215768..5cd190e 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-14411.0.0
\ No newline at end of file
+14412.0.0
\ No newline at end of file
diff --git a/chromeos/services/bluetooth_config/cros_bluetooth_config.cc b/chromeos/services/bluetooth_config/cros_bluetooth_config.cc
index f8fd335..7ad73cf 100644
--- a/chromeos/services/bluetooth_config/cros_bluetooth_config.cc
+++ b/chromeos/services/bluetooth_config/cros_bluetooth_config.cc
@@ -46,7 +46,8 @@
           discovered_devices_provider_.get())),
       device_operation_handler_(initializer.CreateDeviceOperationHandler(
           adapter_state_controller_.get(),
-          bluetooth_adapter)),
+          bluetooth_adapter,
+          device_name_manager_.get())),
       fast_pair_delegate_(fast_pair_delegate) {
   if (fast_pair_delegate_)
     fast_pair_delegate_->SetDeviceNameManager(device_name_manager_.get());
diff --git a/chromeos/services/bluetooth_config/device_cache_impl.cc b/chromeos/services/bluetooth_config/device_cache_impl.cc
index 7e689b1..2fc57b1 100644
--- a/chromeos/services/bluetooth_config/device_cache_impl.cc
+++ b/chromeos/services/bluetooth_config/device_cache_impl.cc
@@ -142,15 +142,13 @@
   DeviceChanged(adapter, device);
 }
 
-void DeviceCacheImpl::OnDeviceNicknameChanged(const std::string& device_id,
-                                              const std::string&) {
+void DeviceCacheImpl::OnDeviceNicknameChanged(
+    const std::string& device_id,
+    const absl::optional<std::string>&) {
   for (device::BluetoothDevice* device : bluetooth_adapter_->GetDevices()) {
     if (device->GetIdentifier() != device_id)
       continue;
 
-    // The device should be paired or its nickname shouldn't have been able to
-    // be changed.
-    DCHECK(device->IsPaired());
     DeviceChanged(bluetooth_adapter_.get(), device);
     return;
   }
diff --git a/chromeos/services/bluetooth_config/device_cache_impl.h b/chromeos/services/bluetooth_config/device_cache_impl.h
index 13e05ff8..9702511 100644
--- a/chromeos/services/bluetooth_config/device_cache_impl.h
+++ b/chromeos/services/bluetooth_config/device_cache_impl.h
@@ -78,8 +78,9 @@
                             device::BluetoothDevice::BatteryType type) override;
 
   // DeviceNameManager::Observer:
-  void OnDeviceNicknameChanged(const std::string& device_id,
-                               const std::string& nickname) override;
+  void OnDeviceNicknameChanged(
+      const std::string& device_id,
+      const absl::optional<std::string>& nickname) override;
 
   // Fetches all known devices from BluetoothAdapter and populates them into
   // |paired_devices_| and |unpaired_devices_|.
diff --git a/chromeos/services/bluetooth_config/device_name_manager.cc b/chromeos/services/bluetooth_config/device_name_manager.cc
index 29ea3c6..f82509ae 100644
--- a/chromeos/services/bluetooth_config/device_name_manager.cc
+++ b/chromeos/services/bluetooth_config/device_name_manager.cc
@@ -21,7 +21,7 @@
 
 void DeviceNameManager::NotifyDeviceNicknameChanged(
     const std::string& device_id,
-    const std::string& nickname) {
+    const absl::optional<std::string>& nickname) {
   for (auto& observer : observers_)
     observer.OnDeviceNicknameChanged(device_id, nickname);
 }
diff --git a/chromeos/services/bluetooth_config/device_name_manager.h b/chromeos/services/bluetooth_config/device_name_manager.h
index 8e3e1a3..b9917a8 100644
--- a/chromeos/services/bluetooth_config/device_name_manager.h
+++ b/chromeos/services/bluetooth_config/device_name_manager.h
@@ -25,9 +25,11 @@
     ~Observer() override = default;
 
     // Invoked when the nickname of device with id |device_id| has changed to
-    // |nickname|.
-    virtual void OnDeviceNicknameChanged(const std::string& device_id,
-                                         const std::string& nickname) = 0;
+    // |nickname|. If |nickname| is null, the nickname has been removed for
+    // |device_id|.
+    virtual void OnDeviceNicknameChanged(
+        const std::string& device_id,
+        const absl::optional<std::string>& nickname) = 0;
   };
 
   virtual ~DeviceNameManager();
@@ -42,6 +44,10 @@
   virtual void SetDeviceNickname(const std::string& device_id,
                                  const std::string& nickname) = 0;
 
+  // Removes the nickname of the Bluetooth device with ID |device_id| for all
+  // users of the current device.
+  virtual void RemoveDeviceNickname(const std::string& device_id) = 0;
+
   // Sets the PrefService used to store nicknames.
   virtual void SetPrefs(PrefService* local_state) = 0;
 
@@ -52,7 +58,7 @@
   DeviceNameManager();
 
   void NotifyDeviceNicknameChanged(const std::string& device_id,
-                                   const std::string& nickname);
+                                   const absl::optional<std::string>& nickname);
 
   base::ObserverList<Observer> observers_;
 };
diff --git a/chromeos/services/bluetooth_config/device_name_manager_impl.cc b/chromeos/services/bluetooth_config/device_name_manager_impl.cc
index fa23efd4..8bf786aa 100644
--- a/chromeos/services/bluetooth_config/device_name_manager_impl.cc
+++ b/chromeos/services/bluetooth_config/device_name_manager_impl.cc
@@ -75,7 +75,8 @@
 
   if (!local_state_) {
     BLUETOOTH_LOG(ERROR) << "SetDeviceNickname for device failed because "
-                            "no local_state_ was set.";
+                            "no local_state_ was set, device_id: "
+                         << device_id;
     device::RecordSetDeviceNickName(
         device::SetNicknameResult::kPrefsUnavailable);
     return;
@@ -91,6 +92,29 @@
   device::RecordSetDeviceNickName(device::SetNicknameResult::kSuccess);
 }
 
+void DeviceNameManagerImpl::RemoveDeviceNickname(const std::string& device_id) {
+  if (!local_state_) {
+    BLUETOOTH_LOG(ERROR) << "RemoveDeviceNickname for device failed because "
+                         << "no local_state_ was set, device_id: " << device_id;
+    return;
+  }
+
+  base::DictionaryValue* device_id_to_nickname_map =
+      DictionaryPrefUpdate(local_state_, kDeviceIdToNicknameMapPrefName).Get();
+  DCHECK(device_id_to_nickname_map)
+      << "Device ID to nickname map pref is unregistered.";
+
+  // Do nothing if no nickname exists for |device_id|.
+  if (!device_id_to_nickname_map->FindStringKey(device_id)) {
+    BLUETOOTH_LOG(ERROR) << "RemoveDeviceNickname for device failed because no "
+                         << "nickname exists for " << device_id;
+    return;
+  }
+
+  device_id_to_nickname_map->RemoveKey(device_id);
+  NotifyDeviceNicknameChanged(device_id, /*nickname=*/absl::nullopt);
+}
+
 void DeviceNameManagerImpl::SetPrefs(PrefService* local_state) {
   local_state_ = local_state;
 }
diff --git a/chromeos/services/bluetooth_config/device_name_manager_impl.h b/chromeos/services/bluetooth_config/device_name_manager_impl.h
index f94025d..6a2d1e2 100644
--- a/chromeos/services/bluetooth_config/device_name_manager_impl.h
+++ b/chromeos/services/bluetooth_config/device_name_manager_impl.h
@@ -29,6 +29,7 @@
       const std::string& device_id) override;
   void SetDeviceNickname(const std::string& device_id,
                          const std::string& nickname) override;
+  void RemoveDeviceNickname(const std::string& device_id) override;
   void SetPrefs(PrefService* local_state) override;
 
  private:
diff --git a/chromeos/services/bluetooth_config/device_name_manager_impl_unittest.cc b/chromeos/services/bluetooth_config/device_name_manager_impl_unittest.cc
index 332d0e3..13848b5a 100644
--- a/chromeos/services/bluetooth_config/device_name_manager_impl_unittest.cc
+++ b/chromeos/services/bluetooth_config/device_name_manager_impl_unittest.cc
@@ -37,14 +37,15 @@
     return last_device_id_nickname_changed_;
   }
 
-  const std::string& last_device_nickname_changed() const {
+  const absl::optional<std::string>& last_device_nickname_changed() const {
     return last_device_nickname_changed_;
   }
 
  private:
   // DeviceNameManager::Observer:
-  void OnDeviceNicknameChanged(const std::string& device_id,
-                               const std::string& nickname) override {
+  void OnDeviceNicknameChanged(
+      const std::string& device_id,
+      const absl::optional<std::string>& nickname) override {
     ++num_device_nickname_changed_calls_;
     last_device_id_nickname_changed_ = device_id;
     last_device_nickname_changed_ = nickname;
@@ -52,7 +53,7 @@
 
   size_t num_device_nickname_changed_calls_ = 0u;
   std::string last_device_id_nickname_changed_;
-  std::string last_device_nickname_changed_;
+  absl::optional<std::string> last_device_nickname_changed_;
 };
 
 }  // namespace
@@ -108,7 +109,7 @@
     return fake_observer_.last_device_id_nickname_changed();
   }
 
-  const std::string& GetLastDeviceNicknameChanged() const {
+  const absl::optional<std::string>& GetLastDeviceNicknameChanged() const {
     return fake_observer_.last_device_nickname_changed();
   }
 
@@ -212,5 +213,33 @@
                                      device::SetNicknameResult::kSuccess, 0);
 }
 
+TEST_F(DeviceNameManagerImplTest, RemoveThenSetThenRemove) {
+  std::string device_id;
+  AddDevice(&device_id);
+  std::unique_ptr<DeviceNameManagerImpl> manager = CreateDeviceNameManager();
+  EXPECT_FALSE(manager->GetDeviceNickname(device_id));
+
+  // Nothing should happen when removing a nickname that doesn't exist.
+  manager->RemoveDeviceNickname(device_id);
+  EXPECT_EQ(GetNumDeviceNicknameObserverEvents(), 0u);
+  EXPECT_FALSE(manager->GetDeviceNickname(device_id));
+
+  manager->SetDeviceNickname(device_id, kTestNickname);
+  EXPECT_EQ(manager->GetDeviceNickname(device_id), kTestNickname);
+  EXPECT_EQ(GetNumDeviceNicknameObserverEvents(), 1u);
+  EXPECT_EQ(GetLastDeviceIdNicknameChanged(), device_id);
+  EXPECT_EQ(GetLastDeviceNicknameChanged(), kTestNickname);
+
+  manager->RemoveDeviceNickname(device_id);
+  EXPECT_EQ(GetNumDeviceNicknameObserverEvents(), 2u);
+  EXPECT_FALSE(manager->GetDeviceNickname(device_id));
+  EXPECT_EQ(GetLastDeviceIdNicknameChanged(), device_id);
+  EXPECT_EQ(GetLastDeviceNicknameChanged(), absl::nullopt);
+
+  // Create a new manager and destroy the old one.
+  manager = CreateDeviceNameManager();
+  EXPECT_FALSE(manager->GetDeviceNickname(device_id));
+}
+
 }  // namespace bluetooth_config
 }  // namespace chromeos
diff --git a/chromeos/services/bluetooth_config/device_operation_handler_impl.cc b/chromeos/services/bluetooth_config/device_operation_handler_impl.cc
index ababdd4f..9c082d7 100644
--- a/chromeos/services/bluetooth_config/device_operation_handler_impl.cc
+++ b/chromeos/services/bluetooth_config/device_operation_handler_impl.cc
@@ -11,9 +11,11 @@
 
 DeviceOperationHandlerImpl::DeviceOperationHandlerImpl(
     AdapterStateController* adapter_state_controller,
-    scoped_refptr<device::BluetoothAdapter> bluetooth_adapter)
+    scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
+    DeviceNameManager* device_name_manager)
     : DeviceOperationHandler(adapter_state_controller),
-      bluetooth_adapter_(std::move(bluetooth_adapter)) {}
+      bluetooth_adapter_(std::move(bluetooth_adapter)),
+      device_name_manager_(device_name_manager) {}
 
 DeviceOperationHandlerImpl::~DeviceOperationHandlerImpl() = default;
 
@@ -71,6 +73,7 @@
                                         },
                                         device_id));
 
+  device_name_manager_->RemoveDeviceNickname(device_id);
   HandleFinishedOperation(/*success=*/true);
 }
 
diff --git a/chromeos/services/bluetooth_config/device_operation_handler_impl.h b/chromeos/services/bluetooth_config/device_operation_handler_impl.h
index 1ce067f6..8956bab 100644
--- a/chromeos/services/bluetooth_config/device_operation_handler_impl.h
+++ b/chromeos/services/bluetooth_config/device_operation_handler_impl.h
@@ -7,6 +7,7 @@
 
 #include "base/memory/weak_ptr.h"
 #include "chromeos/services/bluetooth_config/adapter_state_controller.h"
+#include "chromeos/services/bluetooth_config/device_name_manager.h"
 #include "chromeos/services/bluetooth_config/device_operation_handler.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_device.h"
@@ -20,7 +21,8 @@
  public:
   DeviceOperationHandlerImpl(
       AdapterStateController* adapter_state_controller,
-      scoped_refptr<device::BluetoothAdapter> bluetooth_adapter);
+      scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
+      DeviceNameManager* device_name_manager);
   ~DeviceOperationHandlerImpl() override;
 
  private:
@@ -39,6 +41,7 @@
   device::BluetoothDevice* FindDevice(const std::string& device_id) const;
 
   scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
+  DeviceNameManager* device_name_manager_;
 
   base::WeakPtrFactory<DeviceOperationHandlerImpl> weak_ptr_factory_{this};
 };
diff --git a/chromeos/services/bluetooth_config/device_operation_handler_impl_unittest.cc b/chromeos/services/bluetooth_config/device_operation_handler_impl_unittest.cc
index 4841d4ee..abf9d389 100644
--- a/chromeos/services/bluetooth_config/device_operation_handler_impl_unittest.cc
+++ b/chromeos/services/bluetooth_config/device_operation_handler_impl_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/test/task_environment.h"
 #include "chromeos/services/bluetooth_config/fake_adapter_state_controller.h"
+#include "chromeos/services/bluetooth_config/fake_device_name_manager.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/bluetooth/test/mock_bluetooth_device.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -22,6 +23,7 @@
 
 const uint32_t kTestBluetoothClass = 1337u;
 const char kTestBluetoothName[] = "testName";
+const char kTestBluetoothNickname[] = "testNickname";
 
 }  // namespace
 
@@ -48,7 +50,8 @@
             this, &DeviceOperationHandlerImplTest::GetMockDevices));
 
     device_operation_handler_ = std::make_unique<DeviceOperationHandlerImpl>(
-        &fake_adapter_state_controller_, mock_adapter_);
+        &fake_adapter_state_controller_, mock_adapter_,
+        &fake_device_name_manager_);
   }
 
   void SetBluetoothSystemState(mojom::BluetoothSystemState system_state) {
@@ -169,6 +172,15 @@
     forget_callbacks_.reset();
   }
 
+  void SetDeviceNickname(const std::string& device_id) {
+    fake_device_name_manager_.SetDeviceNickname(device_id,
+                                                kTestBluetoothNickname);
+  }
+
+  absl::optional<std::string> GetDeviceNickname(const std::string& device_id) {
+    return fake_device_name_manager_.GetDeviceNickname(device_id);
+  }
+
  private:
   std::vector<const device::BluetoothDevice*> GetMockDevices() {
     std::vector<const device::BluetoothDevice*> devices;
@@ -196,6 +208,7 @@
 
   FakeAdapterStateController fake_adapter_state_controller_;
   scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> mock_adapter_;
+  FakeDeviceNameManager fake_device_name_manager_;
 
   std::unique_ptr<DeviceOperationHandlerImpl> device_operation_handler_;
 };
@@ -256,7 +269,7 @@
                                           /*success=*/true));
 }
 
-TEST_F(DeviceOperationHandlerImplTest, ForgetNotFoundFailThenSucceed) {
+TEST_F(DeviceOperationHandlerImplTest, ForgetNotFoundThenSucceed) {
   std::string device_id = "testid";
 
   // Forget should fail due to device not being found.
@@ -275,6 +288,21 @@
             std::make_tuple(device_id, Operation::kForget, /*success=*/true));
 }
 
+TEST_F(DeviceOperationHandlerImplTest, ForgettingDeviceRemovesNickname) {
+  std::string device_id;
+  AddDevice(&device_id);
+
+  SetDeviceNickname(device_id);
+  absl::optional<std::string> nickname = GetDeviceNickname(device_id);
+  EXPECT_TRUE(nickname.has_value());
+  EXPECT_EQ(kTestBluetoothNickname, nickname.value());
+
+  ForgetDevice(device_id);
+  EXPECT_EQ(results()[0],
+            std::make_tuple(device_id, Operation::kForget, /*success=*/true));
+  EXPECT_FALSE(GetDeviceNickname(device_id).has_value());
+}
+
 TEST_F(DeviceOperationHandlerImplTest, SimultaneousOperationsAreQueued) {
   std::string device_id1 = "device_id1";
   AddDevice(&device_id1);
diff --git a/chromeos/services/bluetooth_config/fake_device_name_manager.cc b/chromeos/services/bluetooth_config/fake_device_name_manager.cc
index 3839267e..2d04de2 100644
--- a/chromeos/services/bluetooth_config/fake_device_name_manager.cc
+++ b/chromeos/services/bluetooth_config/fake_device_name_manager.cc
@@ -27,5 +27,10 @@
   NotifyDeviceNicknameChanged(device_id, nickname);
 }
 
+void FakeDeviceNameManager::RemoveDeviceNickname(const std::string& device_id) {
+  device_id_to_nickname_map_.erase(device_id);
+  NotifyDeviceNicknameChanged(device_id, /*nickname=*/absl::nullopt);
+}
+
 }  // namespace bluetooth_config
 }  // namespace chromeos
diff --git a/chromeos/services/bluetooth_config/fake_device_name_manager.h b/chromeos/services/bluetooth_config/fake_device_name_manager.h
index 3a2a348e..7dcfee5f 100644
--- a/chromeos/services/bluetooth_config/fake_device_name_manager.h
+++ b/chromeos/services/bluetooth_config/fake_device_name_manager.h
@@ -24,6 +24,7 @@
       const std::string& device_id) override;
   void SetDeviceNickname(const std::string& device_id,
                          const std::string& nickname) override;
+  void RemoveDeviceNickname(const std::string& device_id) override;
   void SetPrefs(PrefService* local_state) override {}
 
  private:
diff --git a/chromeos/services/bluetooth_config/initializer.h b/chromeos/services/bluetooth_config/initializer.h
index f546cc5f..ca7824dc1 100644
--- a/chromeos/services/bluetooth_config/initializer.h
+++ b/chromeos/services/bluetooth_config/initializer.h
@@ -55,7 +55,8 @@
       DiscoveredDevicesProvider* discovered_devices_provider) = 0;
   virtual std::unique_ptr<DeviceOperationHandler> CreateDeviceOperationHandler(
       AdapterStateController* adapter_state_controller,
-      scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) = 0;
+      scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
+      DeviceNameManager* device_name_manager) = 0;
 
  protected:
   Initializer() = default;
diff --git a/chromeos/services/bluetooth_config/initializer_impl.cc b/chromeos/services/bluetooth_config/initializer_impl.cc
index cfef9d8..9f7b5af 100644
--- a/chromeos/services/bluetooth_config/initializer_impl.cc
+++ b/chromeos/services/bluetooth_config/initializer_impl.cc
@@ -72,9 +72,11 @@
 std::unique_ptr<DeviceOperationHandler>
 InitializerImpl::CreateDeviceOperationHandler(
     AdapterStateController* adapter_state_controller,
-    scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) {
+    scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
+    DeviceNameManager* device_name_manager) {
   return std::make_unique<DeviceOperationHandlerImpl>(
-      adapter_state_controller, std::move(bluetooth_adapter));
+      adapter_state_controller, std::move(bluetooth_adapter),
+      device_name_manager);
 }
 
 }  // namespace bluetooth_config
diff --git a/chromeos/services/bluetooth_config/initializer_impl.h b/chromeos/services/bluetooth_config/initializer_impl.h
index 27ec50f..df24f574 100644
--- a/chromeos/services/bluetooth_config/initializer_impl.h
+++ b/chromeos/services/bluetooth_config/initializer_impl.h
@@ -40,7 +40,8 @@
       DiscoveredDevicesProvider* discovered_devices_provider) override;
   std::unique_ptr<DeviceOperationHandler> CreateDeviceOperationHandler(
       AdapterStateController* adapter_state_controller,
-      scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) override;
+      scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
+      DeviceNameManager* device_name_manager) override;
 };
 
 }  // namespace bluetooth_config
diff --git a/chromeos/services/bluetooth_config/scoped_bluetooth_config_test_helper.cc b/chromeos/services/bluetooth_config/scoped_bluetooth_config_test_helper.cc
index 8d1de5e..906e83ce 100644
--- a/chromeos/services/bluetooth_config/scoped_bluetooth_config_test_helper.cc
+++ b/chromeos/services/bluetooth_config/scoped_bluetooth_config_test_helper.cc
@@ -96,7 +96,8 @@
 std::unique_ptr<DeviceOperationHandler>
 ScopedBluetoothConfigTestHelper::CreateDeviceOperationHandler(
     AdapterStateController* adapter_state_controller,
-    scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) {
+    scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
+    DeviceNameManager* device_name_manager) {
   auto fake_device_operation_handler =
       std::make_unique<FakeDeviceOperationHandler>(adapter_state_controller);
   fake_device_operation_handler_ = fake_device_operation_handler.get();
diff --git a/chromeos/services/bluetooth_config/scoped_bluetooth_config_test_helper.h b/chromeos/services/bluetooth_config/scoped_bluetooth_config_test_helper.h
index a915632..f5edc59 100644
--- a/chromeos/services/bluetooth_config/scoped_bluetooth_config_test_helper.h
+++ b/chromeos/services/bluetooth_config/scoped_bluetooth_config_test_helper.h
@@ -89,7 +89,8 @@
       DiscoveredDevicesProvider* discovered_devices_provider) override;
   std::unique_ptr<DeviceOperationHandler> CreateDeviceOperationHandler(
       AdapterStateController* adapter_state_controller,
-      scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) override;
+      scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
+      DeviceNameManager* device_name_manager) override;
 
   FakeAdapterStateController* fake_adapter_state_controller_;
   FakeBluetoothDeviceStatusNotifier* fake_bluetooth_device_status_notifier_;
diff --git a/components/BUILD.gn b/components/BUILD.gn
index f4ac6f2..1f558c9 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -848,6 +848,22 @@
         "//build/config/fuchsia/test/present_view_capabilities.test-cmx",
       ]
     }
+
+    # This test won't work as-is on POSIX platforms, where fork()+exec() is
+    # used to launch child processes, failure does not happen until exec().
+    # See also ServiceProcessLauncherTest.FailToLaunchProcess and
+    # UtilityProcessHostBrowserTest.FailToLaunchProcess.
+    if (!is_posix || is_mac) {
+      sources += [
+        "metrics/content/content_stability_metrics_provider_browsertest.cc",
+      ]
+      deps += [
+        "//components/prefs:test_support",
+        "//components/variations",
+        "//content/test:content_test_mojo_bindings",
+        "//sandbox",
+      ]
+    }
   }
 
   test("components_perftests") {
diff --git a/components/autofill/core/browser/payments/payments_client.h b/components/autofill/core/browser/payments/payments_client.h
index d69bfe5a..2202ea7 100644
--- a/components/autofill/core/browser/payments/payments_client.h
+++ b/components/autofill/core/browser/payments/payments_client.h
@@ -277,6 +277,9 @@
     LOCAL_CARD_MIGRATION_SETTINGS_PAGE,
   };
 
+  // TODO(crbug.com/1281695): Add GetDetailsForEnrollRequest.
+  // A collection of information received in the response for a
+  // GetDetailsForEnrollRequest.
   struct GetDetailsForEnrollmentResponseDetails {
     GetDetailsForEnrollmentResponseDetails();
     GetDetailsForEnrollmentResponseDetails(
@@ -284,17 +287,17 @@
     GetDetailsForEnrollmentResponseDetails& operator=(
         const GetDetailsForEnrollmentResponseDetails&) = delete;
     ~GetDetailsForEnrollmentResponseDetails();
-    // |vcn_context_token_| is used in the sequential Enroll call, where it
-    // allows the server to get the instrument id for this |vcn_context_token_|
+    // |vcn_context_token| is used in the sequential Enroll call, where it
+    // allows the server to get the instrument id for this |vcn_context_token|
     // and link this specific GetDetailsForEnroll call with its corresponding
     // enroll call.
-    std::string vcn_context_token_;
+    std::string vcn_context_token;
     // Google's legal message lines in the virtual card enroll flow for this
-    // specific card based on |vcn_context_token_|.
-    LegalMessageLines google_legal_message_;
+    // specific card based on |vcn_context_token|.
+    LegalMessageLines google_legal_message;
     // The issuer's legal message lines in the virtual card enroll flow for this
-    // specific card based on |vcn_context_token_|.
-    LegalMessageLines issuer_legal_message_;
+    // specific card based on |vcn_context_token|.
+    LegalMessageLines issuer_legal_message;
   };
 
   // |url_loader_factory| is reference counted so it has no lifetime or
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
index 4b8f074..56d1dc5 100644
--- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
+++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
@@ -46,7 +46,7 @@
     raw_ptr<CreditCard> credit_card) {}
 
 void VirtualCardEnrollmentManager::OnDidGetUpdateVirtualCardEnrollmentResponse(
-    CreditCard::VirtualCardEnrollmentState virtual_card_enrollment_state) {}
+    AutofillClient::PaymentsRpcResult result) {}
 
 void VirtualCardEnrollmentManager::OnVirtualCardEnrollmentBubbleCancelled() {}
 
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
index 4817a42..9139271 100644
--- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
+++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
@@ -9,11 +9,14 @@
 
 #include "base/memory/raw_ptr.h"
 #include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/payments/payments_client.h"
 
 namespace autofill {
 
+class CreditCard;
+
+// This enum is used to denote the specific flow that the virtual card
+// enrollment process is a part of.
 enum class VirtualCardEnrollmentFlow {
   // Default value, should never be used.
   kNone = 0,
@@ -32,7 +35,7 @@
 // This struct is passed into the controller when we show the
 // VirtualCardEnrollmentBubble, and it lets the controller customize the
 // bubble based on the fields in this struct. For example, we will show
-// different last 4 digits of a credit card based on the |credit_card_| object
+// different last 4 digits of a credit card based on the |credit_card| object
 // in this struct.
 struct VirtualCardEnrollmentFields {
   VirtualCardEnrollmentFields();
@@ -40,20 +43,23 @@
   VirtualCardEnrollmentFields& operator=(const VirtualCardEnrollmentFields&) =
       delete;
   ~VirtualCardEnrollmentFields();
-  // Pointer to the credit card to enroll. The |credit_card_| object is owned
+  // Pointer to the credit card to enroll. The |credit_card| object is owned
   // by PersonalDataManager.
-  raw_ptr<CreditCard> credit_card_ = nullptr;
-  // Raw pointer to the image for the card art. The |card_art_image_| object is
+  raw_ptr<CreditCard> credit_card = nullptr;
+  // Raw pointer to the image for the card art. The |card_art_image| object is
   // owned by PersonalDataManager.
-  raw_ptr<gfx::Image> card_art_image_ = nullptr;
+  raw_ptr<gfx::Image> card_art_image = nullptr;
   // The legal message lines for the footer of the
   // VirtualCardEnrollmentBubble.
-  LegalMessageLines legal_message_lines_;
+  LegalMessageLines legal_message_lines;
   // The flow for which the VirtualCardEnrollmentBubble will be shown.
-  VirtualCardEnrollmentFlow virtual_card_enroll_flow_ =
+  VirtualCardEnrollmentFlow virtual_card_enrollment_flow =
       VirtualCardEnrollmentFlow::kNone;
 };
 
+// This struct is used to track the state of the virtual card enrollment
+// process, and its members are read from and written to throughout the process
+// where needed. It is created and owned by VirtualCardEnrollmentManager.
 struct VirtualCardEnrollmentProcessState {
   VirtualCardEnrollmentProcessState();
   VirtualCardEnrollmentProcessState(const VirtualCardEnrollmentProcessState&) =
@@ -62,11 +68,18 @@
       const VirtualCardEnrollmentProcessState&) = delete;
   ~VirtualCardEnrollmentProcessState();
   // Only populated once the risk engine responded.
-  absl::optional<std::string> risk_data_;
-  // |credit_card_| and |virtual_card_enroll_flow_| are populated in the
-  // beginning of the virtual card enrollment flow, but the rest of the fields
-  // are only populated before showing the VirtualCardEnrollmentBubble.
-  VirtualCardEnrollmentFields virtual_card_enrollment_fields_;
+  absl::optional<std::string> risk_data;
+  // |virtual_card_enrollment_fields|'s |credit_card| and
+  // |virtual_card_enrollment_flow| are populated in the beginning of the
+  // virtual card enrollment flow, but the rest of the fields are only populated
+  // before showing the VirtualCardEnrollmentBubble.
+  VirtualCardEnrollmentFields virtual_card_enrollment_fields;
+  // Populated after the GetDetailsForEnrollResponseDetails are received. Based
+  // on the |vcn_context_token| the server is able to retrieve the instrument
+  // id, and using |vcn_context_token| for enroll allows the server to link a
+  // GetDetailsForEnrollRequest with the corresponding
+  // UpdateVirtualCardEnrollmentRequest for the enroll process.
+  absl::optional<std::string> vcn_context_token;
 };
 
 // Owned by FormDataImporter. There is one instance of this class per tab. This
@@ -81,7 +94,6 @@
   VirtualCardEnrollmentManager& operator=(const VirtualCardEnrollmentManager&) =
       delete;
   ~VirtualCardEnrollmentManager();
-
   // Starting point for the VCN enroll flow. The fields in |credit_card| will
   // be used throughout the flow, such as for request fields as well as credit
   // card specific fields for the bubble to display.
@@ -97,24 +109,29 @@
 
  private:
   // Called once the risk data is loaded. The |risk_data| will be used with
-  // |credit_card|'s |instrument_id_| field to make a GetDetailsForEnroll
-  // request, and |virtual_card_enroll_flow| will be passed down to when we show
-  // the bubble so that we show the correct bubble version.
+  // |state|'s |virtual_card_enrollment_fields|'s |credit_card|'s
+  // |instrument_id_| field to make a GetDetailsForEnroll request, and
+  // |state|'s |virtual_card_enrollment_flow| will be passed down to when we
+  // show the bubble so that we show the correct bubble version.
   void OnRiskDataLoadedForVirtualCard(
       std::unique_ptr<VirtualCardEnrollmentProcessState> state,
       const std::string& risk_data);
 
-  // Sends the GetDetailsForEnrollRequest using AutofillClient's
-  // |payments_client_|. |state|'s |risk_data| and |credit_card|'s
-  // |instrument_id| are the fields the server requires for the
-  // GetDetailsForEnrollRequest, and will be used by |payments_client_|.
-  // |state|'s |virtual_card_enrollment_fields_|'s
-  // |virtual_card_enrollment_flow| is passed here so that it can be forwarded
-  // to ShowVirtualCardEnrollBubble.
+  // TODO(crbug.com/1281695): Add |client_| data member.
+  // Sends the GetDetailsForEnrollRequest using |client_|'s
+  // |payments_client_|. |state|'s |risk_data| and its
+  // |virtual_card_enrollment_fields|'s |credit_card|'s |instrument_id| are the
+  // fields the server requires for the GetDetailsForEnrollRequest, and will be
+  // used by |client_|'s |payments_client_|. |state|'s
+  // |virtual_card_enrollment_fields_|'s |virtual_card_enrollment_flow| is
+  // passed here so that it can be forwarded to ShowVirtualCardEnrollBubble.
   void GetDetailsForEnroll(
       std::unique_ptr<VirtualCardEnrollmentProcessState> state);
 
-  // Handles the response from the GetDetailsForEnrollRequest.
+  // Handles the response from the GetDetailsForEnrollRequest. |result| and
+  // |get_details_for_enrollment_response_fields| are received from the
+  // GetDetailsForEnroll server call response, while |state| is passed down from
+  // GetDetailsForEnroll() to track the current process' state.
   void OnDidGetDetailsForEnrollResponse(
       std::unique_ptr<VirtualCardEnrollmentProcessState> state,
       AutofillClient::PaymentsRpcResult result,
@@ -127,17 +144,21 @@
   void ShowVirtualCardEnrollmentBubble(
       std::unique_ptr<VirtualCardEnrollmentProcessState> state);
 
-  // Uses AutofillClient's |payments_client_| to send the enroll request when
-  // the user accepts the bubble. |vcn_context_token_|, which
+  // TODO(crbug.com/1281695): Add |client_| data member.
+  // Uses |client_|'s |payments_client_| to send the enroll request when
+  // the user accepts the bubble. |state|'s |vcn_context_token_|, which
   // should be set when we receive the GetDetailsForEnrollResponse, is used in
-  // the enroll request to enroll the correct card.
+  // the UpdateVirtualCardEnrollmentRequest to enroll the correct card.
   void OnVirtualCardEnrollmentBubbleAccepted(raw_ptr<CreditCard> credit_card);
 
-  // Handles the response from the Update Virtual Card Enrollment Request.
+  // Handles the response from the UpdateVirtualCardEnrollmentRequest.
+  // |result| represents the result from the server call to change the virtual
+  // card enrollment state for the credit card passed into
+  // OfferVirtualCardEnroll().
   void OnDidGetUpdateVirtualCardEnrollmentResponse(
-      CreditCard::VirtualCardEnrollmentState virtual_card_enrollment_state);
+      AutofillClient::PaymentsRpcResult result);
 
-  // Cancels the entire Virtual Card Enrollment flow.
+  // Cancels the entire Virtual Card Enrollment process.
   void OnVirtualCardEnrollmentBubbleCancelled();
 };
 
diff --git a/components/autofill/core/browser/ui/suggestion.h b/components/autofill/core/browser/ui/suggestion.h
index 96a6338..00cfc654 100644
--- a/components/autofill/core/browser/ui/suggestion.h
+++ b/components/autofill/core/browser/ui/suggestion.h
@@ -10,6 +10,7 @@
 #include "base/strings/string_piece.h"
 #include "base/types/strong_alias.h"
 #include "build/build_config.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/gfx/image/image.h"
 #include "url/gurl.h"
 namespace autofill {
@@ -85,6 +86,9 @@
   IsLoading is_loading = IsLoading(false);
   // The In-Product-Help feature that should be shown for the suggestion.
   std::string feature_for_iph;
+
+  // If specified, this text will be played back as voice over for a11y.
+  absl::optional<std::u16string> voice_over;
 };
 
 }  // namespace autofill
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index 957d363..eb012ce 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "4.64",
-  "log_list_timestamp": "2021-12-20T01:34:42Z",
+  "version": "4.66",
+  "log_list_timestamp": "2021-12-22T01:34:28Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/content_settings/core/browser/content_settings_default_provider.cc b/components/content_settings/core/browser/content_settings_default_provider.cc
index 8169e36..e7d8c4c 100644
--- a/components/content_settings/core/browser/content_settings_default_provider.cc
+++ b/components/content_settings/core/browser/content_settings_default_provider.cc
@@ -221,10 +221,15 @@
                                 ContentSettingsType::AUTO_DARK_WEB_CONTENT))),
                             CONTENT_SETTING_NUM_SETTINGS);
 
+#endif
+
+#if defined(OS_ANDROID) || defined(OS_IOS)
+
   UMA_HISTOGRAM_ENUMERATION("ContentSettings.DefaultRequestDesktopSiteSetting",
                             IntToContentSetting(prefs_->GetInteger(GetPrefName(
                                 ContentSettingsType::REQUEST_DESKTOP_SITE))),
                             CONTENT_SETTING_NUM_SETTINGS);
+
 #endif
 
   pref_change_registrar_.Init(prefs_);
diff --git a/components/content_settings/core/browser/content_settings_registry.cc b/components/content_settings/core/browser/content_settings_registry.cc
index b8968af..2a48c11 100644
--- a/components/content_settings/core/browser/content_settings_registry.cc
+++ b/components/content_settings/core/browser/content_settings_registry.cc
@@ -637,7 +637,8 @@
            AllowlistedSchemes(),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
            WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
-           WebsiteSettingsRegistry::PLATFORM_ANDROID,
+           WebsiteSettingsRegistry::PLATFORM_ANDROID |
+               WebsiteSettingsRegistry::PLATFORM_IOS,
            ContentSettingsInfo::INHERIT_IN_INCOGNITO,
            ContentSettingsInfo::PERSISTENT,
            ContentSettingsInfo::EXCEPTIONS_ON_SECURE_AND_INSECURE_ORIGINS);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
index 29117fd..1699ed7 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
@@ -49,12 +49,13 @@
   }
 
 // Returns the value at |index| of |list_value| as an int64_t.
-int64_t GetInt64PrefValue(const base::ListValue& list_value, size_t index) {
+int64_t GetInt64PrefValue(const base::Value& list_value, size_t index) {
   int64_t val = 0;
   base::Value::ConstListView list_value_view = list_value.GetList();
   if (index < list_value_view.size() && list_value_view[index].is_string()) {
-    std::string pref_value = list_value_view[index].GetString();
-    bool rv = base::StringToInt64(pref_value, &val);
+    const base::Value& pref_value = list_value_view[index];
+    DCHECK(pref_value.is_string());
+    bool rv = base::StringToInt64(pref_value.GetString(), &val);
     DCHECK(rv);
   }
   return val;
@@ -62,7 +63,7 @@
 
 // Ensure list has exactly |length| elements, either by truncating at the
 // front, or appending "0"'s to the back.
-void MaintainContentLengthPrefsWindow(base::ListValue* list, size_t length) {
+void MaintainContentLengthPrefsWindow(base::Value* list, size_t length) {
   // Remove data for old days from the front.
   base::Value::ListView list_view = list->GetList();
   while (list_view.size() > length)
@@ -79,7 +80,7 @@
 // number.
 void AddInt64ToListPref(size_t index,
                         int64_t length,
-                        base::ListValue* list_update) {
+                        base::Value* list_update) {
   int64_t value = GetInt64PrefValue(*list_update, index) + length;
   list_update->GetList()[index] = base::Value(base::NumberToString(value));
 }
@@ -111,7 +112,7 @@
                          int key,
                          int value) {
   DictionaryPrefUpdate pref_update(pref_service, pref);
-  base::DictionaryValue* pref_dict = pref_update.Get();
+  base::Value* pref_dict = pref_update.Get();
   const std::string key_str = base::NumberToString(key);
   base::Value* dict_value = pref_dict->FindKey(key_str);
   if (dict_value)
@@ -264,7 +265,7 @@
   }
 
   // Non-owned. Lazily initialized, set to nullptr until initialized.
-  raw_ptr<base::ListValue> update_;
+  raw_ptr<base::Value> update_;
   // Non-owned pointer.
   raw_ptr<DataReductionProxyCompressionStats> compression_stats_;
   // The path of the content length pref for |this|.
@@ -396,8 +397,7 @@
 
 void DataReductionProxyCompressionStats::InitListPref(const char* pref) {
   base::Value pref_value = pref_service_->GetList(pref)->Clone();
-  list_pref_map_[pref] = base::ListValue::From(
-      base::Value::ToUniquePtrValue(std::move(pref_value)));
+  list_pref_map_[pref] = std::move(pref_value);
 }
 
 int64_t DataReductionProxyCompressionStats::GetInt64(const char* pref_path) {
@@ -425,7 +425,7 @@
   SetInt64(pref_path, GetInt64(pref_path) + delta);
 }
 
-base::ListValue* DataReductionProxyCompressionStats::GetList(
+base::Value* DataReductionProxyCompressionStats::GetList(
     const char* pref_path) {
   if (delay_.is_zero())
     return ListPrefUpdate(pref_service_, pref_path).Get();
@@ -434,7 +434,7 @@
   auto it = list_pref_map_.find(pref_path);
   if (it == list_pref_map_.end())
     return nullptr;
-  return it->second.get();
+  return &it->second;
 }
 
 void DataReductionProxyCompressionStats::WritePrefs() {
@@ -448,7 +448,7 @@
 
   for (auto iter = list_pref_map_.begin(); iter != list_pref_map_.end();
        ++iter) {
-    TransferList(*(iter->second.get()),
+    TransferList(iter->second,
                  ListPrefUpdate(pref_service_, iter->first).Get());
   }
 }
@@ -461,9 +461,9 @@
 }
 
 void DataReductionProxyCompressionStats::ResetStatistics() {
-  base::ListValue* original_update =
+  base::Value* original_update =
       GetList(prefs::kDailyHttpOriginalContentLength);
-  base::ListValue* received_update =
+  base::Value* received_update =
       GetList(prefs::kDailyHttpReceivedContentLength);
   original_update->ClearList();
   received_update->ClearList();
@@ -484,7 +484,7 @@
 ContentLengthList DataReductionProxyCompressionStats::GetDailyContentLengths(
     const char* pref_name) {
   ContentLengthList content_lengths;
-  const base::ListValue* list_value = GetList(pref_name);
+  const base::Value* list_value = GetList(pref_name);
   if (list_value->GetList().size() == kNumDaysInHistory) {
     for (size_t i = 0; i < kNumDaysInHistory; ++i)
       content_lengths.push_back(GetInt64PrefValue(*list_value, i));
@@ -499,9 +499,9 @@
     int64_t* last_update_time) {
   DCHECK_LE(days, kNumDaysInHistory);
 
-  const base::ListValue* original_list =
+  const base::Value* original_list =
       GetList(prefs::kDailyHttpOriginalContentLength);
-  const base::ListValue* received_list =
+  const base::Value* received_list =
       GetList(prefs::kDailyHttpReceivedContentLength);
 
   if (original_list->GetList().size() != kNumDaysInHistory ||
@@ -611,7 +611,7 @@
 
   for (auto iter = list_pref_map_.begin(); iter != list_pref_map_.end();
        ++iter) {
-    iter->second->ClearList();
+    iter->second.ClearList();
   }
 
   RecordSavingsClearedMetric(reason);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
index cc86976..4595582 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
@@ -28,7 +28,6 @@
 class PrefService;
 
 namespace base {
-class ListValue;
 class Value;
 }
 
@@ -169,7 +168,7 @@
   friend class DataReductionProxyCompressionStatsTest;
 
   typedef std::map<const char*, int64_t> DataReductionProxyPrefMap;
-  typedef std::unordered_map<const char*, std::unique_ptr<base::ListValue>>
+  typedef std::unordered_map<const char*, base::Value>
       DataReductionProxyListPrefMap;
 
   class DailyContentLengthUpdate;
@@ -201,7 +200,7 @@
   void IncreaseInt64Pref(const char* pref_path, int64_t delta);
 
   // Gets the pref list at |pref_path| from the |DataReductionProxyPrefMap|.
-  base::ListValue* GetList(const char* pref_path);
+  base::Value* GetList(const char* pref_path);
 
   // Writes the prefs stored in |DataReductionProxyPrefMap| and
   // |DataReductionProxyListPrefMap| to |pref_service|.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
index d45ccd464..932ff0e0 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
@@ -38,8 +38,7 @@
 // for 60 days.
 const int kNumExpectedBuckets = 60 * 24 * 60 / 15;
 
-int64_t GetListPrefInt64Value(const base::ListValue& list_update,
-                              size_t index) {
+int64_t GetListPrefInt64Value(const base::Value& list_update, size_t index) {
   std::string string_value;
   base::Value::ConstListView list_view = list_update.GetList();
   if (index < list_view.size() && list_view[index].is_string()) {
@@ -157,9 +156,9 @@
     compression_stats_->SetInt64(
         prefs::kHttpReceivedContentLength, kReceivedLength);
 
-    base::ListValue* original_daily_content_length_list =
+    base::Value* original_daily_content_length_list =
         compression_stats_->GetList(prefs::kDailyHttpOriginalContentLength);
-    base::ListValue* received_daily_content_length_list =
+    base::Value* received_daily_content_length_list =
         compression_stats_->GetList(prefs::kDailyHttpReceivedContentLength);
 
     for (size_t i = 0; i < kNumDaysInHistory; ++i) {
@@ -185,9 +184,8 @@
   // Verify the pref list values in |pref_service_| are equal to those in
   // |simple_pref_service| for |pref|.
   void VerifyPrefListWasWritten(const char* pref) {
-    const base::ListValue* delayed_list = compression_stats_->GetList(pref);
-    const base::ListValue* written_list =
-        &base::Value::AsListValue(*pref_service()->GetList(pref));
+    const base::Value* delayed_list = compression_stats_->GetList(pref);
+    const base::Value* written_list = pref_service()->GetList(pref);
     ASSERT_EQ(delayed_list->GetList().size(), written_list->GetList().size());
     size_t count = delayed_list->GetList().size();
 
@@ -205,25 +203,6 @@
     EXPECT_EQ(delayed_pref, written_pref);
   }
 
-  // Verify the pref values in |dict| are equal to that in |compression_stats_|.
-  void VerifyPrefs(base::DictionaryValue* dict) {
-    std::u16string dict_pref_string;
-    int64_t dict_pref;
-    int64_t service_pref;
-
-    dict->GetString("historic_original_content_length", &dict_pref_string);
-    base::StringToInt64(dict_pref_string, &dict_pref);
-    service_pref =
-        compression_stats_->GetInt64(prefs::kHttpOriginalContentLength);
-    EXPECT_EQ(service_pref, dict_pref);
-
-    dict->GetString("historic_received_content_length", &dict_pref_string);
-    base::StringToInt64(dict_pref_string, &dict_pref);
-    service_pref =
-        compression_stats_->GetInt64(prefs::kHttpReceivedContentLength);
-    EXPECT_EQ(service_pref, dict_pref);
-  }
-
   // Verify the pref list values are equal to the given values.
   // If the count of values is less than kNumDaysInHistory, zeros are assumed
   // at the beginning.
@@ -232,7 +211,7 @@
                       size_t count,
                       size_t num_days_in_history) {
     ASSERT_GE(num_days_in_history, count);
-    base::ListValue* update = compression_stats_->GetList(pref);
+    base::Value* update = compression_stats_->GetList(pref);
     ASSERT_EQ(num_days_in_history, update->GetList().size())
         << "Pref: " << pref;
 
diff --git a/components/embedder_support/user_agent_utils.cc b/components/embedder_support/user_agent_utils.cc
index 2c451bda..0c5532b 100644
--- a/components/embedder_support/user_agent_utils.cc
+++ b/components/embedder_support/user_agent_utils.cc
@@ -39,6 +39,7 @@
 namespace {
 
 constexpr char kVersion100[] = "100";
+constexpr char kVersion99[] = "99";
 
 #if defined(OS_WIN)
 
@@ -138,6 +139,31 @@
   return *m100_version_number;
 }
 
+const std::string& GetMajorInMinorVersionNumber() {
+  static const base::NoDestructor<std::string> version_number([] {
+    base::Version version(version_info::GetVersionNumber());
+    std::string version_str;
+    const std::vector<uint32_t>& components = version.components();
+    for (size_t i = 0; i < components.size(); ++i) {
+      if (i > 0) {
+        version_str.append(".");
+      }
+      if (i == 0) {
+        // Hardcode major version to 99
+        version_str.append(kVersion99);
+      } else if (i == 1) {
+        // Force major into minor version
+        version_str.append(base::NumberToString(components[0]));
+      } else {
+        // build and patch stay the same
+        version_str.append(base::NumberToString(components[i]));
+      }
+    }
+    return version_str;
+  }());
+  return *version_number;
+}
+
 const std::string& GetM100InMinorVersionNumber() {
   static const base::NoDestructor<std::string> m100_version_number([] {
     base::Version version(version_info::GetVersionNumber());
@@ -248,10 +274,20 @@
 }
 
 std::string GetProduct(const bool allow_version_override) {
+  // FF Priority 1: force major version to 99 and minor version to major version
+  // number.
+  if (allow_version_override &&
+      base::FeatureList::IsEnabled(
+          blink::features::kForceMajorVersionInMinorPositionInUserAgent))
+    return "Chrome/" + GetMajorInMinorVersionNumber();
+
+  // FF Priority 2: Force major version to 100, leave the rest the same.
   if (allow_version_override &&
       base::FeatureList::IsEnabled(
           blink::features::kForceMajorVersion100InUserAgent))
     return "Chrome/" + GetM100VersionNumber();
+
+  // FF Priority 3: Force minor version to 100, leave the rest the same.
   if (allow_version_override &&
       base::FeatureList::IsEnabled(
           blink::features::kForceMinorVersion100InUserAgent))
diff --git a/components/embedder_support/user_agent_utils_unittest.cc b/components/embedder_support/user_agent_utils_unittest.cc
index 5129237..e8ef75e2 100644
--- a/components/embedder_support/user_agent_utils_unittest.cc
+++ b/components/embedder_support/user_agent_utils_unittest.cc
@@ -49,7 +49,7 @@
 // the User-Agent string, where the first capture is the {major_version} and the
 // second capture is the {minor_version}.
 static constexpr char kChromeProductVersionRegex[] =
-    "Chrome/([0-9]+)\\.([0-9]+\\.[0-9]+\\.[0-9]+)";
+    "Chrome/([0-9]+).([0-9]+).([0-9]+).([0-9]+)";
 
 void CheckUserAgentStringOrdering(bool mobile_device) {
   std::vector<std::string> pieces;
@@ -762,7 +762,7 @@
   EXPECT_TRUE(
       re2::RE2::FullMatch(product, kChromeProductVersionRegex, &major_version));
   // Whether the force M100 experiment is on or not, the product value should
-  // contain the actual major version number.
+  // contain the actual major version number which is 0.
   EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
 }
 
@@ -776,7 +776,8 @@
     EXPECT_EQ(major_version, "100");
   else
     EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
-  EXPECT_NE(minor_version, "0.0.0");
+  // Minor version should contain the actual minor version number.
+  EXPECT_EQ(minor_version, "0");
 }
 
 class UserAgentUtilsMinorVersionTest
@@ -784,12 +785,12 @@
       public testing::WithParamInterface<bool> {
  public:
   void SetUp() override {
-    if (ForceMinorVersionTo100())
+    if (ForceMajorInMinorVersion())
       scoped_feature_list_.InitAndEnableFeature(
-          blink::features::kForceMinorVersion100InUserAgent);
+          blink::features::kForceMajorVersionInMinorPositionInUserAgent);
   }
 
-  bool ForceMinorVersionTo100() { return GetParam(); }
+  bool ForceMajorInMinorVersion() { return GetParam(); }
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
@@ -797,7 +798,7 @@
 
 INSTANTIATE_TEST_CASE_P(All,
                         UserAgentUtilsMinorVersionTest,
-                        /*force_minor_version_to_M100*/ testing::Bool());
+                        /*force_major_version_in_minor*/ testing::Bool());
 
 TEST_P(UserAgentUtilsMinorVersionTest, GetUserAgent) {
   const std::string ua = GetUserAgent();
@@ -805,11 +806,54 @@
   std::string minor_version;
   EXPECT_TRUE(re2::RE2::PartialMatch(ua, kChromeProductVersionRegex,
                                      &major_version, &minor_version));
-  EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
-  if (ForceMinorVersionTo100()) {
-    EXPECT_NE(minor_version, "100.0.0");
+  if (ForceMajorInMinorVersion()) {
+    // When enabled major versions should be locked at 99 and minor version
+    // should hold the major version number.
+    EXPECT_EQ(major_version, "99");
+    EXPECT_EQ(minor_version, version_info::GetMajorVersionNumber());
   } else {
-    EXPECT_NE(minor_version, "0.0.0");
+    // When disabled major version should hold major version number and minor
+    // version should be the minor version number which is 0.
+    EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
+    EXPECT_EQ(minor_version, "0");
+  }
+}
+
+class UserAgentUtilsMinorVersionM100Test
+    : public testing::Test,
+      public testing::WithParamInterface<bool> {
+ public:
+  void SetUp() override {
+    if (ForceMinorVersion100InUserAgent())
+      scoped_feature_list_.InitAndEnableFeature(
+          blink::features::kForceMinorVersion100InUserAgent);
+  }
+
+  bool ForceMinorVersion100InUserAgent() { return GetParam(); }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_CASE_P(All,
+                        UserAgentUtilsMinorVersionM100Test,
+                        /*force_minor_version_to_M100*/ testing::Bool());
+
+TEST_P(UserAgentUtilsMinorVersionM100Test, GetUserAgent) {
+  const std::string ua = GetUserAgent();
+  std::string major_version;
+  std::string minor_version;
+  EXPECT_TRUE(re2::RE2::PartialMatch(ua, kChromeProductVersionRegex,
+                                     &major_version, &minor_version));
+  if (ForceMinorVersion100InUserAgent()) {
+    // When enabled minor version should be hardcoded to 100.
+    EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
+    EXPECT_EQ(minor_version, "100");
+  } else {
+    // When disabled major version should hold major version number and minor
+    // version should be the minor version number which is 0.
+    EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
+    EXPECT_EQ(minor_version, "0");
   }
 }
 
diff --git a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
index f99af4c1..cc4a22b 100644
--- a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
+++ b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
@@ -51,6 +51,15 @@
          * Creates image fetcher parameters. The image will not be resized.
          * @See {@link #Params(String, String, int, int, int)}.
          */
+        public static Params create(final GURL url, String clientName) {
+            return create(url.getSpec(), clientName);
+        }
+
+        /**
+         * Creates image fetcher parameters. The image will not be resized.
+         * @See {@link #Params(String, String, int, int, int)}.
+         */
+        @Deprecated
         public static Params create(final String url, String clientName) {
             return new Params(url, clientName, DEFAULT_IMAGE_SIZE, DEFAULT_IMAGE_SIZE,
                     INVALID_EXPIRATION_INTERVAL);
@@ -60,6 +69,15 @@
          * Creates image fetcher parameters with image size specified.
          * @See {@link #Params(String, String, int, int, int)}.
          */
+        public static Params create(final GURL url, String clientName, int width, int height) {
+            return create(url.getSpec(), clientName, width, height);
+        }
+
+        /**
+         * Creates image fetcher parameters with image size specified.
+         * @See {@link #Params(String, String, int, int, int)}.
+         */
+        @Deprecated
         public static Params create(final String url, String clientName, int width, int height) {
             return new Params(url, clientName, width, height, INVALID_EXPIRATION_INTERVAL);
         }
diff --git a/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherTest.java b/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherTest.java
index d535318..953f102 100644
--- a/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherTest.java
+++ b/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherTest.java
@@ -36,6 +36,7 @@
 @Config(manifest = Config.NONE)
 public class ImageFetcherTest {
     private static final GURL URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL);
+    private static final GURL URL_2 = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_2);
     private static final String CLIENT_NAME = "client";
     private static final int WIDTH_PX = 100;
     private static final int HEIGHT_PX = 200;
@@ -110,19 +111,17 @@
 
     @Test
     public void testFetchImageNoDimensionsAlias() {
-        mImageFetcher.fetchImage(
-                ImageFetcher.Params.create(URL.getSpec(), CLIENT_NAME), result -> {});
+        mImageFetcher.fetchImage(ImageFetcher.Params.create(URL, CLIENT_NAME), result -> {});
 
         // No arguments should alias to 0, 0.
         verify(mImageFetcher)
-                .fetchImage(
-                        eq(ImageFetcher.Params.create(URL.getSpec(), CLIENT_NAME, 0, 0)), any());
+                .fetchImage(eq(ImageFetcher.Params.create(URL, CLIENT_NAME, 0, 0)), any());
     }
 
     @Test
     public void testCreateParams() {
         // Verifies params without size specified.
-        ImageFetcher.Params params = ImageFetcher.Params.create(URL.getSpec(), CLIENT_NAME);
+        ImageFetcher.Params params = ImageFetcher.Params.create(URL, CLIENT_NAME);
         assertEquals(URL.getSpec(), params.url);
         assertEquals(CLIENT_NAME, params.clientName);
         assertEquals(0, params.width);
@@ -130,7 +129,7 @@
         assertEquals(0, params.expirationIntervalMinutes);
 
         // Verifies params with size.
-        params = ImageFetcher.Params.create(URL.getSpec(), CLIENT_NAME, WIDTH_PX, HEIGHT_PX);
+        params = ImageFetcher.Params.create(URL, CLIENT_NAME, WIDTH_PX, HEIGHT_PX);
         assertEquals(URL.getSpec(), params.url);
         assertEquals(CLIENT_NAME, params.clientName);
         assertEquals(WIDTH_PX, params.width);
@@ -153,14 +152,14 @@
     @Test
     public void testParamsEqual() {
         // Different URLs.
-        ImageFetcher.Params params1 = ImageFetcher.Params.create(URL.getSpec(), CLIENT_NAME);
-        ImageFetcher.Params params2 = ImageFetcher.Params.create("Not the same URL", CLIENT_NAME);
+        ImageFetcher.Params params1 = ImageFetcher.Params.create(URL, CLIENT_NAME);
+        ImageFetcher.Params params2 = ImageFetcher.Params.create(URL_2, CLIENT_NAME);
         assertFalse(params1.equals(params2));
         assertFalse(params2.equals(params1));
         assertNotEquals(params1.hashCode(), params2.hashCode());
 
         // Different width and height.
-        params2 = ImageFetcher.Params.create(URL.getSpec(), CLIENT_NAME, WIDTH_PX, HEIGHT_PX);
+        params2 = ImageFetcher.Params.create(URL, CLIENT_NAME, WIDTH_PX, HEIGHT_PX);
         assertFalse(params1.equals(params2));
         assertFalse(params2.equals(params1));
         assertNotEquals(params1.hashCode(), params2.hashCode());
diff --git a/components/language/core/browser/url_language_histogram.cc b/components/language/core/browser/url_language_histogram.cc
index 42713037..7663776 100644
--- a/components/language/core/browser/url_language_histogram.cc
+++ b/components/language/core/browser/url_language_histogram.cc
@@ -25,31 +25,29 @@
 const float kDiscountFactor = 0.75f;
 
 // Gets the sum of the counter for all languages in the histogram.
-int GetCountersSum(const base::DictionaryValue& dict) {
+int GetCountersSum(const base::Value& dict) {
   int sum = 0;
-  for (base::DictionaryValue::Iterator itr(dict); !itr.IsAtEnd();
-       itr.Advance()) {
-    if (itr.value().is_int())
-      sum += itr.value().GetInt();
+  for (const auto itr : dict.DictItems()) {
+    if (itr.second.is_int())
+      sum += itr.second.GetInt();
   }
   return sum;
 }
 
 // Removes languages with small counter values and discount remaining counters.
-void DiscountAndCleanCounters(base::DictionaryValue* dict) {
+void DiscountAndCleanCounters(base::Value* dict) {
   std::set<std::string> remove_keys;
 
-  for (base::DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
-       itr.Advance()) {
+  for (const auto itr : dict->DictItems()) {
     // Remove languages with invalid or small values.
-    if (!itr.value().is_int() ||
-        itr.value().GetInt() < (kCutoffRatio * kMaxCountersSum)) {
-      remove_keys.insert(itr.key());
+    if (!itr.second.is_int() ||
+        itr.second.GetInt() < (kCutoffRatio * kMaxCountersSum)) {
+      remove_keys.insert(itr.first);
       continue;
     }
 
     // Discount the value.
-    dict->SetInteger(itr.key(), itr.value().GetInt() * kDiscountFactor);
+    dict->SetIntKey(itr.first, itr.second.GetInt() * kDiscountFactor);
   }
 
   for (const std::string& lang_to_remove : remove_keys)
@@ -58,7 +56,7 @@
 
 // Transforms the counters from prefs into a list of LanguageInfo structs.
 std::vector<UrlLanguageHistogram::LanguageInfo> GetAllLanguages(
-    const base::DictionaryValue& dict) {
+    const base::Value& dict) {
   int counters_sum = GetCountersSum(dict);
 
   // If the sample is not large enough yet, pretend there are no top languages.
@@ -66,12 +64,11 @@
     return std::vector<UrlLanguageHistogram::LanguageInfo>();
 
   std::vector<UrlLanguageHistogram::LanguageInfo> top_languages;
-  for (base::DictionaryValue::Iterator itr(dict); !itr.IsAtEnd();
-       itr.Advance()) {
-    if (!itr.value().is_int())
+  for (const auto itr : dict.DictItems()) {
+    if (!itr.second.is_int())
       continue;
     top_languages.emplace_back(
-        itr.key(), static_cast<float>(itr.value().GetInt()) / counters_sum);
+        itr.first, static_cast<float>(itr.second.GetInt()) / counters_sum);
   }
   return top_languages;
 }
@@ -92,8 +89,8 @@
 std::vector<UrlLanguageHistogram::LanguageInfo>
 UrlLanguageHistogram::GetTopLanguages() const {
   std::vector<UrlLanguageHistogram::LanguageInfo> top_languages =
-      GetAllLanguages(base::Value::AsDictionaryValue(
-          *pref_service_->GetDictionary(kUrlLanguageHistogramCounters)));
+      GetAllLanguages(
+          *pref_service_->GetDictionary(kUrlLanguageHistogramCounters));
 
   std::sort(top_languages.begin(), top_languages.end(),
             [](UrlLanguageHistogram::LanguageInfo a,
@@ -106,27 +103,25 @@
 
 float UrlLanguageHistogram::GetLanguageFrequency(
     const std::string& language_code) const {
-  const base::DictionaryValue* dict = &base::Value::AsDictionaryValue(
-      *pref_service_->GetDictionary(kUrlLanguageHistogramCounters));
+  const base::Value* dict =
+      pref_service_->GetDictionary(kUrlLanguageHistogramCounters);
   int counters_sum = GetCountersSum(*dict);
   // If the sample is not large enough yet, pretend there are no top languages.
   if (counters_sum < kMinCountersSum)
     return 0;
 
-  int counter_value = 0;
   // If the key |language_code| does not exist, |counter_value| stays 0.
-  dict->GetInteger(language_code, &counter_value);
+  int counter_value = dict->FindIntKey(language_code).value_or(0);
 
   return static_cast<float>(counter_value) / counters_sum;
 }
 
 void UrlLanguageHistogram::OnPageVisited(const std::string& language_code) {
   DictionaryPrefUpdate update(pref_service_, kUrlLanguageHistogramCounters);
-  base::DictionaryValue* dict = update.Get();
-  int counter_value = 0;
+  base::Value* dict = update.Get();
   // If the key |language_code| does not exist, |counter_value| stays 0.
-  dict->GetInteger(language_code, &counter_value);
-  dict->SetInteger(language_code, counter_value + 1);
+  int counter_value = dict->FindIntKey(language_code).value_or(0);
+  dict->SetIntKey(language_code, counter_value + 1);
 
   if (GetCountersSum(*dict) > kMaxCountersSum)
     DiscountAndCleanCounters(dict);
diff --git a/components/metrics/content/DEPS b/components/metrics/content/DEPS
index c8b2783..01ec3c7 100644
--- a/components/metrics/content/DEPS
+++ b/components/metrics/content/DEPS
@@ -10,5 +10,9 @@
   "subprocess_metrics_provider_browsertest\.cc": [
     "+content/shell/browser/shell.h",
     "+net/dns/mock_host_resolver.h",
+  ],
+
+  "content_stability_metrics_provider_browsertest\.cc": [
+    "+sandbox"
   ]
 }
diff --git a/components/metrics/content/content_stability_metrics_provider.cc b/components/metrics/content/content_stability_metrics_provider.cc
index f2f4b51..083128c3 100644
--- a/components/metrics/content/content_stability_metrics_provider.cc
+++ b/components/metrics/content/content_stability_metrics_provider.cc
@@ -128,6 +128,20 @@
     helper_.BrowserUtilityProcessLaunched(data.metrics_name);
 }
 
+void ContentStabilityMetricsProvider::BrowserChildProcessLaunchFailed(
+    const content::ChildProcessData& data,
+    const content::ChildProcessTerminationInfo& info) {
+  DCHECK(!data.metrics_name.empty());
+  DCHECK_EQ(info.status, base::TERMINATION_STATUS_LAUNCH_FAILED);
+  if (data.process_type == content::PROCESS_TYPE_UTILITY)
+    helper_.BrowserUtilityProcessLaunchFailed(data.metrics_name, info.exit_code
+#if defined(OS_WIN)
+                                              ,
+                                              info.last_error
+#endif
+    );
+}
+
 #if defined(OS_ANDROID)
 void ContentStabilityMetricsProvider::OnCrashDumpProcessed(
     int rph_id,
diff --git a/components/metrics/content/content_stability_metrics_provider.h b/components/metrics/content/content_stability_metrics_provider.h
index 3710e37..1d42ed9 100644
--- a/components/metrics/content/content_stability_metrics_provider.h
+++ b/components/metrics/content/content_stability_metrics_provider.h
@@ -76,6 +76,9 @@
       const content::ChildProcessTerminationInfo& info) override;
   void BrowserChildProcessLaunchedAndConnected(
       const content::ChildProcessData& data) override;
+  void BrowserChildProcessLaunchFailed(
+      const content::ChildProcessData& data,
+      const content::ChildProcessTerminationInfo& info) override;
 
 #if defined(OS_ANDROID)
   // crash_reporter::CrashMetricsReporter::Observer:
diff --git a/components/metrics/content/content_stability_metrics_provider_browsertest.cc b/components/metrics/content/content_stability_metrics_provider_browsertest.cc
new file mode 100644
index 0000000..e668e6e
--- /dev/null
+++ b/components/metrics/content/content_stability_metrics_provider_browsertest.cc
@@ -0,0 +1,124 @@
+// Copyright 2021 The Chromium 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/metrics/content/content_stability_metrics_provider.h"
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/metrics/histogram.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "build/build_config.h"
+#include "components/metrics/content/extensions_helper.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/variations/hashing.h"
+#include "content/public/browser/browser_child_process_observer.h"
+#include "content/public/browser/child_process_data.h"
+#include "content/public/browser/service_process_host.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_base.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_service.mojom.h"
+#include "sandbox/policy/mojom/sandbox.mojom.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+
+#include "sandbox/win/src/sandbox_types.h"
+#endif
+
+namespace content {
+
+template <>
+sandbox::mojom::Sandbox GetServiceSandboxType<content::mojom::TestService>() {
+  // On Windows, the sandbox does not like having a different binary name
+  // 'non_existent_path' from the browser process, so set no sandbox here.
+#if defined(OS_WIN)
+  return sandbox::mojom::Sandbox::kNoSandbox;
+#else
+  return sandbox::mojom::Sandbox::kService;
+#endif
+}
+
+}  // namespace content
+
+namespace metrics {
+
+class ContentStabilityProviderBrowserTest
+    : public content::ContentBrowserTest,
+      content::BrowserChildProcessObserver {
+ public:
+  // Either the process launched, or did not launch. Both cause the run_loop to
+  // terminate.
+  void BrowserChildProcessLaunchFailed(
+      const content::ChildProcessData& data,
+      const content::ChildProcessTerminationInfo& info) override {
+    if (data.metrics_name == content::mojom::TestService::Name_)
+      std::move(done_closure_).Run();
+  }
+
+  void BrowserChildProcessLaunchedAndConnected(
+      const content::ChildProcessData& data) override {
+    if (data.metrics_name == content::mojom::TestService::Name_)
+      std::move(done_closure_).Run();
+  }
+
+ protected:
+  void AddObserver() { content::BrowserChildProcessObserver::Add(this); }
+
+  void RemoveObserver() { content::BrowserChildProcessObserver::Remove(this); }
+
+  base::OnceClosure done_closure_;
+  TestingPrefServiceSimple prefs_;
+};
+
+IN_PROC_BROWSER_TEST_F(ContentStabilityProviderBrowserTest,
+                       FailedUtilityProcessLaunches) {
+  base::RunLoop run_loop;
+  done_closure_ = run_loop.QuitClosure();
+  AddObserver();
+
+  ContentStabilityMetricsProvider provider(&prefs_, nullptr);
+  base::HistogramTester histogram_tester;
+
+  // Simulate a catastrophic utility process launch failure by specifying a bad
+  // path.
+  base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
+      switches::kBrowserSubprocessPath,
+      base::FilePath(FILE_PATH_LITERAL("non_existent_path")));
+  mojo::Remote<content::mojom::TestService> test_service;
+  content::ServiceProcessHost::Launch(
+      test_service.BindNewPipeAndPassReceiver());
+
+  // run_loop runs until either the process launches or fails to launch.
+  run_loop.Run();
+
+  RemoveObserver();
+
+  histogram_tester.ExpectUniqueSample(
+      "ChildProcess.LaunchFailed.UtilityProcessHash",
+      variations::HashName(content::mojom::TestService::Name_), 1);
+#if defined(OS_WIN)
+  int expected_error_code =
+      sandbox::SBOX_ERROR_CANNOT_LAUNCH_UNSANDBOXED_PROCESS;
+#else
+  int expected_error_code =
+      1003;  // content::LaunchResultCode::LAUNCH_RESULT_FAILURE.
+#endif
+  histogram_tester.ExpectUniqueSample(
+      "ChildProcess.LaunchFailed.UtilityProcessErrorCode", expected_error_code,
+      1);
+
+#if defined(OS_WIN)
+  // Last Error is only recorded on Windows.
+  histogram_tester.ExpectUniqueSample("ChildProcess.LaunchFailed.WinLastError",
+                                      DWORD{ERROR_FILE_NOT_FOUND}, 1);
+#endif
+}
+
+}  // namespace metrics
diff --git a/components/metrics/stability_metrics_helper.cc b/components/metrics/stability_metrics_helper.cc
index 38e5b30..7b8e4e5 100644
--- a/components/metrics/stability_metrics_helper.cc
+++ b/components/metrics/stability_metrics_helper.cc
@@ -194,6 +194,27 @@
   RecordStabilityEvent(StabilityEventType::kUtilityCrash);
 }
 
+void StabilityMetricsHelper::BrowserUtilityProcessLaunchFailed(
+    const std::string& metrics_name,
+    int launch_error_code
+#if defined(OS_WIN)
+    ,
+    DWORD last_error
+#endif
+) {
+  uint32_t hash = variations::HashName(metrics_name);
+  base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessHash",
+                           hash);
+  base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessErrorCode",
+                           launch_error_code);
+#if defined(OS_WIN)
+  base::UmaHistogramSparse("ChildProcess.LaunchFailed.WinLastError",
+                           last_error);
+#endif
+  // TODO(wfh): Decide if this utility process launch failure should also
+  // trigger a Stability Event.
+}
+
 void StabilityMetricsHelper::BrowserChildProcessCrashed() {
   IncrementPrefValue(prefs::kStabilityChildProcessCrashCount);
   RecordStabilityEvent(StabilityEventType::kChildProcessCrash);
diff --git a/components/metrics/stability_metrics_helper.h b/components/metrics/stability_metrics_helper.h
index 94710cf..7758fde 100644
--- a/components/metrics/stability_metrics_helper.h
+++ b/components/metrics/stability_metrics_helper.h
@@ -9,6 +9,11 @@
 
 #include "base/memory/raw_ptr.h"
 #include "base/process/kill.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_types.h"
+#endif
 
 class PrefRegistrySimple;
 class PrefService;
@@ -64,6 +69,17 @@
   void BrowserUtilityProcessCrashed(const std::string& metrics_name,
                                     int exit_code);
 
+  // Records that a utility process with name |metrics_name| failed to launch.
+  // The |launch_error_code| is a platform-specific error code. On Windows, a
+  // |last_error| is also supplied to help diagnose the launch failure.
+  void BrowserUtilityProcessLaunchFailed(const std::string& metrics_name,
+                                         int launch_error_code
+#if defined(OS_WIN)
+                                         ,
+                                         DWORD last_error
+#endif
+  );
+
   // Records a browser child process crash.
   void BrowserChildProcessCrashed();
 
diff --git a/components/optimization_guide/core/hints_manager.cc b/components/optimization_guide/core/hints_manager.cc
index ce685a5..7ae4f3a 100644
--- a/components/optimization_guide/core/hints_manager.cc
+++ b/components/optimization_guide/core/hints_manager.cc
@@ -861,7 +861,7 @@
           &HintsManager::OnBatchUpdateHintsFetched,
           weak_ptr_factory_.GetWeakPtr(), request_id_and_fetcher.first,
           request_context, target_hosts.set(), target_urls.set(),
-          registered_optimization_types_,
+          target_urls.set(), registered_optimization_types_,
           base::DoNothingAs<void(
               const GURL&, const base::flat_map<
                                proto::OptimizationType,
@@ -990,18 +990,16 @@
 
   // TODO(crbug/1275612): Check whether we have consent to fetch.
 
+  // This set contains URLs that require some information to be fetched, whether
+  // that be a URL-keyed hint or a host-keyed hint.
+  base::flat_set<GURL> urls_with_pending_callback;
+
   InsertionOrderedSet<GURL> urls_to_fetch;
   InsertionOrderedSet<std::string> hosts_to_fetch;
   for (const auto& url : urls) {
-    base::flat_map<proto::OptimizationType,
-                   OptimizationGuideDecisionWithMetadata>
-        decisions = GetDecisionsWithCachedInformationForURLAndOptimizationTypes(
-            url, optimization_types);
-
-    bool has_something_to_fetch_for = false;
     if (!hint_cache_->HasURLKeyedEntryForURL(url)) {
       urls_to_fetch.insert(url);
-      has_something_to_fetch_for = true;
+      urls_with_pending_callback.insert(url);
     }
     // We check for the hint being loaded mostly for code simplicity. If we just
     // check for the presence in the cache and the hint wasn't loaded, we need
@@ -1012,14 +1010,21 @@
     if (!hint_cache_->HasHint(url.host()) ||
         (hint_cache_->GetHostKeyedHintIfLoaded(url.host()) == nullptr)) {
       hosts_to_fetch.insert(url.host());
-      has_something_to_fetch_for = true;
+      urls_with_pending_callback.insert(url);
     }
-    if (!has_something_to_fetch_for) {
+
+    if (!urls_with_pending_callback.contains(url)) {
+      // Only get decisions if we know we do not need to fetch for anything.
+      base::flat_map<proto::OptimizationType,
+                     OptimizationGuideDecisionWithMetadata>
+          decisions =
+              GetDecisionsWithCachedInformationForURLAndOptimizationTypes(
+                  url, optimization_types);
       callback.Run(url, decisions);
     }
   }
 
-  if (urls_to_fetch.empty() && hosts_to_fetch.empty()) {
+  if (urls_with_pending_callback.empty()) {
     // Nothing to fetch for.
     return;
   }
@@ -1037,7 +1042,7 @@
                      weak_ptr_factory_.GetWeakPtr(),
                      request_id_and_fetcher.first, request_context,
                      hosts_to_fetch.set(), urls_to_fetch.set(),
-                     optimization_types, callback));
+                     urls_with_pending_callback, optimization_types, callback));
 }
 
 void HintsManager::OnBatchUpdateHintsFetched(
@@ -1045,6 +1050,7 @@
     proto::RequestContext request_context,
     const base::flat_set<std::string>& hosts_requested,
     const base::flat_set<GURL>& urls_requested,
+    const base::flat_set<GURL>& urls_with_pending_callback,
     const base::flat_set<proto::OptimizationType>& optimization_types,
     OnDemandOptimizationGuideDecisionRepeatingCallback callback,
     absl::optional<std::unique_ptr<proto::GetHintsResponse>>
@@ -1052,7 +1058,8 @@
   CleanUpBatchUpdateHintsFetcher(request_id);
 
   if (!get_hints_response.has_value() || !get_hints_response.value()) {
-    OnBatchUpdateHintsStored(urls_requested, optimization_types, callback);
+    OnBatchUpdateHintsStored(urls_with_pending_callback, optimization_types,
+                             callback);
     return;
   }
 
@@ -1063,7 +1070,7 @@
       clock_->Now() + features::GetActiveTabsFetchRefreshDuration(),
       hosts_requested, urls_requested,
       base::BindOnce(&HintsManager::OnBatchUpdateHintsStored,
-                     weak_ptr_factory_.GetWeakPtr(), urls_requested,
+                     weak_ptr_factory_.GetWeakPtr(), urls_with_pending_callback,
                      optimization_types, callback));
 
   if (switches::IsDebugLogsEnabled()) {
diff --git a/components/optimization_guide/core/hints_manager.h b/components/optimization_guide/core/hints_manager.h
index b4b72b7c..59b0782d 100644
--- a/components/optimization_guide/core/hints_manager.h
+++ b/components/optimization_guide/core/hints_manager.h
@@ -253,6 +253,7 @@
       proto::RequestContext request_context,
       const base::flat_set<std::string>& hosts_fetched,
       const base::flat_set<GURL>& urls_fetched,
+      const base::flat_set<GURL>& urls_for_callback,
       const base::flat_set<proto::OptimizationType>& optimization_types,
       OnDemandOptimizationGuideDecisionRepeatingCallback callback,
       absl::optional<std::unique_ptr<proto::GetHintsResponse>>
diff --git a/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc b/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc
index 32c4aeec..9d50e42 100644
--- a/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc
+++ b/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc
@@ -11,6 +11,7 @@
 #include "base/containers/flat_set.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/ranges/algorithm.h"
+#include "components/password_manager/core/browser/password_store_util.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
@@ -27,15 +28,6 @@
   }
 };
 
-base::OnceCallback<void(absl::optional<PasswordStoreChangeList>)>
-IgnoreChangeListAndRunCallback(base::OnceClosure callback) {
-  return base::BindOnce(
-      [](base::OnceClosure callback, absl::optional<PasswordStoreChangeList>) {
-        std::move(callback).Run();
-      },
-      std::move(callback));
-}
-
 bool IsInitialMigrationNeeded(PrefService* prefs) {
   return features::kMigrationVersion.Get() >
          prefs->GetInteger(
diff --git a/components/password_manager/core/browser/fake_password_store_backend.cc b/components/password_manager/core/browser/fake_password_store_backend.cc
index b0f55816..5196785 100644
--- a/components/password_manager/core/browser/fake_password_store_backend.cc
+++ b/components/password_manager/core/browser/fake_password_store_backend.cc
@@ -131,6 +131,10 @@
   return nullptr;
 }
 
+void FakePasswordStoreBackend::ClearAllLocalPasswords() {
+  NOTIMPLEMENTED();
+}
+
 LoginsResult FakePasswordStoreBackend::GetAllLoginsInternal() {
   LoginsResult result;
   for (const auto& elements : stored_passwords_) {
diff --git a/components/password_manager/core/browser/fake_password_store_backend.h b/components/password_manager/core/browser/fake_password_store_backend.h
index 5a54560..57fbad6 100644
--- a/components/password_manager/core/browser/fake_password_store_backend.h
+++ b/components/password_manager/core/browser/fake_password_store_backend.h
@@ -63,6 +63,7 @@
   FieldInfoStore* GetFieldInfoStore() override;
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
+  void ClearAllLocalPasswords() override;
 
   LoginsResult GetAllLoginsInternal();
   LoginsResult GetAutofillableLoginsInternal();
diff --git a/components/password_manager/core/browser/mock_password_store_backend.h b/components/password_manager/core/browser/mock_password_store_backend.h
index df756d8..8ab46f8 100644
--- a/components/password_manager/core/browser/mock_password_store_backend.h
+++ b/components/password_manager/core/browser/mock_password_store_backend.h
@@ -87,6 +87,7 @@
               CreateSyncControllerDelegate,
               (),
               (override));
+  MOCK_METHOD(void, ClearAllLocalPasswords, (), (override));
 
  private:
   base::WeakPtrFactory<MockPasswordStoreBackend> weak_ptr_factory_{this};
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc
index c06b0fe..52fd554 100644
--- a/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -128,6 +128,8 @@
     suggestion.label = GetHumanReadableRealm(signon_realm);
     suggestion.additional_label =
         std::u16string(password_length, kPasswordReplacementChar);
+    suggestion.voice_over = l10n_util::GetStringFUTF16(
+        IDS_PASSWORD_MANAGER_PASSWORD_FOR_ACCOUNT, suggestion.label);
     if (from_account_store) {
       suggestion.frontend_id =
           is_password_field
diff --git a/components/password_manager/core/browser/password_store_backend.h b/components/password_manager/core/browser/password_store_backend.h
index 01a28ae..4654240 100644
--- a/components/password_manager/core/browser/password_store_backend.h
+++ b/components/password_manager/core/browser/password_store_backend.h
@@ -128,6 +128,9 @@
   virtual std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() = 0;
 
+  // Clears all the passwords from the local storage.
+  virtual void ClearAllLocalPasswords() = 0;
+
   // Factory function for creating the backend. The Local backend requires the
   // provided `login_db` for storage and Android backend for migration purposes.
   static std::unique_ptr<PasswordStoreBackend> Create(
diff --git a/components/password_manager/core/browser/password_store_backend_migration_decorator.cc b/components/password_manager/core/browser/password_store_backend_migration_decorator.cc
index f95f8c3..61c4d29 100644
--- a/components/password_manager/core/browser/password_store_backend_migration_decorator.cc
+++ b/components/password_manager/core/browser/password_store_backend_migration_decorator.cc
@@ -5,10 +5,12 @@
 #include "components/password_manager/core/browser/password_store_backend_migration_decorator.h"
 
 #include "base/bind.h"
+#include "base/task/sequenced_task_runner.h"
 #include "components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.h"
 #include "components/password_manager/core/browser/field_info_table.h"
 #include "components/password_manager/core/browser/password_store_proxy_backend.h"
 #include "components/password_manager/core/common/password_manager_features.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/model/proxy_model_type_controller_delegate.h"
 
@@ -34,7 +36,7 @@
   DCHECK(built_in_backend_);
   DCHECK(android_backend_);
   active_backend_ = std::make_unique<PasswordStoreProxyBackend>(
-      built_in_backend_.get(), android_backend_.get(),
+      built_in_backend_.get(), android_backend_.get(), prefs_,
       is_syncing_passwords_callback_);
 }
 
@@ -50,6 +52,24 @@
     RemoteChangesReceived remote_form_changes_received,
     base::RepeatingClosure sync_enabled_or_disabled_cb,
     base::OnceCallback<void(bool)> completion) {
+  base::RepeatingClosure handle_sync_status_change = base::BindRepeating(
+      &PasswordStoreBackendMigrationDecorator::SyncStatusChanged,
+      weak_ptr_factory_.GetWeakPtr());
+
+  // |sync_enabled_or_disabled_cb| is called on a background sequence so it
+  // should be posted to the main sequence before invoking
+  // PasswordStoreBackendMigrationDecorator::SyncStatusChanged().
+  base::RepeatingClosure handle_sync_status_change_on_main_thread =
+      base::BindRepeating(
+          base::IgnoreResult(&base::SequencedTaskRunner::PostTask),
+          base::SequencedTaskRunnerHandle::Get(), FROM_HERE,
+          std::move(handle_sync_status_change));
+
+  // Inject nested callback to listen for sync status changes.
+  sync_enabled_or_disabled_cb =
+      std::move(handle_sync_status_change_on_main_thread)
+          .Then(std::move(sync_enabled_or_disabled_cb));
+
   active_backend_->InitBackend(std::move(remote_form_changes_received),
                                std::move(sync_enabled_or_disabled_cb),
                                std::move(completion));
@@ -168,6 +188,10 @@
   return built_in_backend_->CreateSyncControllerDelegate();
 }
 
+void PasswordStoreBackendMigrationDecorator::ClearAllLocalPasswords() {
+  NOTIMPLEMENTED();
+}
+
 void PasswordStoreBackendMigrationDecorator::StartMigration() {
   migrator_ = std::make_unique<BuiltInBackendToAndroidBackendMigrator>(
       built_in_backend_.get(), android_backend_.get(), prefs_,
@@ -175,4 +199,16 @@
   migrator_->StartMigrationIfNecessary();
 }
 
+void PasswordStoreBackendMigrationDecorator::SyncStatusChanged() {
+  if (is_syncing_passwords_callback_.Run()) {
+    // Sync was enabled. Delete all the passwords from GMS Core local storage.
+    // TODO(https://crbug.com/1278748) Implement.
+  } else {
+    // Clear migration pref to force rerun of initial migration of passwords
+    // from Chrome to GMS Core local storage.
+    prefs_->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices,
+                       0);
+  }
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_backend_migration_decorator.h b/components/password_manager/core/browser/password_store_backend_migration_decorator.h
index 9353be1..8453e06 100644
--- a/components/password_manager/core/browser/password_store_backend_migration_decorator.h
+++ b/components/password_manager/core/browser/password_store_backend_migration_decorator.h
@@ -77,10 +77,15 @@
   FieldInfoStore* GetFieldInfoStore() override;
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
+  void ClearAllLocalPasswords() override;
 
   // Creates 'migrator_' and starts migration process.
   void StartMigration();
 
+  // React on sync changes to keep GMS Core local storage up-to-date.
+  // TODO(https://crbug.com/) Remove this method when no longer needed.
+  void SyncStatusChanged();
+
   std::unique_ptr<PasswordStoreBackend> built_in_backend_;
   std::unique_ptr<PasswordStoreBackend> android_backend_;
 
diff --git a/components/password_manager/core/browser/password_store_backend_migration_decorator_unittest.cc b/components/password_manager/core/browser/password_store_backend_migration_decorator_unittest.cc
index 3c0f0fe..1ce8b59 100644
--- a/components/password_manager/core/browser/password_store_backend_migration_decorator_unittest.cc
+++ b/components/password_manager/core/browser/password_store_backend_migration_decorator_unittest.cc
@@ -4,47 +4,37 @@
 
 #include "components/password_manager/core/browser/password_store_backend_migration_decorator.h"
 
+#include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
-#include "components/password_manager/core/browser/fake_password_store_backend.h"
+#include "components/password_manager/core/browser/mock_password_store_backend.h"
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace password_manager {
 namespace {
 
-using ::testing::_;
-using ::testing::Invoke;
 using ::testing::WithArg;
-
-std::vector<std::unique_ptr<PasswordForm>> CreateTestLogins() {
-  std::vector<std::unique_ptr<PasswordForm>> forms;
-  forms.push_back(CreateEntry("Todd Tester", "S3cr3t",
-                              GURL(u"https://example.com"),
-                              /*is_psl_match=*/false,
-                              /*is_affiliation_based_match=*/false));
-  forms.push_back(CreateEntry("Marcus McSpartanGregor", "S0m3th1ngCr34t1v3",
-                              GURL(u"https://m.example.com"),
-                              /*is_psl_match=*/true,
-                              /*is_affiliation_based_match=*/false));
-  forms[0]->in_store = PasswordForm::Store::kProfileStore;
-  forms[1]->in_store = PasswordForm::Store::kProfileStore;
-  return forms;
-}
+using ::testing::WithArgs;
 
 }  // namespace
 
 class PasswordStoreBackendMigrationDecoratorTest : public testing::Test {
  protected:
-  PasswordStoreBackendMigrationDecoratorTest() {
+  PasswordStoreBackendMigrationDecoratorTest() = default;
+
+  void Init(base::RepeatingCallback<bool()> is_sync_enabled) {
     backend_migration_decorator_ =
         std::make_unique<PasswordStoreBackendMigrationDecorator>(
-            CreateBuiltInBackend(), CreateAndroidBackend(), /*prefs=*/nullptr,
-            /*is_syncing_passwords_callback=*/base::BindRepeating([]() {
-              return false;
-            }));
+            CreateBuiltInBackend(), CreateAndroidBackend(), &prefs_,
+            std::move(is_sync_enabled));
   }
 
   ~PasswordStoreBackendMigrationDecoratorTest() override {
@@ -54,49 +44,79 @@
   PasswordStoreBackend* backend_migration_decorator() {
     return backend_migration_decorator_.get();
   }
-  PasswordStoreBackend* built_in_backend() { return built_in_backend_; }
-  PasswordStoreBackend* android_backend() { return android_backend_; }
+  MockPasswordStoreBackend* built_in_backend() { return built_in_backend_; }
+  MockPasswordStoreBackend* android_backend() { return android_backend_; }
 
-  void AddTestLogins() {
-    for (const auto& login : CreateTestLogins()) {
-      built_in_backend()->AddLoginAsync(*login, base::DoNothing());
-      android_backend()->AddLoginAsync(*login, base::DoNothing());
-    }
-    RunUntilIdle();
-  }
+  TestingPrefServiceSimple& prefs() { return prefs_; }
 
   void RunUntilIdle() { task_env_.RunUntilIdle(); }
 
  private:
   std::unique_ptr<PasswordStoreBackend> CreateBuiltInBackend() {
-    auto unique_backend = std::make_unique<FakePasswordStoreBackend>();
+    auto unique_backend = std::make_unique<MockPasswordStoreBackend>();
     built_in_backend_ = unique_backend.get();
     return unique_backend;
   }
 
   std::unique_ptr<PasswordStoreBackend> CreateAndroidBackend() {
-    auto unique_backend = std::make_unique<FakePasswordStoreBackend>();
+    auto unique_backend = std::make_unique<MockPasswordStoreBackend>();
     android_backend_ = unique_backend.get();
     return unique_backend;
   }
 
   base::test::SingleThreadTaskEnvironment task_env_;
-  raw_ptr<FakePasswordStoreBackend> built_in_backend_;
-  raw_ptr<FakePasswordStoreBackend> android_backend_;
+  TestingPrefServiceSimple prefs_;
+  raw_ptr<MockPasswordStoreBackend> built_in_backend_;
+  raw_ptr<MockPasswordStoreBackend> android_backend_;
 
   std::unique_ptr<PasswordStoreBackendMigrationDecorator>
       backend_migration_decorator_;
 };
 
 TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       UseBuiltInBackendToGetAllLoginsAsync) {
-  base::MockCallback<LoginsOrErrorReply> mock_reply;
-  std::vector<std::unique_ptr<PasswordForm>> expected_logins =
-      CreateTestLogins();
-  AddTestLogins();
-  EXPECT_CALL(mock_reply, Run(LoginsResultsOrErrorAre(&expected_logins)));
-  backend_migration_decorator()->GetAllLoginsAsync(mock_reply.Get());
+       MigrationPreferenceClearedWhenSyncDisabled) {
+  // Set up pref to indicate that initial migration is finished.
+  prefs().registry()->RegisterIntegerPref(
+      prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+
+  base::MockCallback<base::OnceCallback<void(bool)>> mock_completion_callback;
+  base::MockCallback<base::RepeatingCallback<bool()>> is_sync_enabled_callback_;
+  base::RepeatingClosure sync_status_changed_closure;
+
+  Init(is_sync_enabled_callback_.Get());
+
+  EXPECT_CALL(mock_completion_callback, Run(/*success=*/true));
+
+  EXPECT_CALL(*built_in_backend(), InitBackend)
+      .WillOnce(WithArgs<1, 2>(
+          [&sync_status_changed_closure](auto sync_status_changed,
+                                         auto completion_callback) {
+            std::move(completion_callback).Run(/*success=*/true);
+            // Capture |sync_enabled_or_disabled_cb| passed to the
+            // build_in_backend.
+            sync_status_changed_closure = std::move(sync_status_changed);
+          }));
+  EXPECT_CALL(*android_backend(), InitBackend)
+      .WillOnce(WithArg<2>([](auto completion_callback) {
+        std::move(completion_callback).Run(/*success=*/true);
+      }));
+
+  backend_migration_decorator()->InitBackend(
+      /*remote_form_changes_received=*/base::DoNothing(),
+      /*sync_enabled_or_disabled_cb=*/base::DoNothing(),
+      /*completion=*/mock_completion_callback.Get());
+
+  // Invoke sync callback to simulate a change in sync status. Set expectation
+  // for sync to be turned off.
+  EXPECT_CALL(is_sync_enabled_callback_, Run())
+      .WillOnce(testing::Return(false));
+  sync_status_changed_closure.Run();
+
   RunUntilIdle();
+
+  // Since sync was disabled pref value for migration version should be reset.
+  EXPECT_EQ(0, prefs().GetInteger(
+                   prefs::kCurrentMigrationVersionToGoogleMobileServices));
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_built_in_backend.cc b/components/password_manager/core/browser/password_store_built_in_backend.cc
index a272280..eab741d 100644
--- a/components/password_manager/core/browser/password_store_built_in_backend.cc
+++ b/components/password_manager/core/browser/password_store_built_in_backend.cc
@@ -439,6 +439,10 @@
           weak_ptr_factory_.GetWeakPtr()));
 }
 
+void PasswordStoreBuiltInBackend::ClearAllLocalPasswords() {
+  NOTREACHED();
+}
+
 void PasswordStoreBuiltInBackend::AddSiteStats(const InteractionsStats& stats) {
   DCHECK(!was_shutdown_);
   DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
diff --git a/components/password_manager/core/browser/password_store_built_in_backend.h b/components/password_manager/core/browser/password_store_built_in_backend.h
index ba23748..2729462 100644
--- a/components/password_manager/core/browser/password_store_built_in_backend.h
+++ b/components/password_manager/core/browser/password_store_built_in_backend.h
@@ -113,6 +113,7 @@
   FieldInfoStore* GetFieldInfoStore() override;
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
+  void ClearAllLocalPasswords() override;
 
   // SmartBubbleStatsStore:
   void AddSiteStats(const InteractionsStats& stats) override;
diff --git a/components/password_manager/core/browser/password_store_proxy_backend.cc b/components/password_manager/core/browser/password_store_proxy_backend.cc
index 7e964a5..177a630 100644
--- a/components/password_manager/core/browser/password_store_proxy_backend.cc
+++ b/components/password_manager/core/browser/password_store_proxy_backend.cc
@@ -18,12 +18,32 @@
 #include "base/strings/strcat.h"
 #include "components/password_manager/core/browser/field_info_table.h"
 #include "components/password_manager/core/common/password_manager_features.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_service.h"
 #include "components/sync/model/proxy_model_type_controller_delegate.h"
 
 namespace password_manager {
 
 namespace {
 
+bool ShouldExecuteModifyOperationsOnShadowBackend(PrefService* prefs,
+                                                  bool is_syncing) {
+  if (!base::FeatureList::IsEnabled(
+          features::kUnifiedPasswordManagerShadowWriteOperationsAndroid)) {
+    return false;
+  }
+  if (is_syncing)
+    return false;
+  if (features::kMigrationVersion.Get() >
+      prefs->GetInteger(
+          prefs::kCurrentMigrationVersionToGoogleMobileServices)) {
+    // If initial migration isn't completed yet, we shouldn't modify the shadow
+    // backend.
+    return false;
+  }
+  return true;
+}
+
 using MethodName = base::StrongAlias<struct MethodNameTag, std::string>;
 
 struct LoginsResultOrErrorImpl {
@@ -53,6 +73,33 @@
   }
 };
 
+struct PasswordStoreChangeListImpl {
+  using ResultType = absl::optional<PasswordStoreChangeList>;
+  using ElementsType = PasswordStoreChangeList;
+
+  static PasswordStoreChangeList* GetElements(
+      absl::optional<PasswordStoreChangeList>& changelist) {
+    return changelist.has_value() ? &changelist.value() : nullptr;
+  }
+
+  static PasswordStoreChange Clone(const PasswordStoreChange& change) {
+    return change;
+  }
+
+  static bool IsLess(const PasswordStoreChange& lhs,
+                     const PasswordStoreChange& rhs) {
+    return std::forward_as_tuple(PasswordFormUniqueKey(lhs.form()),
+                                 lhs.type()) <
+           std::forward_as_tuple(PasswordFormUniqueKey(rhs.form()), rhs.type());
+  }
+
+  static bool HaveInconsistentPasswords(const PasswordStoreChange& lhs,
+                                        const PasswordStoreChange& rhs) {
+    // We never consider PasswordStoreChange having inconsistent passwords.
+    return false;
+  }
+};
+
 void InvokeCallbackWithCombinedStatus(base::OnceCallback<void(bool)> completion,
                                       std::vector<bool> statuses) {
   std::move(completion).Run(base::ranges::all_of(statuses, base::identity()));
@@ -191,9 +238,11 @@
 PasswordStoreProxyBackend::PasswordStoreProxyBackend(
     PasswordStoreBackend* main_backend,
     PasswordStoreBackend* shadow_backend,
+    PrefService* prefs,
     base::RepeatingCallback<bool()> is_syncing_passwords_callback)
     : main_backend_(main_backend),
       shadow_backend_(shadow_backend),
+      prefs_(prefs),
       is_syncing_passwords_callback_(std::move(is_syncing_passwords_callback)) {
 }
 
@@ -227,10 +276,9 @@
 }
 
 void PasswordStoreProxyBackend::GetAllLoginsAsync(LoginsOrErrorReply callback) {
-  scoped_refptr<ShadowTrafficMetricsRecorder<LoginsResultOrErrorImpl>> handler =
-      base::MakeRefCounted<
-          ShadowTrafficMetricsRecorder<LoginsResultOrErrorImpl>>(
-          MethodName("GetAllLoginsAsync"));
+  auto handler = base::MakeRefCounted<
+      ShadowTrafficMetricsRecorder<LoginsResultOrErrorImpl>>(
+      MethodName("GetAllLoginsAsync"));
   main_backend_->GetAllLoginsAsync(
       base::BindOnce(&ShadowTrafficMetricsRecorder<
                          LoginsResultOrErrorImpl>::RecordMainResult,
@@ -265,8 +313,23 @@
 void PasswordStoreProxyBackend::AddLoginAsync(
     const PasswordForm& form,
     PasswordStoreChangeListReply callback) {
-  main_backend_->AddLoginAsync(form, std::move(callback));
-  // TODO(crbug.com/1229655): Request shadow_backend_ and compare results.
+  auto handler = base::MakeRefCounted<
+      ShadowTrafficMetricsRecorder<PasswordStoreChangeListImpl>>(
+      MethodName("AddLoginAsync"));
+
+  main_backend_->AddLoginAsync(
+      form, base::BindOnce(&ShadowTrafficMetricsRecorder<
+                               PasswordStoreChangeListImpl>::RecordMainResult,
+                           handler)
+                .Then(std::move(callback)));
+  if (ShouldExecuteModifyOperationsOnShadowBackend(
+          prefs_, is_syncing_passwords_callback_.Run())) {
+    shadow_backend_->AddLoginAsync(
+        form,
+        base::BindOnce(&ShadowTrafficMetricsRecorder<
+                           PasswordStoreChangeListImpl>::RecordShadowResult,
+                       handler));
+  }
 }
 
 void PasswordStoreProxyBackend::UpdateLoginAsync(
@@ -325,4 +388,8 @@
   return main_backend_->CreateSyncControllerDelegate();
 }
 
+void PasswordStoreProxyBackend::ClearAllLocalPasswords() {
+  NOTIMPLEMENTED();
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_proxy_backend.h b/components/password_manager/core/browser/password_store_proxy_backend.h
index 0724074e..bc6e2fa5e 100644
--- a/components/password_manager/core/browser/password_store_proxy_backend.h
+++ b/components/password_manager/core/browser/password_store_proxy_backend.h
@@ -12,6 +12,8 @@
 #include "base/memory/weak_ptr.h"
 #include "components/password_manager/core/browser/password_store_backend.h"
 
+class PrefService;
+
 namespace password_manager {
 
 // This backend forwards requests to two backends in order to compare and record
@@ -24,6 +26,7 @@
   PasswordStoreProxyBackend(
       PasswordStoreBackend* main_backend,
       PasswordStoreBackend* shadow_backend,
+      PrefService* prefs,
       base::RepeatingCallback<bool()> is_syncing_passwords_callback);
   PasswordStoreProxyBackend(const PasswordStoreProxyBackend&) = delete;
   PasswordStoreProxyBackend(PasswordStoreProxyBackend&&) = delete;
@@ -68,9 +71,11 @@
   FieldInfoStore* GetFieldInfoStore() override;
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
+  void ClearAllLocalPasswords() override;
 
   const raw_ptr<PasswordStoreBackend> main_backend_;
   const raw_ptr<PasswordStoreBackend> shadow_backend_;
+  raw_ptr<PrefService> const prefs_ = nullptr;
   base::RepeatingCallback<bool()> is_syncing_passwords_callback_;
   base::WeakPtrFactory<PasswordStoreProxyBackend> weak_ptr_factory_{this};
 };
diff --git a/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc b/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
index cd6e7fbb..213e3a8c 100644
--- a/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
+++ b/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
@@ -18,6 +18,9 @@
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/password_store_change.h"
 #include "components/password_manager/core/common/password_manager_features.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -68,10 +71,17 @@
  protected:
   PasswordStoreProxyBackendTest() {
     proxy_backend_ = std::make_unique<PasswordStoreProxyBackend>(
-        &main_backend_, &shadow_backend_, is_syncing_passwords_callback_.Get());
+        &main_backend_, &shadow_backend_, &prefs_,
+        is_syncing_passwords_callback_.Get());
 
-    feature_list_.InitAndEnableFeature(
-        features::kUnifiedPasswordManagerShadowAndroid);
+    feature_list_.InitWithFeatures(
+        /*enabled_features=*/
+        {features::kUnifiedPasswordManagerShadowAndroid,
+         features::kUnifiedPasswordManagerShadowWriteOperationsAndroid},
+        /*disabled_features=*/{});
+
+    prefs_.registry()->RegisterIntegerPref(
+        prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
   }
 
   void TearDown() override {
@@ -85,12 +95,14 @@
   PasswordStoreBackend& proxy_backend() { return *proxy_backend_; }
   MockPasswordStoreBackend& main_backend() { return main_backend_; }
   MockPasswordStoreBackend& shadow_backend() { return shadow_backend_; }
+  TestingPrefServiceSimple* prefs() { return &prefs_; }
 
   base::MockCallback<base::RepeatingCallback<bool(void)>>
       is_syncing_passwords_callback_;
 
  private:
   base::test::ScopedFeatureList feature_list_;
+  TestingPrefServiceSimple prefs_;
   std::unique_ptr<PasswordStoreProxyBackend> proxy_backend_;
   StrictMock<MockPasswordStoreBackend> main_backend_;
   StrictMock<MockPasswordStoreBackend> shadow_backend_;
@@ -186,6 +198,8 @@
   PasswordStoreChangeList change_list;
   change_list.push_back(PasswordStoreChange(Type::ADD, form));
   EXPECT_CALL(mock_reply, Run(Eq(change_list)));
+  // This test doesn't care about the shadow backend.
+  EXPECT_CALL(shadow_backend(), AddLoginAsync).Times(testing::AnyNumber());
   EXPECT_CALL(main_backend(), AddLoginAsync(Eq(form), _))
       .WillOnce(WithArg<1>(
           Invoke([&change_list](PasswordStoreChangeListReply reply) -> void {
@@ -315,6 +329,97 @@
   histogram_tester.ExpectTotalCount(prefix + "InconsistentPasswords.Rel", 0);
 }
 
+TEST_F(PasswordStoreProxyBackendTest, NoShadowAddLoginsAsyncWhenSyncEnabled) {
+  EXPECT_CALL(is_syncing_passwords_callback_, Run).WillRepeatedly(Return(true));
+
+  EXPECT_CALL(main_backend(), AddLoginAsync);
+  EXPECT_CALL(shadow_backend(), AddLoginAsync).Times(0);
+  proxy_backend().AddLoginAsync(CreateTestForm(),
+                                /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+       NoShadowAddLoginsAsyncWhenSyncDisabledAndInitialMigrationIncomplete) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeaturesAndParameters(
+      /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+                             {{"migration_version", "2"}}}},
+      /*disabled_features=*/{});
+  prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+
+  EXPECT_CALL(is_syncing_passwords_callback_, Run)
+      .WillRepeatedly(Return(false));
+
+  EXPECT_CALL(main_backend(), AddLoginAsync);
+  EXPECT_CALL(shadow_backend(), AddLoginAsync).Times(0);
+  proxy_backend().AddLoginAsync(CreateTestForm(),
+                                /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+       ShadowAddLoginsAsyncWhenSyncDisabledAndInitialMigrationComplete) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeaturesAndParameters(
+      /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+                             {{"migration_version", "2"}}}},
+      /*disabled_features=*/{});
+  prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+
+  EXPECT_CALL(is_syncing_passwords_callback_, Run)
+      .WillRepeatedly(Return(false));
+
+  EXPECT_CALL(main_backend(), AddLoginAsync);
+  EXPECT_CALL(shadow_backend(), AddLoginAsync);
+  proxy_backend().AddLoginAsync(CreateTestForm(),
+                                /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest, ShadowAddLoginsAsyncBasicMetricsTesting) {
+  base::HistogramTester histogram_tester;
+  // Set the prefs such that no initial migration is required to allow shadow
+  // write operations.
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeaturesAndParameters(
+      /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+                             {{"migration_version", "2"}}}},
+      /*disabled_features=*/{});
+  prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+  // Shadow write operations run only for non-syncing users.
+  EXPECT_CALL(is_syncing_passwords_callback_, Run)
+      .WillRepeatedly(Return(false));
+
+  PasswordForm test_form = CreateTestForm();
+
+  PasswordStoreChangeList main_backend_changelist;
+  main_backend_changelist.emplace_back(PasswordStoreChange::ADD, test_form);
+
+  PasswordStoreChangeList shadow_backend_changelist;
+  shadow_backend_changelist.emplace_back(PasswordStoreChange::UPDATE,
+                                         test_form);
+
+  EXPECT_CALL(main_backend(), AddLoginAsync)
+      .WillOnce(WithArg<1>(Invoke(
+          [&main_backend_changelist](PasswordStoreChangeListReply reply)
+              -> void { std::move(reply).Run(main_backend_changelist); })));
+
+  EXPECT_CALL(shadow_backend(), AddLoginAsync)
+      .WillOnce(WithArg<1>(Invoke(
+          [&shadow_backend_changelist](PasswordStoreChangeListReply reply)
+              -> void { std::move(reply).Run(shadow_backend_changelist); })));
+
+  proxy_backend().AddLoginAsync(test_form,
+                                /*callback=*/base::DoNothing());
+
+  std::string prefix =
+      "PasswordManager.PasswordStoreProxyBackend.AddLoginAsync.";
+
+  histogram_tester.ExpectUniqueSample(prefix + "Diff.Abs", 2, 1);
+  histogram_tester.ExpectUniqueSample(prefix + "MainMinusShadow.Abs", 1, 1);
+  histogram_tester.ExpectUniqueSample(prefix + "ShadowMinusMain.Abs", 1, 1);
+  histogram_tester.ExpectUniqueSample(prefix + "InconsistentPasswords.Abs", 0,
+                                      1);
+}
+
 // Holds the main and shadow backend's logins and the expected number of common
 // and different logins.
 struct LoginsMetricsParam {
diff --git a/components/password_manager/core/browser/password_store_util.cc b/components/password_manager/core/browser/password_store_util.cc
index 2c8f99e..78a021b8 100644
--- a/components/password_manager/core/browser/password_store_util.cc
+++ b/components/password_manager/core/browser/password_store_util.cc
@@ -25,4 +25,13 @@
   return std::move(absl::get<LoginsResult>(result));
 }
 
+PasswordStoreChangeListReply IgnoreChangeListAndRunCallback(
+    base::OnceClosure callback) {
+  return base::BindOnce(
+      [](base::OnceClosure callback, absl::optional<PasswordStoreChangeList>) {
+        std::move(callback).Run();
+      },
+      std::move(callback));
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_util.h b/components/password_manager/core/browser/password_store_util.h
index c98fc94..346f089 100644
--- a/components/password_manager/core/browser/password_store_util.h
+++ b/components/password_manager/core/browser/password_store_util.h
@@ -22,6 +22,11 @@
 // holds an error.
 LoginsResult GetLoginsOrEmptyListOnFailure(LoginsResultOrError result);
 
+// Helper function allowing to bind base::OnceClosure to
+// PasswordStoreChangeListReply.
+PasswordStoreChangeListReply IgnoreChangeListAndRunCallback(
+    base::OnceClosure callback);
+
 }  // namespace password_manager
 
 #endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_UTIL_H_
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc
index 28a6675c..d0db0bc 100644
--- a/components/password_manager/core/browser/test_password_store.cc
+++ b/components/password_manager/core/browser/test_password_store.cc
@@ -258,6 +258,10 @@
   return nullptr;
 }
 
+void TestPasswordStore::ClearAllLocalPasswords() {
+  NOTIMPLEMENTED();
+}
+
 bool TestPasswordStore::IsAccountStore() const {
   return is_account_store_.value();
 }
diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h
index da5b071..d44eec8 100644
--- a/components/password_manager/core/browser/test_password_store.h
+++ b/components/password_manager/core/browser/test_password_store.h
@@ -99,6 +99,7 @@
   FieldInfoStore* GetFieldInfoStore() override;
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
+  void ClearAllLocalPasswords() override;
 
  private:
   LoginsResult GetAllLoginsInternal();
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index a30673a5..62dc10e7 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -168,6 +168,12 @@
 const base::Feature kUnifiedPasswordManagerShadowAndroid{
     "UnifiedPasswordManagerShadowAndroid", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Similar to kUnifiedPasswordManagerShadowAndroid but send modify operations
+// instead of read operations.Relevant only for non-sync'ing users.
+const base::Feature kUnifiedPasswordManagerShadowWriteOperationsAndroid{
+    "UnifiedPasswordManagerShadowWriteOperationsAndroid",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // If enabled, the built-in sync functionality in PasswordSyncBridge becomes
 // unused, meaning that SyncService/SyncEngine will no longer download or
 // upload changes to/from the Sync server. Instead, an external Android-specific
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h
index 74618e62..d80920e 100644
--- a/components/password_manager/core/common/password_manager_features.h
+++ b/components/password_manager/core/common/password_manager_features.h
@@ -50,6 +50,7 @@
 extern const base::Feature kUnifiedPasswordManagerAndroid;
 extern const base::Feature kUnifiedPasswordManagerMigration;
 extern const base::Feature kUnifiedPasswordManagerShadowAndroid;
+extern const base::Feature kUnifiedPasswordManagerShadowWriteOperationsAndroid;
 extern const base::Feature kUnifiedPasswordManagerSyncUsingAndroidBackendOnly;
 
 #endif
diff --git a/components/password_manager_strings.grdp b/components/password_manager_strings.grdp
index 7cede914..c3c12aba 100644
--- a/components/password_manager_strings.grdp
+++ b/components/password_manager_strings.grdp
@@ -100,4 +100,7 @@
   <message name="IDS_PASSWORD_MANAGER_DEFAULT_EXPORT_FILENAME" desc="Chrome suggests this file name when user chooses to export their passwords saved with Chrome.">
     Chrome Passwords
   </message>
+  <message name="IDS_PASSWORD_MANAGER_PASSWORD_FOR_ACCOUNT" desc="Voice over text read if the user focuses a drop down entry to fill a password for a given account.">
+    Password for <ph name="username">$1<ex>chef@google.com</ex></ph>
+  </message>
 </grit-part>
diff --git a/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_PASSWORD_FOR_ACCOUNT.png.sha1 b/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_PASSWORD_FOR_ACCOUNT.png.sha1
new file mode 100644
index 0000000..661cafd
--- /dev/null
+++ b/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_PASSWORD_FOR_ACCOUNT.png.sha1
@@ -0,0 +1 @@
+84e591dd00200eac4f46e43493a13039be622434
\ No newline at end of file
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc
index b87c2b1..94d9fa4 100644
--- a/components/plugins/renderer/webview_plugin.cc
+++ b/components/plugins/renderer/webview_plugin.cc
@@ -438,7 +438,6 @@
   // The delegate may instantiate a new plugin.
   delegate_->OnUnobscuredRectUpdate(gfx::Rect(unobscured_rect));
   // The delegate may have dirtied style and layout of the WebView.
-  // See for example the resizePoster function in plugin_poster.html.
   // Run the lifecycle now so that it is clean.
   DCHECK(web_view()->MainFrameWidget());
   web_view()->MainFrameWidget()->UpdateAllLifecyclePhases(
diff --git a/components/policy/core/common/preg_parser.cc b/components/policy/core/common/preg_parser.cc
index 8b8e1d188..bde1934 100644
--- a/components/policy/core/common/preg_parser.cc
+++ b/components/policy/core/common/preg_parser.cc
@@ -159,14 +159,14 @@
 // Decodes a value from a PReg file given as a uint8_t vector.
 bool DecodePRegValue(uint32_t type,
                      const std::vector<uint8_t>& data,
-                     std::unique_ptr<base::Value>* value) {
+                     base::Value& value) {
   std::string data_utf8;
   switch (type) {
     case REG_SZ:
     case REG_EXPAND_SZ:
       if (!DecodePRegStringValue(data, &data_utf8))
         return false;
-      *value = std::make_unique<base::Value>(data_utf8);
+      value = base::Value(data_utf8);
       return true;
     case REG_DWORD_LITTLE_ENDIAN:
     case REG_DWORD_BIG_ENDIAN:
@@ -176,7 +176,7 @@
           val = base::NetToHost32(val);
         else
           val = base::ByteSwapToLE32(val);
-        *value = std::make_unique<base::Value>(static_cast<int>(val));
+        value = base::Value(static_cast<int>(val));
         return true;
       } else {
         LOG(ERROR) << "Bad data size " << data.size();
@@ -250,9 +250,9 @@
   std::string value_name(base::UTF16ToUTF8(value));
   if (!base::StartsWith(value_name, kActionTriggerPrefix,
                         base::CompareCase::SENSITIVE)) {
-    std::unique_ptr<base::Value> value_ptr;
-    if (DecodePRegValue(type, data, &value_ptr))
-      dict->SetValue(value_name, std::move(value_ptr));
+    base::Value value;
+    if (DecodePRegValue(type, data, value))
+      dict->SetValue(value_name, std::move(value));
     return;
   }
 
diff --git a/components/policy/core/common/preg_parser_unittest.cc b/components/policy/core/common/preg_parser_unittest.cc
index f950a5f8..3e75265 100644
--- a/components/policy/core/common/preg_parser_unittest.cc
+++ b/components/policy/core/common/preg_parser_unittest.cc
@@ -58,33 +58,33 @@
   for (; iter_value_a != a.values().end() && iter_value_b != b.values().end();
        ++iter_value_a, ++iter_value_b) {
     if (iter_value_a->first != iter_value_b->first ||
-        *iter_value_a->second != *iter_value_b->second) {
+        iter_value_a->second != iter_value_b->second) {
       return testing::AssertionFailure()
              << "Value mismatch " << iter_value_a->first << "="
-             << *iter_value_a->second << " vs. " << iter_value_b->first << "="
-             << *iter_value_b->second;
+             << iter_value_a->second << " vs. " << iter_value_b->first << "="
+             << iter_value_b->second;
     }
   }
   if (iter_value_a != a.values().end())
     return testing::AssertionFailure()
            << "Value mismatch, a has extra value " << iter_value_a->first << "="
-           << *iter_value_a->second;
+           << iter_value_a->second;
   if (iter_value_b != b.values().end())
     return testing::AssertionFailure()
            << "Value mismatch, b has extra value " << iter_value_b->first << "="
-           << *iter_value_b->second;
+           << iter_value_b->second;
 
   return testing::AssertionSuccess();
 }
 
 void SetInteger(RegistryDict* dict, const std::string& name, int value) {
-  dict->SetValue(name, base::WrapUnique<base::Value>(new base::Value(value)));
+  dict->SetValue(name, base::Value(value));
 }
 
 void SetString(RegistryDict* dict,
                const std::string& name,
                const std::string& value) {
-  dict->SetValue(name, base::WrapUnique<base::Value>(new base::Value(value)));
+  dict->SetValue(name, base::Value(value));
 }
 
 class PRegParserTest : public testing::Test {
diff --git a/components/policy/core/common/registry_dict.cc b/components/policy/core/common/registry_dict.cc
index 329e1ca9..5f56191 100644
--- a/components/policy/core/common/registry_dict.cc
+++ b/components/policy/core/common/registry_dict.cc
@@ -15,6 +15,7 @@
 #include "base/sys_byteorder.h"
 #include "base/values.h"
 #include "components/policy/core/common/schema.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 #if defined(OS_WIN)
 #include "base/win/registry.h"
@@ -188,27 +189,20 @@
 
 base::Value* RegistryDict::GetValue(const std::string& name) {
   auto entry = values_.find(name);
-  return entry != values_.end() ? entry->second.get() : nullptr;
+  return entry != values_.end() ? &entry->second : nullptr;
 }
 
 const base::Value* RegistryDict::GetValue(const std::string& name) const {
   auto entry = values_.find(name);
-  return entry != values_.end() ? entry->second.get() : nullptr;
+  return entry != values_.end() ? &entry->second : nullptr;
 }
 
-void RegistryDict::SetValue(const std::string& name,
-                            std::unique_ptr<base::Value> dict) {
-  if (!dict) {
-    RemoveValue(name);
-    return;
-  }
-
+void RegistryDict::SetValue(const std::string& name, base::Value&& dict) {
   values_[name] = std::move(dict);
 }
 
-std::unique_ptr<base::Value> RegistryDict::RemoveValue(
-    const std::string& name) {
-  std::unique_ptr<base::Value> result;
+absl::optional<base::Value> RegistryDict::RemoveValue(const std::string& name) {
+  absl::optional<base::Value> result;
   auto entry = values_.find(name);
   if (entry != values_.end()) {
     result = std::move(entry->second);
@@ -231,8 +225,7 @@
 
   for (auto entry(other.values_.begin()); entry != other.values_.end();
        ++entry) {
-    SetValue(entry->first,
-             base::Value::ToUniquePtrValue(entry->second->Clone()));
+    SetValue(entry->first, entry->second.Clone());
   }
 }
 
@@ -252,8 +245,7 @@
     switch (it.Type()) {
       case REG_SZ:
       case REG_EXPAND_SZ:
-        SetValue(name,
-                 std::make_unique<base::Value>(base::WideToUTF8(it.Value())));
+        SetValue(name, base::Value(base::WideToUTF8(it.Value())));
         continue;
       case REG_DWORD_LITTLE_ENDIAN:
       case REG_DWORD_BIG_ENDIAN:
@@ -263,8 +255,7 @@
             dword_value = base::NetToHost32(dword_value);
           else
             dword_value = base::ByteSwapToLE32(dword_value);
-          SetValue(name, std::make_unique<base::Value>(
-                             static_cast<int>(dword_value)));
+          SetValue(name, base::Value(static_cast<int>(dword_value)));
           continue;
         }
         FALLTHROUGH;
@@ -310,7 +301,7 @@
           matching_schemas.push_back(Schema());
         for (const Schema& subschema : matching_schemas) {
           absl::optional<base::Value> converted =
-              ConvertRegistryValue(*entry->second, subschema);
+              ConvertRegistryValue(entry->second, subschema);
           if (converted.has_value()) {
             result->SetKey(entry->first, std::move(converted.value()));
             break;
@@ -353,7 +344,7 @@
         if (!IsKeyNumerical(entry->first))
           continue;
         absl::optional<base::Value> converted =
-            ConvertRegistryValue(*entry->second, item_schema);
+            ConvertRegistryValue(entry->second, item_schema);
         if (converted.has_value())
           result->Append(std::move(converted.value()));
       }
diff --git a/components/policy/core/common/registry_dict.h b/components/policy/core/common/registry_dict.h
index 7bbd392c..82742791 100644
--- a/components/policy/core/common/registry_dict.h
+++ b/components/policy/core/common/registry_dict.h
@@ -44,9 +44,8 @@
   using KeyMap = std::map<std::string,
                           std::unique_ptr<RegistryDict>,
                           CaseInsensitiveStringCompare>;
-  using ValueMap = std::map<std::string,
-                            std::unique_ptr<base::Value>,
-                            CaseInsensitiveStringCompare>;
+  using ValueMap =
+      std::map<std::string, base::Value, CaseInsensitiveStringCompare>;
 
   RegistryDict();
   RegistryDict(const RegistryDict&) = delete;
@@ -66,10 +65,10 @@
   // Returns a pointer to a value, NULL if not present.
   base::Value* GetValue(const std::string& name);
   const base::Value* GetValue(const std::string& name) const;
-  // Sets a value. If |value| is NULL, removes the value.
-  void SetValue(const std::string& name, std::unique_ptr<base::Value> value);
-  // Removes a value. If the value doesn't exist, NULL is returned.
-  std::unique_ptr<base::Value> RemoveValue(const std::string& name);
+  // Sets a value.
+  void SetValue(const std::string& name, base::Value&& value);
+  // Removes a value. If the value doesn't exist, nullopt is returned.
+  absl::optional<base::Value> RemoveValue(const std::string& name);
   // Clears all values.
   void ClearValues();
 
diff --git a/components/policy/core/common/registry_dict_unittest.cc b/components/policy/core/common/registry_dict_unittest.cc
index aa2ad40..bce87239 100644
--- a/components/policy/core/common/registry_dict_unittest.cc
+++ b/components/policy/core/common/registry_dict_unittest.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/values.h"
+#include "build/build_config.h"
 #include "components/policy/core/common/schema.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -21,19 +22,20 @@
   base::Value int_value(42);
   base::Value string_value("fortytwo");
 
-  test_dict.SetValue("one", int_value.CreateDeepCopy());
+  test_dict.SetValue("one", int_value.Clone());
   EXPECT_EQ(1u, test_dict.values().size());
   EXPECT_EQ(int_value, *test_dict.GetValue("one"));
   EXPECT_FALSE(test_dict.GetValue("two"));
 
-  test_dict.SetValue("two", string_value.CreateDeepCopy());
+  test_dict.SetValue("two", string_value.Clone());
   EXPECT_EQ(2u, test_dict.values().size());
   EXPECT_EQ(int_value, *test_dict.GetValue("one"));
   EXPECT_EQ(string_value, *test_dict.GetValue("two"));
 
-  std::unique_ptr<base::Value> one(test_dict.RemoveValue("one"));
+  absl::optional<base::Value> one(test_dict.RemoveValue("one"));
+  ASSERT_TRUE(one.has_value());
   EXPECT_EQ(1u, test_dict.values().size());
-  EXPECT_EQ(int_value, *one);
+  EXPECT_EQ(int_value, one.value());
   EXPECT_FALSE(test_dict.GetValue("one"));
   EXPECT_EQ(string_value, *test_dict.GetValue("two"));
 
@@ -49,7 +51,7 @@
   base::Value int_value(42);
   base::Value string_value("fortytwo");
 
-  test_dict.SetValue("One", int_value.CreateDeepCopy());
+  test_dict.SetValue("One", int_value.Clone());
   EXPECT_EQ(1u, test_dict.values().size());
   EXPECT_EQ(int_value, *test_dict.GetValue("oNe"));
 
@@ -57,12 +59,13 @@
   ASSERT_NE(entry, test_dict.values().end());
   EXPECT_EQ("One", entry->first);
 
-  test_dict.SetValue("ONE", string_value.CreateDeepCopy());
+  test_dict.SetValue("ONE", string_value.Clone());
   EXPECT_EQ(1u, test_dict.values().size());
   EXPECT_EQ(string_value, *test_dict.GetValue("one"));
 
-  std::unique_ptr<base::Value> removed_value(test_dict.RemoveValue("onE"));
-  EXPECT_EQ(string_value, *removed_value);
+  absl::optional<base::Value> removed_value(test_dict.RemoveValue("onE"));
+  ASSERT_TRUE(removed_value.has_value());
+  EXPECT_EQ(string_value, removed_value.value());
   EXPECT_TRUE(test_dict.values().empty());
 }
 
@@ -73,7 +76,7 @@
   base::Value string_value("fortytwo");
 
   std::unique_ptr<RegistryDict> subdict(new RegistryDict());
-  subdict->SetValue("one", int_value.CreateDeepCopy());
+  subdict->SetValue("one", int_value.Clone());
   test_dict.SetKey("two", std::move(subdict));
   EXPECT_EQ(1u, test_dict.keys().size());
   RegistryDict* actual_subdict = test_dict.GetKey("two");
@@ -81,7 +84,7 @@
   EXPECT_EQ(int_value, *actual_subdict->GetValue("one"));
 
   subdict = std::make_unique<RegistryDict>();
-  subdict->SetValue("three", string_value.CreateDeepCopy());
+  subdict->SetValue("three", string_value.Clone());
   test_dict.SetKey("four", std::move(subdict));
   EXPECT_EQ(2u, test_dict.keys().size());
   actual_subdict = test_dict.GetKey("two");
@@ -113,7 +116,7 @@
   EXPECT_EQ("One", entry->first);
 
   std::unique_ptr<RegistryDict> subdict(new RegistryDict());
-  subdict->SetValue("two", int_value.CreateDeepCopy());
+  subdict->SetValue("two", int_value.Clone());
   test_dict.SetKey("ONE", std::move(subdict));
   EXPECT_EQ(1u, test_dict.keys().size());
   actual_subdict = test_dict.GetKey("One");
@@ -133,17 +136,17 @@
   base::Value int_value(42);
   base::Value string_value("fortytwo");
 
-  dict_a.SetValue("one", int_value.CreateDeepCopy());
+  dict_a.SetValue("one", int_value.Clone());
   std::unique_ptr<RegistryDict> subdict(new RegistryDict());
-  subdict->SetValue("two", string_value.CreateDeepCopy());
+  subdict->SetValue("two", string_value.Clone());
   dict_a.SetKey("three", std::move(subdict));
 
-  dict_b.SetValue("four", string_value.CreateDeepCopy());
+  dict_b.SetValue("four", string_value.Clone());
   subdict = std::make_unique<RegistryDict>();
-  subdict->SetValue("two", int_value.CreateDeepCopy());
+  subdict->SetValue("two", int_value.Clone());
   dict_b.SetKey("three", std::move(subdict));
   subdict = std::make_unique<RegistryDict>();
-  subdict->SetValue("five", int_value.CreateDeepCopy());
+  subdict->SetValue("five", int_value.Clone());
   dict_b.SetKey("six", std::move(subdict));
 
   dict_a.Merge(dict_b);
@@ -165,9 +168,9 @@
   base::Value int_value(42);
   base::Value string_value("fortytwo");
 
-  dict_a.SetValue("one", int_value.CreateDeepCopy());
+  dict_a.SetValue("one", int_value.Clone());
   dict_a.SetKey("two", std::make_unique<RegistryDict>());
-  dict_b.SetValue("three", string_value.CreateDeepCopy());
+  dict_b.SetValue("three", string_value.Clone());
 
   dict_a.Swap(&dict_b);
 
@@ -189,19 +192,19 @@
   base::Value string_zero("0");
   base::Value string_dict("{ \"key\": [ \"value\" ] }");
 
-  test_dict.SetValue("one", int_value.CreateDeepCopy());
+  test_dict.SetValue("one", int_value.Clone());
   std::unique_ptr<RegistryDict> subdict(new RegistryDict());
-  subdict->SetValue("two", string_value.CreateDeepCopy());
+  subdict->SetValue("two", string_value.Clone());
   test_dict.SetKey("three", std::move(subdict));
   std::unique_ptr<RegistryDict> list(new RegistryDict());
-  list->SetValue("1", string_value.CreateDeepCopy());
+  list->SetValue("1", string_value.Clone());
   test_dict.SetKey("dict-to-list", std::move(list));
-  test_dict.SetValue("int-to-bool", int_value.CreateDeepCopy());
-  test_dict.SetValue("int-to-double", int_value.CreateDeepCopy());
-  test_dict.SetValue("string-to-bool", string_zero.CreateDeepCopy());
-  test_dict.SetValue("string-to-double", string_zero.CreateDeepCopy());
-  test_dict.SetValue("string-to-int", string_zero.CreateDeepCopy());
-  test_dict.SetValue("string-to-dict", string_dict.CreateDeepCopy());
+  test_dict.SetValue("int-to-bool", int_value.Clone());
+  test_dict.SetValue("int-to-double", int_value.Clone());
+  test_dict.SetValue("string-to-bool", string_zero.Clone());
+  test_dict.SetValue("string-to-double", string_zero.Clone());
+  test_dict.SetValue("string-to-int", string_zero.Clone());
+  test_dict.SetValue("string-to-dict", string_dict.Clone());
 
   std::string error;
   Schema schema = Schema::Parse(
@@ -251,10 +254,10 @@
   RegistryDict test_dict;
 
   std::unique_ptr<RegistryDict> list(new RegistryDict());
-  list->SetValue("1", base::Value("1").CreateDeepCopy());
-  list->SetValue("2", base::Value("2").CreateDeepCopy());
-  list->SetValue("THREE", base::Value("3").CreateDeepCopy());
-  list->SetValue("4", base::Value("4").CreateDeepCopy());
+  list->SetValue("1", base::Value("1").Clone());
+  list->SetValue("2", base::Value("2").Clone());
+  list->SetValue("THREE", base::Value("3").Clone());
+  list->SetValue("4", base::Value("4").Clone());
   test_dict.SetKey("dict-to-list", std::move(list));
 
   std::string error;
@@ -275,9 +278,9 @@
 
   base::DictionaryValue expected;
   std::unique_ptr<base::ListValue> expected_list(new base::ListValue());
-  expected_list->Append(base::Value("1").CreateDeepCopy());
-  expected_list->Append(base::Value("2").CreateDeepCopy());
-  expected_list->Append(base::Value("4").CreateDeepCopy());
+  expected_list->Append(base::Value("1").Clone());
+  expected_list->Append(base::Value("2").Clone());
+  expected_list->Append(base::Value("4").Clone());
   expected.Set("dict-to-list", std::move(expected_list));
 
   EXPECT_EQ(expected, *actual);
@@ -292,15 +295,14 @@
   std::unique_ptr<RegistryDict> policy_dict(new RegistryDict());
   std::unique_ptr<RegistryDict> subdict_id(new RegistryDict());
   // Values with schema are parsed even if the schema is a regexp property.
-  subdict_id->SetValue("runtime_blocked_hosts", string_dict.CreateDeepCopy());
-  subdict_id->SetValue("runtime_allowed_hosts", string_dict.CreateDeepCopy());
+  subdict_id->SetValue("runtime_blocked_hosts", string_dict.Clone());
+  subdict_id->SetValue("runtime_allowed_hosts", string_dict.Clone());
   // Regexp. validated properties are valid too.
-  subdict_id->SetValue("minimum_version_required",
-                       version_string.CreateDeepCopy());
+  subdict_id->SetValue("minimum_version_required", version_string.Clone());
   policy_dict->SetKey("aaaabbbbaaaabbbbaaaabbbbaaaabbbb",
                       std::move(subdict_id));
   // Values that have no schema are left as strings regardless of structure.
-  policy_dict->SetValue("invalid_key", string_dict.CreateDeepCopy());
+  policy_dict->SetValue("invalid_key", string_dict.Clone());
   test_dict.SetKey("ExtensionSettings", std::move(policy_dict));
 
   std::string error;
@@ -346,12 +348,15 @@
   list_value->Append("*://*.google.com");
   std::unique_ptr<base::DictionaryValue> restrictions_properties(
       new base::DictionaryValue());
-  restrictions_properties->Set("runtime_blocked_hosts",
-                               list_value->CreateDeepCopy());
-  restrictions_properties->Set("runtime_allowed_hosts",
-                               list_value->CreateDeepCopy());
-  restrictions_properties->Set("minimum_version_required",
-                               version_string.CreateDeepCopy());
+  restrictions_properties->Set(
+      "runtime_blocked_hosts",
+      base::Value::ToUniquePtrValue(list_value->Clone()));
+  restrictions_properties->Set(
+      "runtime_allowed_hosts",
+      base::Value::ToUniquePtrValue(list_value->Clone()));
+  restrictions_properties->Set(
+      "minimum_version_required",
+      base::Value::ToUniquePtrValue(version_string.Clone()));
   expected_extension_settings->Set("aaaabbbbaaaabbbbaaaabbbbaaaabbbb",
                                    std::move(restrictions_properties));
   expected_extension_settings->Set(
@@ -370,9 +375,9 @@
   base::Value int_value(42);
   base::Value string_value("fortytwo");
 
-  test_dict.SetValue("one", int_value.CreateDeepCopy());
+  test_dict.SetValue("one", int_value.Clone());
   std::unique_ptr<RegistryDict> subdict(new RegistryDict());
-  subdict->SetValue("two", string_value.CreateDeepCopy());
+  subdict->SetValue("two", string_value.Clone());
   test_dict.SetKey("one", std::move(subdict));
 
   EXPECT_EQ(int_value, *test_dict.GetValue("one"));
diff --git a/components/site_engagement/content/site_engagement_service.cc b/components/site_engagement/content/site_engagement_service.cc
index bb19a13..0f62e5e 100644
--- a/components/site_engagement/content/site_engagement_service.cc
+++ b/components/site_engagement/content/site_engagement_service.cc
@@ -14,6 +14,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/strings/string_util.h"
 #include "base/task/thread_pool.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
@@ -220,6 +221,7 @@
     base::Time now,
     scoped_refptr<HostContentSettingsMap> map) {
   StoppedClock clock(now);
+  base::AssertLongCPUWorkAllowed();
   return GetAllDetailsImpl(browsing_data::TimePeriod::ALL_TIME, &clock,
                            map.get());
 }
@@ -255,7 +257,6 @@
     const {
   if (IsLastEngagementStale())
     CleanupEngagementScores(true);
-
   return GetAllDetailsImpl(
       browsing_data::TimePeriod::ALL_TIME, clock_,
       permissions::PermissionsClient::Get()->GetSettingsMap(browser_context_));
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 4fbea6e..da0221a 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -2173,7 +2173,7 @@
       quad_alpha = 1.f;
       DCHECK(cf);
     }
-    paint.setColorFilter(std::move(cf));
+    paint.setColorFilter(cf->makeComposed(paint.refColorFilter()));
   }
 
   if (needs_color_conversion_filter) {
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index a95a948..da9b85e8 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -676,18 +676,18 @@
     const FrameSinkId& root_frame_sink_id) {
   auto it = root_sink_map_.find(root_frame_sink_id);
 
-  DCHECK(it != root_sink_map_.end());
-  DCHECK(cached_back_buffers_.find(cache_id) == cached_back_buffers_.end());
+  // If creating RootCompositorFrameSinkImpl failed there might not be an entry
+  // in |root_sink_map_|.
+  if (it == root_sink_map_.end())
+    return;
 
+  DCHECK(!base::Contains(cached_back_buffers_, cache_id));
   cached_back_buffers_[cache_id] = it->second->GetCacheBackBufferCb();
 }
 
 void FrameSinkManagerImpl::EvictBackBuffer(uint32_t cache_id,
                                            EvictBackBufferCallback callback) {
-  auto it = cached_back_buffers_.find(cache_id);
-  DCHECK(it != cached_back_buffers_.end());
-
-  cached_back_buffers_.erase(it);
+  cached_back_buffers_.erase(cache_id);
   std::move(callback).Run();
 }
 
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.cc b/content/browser/attribution_reporting/attribution_storage_sql.cc
index 75f264cf..7ebd654 100644
--- a/content/browser/attribution_reporting/attribution_storage_sql.cc
+++ b/content/browser/attribution_reporting/attribution_storage_sql.cc
@@ -1422,8 +1422,7 @@
     }
   }
 
-  if (InitializeSchema(db_init_status_ == DbStatus::kDeferringCreation) ==
-      false) {
+  if (!InitializeSchema(db_init_status_ == DbStatus::kDeferringCreation)) {
     HandleInitializationFailure(InitStatus::kFailedToInitializeSchema);
     return false;
   }
@@ -1452,19 +1451,16 @@
   if (current_version == kCurrentVersionNumber)
     return true;
 
-  if (current_version <= kDeprecatedVersionNumber) {
+  // Recreate the DB if the version is deprecated or too new. In the latter
+  // case, the DB will never work until Chrome is re-upgraded. Assume the user
+  // will continue using this Chrome version and raze the DB to get attribution
+  // reporting working.
+  if (current_version <= kDeprecatedVersionNumber ||
+      meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
     // Note that this also razes the meta table, so it will need to be
     // initialized again.
     db_->Raze();
-    return CreateSchema();
-  }
-
-  if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
-    // In this case the database version is too new to be used. The DB will
-    // never work until Chrome is re-upgraded. Assume the user will continue
-    // using this Chrome version and raze the DB to get attribution reporting
-    // working.
-    db_->Raze();
+    meta_table_.Reset();
     return CreateSchema();
   }
 
@@ -1474,6 +1470,11 @@
 
 bool AttributionStorageSql::CreateSchema() {
   base::ThreadTicks start_timestamp = base::ThreadTicks::Now();
+
+  sql::Transaction transaction(db_.get());
+  if (!transaction.Begin())
+    return false;
+
   // TODO(johnidel, csharrison): Many sources will share a target origin and
   // a reporting origin, so it makes sense to make a "shared string" table for
   // these to save disk / memory. However, this complicates the schema a lot, so
@@ -1619,6 +1620,9 @@
     return false;
   }
 
+  if (!transaction.Commit())
+    return false;
+
   base::UmaHistogramMediumTimes("Conversions.Storage.CreationTime",
                                 base::ThreadTicks::Now() - start_timestamp);
   return true;
diff --git a/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc b/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc
index 8afb233..f5d4589 100644
--- a/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc
@@ -20,6 +20,7 @@
 #include "content/browser/attribution_reporting/storable_source.h"
 #include "content/browser/attribution_reporting/storable_trigger.h"
 #include "sql/database.h"
+#include "sql/meta_table.h"
 #include "sql/test/scoped_error_expecter.h"
 #include "sql/test/test_helpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -187,6 +188,29 @@
   EXPECT_TRUE(expecter.SawExpectedErrors());
 }
 
+TEST_F(AttributionStorageSqlTest, VersionTooNew_RazesDB) {
+  OpenDatabase();
+  AddReportToStorage();
+  ASSERT_THAT(storage()->GetAttributionsToReport(clock()->Now()), SizeIs(1));
+  CloseDatabase();
+
+  {
+    sql::Database raw_db;
+    EXPECT_TRUE(raw_db.Open(db_path()));
+
+    sql::MetaTable meta;
+    // The values here are irrelevant, as the meta table already exists.
+    ASSERT_TRUE(meta.Init(&raw_db, /*version=*/1, /*compatible_version=*/1));
+
+    meta.SetVersionNumber(meta.GetVersionNumber() + 1);
+    meta.SetCompatibleVersionNumber(meta.GetCompatibleVersionNumber() + 1);
+  }
+
+  // The DB should be razed because the version is too new.
+  ASSERT_NO_FATAL_FAILURE(OpenDatabase());
+  ASSERT_THAT(storage()->GetAttributionsToReport(clock()->Now()), IsEmpty());
+}
+
 //  Create an impression with two conversions (C1 and C2). Craft a query that
 //  will target C2, which will in turn delete the impression. We should ensure
 //  that C1 is properly deleted (conversions should not be stored unattributed).
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 6ed02d4..1ccb50d5 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -670,7 +670,7 @@
           request_info_->sandbox_flags,
           static_cast<ui::PageTransition>(resource_request_->transition_type),
           resource_request_->has_user_gesture, initiating_origin,
-          &loader_factory);
+          initiator_document_.AsRenderFrameHostIfValid(), &loader_factory);
 
       if (loader_factory) {
         factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
@@ -1194,6 +1194,7 @@
       url_(request_info_->common_params->url),
       frame_tree_node_id_(request_info_->frame_tree_node_id),
       global_request_id_(GlobalRequestID::MakeBrowserInitiated()),
+      initiator_document_(request_info_->initiator_document),
       web_contents_getter_(
           base::BindRepeating(&WebContents::FromFrameTreeNodeId,
                               frame_tree_node_id_)),
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h
index 8334abb..3d75a59e 100644
--- a/content/browser/loader/navigation_url_loader_impl.h
+++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -15,6 +15,7 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/ssl_status.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/url_request/url_request.h"
@@ -230,6 +231,7 @@
 
   const int frame_tree_node_id_;
   const GlobalRequestID global_request_id_;
+  const WeakDocumentPtr initiator_document_;
   net::RedirectInfo redirect_info_;
   int redirect_limit_ = net::URLRequest::kMaxRedirects;
   base::RepeatingCallback<WebContents*()> web_contents_getter_;
diff --git a/content/browser/loader/navigation_url_loader_impl_unittest.cc b/content/browser/loader/navigation_url_loader_impl_unittest.cc
index 6e859b1..46bbcdc 100644
--- a/content/browser/loader/navigation_url_loader_impl_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_impl_unittest.cc
@@ -228,7 +228,8 @@
             net::HttpRequestHeaders() /* cors_exempt_headers */,
             nullptr /* client_security_state */,
             absl::nullopt /* devtools_accepted_stream_types */,
-            false /* is_pdf */));
+            false /* is_pdf */,
+            content::WeakDocumentPtr() /* initiator_document */));
     std::vector<std::unique_ptr<NavigationLoaderInterceptor>> interceptors;
     most_recent_resource_request_ = absl::nullopt;
     interceptors.push_back(std::make_unique<TestNavigationLoaderInterceptor>(
diff --git a/content/browser/loader/navigation_url_loader_unittest.cc b/content/browser/loader/navigation_url_loader_unittest.cc
index bb9ca5fb..a971c73 100644
--- a/content/browser/loader/navigation_url_loader_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_unittest.cc
@@ -100,7 +100,8 @@
             net::HttpRequestHeaders() /* cors_exempt_headers */,
             nullptr /* client_security_state */,
             absl::nullopt /* devtools_accepted_stream_types */,
-            false /* is_pdf */));
+            false /* is_pdf */,
+            content::WeakDocumentPtr() /* initiator_document */));
     return NavigationURLLoader::Create(
         browser_context_.get(), storage_partition, std::move(request_info),
         nullptr, nullptr, nullptr, delegate,
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 7efec132..5ba43e5 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -97,6 +97,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
@@ -1436,10 +1437,8 @@
   if (GetInitiatorFrameToken().has_value()) {
     RenderFrameHostImpl* initiator_rfh = RenderFrameHostImpl::FromFrameToken(
         GetInitiatorProcessID(), GetInitiatorFrameToken().value());
-    if (initiator_rfh) {
-      initiator_commit_navigation_sent_counter_ =
-          initiator_rfh->commit_navigation_sent_counter();
-    }
+    if (initiator_rfh)
+      initiator_document_ = initiator_rfh->GetWeakDocumentPtr();
   }
 
   policy_container_navigation_bundle_.emplace(
@@ -3926,7 +3925,7 @@
           devtools_navigation_token(), frame_tree_node_->devtools_frame_token(),
           OriginPolicyThrottle::ShouldRequestOriginPolicy(common_params_->url),
           std::move(cors_exempt_headers), std::move(client_security_state),
-          devtools_accepted_stream_types, is_pdf_),
+          devtools_accepted_stream_types, is_pdf_, initiator_document_),
       std::move(navigation_ui_data), service_worker_handle_.get(),
       std::move(prefetched_signed_exchange_cache_), this, loader_type,
       CreateCookieAccessObserver(),
@@ -6859,24 +6858,8 @@
 }
 
 RenderFrameHostImpl* NavigationRequest::GetInitiatorDocumentRenderFrameHost() {
-  if (!initiator_frame_token_.has_value()) {
-    return nullptr;
-  }
-
-  RenderFrameHostImpl* initiator_render_frame_host =
-      RenderFrameHostImpl::FromFrameToken(initiator_process_id_,
-                                          *initiator_frame_token_);
-
-  if (!initiator_render_frame_host ||
-      initiator_render_frame_host->commit_navigation_sent_counter() !=
-          initiator_commit_navigation_sent_counter_) {
-    // Either the initiator RFH has been destroyed, or the initiator document
-    // within that RFH has navigated away since the navigation started. In any
-    // case the initiator document is no longer available.
-    return nullptr;
-  }
-
-  return initiator_render_frame_host;
+  return static_cast<RenderFrameHostImpl*>(
+      initiator_document_.AsRenderFrameHostIfValid());
 }
 
 void NavigationRequest::RecordAddressSpaceFeature() {
@@ -7261,6 +7244,14 @@
         ->GetWebExposedIsolationInfo();
   }
 
+  // This accommodates for web tests that use COOP. They expect an about:blank
+  // page to stay in process, and hang otherwise. In general, it is safe to
+  // allow about:blank pages to stay in process, since scriptability is limited
+  // to the BrowsingInstance and all pages with the same web-exposed isolation
+  // level are trusted.
+  if (common_params_->url.IsAboutBlank())
+    return absl::nullopt;
+
   // If we haven't yet received a definitive network response, it is too early
   // to guess the isolation state.
   if (state_ < WILL_PROCESS_RESPONSE)
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index 042fb6d..266cfa4 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -45,6 +45,7 @@
 #include "content/public/browser/peak_gpu_memory_tracker.h"
 #include "content/public/browser/prerender_trigger_type.h"
 #include "content/public/browser/render_process_host_observer.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -1921,9 +1922,9 @@
   // NavigationRequest.
   std::vector<ConsoleMessage> console_messages_;
 
-  // The `commit_navigation_sent_counter` of the initiator RenderFrameHost at
-  // the time when this NavigationRequest was created.
-  int initiator_commit_navigation_sent_counter_ = -1;
+  // The initiator RenderFrameHost, if the same document is present as when this
+  // NavigationRequest was created.
+  WeakDocumentPtr initiator_document_;
 
   // Indicates that this navigation is for PDF content in a renderer.
   bool is_pdf_ = false;
diff --git a/content/browser/renderer_host/navigation_request_info.cc b/content/browser/renderer_host/navigation_request_info.cc
index 21cd58e..f096bd3 100644
--- a/content/browser/renderer_host/navigation_request_info.cc
+++ b/content/browser/renderer_host/navigation_request_info.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/renderer_host/navigation_request_info.h"
 
+#include "content/public/browser/weak_document_ptr.h"
 #include "third_party/blink/public/mojom/navigation/navigation_params.mojom.h"
 
 namespace content {
@@ -27,7 +28,8 @@
     network::mojom::ClientSecurityStatePtr client_security_state,
     const absl::optional<std::vector<net::SourceStream::SourceType>>&
         devtools_accepted_stream_types,
-    bool is_pdf)
+    bool is_pdf,
+    WeakDocumentPtr initiator_document)
     : common_params(std::move(common_params)),
       begin_params(std::move(begin_params)),
       sandbox_flags(sandbox_flags),
@@ -44,7 +46,8 @@
       cors_exempt_headers(std::move(cors_exempt_headers)),
       client_security_state(std::move(client_security_state)),
       devtools_accepted_stream_types(devtools_accepted_stream_types),
-      is_pdf(is_pdf) {}
+      is_pdf(is_pdf),
+      initiator_document(std::move(initiator_document)) {}
 
 NavigationRequestInfo::~NavigationRequestInfo() {}
 
diff --git a/content/browser/renderer_host/navigation_request_info.h b/content/browser/renderer_host/navigation_request_info.h
index e1a0e82..6635caa 100644
--- a/content/browser/renderer_host/navigation_request_info.h
+++ b/content/browser/renderer_host/navigation_request_info.h
@@ -8,6 +8,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/unguessable_token.h"
 #include "content/common/content_export.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/common/referrer.h"
 #include "net/base/isolation_info.h"
 #include "net/filter/source_stream.h"
@@ -44,7 +45,8 @@
       network::mojom::ClientSecurityStatePtr client_security_state,
       const absl::optional<std::vector<net::SourceStream::SourceType>>&
           devtools_accepted_stream_types,
-      bool is_pdf);
+      bool is_pdf,
+      WeakDocumentPtr initiator_document);
   NavigationRequestInfo(const NavigationRequestInfo& other) = delete;
   ~NavigationRequestInfo();
 
@@ -113,6 +115,9 @@
 
   // Indicates that this navigation is for PDF content in a renderer.
   const bool is_pdf;
+
+  // The initiator document, if still available.
+  const WeakDocumentPtr initiator_document;
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 8d2e57caf..3b3a2ce 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -161,6 +161,7 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/context_menu_params.h"
 #include "content/public/browser/disallow_activation_reason.h"
+#include "content/public/browser/document_ref.h"
 #include "content/public/browser/document_service_internal.h"
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/global_routing_id.h"
@@ -171,6 +172,7 @@
 #include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/sms_fetcher.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/browser/weak_document_ptr.h"
 #include "content/public/browser/web_ui_url_loader_factory.h"
 #include "content/public/common/bindings_policy.h"
 #include "content/public/common/content_client.h"
@@ -2150,6 +2152,15 @@
   return is_error_page_;
 }
 
+DocumentRef RenderFrameHostImpl::GetDocumentRef() {
+  return DocumentRef(document_associated_data_->weak_ptr_factory.GetSafeRef());
+}
+
+WeakDocumentPtr RenderFrameHostImpl::GetWeakDocumentPtr() {
+  return WeakDocumentPtr(
+      document_associated_data_->weak_ptr_factory.GetWeakPtr());
+}
+
 void RenderFrameHostImpl::GetSerializedHtmlWithLocalLinks(
     const base::flat_map<GURL, base::FilePath>& url_map,
     const base::flat_map<blink::FrameToken, base::FilePath>& frame_token_map,
@@ -12842,7 +12853,8 @@
 }
 
 RenderFrameHostImpl::DocumentAssociatedData::DocumentAssociatedData(
-    RenderFrameHostImpl& document) {
+    RenderFrameHostImpl& document)
+    : weak_ptr_factory(&document) {
   // Only create page object for the main document as the PageImpl is 1:1 with
   // main document.
   if (!document.GetParent()) {
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 0a2fe1a..caa81fe3 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -448,6 +448,8 @@
   void GetCanonicalUrl(
       base::OnceCallback<void(const absl::optional<GURL>&)> callback) override;
   bool IsErrorDocument() override;
+  DocumentRef GetDocumentRef() override;
+  WeakDocumentPtr GetWeakDocumentPtr() override;
 
   // Additional non-override const version of GetMainFrame.
   const RenderFrameHostImpl* GetMainFrame() const;
@@ -3984,6 +3986,11 @@
     // "Owned" but not with std::unique_ptr, as a DocumentServiceBase is
     // allowed to delete itself directly.
     std::vector<internal::DocumentServiceBase*> services;
+
+    // Produces weak pointers to the hosting RenderFrameHostImpl. This is
+    // invalidated whenever DocumentAssociatedData is destroyed, due to
+    // RenderFrameHost deletion or cross-document navigation.
+    base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory;
   };
 
   // Reset immediately before a RenderFrameHost is reused for hosting a new
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index e3eaa7a..8f983a68 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -176,14 +176,6 @@
 bool IsSiteInstanceCompatibleWithWebExposedIsolation(
     SiteInstance* site_instance,
     const UrlInfo& url_info) {
-  // Note: The about blank case is to accommodate web tests that use COOP. They
-  // expect an about:blank page to stay in process, and hang otherwise. In
-  // general, it is safe to allow about:blank pages to stay in process, since
-  // scriptability is limited to the BrowsingInstance and all pages with the
-  // same web-exposed isolation level are trusted.
-  if (url_info.url.IsAboutBlank())
-    return true;
-
   SiteInstanceImpl* site_instance_impl =
       static_cast<SiteInstanceImpl*>(site_instance);
 
diff --git a/content/browser/web_package/web_bundle_element_browsertest.cc b/content/browser/web_package/web_bundle_element_browsertest.cc
index 6799f684..df9493d 100644
--- a/content/browser/web_package/web_bundle_element_browsertest.cc
+++ b/content/browser/web_package/web_bundle_element_browsertest.cc
@@ -54,6 +54,7 @@
       ui::PageTransition page_transition,
       bool has_user_gesture,
       const absl::optional<url::Origin>& initiating_origin,
+      content::RenderFrameHost* initiator_document,
       mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory)
       override {
     EXPECT_FALSE(observed_url_.has_value());
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc
index 3bd9acf..17efaa66 100644
--- a/content/browser/webid/federated_auth_request_impl.cc
+++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -379,6 +379,10 @@
       client_id_metadata_ = data;
       network_manager_->SendAccountsRequest(
           endpoints_.accounts,
+          request_dialog_controller_->GetBrandIconIdealSize(),
+          request_dialog_controller_->GetBrandIconMinimumSize(),
+          base::BindOnce(&FederatedAuthRequestImpl::DownloadBitmap,
+                         weak_ptr_factory_.GetWeakPtr()),
           base::BindOnce(&FederatedAuthRequestImpl::OnAccountsResponseReceived,
                          weak_ptr_factory_.GetWeakPtr()));
     }
@@ -521,10 +525,21 @@
   CompleteRequest(RequestIdTokenStatus::kSuccess, id_token_);
 }
 
+void FederatedAuthRequestImpl::DownloadBitmap(
+    const GURL& icon_url,
+    int ideal_icon_size,
+    WebContents::ImageDownloadCallback callback) {
+  WebContents::FromRenderFrameHost(render_frame_host_)
+      ->DownloadImage(icon_url, /*is_favicon*/ false,
+                      gfx::Size(ideal_icon_size, ideal_icon_size),
+                      0 /* max_bitmap_size */, false /* bypass_cache */,
+                      std::move(callback));
+}
+
 void FederatedAuthRequestImpl::OnAccountsResponseReceived(
     IdpNetworkRequestManager::FetchStatus status,
     IdpNetworkRequestManager::AccountList accounts,
-    content::IdentityProviderMetadata idp_metadata) {
+    IdentityProviderMetadata idp_metadata) {
   switch (status) {
     case IdpNetworkRequestManager::FetchStatus::kHttpNotFoundError: {
       CompleteRequest(RequestIdTokenStatus::kErrorFetchingAccountsHttpNotFound,
diff --git a/content/browser/webid/federated_auth_request_impl.h b/content/browser/webid/federated_auth_request_impl.h
index 3d9790bc..36e7586 100644
--- a/content/browser/webid/federated_auth_request_impl.h
+++ b/content/browser/webid/federated_auth_request_impl.h
@@ -15,6 +15,7 @@
 #include "content/browser/webid/idp_network_request_manager.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/identity_request_dialog_controller.h"
+#include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/mojom/webid/federated_auth_request.mojom.h"
 #include "url/gurl.h"
 
@@ -81,10 +82,14 @@
   void OnIdpPageClosed();
   void OnTokenProvisionApproved(
       IdentityRequestDialogController::UserApproval approval);
+
+  void DownloadBitmap(const GURL& icon_url,
+                      int ideal_icon_size,
+                      WebContents::ImageDownloadCallback callback);
   void OnAccountsResponseReceived(
       IdpNetworkRequestManager::FetchStatus status,
       IdpNetworkRequestManager::AccountList accounts,
-      content::IdentityProviderMetadata idp_metadata);
+      IdentityProviderMetadata idp_metadata);
   void OnAccountSelected(const std::string& account_id);
   void OnTokenResponseReceived(IdpNetworkRequestManager::FetchStatus status,
                                const std::string& id_token);
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc
index 0087516..c38042f4 100644
--- a/content/browser/webid/federated_auth_request_impl_unittest.cc
+++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -572,9 +572,10 @@
                                    std::string token,
                                    bool prefer_auto_sign_in) {
     if (conf.accounts_response) {
-      EXPECT_CALL(*mock_request_manager_, SendAccountsRequest(_, _))
+      EXPECT_CALL(*mock_request_manager_, SendAccountsRequest(_, _, _, _, _))
           .WillOnce(Invoke(
-              [&](const GURL&,
+              [&](const GURL&, int, int,
+                  IdpNetworkRequestManager::BrandIconDownloader,
                   IdpNetworkRequestManager::AccountsRequestCallback callback) {
                 std::move(callback).Run(*conf.accounts_response, conf.accounts,
                                         IdentityProviderMetadata());
diff --git a/content/browser/webid/idp_network_request_manager.cc b/content/browser/webid/idp_network_request_manager.cc
index 03d6c43..b5ed43bb 100644
--- a/content/browser/webid/idp_network_request_manager.cc
+++ b/content/browser/webid/idp_network_request_manager.cc
@@ -23,6 +23,8 @@
 #include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/common/manifest/manifest_icon_selector.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/color_utils.h"
 #include "url/origin.h"
 
@@ -66,6 +68,10 @@
 // response size that is a part of this protocol.
 constexpr int maxResponseSizeInKiB = 1024;
 
+// safe_zone_diameter/icon_size as defined in
+// https://www.w3.org/TR/appmanifest/#icon-masks
+constexpr float kMaskableWebIconSafeZoneRatio = 0.8f;
+
 net::NetworkTrafficAnnotationTag CreateTrafficAnnotation() {
   return net::DefineNetworkTrafficAnnotation("fedcm", R"(
         semantics {
@@ -177,7 +183,10 @@
 // Parse IdentityProviderMetadata from given value. Overwrites |idp_metadata|
 // with the parsed value.
 void ParseIdentityProviderMetadata(const base::Value& idp_metadata_value,
-                                   IdentityProviderMetadata& idp_metadata) {
+                                   int brand_icon_ideal_size,
+                                   int brand_icon_minimum_size,
+                                   IdentityProviderMetadata& idp_metadata,
+                                   GURL* brand_icon_url) {
   if (!idp_metadata_value.is_dict())
     return;
 
@@ -193,6 +202,37 @@
         idp_metadata.brand_text_color = absl::nullopt;
     }
   }
+
+  const base::Value* icons_value = idp_metadata_value.FindKey("icons");
+  if (icons_value != nullptr && icons_value->is_list()) {
+    std::vector<blink::Manifest::ImageResource> icons;
+    for (const base::Value& icon_value : icons_value->GetList()) {
+      if (!icon_value.is_dict())
+        continue;
+
+      const std::string* icon_src = icon_value.FindStringKey("url");
+      if (icon_src == nullptr)
+        continue;
+
+      blink::Manifest::ImageResource icon;
+      icon.src = GURL(*icon_src);
+      if (!icon.src.is_valid())
+        continue;
+
+      icon.purpose = {blink::mojom::ManifestImageResource_Purpose::MASKABLE};
+
+      absl::optional<int> icon_size = icon_value.FindIntKey("size");
+      int icon_size_int = icon_size ? icon_size.value() : 0;
+      icon.sizes.emplace_back(icon_size_int, icon_size_int);
+
+      icons.push_back(icon);
+    }
+
+    *brand_icon_url = blink::ManifestIconSelector::FindBestMatchingSquareIcon(
+        icons, brand_icon_ideal_size / kMaskableWebIconSafeZoneRatio,
+        brand_icon_minimum_size / kMaskableWebIconSafeZoneRatio,
+        blink::mojom::ManifestImageResource_Purpose::MASKABLE);
+  }
 }
 
 using FetchStatus = content::IdpNetworkRequestManager::FetchStatus;
@@ -255,7 +295,9 @@
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory)
     : provider_(provider),
       relying_party_origin_(relying_party_origin),
-      loader_factory_(loader_factory) {}
+      loader_factory_(loader_factory),
+      idp_brand_icon_ideal_size_(0),
+      idp_brand_icon_minimum_size_(0) {}
 
 IdpNetworkRequestManager::~IdpNetworkRequestManager() = default;
 
@@ -303,10 +345,16 @@
 
 void IdpNetworkRequestManager::SendAccountsRequest(
     const GURL& accounts_url,
+    int idp_brand_icon_ideal_size,
+    int idp_brand_icon_minimum_size,
+    BrandIconDownloader brand_icon_downloader,
     AccountsRequestCallback callback) {
   DCHECK(!url_loader_);
   DCHECK(!accounts_request_callback_);
+  idp_brand_icon_ideal_size_ = idp_brand_icon_ideal_size;
+  idp_brand_icon_minimum_size_ = idp_brand_icon_minimum_size;
   accounts_request_callback_ = std::move(callback);
+  brand_icon_downloader_ = std::move(brand_icon_downloader);
 
   // Use ReferrerPolicy::NO_REFERRER for this request so that relying party
   // identity is not exposed to the Identity provider via referrer.
@@ -590,9 +638,40 @@
   }
 
   IdentityProviderMetadata idp_metadata;
+  GURL idp_icon_url;
   const base::Value* idp_metadata_value = response.FindKey(kIdpBrandingKey);
   if (idp_metadata_value)
-    ParseIdentityProviderMetadata(*idp_metadata_value, idp_metadata);
+    ParseIdentityProviderMetadata(
+        *idp_metadata_value, idp_brand_icon_ideal_size_,
+        idp_brand_icon_minimum_size_, idp_metadata, &idp_icon_url);
+
+  auto on_icon_fetched_callback = base::BindOnce(
+      &IdpNetworkRequestManager::OnIdentityProviderBrandIconFetched,
+      weak_ptr_factory_.GetWeakPtr(), std::move(account_list),
+      std::move(idp_metadata));
+
+  if (idp_icon_url.is_valid()) {
+    std::move(brand_icon_downloader_)
+        .Run(idp_icon_url, idp_brand_icon_ideal_size_,
+             std::move(on_icon_fetched_callback));
+    return;
+  }
+
+  std::move(on_icon_fetched_callback).Run(0, 404, GURL(), {}, {});
+}
+
+void IdpNetworkRequestManager::OnIdentityProviderBrandIconFetched(
+    AccountList account_list,
+    IdentityProviderMetadata idp_metadata,
+    int id,
+    int http_status_code,
+    const GURL& image_url,
+    const std::vector<SkBitmap>& bitmaps,
+    const std::vector<gfx::Size>& sizes) {
+  if (bitmaps.size() == 1 && bitmaps[0].width() == bitmaps[0].height() &&
+      bitmaps[0].width() >= idp_brand_icon_minimum_size_) {
+    idp_metadata.brand_icon = bitmaps[0];
+  }
 
   std::move(accounts_request_callback_)
       .Run(FetchStatus::kSuccess, std::move(account_list),
diff --git a/content/browser/webid/idp_network_request_manager.h b/content/browser/webid/idp_network_request_manager.h
index 7ed622ca..e9a5c15 100644
--- a/content/browser/webid/idp_network_request_manager.h
+++ b/content/browser/webid/idp_network_request_manager.h
@@ -12,11 +12,14 @@
 #include "base/callback.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/identity_request_dialog_controller.h"
+#include "content/public/browser/web_contents.h"
 #include "services/data_decoder/public/cpp/data_decoder.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
+class SkBitmap;
+
 namespace net {
 enum class ReferrerPolicy;
 }
@@ -104,6 +107,10 @@
   static constexpr char kWellKnownFilePath[] = ".well-known/fedcm";
 
   using AccountList = std::vector<content::IdentityRequestAccount>;
+  using BrandIconDownloader =
+      base::OnceCallback<void(const GURL& /*icon_url*/,
+                              int /*ideal_icon_size*/,
+                              WebContents::ImageDownloadCallback)>;
   using FetchWellKnownCallback =
       base::OnceCallback<void(FetchStatus, Endpoints)>;
   using FetchClientIdMetadataCallback =
@@ -145,7 +152,10 @@
 
   // Fetch accounts list for this user from the IDP.
   virtual void SendAccountsRequest(const GURL& accounts_url,
-                                   AccountsRequestCallback);
+                                   int idp_brand_icon_ideal_size,
+                                   int idp_brand_icon_minimum_size,
+                                   BrandIconDownloader icon_downloader,
+                                   AccountsRequestCallback callback);
 
   // Request a new token for this user account and RP from the IDP.
   virtual void SendTokenRequest(const GURL& token_url,
@@ -171,6 +181,13 @@
   void OnSigninRequestParsed(data_decoder::DataDecoder::ValueOrError result);
   void OnAccountsRequestResponse(std::unique_ptr<std::string> response_body);
   void OnAccountsRequestParsed(data_decoder::DataDecoder::ValueOrError result);
+  void OnIdentityProviderBrandIconFetched(AccountList account_list,
+                                          IdentityProviderMetadata idp_metadata,
+                                          int id,
+                                          int http_status_code,
+                                          const GURL& image_url,
+                                          const std::vector<SkBitmap>& bitmaps,
+                                          const std::vector<gfx::Size>& sizes);
   void OnTokenRequestResponse(std::unique_ptr<std::string> response_body);
   void OnTokenRequestParsed(data_decoder::DataDecoder::ValueOrError result);
   void OnRevokeResponse(std::unique_ptr<std::string> response_body);
@@ -198,7 +215,11 @@
   RevokeCallback revoke_callback_;
   LogoutCallback logout_callback_;
 
+  int idp_brand_icon_ideal_size_;
+  int idp_brand_icon_minimum_size_;
+
   std::unique_ptr<network::SimpleURLLoader> url_loader_;
+  BrandIconDownloader brand_icon_downloader_;
 
   base::WeakPtrFactory<IdpNetworkRequestManager> weak_ptr_factory_{this};
 };
diff --git a/content/browser/webid/idp_network_request_manager_unittest.cc b/content/browser/webid/idp_network_request_manager_unittest.cc
index e5c2639..7aa629c 100644
--- a/content/browser/webid/idp_network_request_manager_unittest.cc
+++ b/content/browser/webid/idp_network_request_manager_unittest.cc
@@ -5,16 +5,21 @@
 #include "content/browser/webid/idp_network_request_manager.h"
 
 #include <array>
+#include <map>
 #include <string>
 #include <tuple>
+#include <utility>
 #include "base/strings/stringprintf.h"
 #include "base/test/bind.h"
 #include "base/test/task_environment.h"
 #include "base/values.h"
+#include "content/public/browser/manifest_icon_downloader.h"
 #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/size.h"
 #include "url/gurl.h"
 
 using AccountList = content::IdpNetworkRequestManager::AccountList;
@@ -27,6 +32,10 @@
 
 namespace {
 
+// Values for testing. Real minimum and ideal sizes are different.
+const int kTestIdpBrandIconMinimumSize = 16;
+const int kTestIdpBrandIconIdealSize = 32;
+
 const char kTestIdpUrl[] = "https://idp.test";
 const char kTestRpUrl[] = "https://rp.test";
 const char kTestAccountsEndpoint[] = "https://idp.test/accounts_endpoint";
@@ -43,6 +52,10 @@
 
   void TearDown() override { manager_.reset(); }
 
+  void SetBitmapSpecsForUrl(const std::string& url, int size, int color) {
+    bitmap_specs_[GURL(url)] = std::make_pair(size, color);
+  }
+
   std::tuple<FetchStatus, AccountList, IdentityProviderMetadata>
   SendAccountsRequestAndWaitForResponse(const char* test_accounts) {
     GURL accounts_endpoint(kTestAccountsEndpoint);
@@ -61,7 +74,12 @@
           parsed_idp_metadata = std::move(idp_metadata);
           run_loop.Quit();
         });
-    manager().SendAccountsRequest(accounts_endpoint, std::move(callback));
+    manager().SendAccountsRequest(
+        accounts_endpoint, kTestIdpBrandIconIdealSize,
+        kTestIdpBrandIconMinimumSize,
+        base::BindOnce(&IdpNetworkRequestManagerTest::DownloadBitmap,
+                       base::Unretained(this)),
+        std::move(callback));
     run_loop.Run();
 
     return {parsed_accounts_response, parsed_accounts,
@@ -95,10 +113,31 @@
   }
 
  private:
+  void DownloadBitmap(const GURL& url,
+                      int ideal_icon_size,
+                      WebContents::ImageDownloadCallback callback) {
+    auto bitmap_specs_it = bitmap_specs_.find(url);
+    CHECK(bitmap_specs_.empty() || bitmap_specs_it != bitmap_specs_.end());
+
+    SkBitmap bitmap;
+    if (bitmap_specs_it != bitmap_specs_.end()) {
+      int bitmap_edge_size = bitmap_specs_it->second.first;
+      int bitmap_color = bitmap_specs_it->second.second;
+
+      bitmap.allocN32Pixels(bitmap_edge_size, bitmap_edge_size);
+      bitmap.eraseColor(bitmap_color);
+    }
+
+    std::move(callback).Run(0, 200, url, {bitmap},
+                            {gfx::Size(bitmap.width(), bitmap.height())});
+  }
+
   base::test::SingleThreadTaskEnvironment task_environment_;
   network::TestURLLoaderFactory test_url_loader_factory_;
   std::unique_ptr<IdpNetworkRequestManager> manager_;
   data_decoder::test::InProcessDataDecoder in_process_data_decoder;
+
+  std::map<GURL, std::pair<int, SkColor>> bitmap_specs_;
 };
 
 TEST_F(IdpNetworkRequestManagerTest, ParseAccountEmpty) {
@@ -456,6 +495,96 @@
   EXPECT_EQ(absl::nullopt, idp_metadata.brand_text_color);
 }
 
+TEST_F(IdpNetworkRequestManagerTest, ParseAccountBrandingSelectBestSize) {
+  const char test_accounts_json[] = R"({
+  "accounts" : [
+    {
+      "sub" : "1234",
+      "email": "ken@idp.test",
+      "name": "Ken R. Example"
+    }
+  ],
+  "branding" : {
+    "icons": [
+      {
+        "url": "https://example.com/10.png",
+        "size": 10
+      },
+      {
+        "url": "https://example.com/16.png",
+        "size": 16
+      },
+      {
+        "url": "https://example.com/39.png",
+        "size": 39
+      },
+      {
+        "url": "https://example.com/40.png",
+        "size": 40
+      },
+      {
+        "url": "https://example.com/41.png",
+        "size": 41
+      }
+    ]
+  }
+  })";
+
+  ASSERT_EQ(32, kTestIdpBrandIconIdealSize);
+  // 32 / kMaskableWebIconSafeZoneRatio = 40
+
+  SetBitmapSpecsForUrl("https://example.com/10.png", 10, SK_ColorBLACK);
+  SetBitmapSpecsForUrl("https://example.com/16.png", 16, SK_ColorBLACK);
+  SetBitmapSpecsForUrl("https://example.com/39.png", 39, SK_ColorBLACK);
+  SetBitmapSpecsForUrl("https://example.com/40.png", 40, SK_ColorBLUE);
+  SetBitmapSpecsForUrl("https://example.com/41.png", 41, SK_ColorBLACK);
+
+  FetchStatus accounts_response;
+  AccountList accounts;
+  IdentityProviderMetadata idp_metadata;
+  std::tie(accounts_response, accounts, idp_metadata) =
+      SendAccountsRequestAndWaitForResponse(test_accounts_json);
+
+  EXPECT_EQ(FetchStatus::kSuccess, accounts_response);
+  EXPECT_FALSE(idp_metadata.brand_icon.isNull());
+  EXPECT_EQ(SK_ColorBLUE, idp_metadata.brand_icon.getColor(0, 0));
+}
+
+TEST_F(IdpNetworkRequestManagerTest,
+       ParseAccountBrandingIncorrectSizeInMetadata) {
+  const char test_accounts_json[] = R"({
+  "accounts" : [
+    {
+      "sub" : "1234",
+      "email": "ken@idp.test",
+      "name": "Ken R. Example"
+    }
+  ],
+  "branding" : {
+    "icons": [
+      {
+        "url": "https://example.com/icon.png",
+        "size": 32
+      }
+    ]
+  }
+  })";
+
+  SetBitmapSpecsForUrl("https://example.com/icon.png", 1, SK_ColorBLACK);
+
+  FetchStatus accounts_response;
+  AccountList accounts;
+  IdentityProviderMetadata idp_metadata;
+  std::tie(accounts_response, accounts, idp_metadata) =
+      SendAccountsRequestAndWaitForResponse(test_accounts_json);
+
+  // Downloaded brand icon should not be used because it is too small.
+  EXPECT_TRUE(idp_metadata.brand_icon.isNull());
+
+  // An invalid brand icon should not prevent sign in.
+  EXPECT_EQ(FetchStatus::kSuccess, accounts_response);
+}
+
 // Tests the revoke implementation.
 TEST_F(IdpNetworkRequestManagerTest, Revoke) {
   bool called = false;
diff --git a/content/browser/webid/test/mock_idp_network_request_manager.h b/content/browser/webid/test/mock_idp_network_request_manager.h
index 80678333..4175d2b 100644
--- a/content/browser/webid/test/mock_idp_network_request_manager.h
+++ b/content/browser/webid/test/mock_idp_network_request_manager.h
@@ -28,7 +28,12 @@
                     FetchClientIdMetadataCallback));
   MOCK_METHOD3(SendSigninRequest,
                void(const GURL&, const std::string&, SigninRequestCallback));
-  MOCK_METHOD2(SendAccountsRequest, void(const GURL&, AccountsRequestCallback));
+  MOCK_METHOD5(SendAccountsRequest,
+               void(const GURL&,
+                    int,
+                    int,
+                    BrandIconDownloader,
+                    AccountsRequestCallback));
   MOCK_METHOD4(SendTokenRequest,
                void(const GURL&,
                     const std::string&,
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index e3fd09e..ad9774a2 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -139,6 +139,8 @@
     "devtools_permission_overrides.h",
     "devtools_socket_factory.h",
     "disallow_activation_reason.h",
+    "document_ref.cc",
+    "document_ref.h",
     "document_service.h",
     "document_service_internal.cc",
     "document_service_internal.h",
@@ -390,6 +392,8 @@
     "video_capture_service.h",
     "visibility.h",
     "vpn_service_proxy.h",
+    "weak_document_ptr.cc",
+    "weak_document_ptr.h",
     "web_contents.cc",
     "web_contents.h",
     "web_contents_delegate.cc",
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 2054b760..67026e9 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -1009,6 +1009,7 @@
     ui::PageTransition page_transition,
     bool has_user_gesture,
     const absl::optional<url::Origin>& initiating_origin,
+    RenderFrameHost* initiator_document,
     mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
   return true;
 }
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 55b28433..6fbb03d 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -1803,6 +1803,10 @@
   // browser-initiated navigations. The initiating origin is intended to help
   // users make security decisions about whether to allow an external
   // application to launch.
+  //
+  // |initiator_document| refers to the document that initiated the navigation,
+  // if it is still available. Use |initiating_origin| instead for security
+  // decisions.
   virtual bool HandleExternalProtocol(
       const GURL& url,
       base::RepeatingCallback<WebContents*()> web_contents_getter,
@@ -1814,6 +1818,7 @@
       ui::PageTransition page_transition,
       bool has_user_gesture,
       const absl::optional<url::Origin>& initiating_origin,
+      RenderFrameHost* initiator_document,
       mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory);
 
   // Creates an OverlayWindow to be used for Picture-in-Picture. This window
diff --git a/content/public/browser/document_ref.cc b/content/public/browser/document_ref.cc
new file mode 100644
index 0000000..03d1d6b8
--- /dev/null
+++ b/content/public/browser/document_ref.cc
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/document_ref.h"
+
+namespace content {
+
+DocumentRef::DocumentRef(base::SafeRef<RenderFrameHost> safe_document)
+    : safe_document_(std::move(safe_document)) {}
+
+}  // namespace content
diff --git a/content/public/browser/document_ref.h b/content/public/browser/document_ref.h
new file mode 100644
index 0000000..b55fa998
--- /dev/null
+++ b/content/public/browser/document_ref.h
@@ -0,0 +1,62 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_DOCUMENT_REF_H_
+#define CONTENT_PUBLIC_BROWSER_DOCUMENT_REF_H_
+
+#include "base/memory/safe_ref.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class RenderFrameHost;
+
+// A non-nullable, checked reference to a document. This will CHECK if it is
+// accessed after the document is no longer valid, because the RenderFrameHost
+// is deleted or navigatese to a different document. See also
+// document_user_data.h.
+//
+// Note that though this is implemented as a base::SafeRef<RenderFrameHost>,
+// it is different from an ordinary SafeRef to the RenderFrameHost.
+//
+// docs/render_document.md will make these equivalent in the future.
+//
+// If the document may become invalid, use a WeakDocumentPtr instead.
+//
+// Treat this like you would a base::SafeRef, because that's essentially what it
+// is.
+class DocumentRef {
+ public:
+  // Copyable and movable.
+  DocumentRef(DocumentRef&&);
+  DocumentRef& operator=(DocumentRef&&);
+  DocumentRef(const DocumentRef&);
+  DocumentRef& operator=(const DocumentRef&);
+
+  ~DocumentRef();
+
+  RenderFrameHost& AsRenderFrameHost() const { return *safe_document_; }
+
+ private:
+  explicit DocumentRef(base::SafeRef<RenderFrameHost> safe_document);
+
+  friend class RenderFrameHostImpl;
+
+  // Created from a factory scoped to document, rather than RenderFrameHost,
+  // lifetime.
+  base::SafeRef<RenderFrameHost> safe_document_;
+};
+
+// [chromium-style] requires these be out of line, but they are small enough to
+// inline the defaults.
+inline DocumentRef::DocumentRef(DocumentRef&&) = default;
+inline DocumentRef& DocumentRef::operator=(DocumentRef&&) = default;
+inline DocumentRef::DocumentRef(const DocumentRef&) = default;
+inline DocumentRef& DocumentRef::operator=(const DocumentRef&) = default;
+inline DocumentRef::~DocumentRef() = default;
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_DOCUMENT_REF_H_
diff --git a/content/public/browser/identity_request_dialog_controller.cc b/content/public/browser/identity_request_dialog_controller.cc
index 4295436..86fe5694 100644
--- a/content/public/browser/identity_request_dialog_controller.cc
+++ b/content/public/browser/identity_request_dialog_controller.cc
@@ -48,6 +48,14 @@
 IdentityProviderMetadata::IdentityProviderMetadata(
     const IdentityProviderMetadata& other) = default;
 
+int IdentityRequestDialogController::GetBrandIconIdealSize() {
+  return 0;
+}
+
+int IdentityRequestDialogController::GetBrandIconMinimumSize() {
+  return 0;
+}
+
 void IdentityRequestDialogController::ShowInitialPermissionDialog(
     WebContents* rp_web_contents,
     const GURL& idp_url,
diff --git a/content/public/browser/identity_request_dialog_controller.h b/content/public/browser/identity_request_dialog_controller.h
index 4b25a3d..8c21396f 100644
--- a/content/public/browser/identity_request_dialog_controller.h
+++ b/content/public/browser/identity_request_dialog_controller.h
@@ -12,6 +12,7 @@
 #include "base/containers/span.h"
 #include "content/common/content_export.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "url/gurl.h"
 
@@ -80,6 +81,7 @@
 
   absl::optional<SkColor> brand_text_color;
   absl::optional<SkColor> brand_background_color;
+  SkBitmap brand_icon;
 };
 
 // IdentityRequestDialogController is in interface for control of the UI
@@ -110,6 +112,14 @@
 
   virtual ~IdentityRequestDialogController() = default;
 
+  // Returns the ideal size for the identity provider brand icon. The brand icon
+  // is displayed in the accounts dialog.
+  virtual int GetBrandIconIdealSize();
+
+  // Returns the minimum size for the identity provider brand icon. The brand
+  // icon is displayed in the accounts dialog.
+  virtual int GetBrandIconMinimumSize();
+
   // Permission-oriented flow methods.
 
   // Shows the initial permission dialog to the user.
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h
index a3cae6b..3472819 100644
--- a/content/public/browser/render_frame_host.h
+++ b/content/public/browser/render_frame_host.h
@@ -101,6 +101,7 @@
 namespace content {
 
 class BrowserContext;
+class DocumentRef;
 struct GlobalRenderFrameHostId;
 class RenderProcessHost;
 class RenderViewHost;
@@ -108,6 +109,7 @@
 class RenderWidgetHostView;
 class SiteInstance;
 class StoragePartition;
+class WeakDocumentPtr;
 class WebUI;
 class Page;
 
@@ -1018,6 +1020,12 @@
   // during call to RenderFrameHostImpl::DidNavigate which happens after commit.
   virtual bool IsErrorDocument() = 0;
 
+  // Return checked and weak references, respectively, to the current document
+  // in this RenderFrameHost, which will be no longer valid once the
+  // RenderFrameHost is deleted or navigates to another document.
+  virtual DocumentRef GetDocumentRef() = 0;
+  virtual WeakDocumentPtr GetWeakDocumentPtr() = 0;
+
  private:
   // This interface should only be implemented inside content.
   friend class RenderFrameHostImpl;
diff --git a/content/public/browser/weak_document_ptr.cc b/content/public/browser/weak_document_ptr.cc
new file mode 100644
index 0000000..e017fb3
--- /dev/null
+++ b/content/public/browser/weak_document_ptr.cc
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/weak_document_ptr.h"
+
+namespace content {
+
+WeakDocumentPtr::WeakDocumentPtr(base::WeakPtr<RenderFrameHost> weak_rfh)
+    : weak_document_(std::move(weak_rfh)) {}
+
+}  // namespace content
diff --git a/content/public/browser/weak_document_ptr.h b/content/public/browser/weak_document_ptr.h
new file mode 100644
index 0000000..05f7ae50
--- /dev/null
+++ b/content/public/browser/weak_document_ptr.h
@@ -0,0 +1,68 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_WEAK_DOCUMENT_PTR_H_
+#define CONTENT_PUBLIC_BROWSER_WEAK_DOCUMENT_PTR_H_
+
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class RenderFrameHost;
+
+// Weakly refers to a document.
+//
+// This is invalidated at the same time as DocumentUserData. It
+// becomes null whenever the RenderFrameHost is deleted or navigates to a
+// different document. See also document_user_data.h.
+//
+// Note that though this is implemented as a base::WeakPtr<RenderFrameHost>,
+// it is different from an ordinary weak pointer to the RenderFrameHost.
+//
+// docs/render_document.md will make these equivalent in the future.
+//
+// Treat this like you would a base::WeakPtr, because that's essentially what it
+// is.
+class WeakDocumentPtr {
+ public:
+  WeakDocumentPtr();
+
+  // Copyable and movable.
+  WeakDocumentPtr(WeakDocumentPtr&&);
+  WeakDocumentPtr& operator=(WeakDocumentPtr&&);
+  WeakDocumentPtr(const WeakDocumentPtr&);
+  WeakDocumentPtr& operator=(const WeakDocumentPtr&);
+
+  ~WeakDocumentPtr();
+
+  // Callers must handle this returning null, in case the frame has been deleted
+  // or a cross-document navigation has committed in the same RenderFrameHost.
+  RenderFrameHost* AsRenderFrameHostIfValid() const {
+    return weak_document_.get();
+  }
+
+ private:
+  explicit WeakDocumentPtr(base::WeakPtr<RenderFrameHost> weak_rfh);
+
+  friend class RenderFrameHostImpl;
+
+  // Created from a factory scoped to document, rather than RenderFrameHost,
+  // lifetime.
+  base::WeakPtr<RenderFrameHost> weak_document_;
+};
+
+// [chromium-style] requires these be out of line, but they are small enough to
+// inline the defaults.
+inline WeakDocumentPtr::WeakDocumentPtr() = default;
+inline WeakDocumentPtr::WeakDocumentPtr(WeakDocumentPtr&&) = default;
+inline WeakDocumentPtr& WeakDocumentPtr::operator=(WeakDocumentPtr&&) = default;
+inline WeakDocumentPtr::WeakDocumentPtr(const WeakDocumentPtr&) = default;
+inline WeakDocumentPtr& WeakDocumentPtr::operator=(const WeakDocumentPtr&) =
+    default;
+inline WeakDocumentPtr::~WeakDocumentPtr() = default;
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_WEAK_DOCUMENT_PTR_H_
diff --git a/content/public/common/content_switch_dependent_feature_overrides.cc b/content/public/common/content_switch_dependent_feature_overrides.cc
index c9122563..df5a13e 100644
--- a/content/public/common/content_switch_dependent_feature_overrides.cc
+++ b/content/public/common/content_switch_dependent_feature_overrides.cc
@@ -126,6 +126,11 @@
     {::switches::kHeadless, std::cref(blink::features::kPaintHolding),
      base::FeatureList::OVERRIDE_DISABLE_FEATURE},
 
+    // Override for --force-major-version-to-minor.
+    {switches::kForceMajorVersionToMinorPosition,
+     std::cref(blink::features::kForceMajorVersionInMinorPositionInUserAgent),
+     base::FeatureList::OVERRIDE_ENABLE_FEATURE},
+
     // Override for --force-major-version-to-100.
     {switches::kForceMajorVersionTo100,
      std::cref(blink::features::kForceMajorVersion100InUserAgent),
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 7e79aca..6b9a2db 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -496,6 +496,10 @@
 // Forces the Chrome minor version to 100 in the User-Agent string.
 const char kForceMinorVersionTo100[] = "force-minor-version-to-100";
 
+// Forces the Chrome major version to the minor position in the User-Agent
+// string. Locks major version to 99.
+const char kForceMajorVersionToMinorPosition[] = "force-major-version-to-minor";
+
 // Forces use of hardware overlay for fullscreen video playback. Useful for
 // testing the Android overlay fullscreen functionality on other platforms.
 const char kForceOverlayFullscreenVideo[]   = "force-overlay-fullscreen-video";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 9d1beef..d09b07e 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -142,6 +142,7 @@
 CONTENT_EXPORT extern const char kForceDisplayList2dCanvas[];
 CONTENT_EXPORT extern const char kDisableOopRasterization[];
 CONTENT_EXPORT extern const char kEnableOopRasterization[];
+CONTENT_EXPORT extern const char kForceMajorVersionToMinorPosition[];
 CONTENT_EXPORT extern const char kForceMajorVersionTo100[];
 CONTENT_EXPORT extern const char kForceMinorVersionTo100[];
 CONTENT_EXPORT extern const char kForceOverlayFullscreenVideo[];
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc
index 57f45c3..0c4a57a 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.cc
+++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -717,6 +717,14 @@
     return;
   }
 
+  // Skip images that do not have an image_src url (e.g. SVGs), or are in
+  // documents that do not have a document_url.
+  // TODO(accessibility): Remove this check when support for SVGs is added.
+  if (!g_ignore_protocol_checks_for_testing &&
+      (src.Url().GetString().Utf8().empty() ||
+       document().Url().GetString().Utf8().empty()))
+    return;
+
   if (!image_annotator_) {
     if (!first_unlabeled_image_id_.has_value() ||
         first_unlabeled_image_id_.value() == src.AxID()) {
diff --git a/content/test/data/accessibility/aria/aria-img-expected-mac.txt b/content/test/data/accessibility/aria/aria-img-expected-mac.txt
index 634a840..0fae38f 100644
--- a/content/test/data/accessibility/aria/aria-img-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-img-expected-mac.txt
@@ -1,2 +1,2 @@
 AXWebArea
-++AXImage AXDescription='To get missing image descriptions, open the context menu.' AXRoleDescription='Unlabeled image'
+++AXImage
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-img-expected-win.txt b/content/test/data/accessibility/aria/aria-img-expected-win.txt
index 418c075..3ce6eef 100644
--- a/content/test/data/accessibility/aria/aria-img-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-img-expected-win.txt
@@ -1,2 +1,2 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_GRAPHIC name='To get missing image descriptions, open the context menu.' READONLY
+++ROLE_SYSTEM_GRAPHIC READONLY
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/canvas-expected-mac.txt b/content/test/data/accessibility/html/canvas-expected-mac.txt
index aab0489c..1e44372 100644
--- a/content/test/data/accessibility/html/canvas-expected-mac.txt
+++ b/content/test/data/accessibility/html/canvas-expected-mac.txt
@@ -1,7 +1,7 @@
 AXWebArea
 ++AXGroup
-++++AXGroup AXDescription='To get missing image descriptions, open the context menu.'
+++++AXGroup
 ++++++AXStaticText AXValue='Static fallback'
 ++++AXGroup
 ++++++AXLink AXDescription='Interactive fallback'
-++++++++AXStaticText AXValue='Interactive fallback'
+++++++++AXStaticText AXValue='Interactive fallback'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/canvas-expected-uia-win.txt b/content/test/data/accessibility/html/canvas-expected-uia-win.txt
index 5e09ab5..76b2d25 100644
--- a/content/test/data/accessibility/html/canvas-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/canvas-expected-uia-win.txt
@@ -1,7 +1,7 @@
 Document
 ++Group IsControlElement=false
-++++Image Name='To get missing image descriptions, open the context menu.'
+++++Image
 ++++++Text Name='Static fallback'
 ++++Image
 ++++++Hyperlink Name='Interactive fallback'
-++++++++Text Name='Interactive fallback' IsControlElement=false
+++++++++Text Name='Interactive fallback' IsControlElement=false
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/canvas-fallback-expected-uia-win.txt b/content/test/data/accessibility/html/canvas-fallback-expected-uia-win.txt
index 4ecbbde..75d6edd 100644
--- a/content/test/data/accessibility/html/canvas-fallback-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/canvas-fallback-expected-uia-win.txt
@@ -1,6 +1,6 @@
 Document
 ++Group IsControlElement=false
-++++Image Name='To get missing image descriptions, open the context menu.'
+++++Image
 ++++++Text Name='Static fallback'
 ++++Image
 ++++++Text Name='<newline>    '
@@ -18,4 +18,4 @@
 ++++++Text Name='<newline>    '
 ++++++Text IsControlElement=false
 ++++++++Text Name='Visibility hidden paragraph in fallback content' IsControlElement=false
-++++++Text Name='<newline>  '
+++++++Text Name='<newline>  '
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-transform-expected-uia-win.txt b/content/test/data/accessibility/html/iframe-transform-expected-uia-win.txt
index 07f2730..015293d2 100644
--- a/content/test/data/accessibility/html/iframe-transform-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/iframe-transform-expected-uia-win.txt
@@ -1,7 +1,7 @@
 Document
 ++Document
-++++Document Name='To get missing image descriptions, open the context menu.'
-++++++Image Name='To get missing image descriptions, open the context menu.'
+++++Document
+++++++Image
 ++Document
-++++Document Name='To get missing image descriptions, open the context menu.'
-++++++Image Name='To get missing image descriptions, open the context menu.'
+++++Document
+++++++Image
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-transform-expected-win.txt b/content/test/data/accessibility/html/iframe-transform-expected-win.txt
index ef94d77d8..1b5b2f2 100644
--- a/content/test/data/accessibility/html/iframe-transform-expected-win.txt
+++ b/content/test/data/accessibility/html/iframe-transform-expected-win.txt
@@ -1,7 +1,7 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0)
 ++IA2_ROLE_INTERNAL_FRAME location=(0, 0)
-++++ROLE_SYSTEM_DOCUMENT name='To get missing image descriptions, open the context menu.' READONLY FOCUSABLE location=(0, 0)
-++++++ROLE_SYSTEM_GRAPHIC name='To get missing image descriptions, open the context menu.' READONLY location=(10, 10) size=(100, 50)
+++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0)
+++++++ROLE_SYSTEM_GRAPHIC READONLY location=(10, 10) size=(100, 50)
 ++IA2_ROLE_INTERNAL_FRAME location=(0, 250)
-++++ROLE_SYSTEM_DOCUMENT name='To get missing image descriptions, open the context menu.' READONLY FOCUSABLE location=(0, 250)
-++++++ROLE_SYSTEM_GRAPHIC name='To get missing image descriptions, open the context menu.' READONLY location=(15, 265) size=(150, 75)
+++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 250)
+++++++ROLE_SYSTEM_GRAPHIC READONLY location=(15, 265) size=(150, 75)
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-date-with-popup-open-expected-mac.txt b/content/test/data/accessibility/html/input-date-with-popup-open-expected-mac.txt
index caa575b..73b47323 100644
--- a/content/test/data/accessibility/html/input-date-with-popup-open-expected-mac.txt
+++ b/content/test/data/accessibility/html/input-date-with-popup-open-expected-mac.txt
@@ -18,9 +18,9 @@
 ++++++++++++++++++AXStaticText AXRoleDescription='text' AXValue='September 2008'
 ++++++++++++++++++AXImage AXRoleDescription='image'
 ++++++++++++++AXButton AXDescription='Show previous month' AXRoleDescription='button'
-++++++++++++++++AXImage
+++++++++++++++++AXImage AXRoleDescription='image'
 ++++++++++++++AXButton AXDescription='Show next month' AXRoleDescription='button'
-++++++++++++++++AXImage
+++++++++++++++++AXImage AXRoleDescription='image'
 ++++++++++++++AXTable AXRoleDescription='table'
 ++++++++++++++++AXGroup AXRoleDescription='group'
 ++++++++++++++++++AXGroup AXRoleDescription='group'
@@ -222,4 +222,4 @@
 ++++++++++++++++++++AXStaticText AXRoleDescription='text' AXValue='4'
 ++++++++++++++++++AXCell AXDescription='Saturday, October 11, 2008' AXRoleDescription='cell'
 ++++++++++++++++++++AXStaticText AXRoleDescription='text' AXValue='11'
-++++++++++++++++AXGroup AXRoleDescription='group'
\ No newline at end of file
+++++++++++++++++AXGroup AXRoleDescription='group'
diff --git a/content/test/data/accessibility/html/input-date-with-popup-open-expected-uia-win.txt b/content/test/data/accessibility/html/input-date-with-popup-open-expected-uia-win.txt
index 637b93c..efac9cd6 100644
--- a/content/test/data/accessibility/html/input-date-with-popup-open-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/input-date-with-popup-open-expected-uia-win.txt
@@ -19,7 +19,7 @@
 ++++++++++++++++++++Text Name='September 2008' IsControlElement=false
 ++++++++++++++++++++Image
 ++++++++++++++++Button Name='Show previous month'
-++++++++++++++++++Image Name='To get missing image descriptions, open the context menu.'
+++++++++++++++++++Image
 ++++++++++++++++Button Name='Show next month'
 ++++++++++++++++++Image
 ++++++++++++++++DataGrid Grid.ColumnCount=7 Grid.RowCount=6 Selection.CanSelectMultiple=false Selection.IsSelectionRequired=false Table.RowOrColumnMajor='RowMajor'
@@ -131,4 +131,4 @@
 ++++++++++++++++++++++++DataItem Name='Saturday, October 11, 2008' GridItem.Column=6 GridItem.ColumnSpan=1 GridItem.Row=5 GridItem.RowSpan=1 SelectionItem.IsSelected=false
 ++++++++++++++++++++++++++Text Name='11' IsControlElement=false
 ++++++++++++++++++Button Name='Clear'
-++++++++++++++++++Button Name='Today'
+++++++++++++++++++Button Name='Today'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-submit-expected-mac.txt b/content/test/data/accessibility/html/input-submit-expected-mac.txt
index 3d1e2369..13b12910 100644
--- a/content/test/data/accessibility/html/input-submit-expected-mac.txt
+++ b/content/test/data/accessibility/html/input-submit-expected-mac.txt
@@ -6,9 +6,9 @@
 ++AXGroup AXRoleDescription='group'
 ++++AXTextField AXRoleDescription='text field'
 ++++AXButton AXDescription='First image button in a form is a valid default button' AXRoleDescription='button'
-++++++AXImage AXDescription='To get missing image descriptions, open the context menu.' AXRoleDescription='Unlabeled image'
+++++++AXImage AXRoleDescription='image'
 ++++++AXStaticText AXRoleDescription='text' AXValue='First image button in a form is a valid default button'
 ++++AXButton AXDescription='Second image button in a form not a valid default button' AXRoleDescription='button'
-++++++AXImage AXRoleDescription='Unlabeled image'
+++++++AXImage AXRoleDescription='image'
 ++++++AXStaticText AXRoleDescription='text' AXValue='Second image button in a form not a valid default button'
-++AXButton AXRoleDescription='button' AXTitle='Submit outside of form not a valid default button'
+++AXButton AXRoleDescription='button' AXTitle='Submit outside of form not a valid default button'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-submit-expected-uia-win.txt b/content/test/data/accessibility/html/input-submit-expected-uia-win.txt
index 64188db3..82ffe210 100644
--- a/content/test/data/accessibility/html/input-submit-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/input-submit-expected-uia-win.txt
@@ -6,7 +6,7 @@
 ++Group
 ++++Edit
 ++++Button Name='First image button in a form is a valid default button'
-++++++Image Name='To get missing image descriptions, open the context menu.'
+++++++Image
 ++++++Text Name='First image button in a form is a valid default button' IsControlElement=false
 ++++Button Name='Second image button in a form not a valid default button'
 ++++++Image
diff --git a/content/test/data/accessibility/html/input-submit-expected-win.txt b/content/test/data/accessibility/html/input-submit-expected-win.txt
index 8352e49..6a443840 100644
--- a/content/test/data/accessibility/html/input-submit-expected-win.txt
+++ b/content/test/data/accessibility/html/input-submit-expected-win.txt
@@ -6,9 +6,9 @@
 ++IA2_ROLE_SECTION
 ++++ROLE_SYSTEM_TEXT FOCUSABLE text-input-type:text
 ++++ROLE_SYSTEM_PUSHBUTTON name='First image button in a form is a valid default button' DEFAULT FOCUSABLE
-++++++ROLE_SYSTEM_GRAPHIC name='To get missing image descriptions, open the context menu.' READONLY
+++++++ROLE_SYSTEM_GRAPHIC READONLY
 ++++++ROLE_SYSTEM_STATICTEXT name='First image button in a form is a valid default button'
 ++++ROLE_SYSTEM_PUSHBUTTON name='Second image button in a form not a valid default button' FOCUSABLE
 ++++++ROLE_SYSTEM_GRAPHIC READONLY
 ++++++ROLE_SYSTEM_STATICTEXT name='Second image button in a form not a valid default button'
-++ROLE_SYSTEM_PUSHBUTTON name='Submit outside of form not a valid default button' FOCUSABLE
+++ROLE_SYSTEM_PUSHBUTTON name='Submit outside of form not a valid default button' FOCUSABLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-types-expected-mac.txt b/content/test/data/accessibility/html/input-types-expected-mac.txt
index e5701d5..d4b2efc 100644
--- a/content/test/data/accessibility/html/input-types-expected-mac.txt
+++ b/content/test/data/accessibility/html/input-types-expected-mac.txt
@@ -20,7 +20,7 @@
 ++++AXGroup
 ++++++AXStaticText AXValue='Image: '
 ++++++AXButton AXTitle='Image:'
-++++++++AXImage AXDescription='To get missing image descriptions, open the context menu.'
+++++++++AXImage
 ++++++++AXStaticText AXValue='Submit'
 ++++AXGroup
 ++++++AXStaticText AXValue='Number: '
@@ -49,4 +49,4 @@
 ++++++AXTextField AXTitle='Text:'
 ++++AXGroup
 ++++++AXStaticText AXValue='Url: '
-++++++AXTextField AXTitle='Url:'
+++++++AXTextField AXTitle='Url:'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-types-expected-uia-win.txt b/content/test/data/accessibility/html/input-types-expected-uia-win.txt
index 5fe5bfb..3b9aa09 100644
--- a/content/test/data/accessibility/html/input-types-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/input-types-expected-uia-win.txt
@@ -20,7 +20,7 @@
 ++++Text
 ++++++Text Name='Image: '
 ++++++Button Name='Image:'
-++++++++Image Name='To get missing image descriptions, open the context menu.'
+++++++++Image
 ++++++++Text Name='Submit' IsControlElement=false
 ++++Text
 ++++++Text Name='Number: '
@@ -49,4 +49,4 @@
 ++++++Edit Name='Text:'
 ++++Text
 ++++++Text Name='Url: '
-++++++Edit Name='Url:'
+++++++Edit Name='Url:'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-types-expected-win.txt b/content/test/data/accessibility/html/input-types-expected-win.txt
index e7b20c43..b459e064 100644
--- a/content/test/data/accessibility/html/input-types-expected-win.txt
+++ b/content/test/data/accessibility/html/input-types-expected-win.txt
@@ -20,7 +20,7 @@
 ++++IA2_ROLE_LABEL
 ++++++ROLE_SYSTEM_STATICTEXT name='Image: '
 ++++++ROLE_SYSTEM_PUSHBUTTON name='Image:' FOCUSABLE
-++++++++ROLE_SYSTEM_GRAPHIC name='To get missing image descriptions, open the context menu.' READONLY
+++++++++ROLE_SYSTEM_GRAPHIC READONLY
 ++++++++ROLE_SYSTEM_STATICTEXT name='Submit'
 ++++IA2_ROLE_LABEL
 ++++++ROLE_SYSTEM_STATICTEXT name='Number: '
@@ -49,4 +49,4 @@
 ++++++ROLE_SYSTEM_TEXT name='Text:' FOCUSABLE text-input-type:text
 ++++IA2_ROLE_LABEL
 ++++++ROLE_SYSTEM_STATICTEXT name='Url: '
-++++++ROLE_SYSTEM_TEXT name='Url:' FOCUSABLE text-input-type:url
+++++++ROLE_SYSTEM_TEXT name='Url:' FOCUSABLE text-input-type:url
\ No newline at end of file
diff --git a/content/test/data/accessibility/mac/methods/accessibility-role-description-expected.txt b/content/test/data/accessibility/mac/methods/accessibility-role-description-expected.txt
index 041a936e..4ad1f85 100644
--- a/content/test/data/accessibility/mac/methods/accessibility-role-description-expected.txt
+++ b/content/test/data/accessibility/mac/methods/accessibility-role-description-expected.txt
@@ -1,4 +1,4 @@
-unlabelled_img.accessibilityRoleDescription='Unlabeled image'
+unlabelled_img.accessibilityRoleDescription='image'
 aria_roledescription.accessibilityRoleDescription='slidy slider button'
 document.accessibilityRoleDescription='HTML content'
 link.accessibilityRoleDescription='link'
@@ -32,4 +32,4 @@
 term.accessibilityRoleDescription='term'
 toggle_button.accessibilityRoleDescription='toggle button'
 fallback_role.accessibilityRoleDescription='text field'
-fallback_subrole.accessibilityRoleDescription='secure text field'
+fallback_subrole.accessibilityRoleDescription='secure text field'
\ No newline at end of file
diff --git a/dbus/values_util.cc b/dbus/values_util.cc
index e7405f9..2cd7b75 100644
--- a/dbus/values_util.cc
+++ b/dbus/values_util.cc
@@ -267,11 +267,9 @@
       break;
     }
     case base::Value::Type::LIST: {
-      const base::ListValue* list = nullptr;
-      value.GetAsList(&list);
       dbus::MessageWriter array_writer(nullptr);
       writer->OpenArray("v", &array_writer);
-      for (const auto& value_in_list : list->GetList()) {
+      for (const auto& value_in_list : value.GetList()) {
         AppendValueDataAsVariant(&array_writer, value_in_list);
       }
       writer->CloseContainer(&array_writer);
diff --git a/extensions/shell/browser/shell_content_browser_client.cc b/extensions/shell/browser/shell_content_browser_client.cc
index 82708394..9faa2ece 100644
--- a/extensions/shell/browser/shell_content_browser_client.cc
+++ b/extensions/shell/browser/shell_content_browser_client.cc
@@ -353,6 +353,7 @@
     ui::PageTransition page_transition,
     bool has_user_gesture,
     const absl::optional<url::Origin>& initiating_origin,
+    content::RenderFrameHost* initiator_document,
     mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
   return false;
 }
diff --git a/extensions/shell/browser/shell_content_browser_client.h b/extensions/shell/browser/shell_content_browser_client.h
index 078b2767..d95927795 100644
--- a/extensions/shell/browser/shell_content_browser_client.h
+++ b/extensions/shell/browser/shell_content_browser_client.h
@@ -129,6 +129,7 @@
       ui::PageTransition page_transition,
       bool has_user_gesture,
       const absl::optional<url::Origin>& initiating_origin,
+      content::RenderFrameHost* initiator_document,
       mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory)
       override;
   void OverrideURLLoaderFactoryParams(
diff --git a/infra/config/subprojects/chromium/ci/chromium.linux.star b/infra/config/subprojects/chromium/ci/chromium.linux.star
index 3970811..55efe99 100644
--- a/infra/config/subprojects/chromium/ci/chromium.linux.star
+++ b/infra/config/subprojects/chromium/ci/chromium.linux.star
@@ -35,18 +35,6 @@
     },
 )
 
-def linux_builder(
-        *,
-        name,
-        notifies = ("chromium.linux",),
-        extra_notifies = None,
-        **kwargs):
-    return ci.builder(
-        name = name,
-        notifies = list(notifies) + (extra_notifies or []),
-        **kwargs
-    )
-
 ci.builder(
     name = "Cast Audio Linux",
     console_view_entry = consoles.console_view_entry(
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 111b643..913f2d29 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -775,6 +775,9 @@
      flag_descriptions::kSaveSessionTabsToSeparateFilesDescription,
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(sessions::kSaveSessionTabsToSeparateFiles)},
+    {"use-sf-symbols-samples", flag_descriptions::kUseSFSymbolsSamplesName,
+     flag_descriptions::kUseSFSymbolsSamplesDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(kUseSFSymbolsSamples)},
 };
 
 bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 6d54880..4d923740 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -534,6 +534,10 @@
     "When enabled, use Lens to search for images from the long press context "
     "menu when Google is the selected search engine.";
 
+const char kUseSFSymbolsSamplesName[] = "Replace Image by SFSymbols";
+const char kUseSFSymbolsSamplesDescription[] =
+    "When enabled, some images (toolbar...) are replaced by SFSymbols";
+
 const char kWaitThresholdMillisecondsForCapabilitiesApiName[] =
     "Maximum wait time (in seconds) for a response from the Account "
     "Capabilities API";
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index cc759a8..e276349 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -480,6 +480,11 @@
 extern const char kUseLensToSearchForImageName[];
 extern const char kUseLensToSearchForImageDescription[];
 
+// Title and description for the flag to enable the replacement of some images
+// by SFSymbols.
+extern const char kUseSFSymbolsSamplesName[];
+extern const char kUseSFSymbolsSamplesDescription[];
+
 // Title and description for the flag to control the maximum wait time (in
 // seconds) for a response from the Account Capabilities API.
 extern const char kWaitThresholdMillisecondsForCapabilitiesApiName[];
diff --git a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm
index ece6291f..5eb3d76 100644
--- a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm
@@ -92,6 +92,9 @@
     SigninCoordinator* advancedSettingsSigninCoordinator;
 // Browser sign-in state to revert to in case sync is canceled.
 @property(nonatomic, assign) IdentitySigninState signinStateOnStart;
+// Sign-in identity when the coordiantor starts. This is used as the identity to
+// revert to in case sync is canceled.
+@property(nonatomic, strong) ChromeIdentity* signinIdentityOnStart;
 
 @end
 
@@ -129,6 +132,11 @@
 - (void)start {
   ChromeBrowserState* browserState = self.browser->GetBrowserState();
 
+  AuthenticationService* authenticationService =
+      AuthenticationServiceFactory::GetForBrowserState(browserState);
+  self.signinIdentityOnStart =
+      authenticationService->GetPrimaryIdentity(signin::ConsentLevel::kSignin);
+
   if (!signin::IsSigninAllowedByPolicy() ||
       IsSyncDisabledByPolicy(browserState)) {
     // Skip the screen if sync is disabled by policy.
@@ -465,6 +473,12 @@
 
   [self.advancedSettingsSigninCoordinator stop];
   self.advancedSettingsSigninCoordinator = nil;
+
+  // Should not stay signed in. Only sign-in the user when they selects the
+  // option to or when they are already signed in.
+  [self.mediator
+      cancelSigninWithIdentitySigninState:self.signinStateOnStart
+                    signinIdentityOnStart:self.signinIdentityOnStart];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.h b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.h
index 3165a99..16920e7 100644
--- a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.h
+++ b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.h
@@ -8,6 +8,7 @@
 #import <Foundation/Foundation.h>
 
 #import "base/ios/block_types.h"
+#import "ios/chrome/browser/ui/authentication/signin/signin_constants.h"
 
 namespace consent_auditor {
 class ConsentAuditor;
@@ -66,6 +67,13 @@
 // Disconnect the mediator.
 - (void)disconnect;
 
+// Reverts the sign-in operation if needed.
+// @param signinStateOnStart: Browser sign-in state when the coordinator starts.
+// @param signinIdentityOnStart: Sign-in identity when the coordinator starts.
+- (void)
+    cancelSigninWithIdentitySigninState:(IdentitySigninState)signinStateOnStart
+                  signinIdentityOnStart:(ChromeIdentity*)signinIdentityOnStart;
+
 // Starts the sync engine.
 // @param confirmationID: The confirmation string ID of sync.
 // @param consentIDs: The consent string IDs of sync screen.
diff --git a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.mm b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.mm
index 8d55040..aa3f3e8 100644
--- a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.mm
@@ -104,6 +104,54 @@
   _accountManagerServiceObserver.reset();
 }
 
+- (void)
+    cancelSigninWithIdentitySigninState:(IdentitySigninState)signinStateOnStart
+                  signinIdentityOnStart:(ChromeIdentity*)signinIdentityOnStart {
+  [self.authenticationFlow cancelAndDismissAnimated:NO];
+
+  self.syncService->GetUserSettings()->SetSyncRequested(false);
+  switch (signinStateOnStart) {
+    case IdentitySigninStateSignedOut: {
+      self.authenticationService->SignOut(signin_metrics::ABORT_SIGNIN,
+                                          /*force_clear_browsing_data=*/false,
+                                          nil);
+      break;
+    }
+    case IdentitySigninStateSignedInWithSyncDisabled: {
+      DCHECK(!self.authenticationService->GetPrimaryIdentity(
+          signin::ConsentLevel::kSync));
+      if ([self.authenticationService->GetPrimaryIdentity(
+              signin::ConsentLevel::kSignin) isEqual:signinIdentityOnStart]) {
+        // Can't be synced in this option because sync has to be disabled.
+        _syncService->StopAndClear();
+      } else {
+        __weak __typeof(self) weakSelf = self;
+        self.authenticationService->SignOut(
+            signin_metrics::ABORT_SIGNIN,
+            /*force_clear_browsing_data=*/false, ^() {
+              AuthenticationService* authenticationService =
+                  weakSelf.authenticationService;
+              ChromeIdentity* identity = signinIdentityOnStart;
+              ChromeAccountManagerService* accountManagerService =
+                  weakSelf.accountManagerService;
+              if (authenticationService && identity &&
+                  accountManagerService->IsValidIdentity(identity)) {
+                // Sign back in with a valid identity.
+                authenticationService->SignIn(identity);
+              }
+            });
+      }
+      break;
+    }
+    case IdentitySigninStateSignedInWithSyncEnabled: {
+      // This view wouldn't be shown if sync is enabled, so this option
+      // shouldn't be reached.
+      NOTREACHED();
+      break;
+    }
+  }
+}
+
 - (void)startSyncWithConfirmationID:(const int)confirmationID
                          consentIDs:(NSArray<NSNumber*>*)consentIDs
                  authenticationFlow:(AuthenticationFlow*)authenticationFlow {
diff --git a/ios/chrome/browser/ui/settings/content_settings/BUILD.gn b/ios/chrome/browser/ui/settings/content_settings/BUILD.gn
index 06f2b87..3e6e6b61 100644
--- a/ios/chrome/browser/ui/settings/content_settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/content_settings/BUILD.gn
@@ -47,9 +47,11 @@
 source_set("content_settings_ui") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
+    "default_page_mode.h",
     "default_page_mode_consumer.h",
     "default_page_mode_table_view_controller.h",
     "default_page_mode_table_view_controller.mm",
+    "default_page_mode_table_view_controller_delegate.h",
   ]
   deps = [
     "//ios/chrome/browser/ui/settings:settings_root",
diff --git a/ios/chrome/browser/ui/settings/content_settings/default_page_mode.h b/ios/chrome/browser/ui/settings/content_settings/default_page_mode.h
new file mode 100644
index 0000000..7cdec4f
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/content_settings/default_page_mode.h
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_CONTENT_SETTINGS_DEFAULT_PAGE_MODE_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_CONTENT_SETTINGS_DEFAULT_PAGE_MODE_H_
+
+#import <Foundation/Foundation.h>
+
+// The mode in which pages should be loaded.
+typedef NS_ENUM(NSUInteger, DefaultPageMode) {
+  DefaultPageModeMobile,
+  DefaultPageModeDesktop,
+};
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CONTENT_SETTINGS_DEFAULT_PAGE_MODE_H_
diff --git a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_consumer.h b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_consumer.h
index 32861e0..aff912f 100644
--- a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_consumer.h
+++ b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_consumer.h
@@ -7,11 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
-// The mode in which pages should be loaded.
-typedef NS_ENUM(NSUInteger, DefaultPageMode) {
-  DefaultPageModeMobile,
-  DefaultPageModeDesktop,
-};
+#import "ios/chrome/browser/ui/settings/content_settings/default_page_mode.h"
 
 // Consumer protocol for the screen allowing the user to choose the default mode
 // (Desktop/Mobile) for loading pages.
diff --git a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_coordinator.mm b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_coordinator.mm
index d76ec8c..79c0161 100644
--- a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_coordinator.mm
@@ -4,15 +4,20 @@
 
 #import "ios/chrome/browser/ui/settings/content_settings/default_page_mode_coordinator.h"
 
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h"
+#import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/ui/settings/content_settings/default_page_mode_mediator.h"
 #import "ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller.h"
+#import "ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller_delegate.h"
 #import "ios/chrome/browser/ui/table_view/table_view_utils.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-@interface DefaultPageModeCoordinator ()
+@interface DefaultPageModeCoordinator () <
+    DefaultPageModeTableViewControllerDelegate>
 
 @property(nonatomic, strong) DefaultPageModeTableViewController* viewController;
 @property(nonatomic, strong) DefaultPageModeMediator* mediator;
@@ -35,12 +40,26 @@
 }
 
 - (void)start {
+  HostContentSettingsMap* settingsMap =
+      ios::HostContentSettingsMapFactory::GetForBrowserState(
+          self.browser->GetBrowserState());
+  self.mediator =
+      [[DefaultPageModeMediator alloc] initWithSettingsMap:settingsMap];
+
   self.viewController = [[DefaultPageModeTableViewController alloc]
       initWithStyle:ChromeTableViewStyle()];
-  self.mediator =
-      [[DefaultPageModeMediator alloc] initWithConsumer:self.viewController];
+  self.viewController.delegate = self;
+
+  self.mediator.consumer = self.viewController;
+
   [self.baseNavigationController pushViewController:self.viewController
                                            animated:YES];
 }
 
+#pragma mark - DefaultPageModeTableViewControllerDelegate
+
+- (void)didSelectMode:(DefaultPageMode)selectedMode {
+  [self.mediator setDefaultMode:selectedMode];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_mediator.h b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_mediator.h
index a14653f..541e095 100644
--- a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_mediator.h
+++ b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_mediator.h
@@ -7,17 +7,25 @@
 
 #import <Foundation/Foundation.h>
 
+#import "ios/chrome/browser/ui/settings/content_settings/default_page_mode.h"
+
 @protocol DefaultPageModeConsumer;
+class HostContentSettingsMap;
 
 // Mediator for the screen allowing the user to choose the default mode
 // (Desktop/Mobile) for loading pages.
 @interface DefaultPageModeMediator : NSObject
 
-- (instancetype)initWithConsumer:(id<DefaultPageModeConsumer>)consumer
+- (instancetype)initWithSettingsMap:(HostContentSettingsMap*)settingsMap
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)init NS_UNAVAILABLE;
 
+@property(nonatomic, weak) id<DefaultPageModeConsumer> consumer;
+
+// Sets the default mode for loading a page.
+- (void)setDefaultMode:(DefaultPageMode)defaultMode;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CONTENT_SETTINGS_DEFAULT_PAGE_MODE_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_mediator.mm b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_mediator.mm
index 8c7cc3c..870ce80 100644
--- a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_mediator.mm
+++ b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_mediator.mm
@@ -4,26 +4,69 @@
 
 #import "ios/chrome/browser/ui/settings/content_settings/default_page_mode_mediator.h"
 
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "components/content_settings/core/common/content_settings_pattern.h"
 #import "ios/chrome/browser/ui/settings/content_settings/default_page_mode_consumer.h"
+#import "ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-@interface DefaultPageModeMediator ()
+@interface DefaultPageModeMediator () <BooleanObserver>
 
-@property(nonatomic, weak) id<DefaultPageModeConsumer> consumer;
+@property(nonatomic, strong) ContentSettingBackedBoolean* requestDesktopSetting;
 
 @end
 
 @implementation DefaultPageModeMediator
 
-- (instancetype)initWithConsumer:(id<DefaultPageModeConsumer>)consumer {
+- (instancetype)initWithSettingsMap:(HostContentSettingsMap*)settingsMap {
   self = [super init];
   if (self) {
-    _consumer = consumer;
+    _requestDesktopSetting = [[ContentSettingBackedBoolean alloc]
+        initWithHostContentSettingsMap:settingsMap
+                             settingID:ContentSettingsType::REQUEST_DESKTOP_SITE
+                              inverted:NO];
+    [_requestDesktopSetting setObserver:self];
   }
   return self;
 }
 
+- (void)setConsumer:(id<DefaultPageModeConsumer>)consumer {
+  if (_consumer == consumer)
+    return;
+
+  _consumer = consumer;
+  [self updateConsumer];
+}
+
+- (void)setDefaultMode:(DefaultPageMode)defaultMode {
+  BOOL newValue = defaultMode == DefaultPageModeDesktop;
+  if (self.requestDesktopSetting.value == newValue)
+    return;
+
+  self.requestDesktopSetting.value = newValue;
+  [self updateConsumer];
+}
+
+#pragma mark - BooleanObserver
+
+- (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean {
+  DCHECK_EQ(observableBoolean, self.requestDesktopSetting);
+  [self updateConsumer];
+}
+
+#pragma mark - Private
+
+- (DefaultPageMode)defaultMode {
+  return self.requestDesktopSetting.value ? DefaultPageModeDesktop
+                                          : DefaultPageModeMobile;
+}
+
+- (void)updateConsumer {
+  [self.consumer setDefaultPageMode:[self defaultMode]];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller.h b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller.h
index 5670228..3f82019 100644
--- a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller.h
+++ b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller.h
@@ -9,12 +9,17 @@
 #import "ios/chrome/browser/ui/settings/settings_controller_protocol.h"
 #import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h"
 
+@protocol DefaultPageModeTableViewControllerDelegate;
+
 // ViewController for the screen allowing the user to choose the default mode
 // (Desktop/Mobile) for loading pages.
 @interface DefaultPageModeTableViewController
     : SettingsRootTableViewController <DefaultPageModeConsumer,
                                        SettingsControllerProtocol>
 
+@property(nonatomic, weak) id<DefaultPageModeTableViewControllerDelegate>
+    delegate;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CONTENT_SETTINGS_DEFAULT_PAGE_MODE_TABLE_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller.mm b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller.mm
index e0949fa..5bf9bfa 100644
--- a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller.mm
@@ -4,18 +4,99 @@
 
 #import "ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller.h"
 
+#import "ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller_delegate.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+namespace {
+
+typedef NS_ENUM(NSInteger, SectionIdentifier) {
+  SectionIdentifierMode = kSectionIdentifierEnumZero,
+};
+
+typedef NS_ENUM(NSInteger, ItemType) {
+  ItemTypeMobile = kItemTypeEnumZero,
+  ItemTypeDesktop,
+};
+
+}  // namespace
+
+@interface DefaultPageModeTableViewController ()
+
+@property(nonatomic, assign) ItemType chosenItemType;
+
+@end
+
 @implementation DefaultPageModeTableViewController
 
+- (void)viewDidLoad {
+  [super viewDidLoad];
+  [self loadModel];
+}
+
+#pragma mark - ChromeTableViewController
+
+- (void)loadModel {
+  [super loadModel];
+
+  TableViewModel* model = self.tableViewModel;
+  [model addSectionWithIdentifier:SectionIdentifierMode];
+
+  TableViewDetailIconItem* mobileItem =
+      [[TableViewDetailIconItem alloc] initWithType:ItemTypeMobile];
+  mobileItem.text = @"TEST - Mobile";
+  [model addItem:mobileItem toSectionWithIdentifier:SectionIdentifierMode];
+
+  TableViewDetailIconItem* desktopItem =
+      [[TableViewDetailIconItem alloc] initWithType:ItemTypeDesktop];
+  desktopItem.text = @"TEST - Desktop";
+  [model addItem:desktopItem toSectionWithIdentifier:SectionIdentifierMode];
+
+  for (TableViewItem* item in [self.tableViewModel
+           itemsInSectionWithIdentifier:SectionIdentifierMode]) {
+    if (item.type == self.chosenItemType) {
+      item.accessoryType = UITableViewCellAccessoryCheckmark;
+    }
+  }
+}
+
+- (void)tableView:(UITableView*)tableView
+    didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
+  TableViewModel* model = self.tableViewModel;
+  NSInteger itemType = [model itemTypeForIndexPath:indexPath];
+
+  DefaultPageMode chosenMode = itemType == ItemTypeMobile
+                                   ? DefaultPageModeMobile
+                                   : DefaultPageModeDesktop;
+
+  [tableView deselectRowAtIndexPath:indexPath animated:YES];
+
+  [self.delegate didSelectMode:chosenMode];
+}
+
 #pragma mark - DefaultPageModeConsumer
 
 - (void)setDefaultPageMode:(DefaultPageMode)mode {
-  // TODO(crbug.com/1276922): change the selected cell based on the mode.
+  ItemType chosenType =
+      mode == DefaultPageModeMobile ? ItemTypeMobile : ItemTypeDesktop;
+
+  self.chosenItemType = chosenType;
+
+  for (TableViewItem* item in [self.tableViewModel
+           itemsInSectionWithIdentifier:SectionIdentifierMode]) {
+    if (item.type == chosenType) {
+      item.accessoryType = UITableViewCellAccessoryCheckmark;
+    } else {
+      item.accessoryType = UITableViewCellAccessoryNone;
+    }
+  }
+
+  [self reloadCellsForItems:[self.tableViewModel itemsInSectionWithIdentifier:
+                                                     SectionIdentifierMode]
+           withRowAnimation:UITableViewRowAnimationAutomatic];
 }
 
 #pragma mark - SettingsControllerProtocol
diff --git a/ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller_delegate.h b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller_delegate.h
new file mode 100644
index 0000000..12ed0c8
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/content_settings/default_page_mode_table_view_controller_delegate.h
@@ -0,0 +1,21 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_CONTENT_SETTINGS_DEFAULT_PAGE_MODE_TABLE_VIEW_CONTROLLER_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_CONTENT_SETTINGS_DEFAULT_PAGE_MODE_TABLE_VIEW_CONTROLLER_DELEGATE_H_
+
+#import <Foundation/Foundation.h>
+
+#import "ios/chrome/browser/ui/settings/content_settings/default_page_mode.h"
+
+// Delegate for the  screen allowing the user to choose the default mode
+// (Desktop/Mobile) for loading pages.
+@protocol DefaultPageModeTableViewControllerDelegate
+
+// Called when the user chose a default page mode.
+- (void)didSelectMode:(DefaultPageMode)selectedMode;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CONTENT_SETTINGS_DEFAULT_PAGE_MODE_TABLE_VIEW_CONTROLLER_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.mm b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.mm
index 28d0ee3..84dbb7e 100644
--- a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.mm
+++ b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.mm
@@ -13,6 +13,7 @@
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_tab_grid_button.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_tools_menu_button.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
+#include "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/ui/util/rtl_geometry.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
@@ -25,6 +26,17 @@
 #error "This file requires ARC support."
 #endif
 
+namespace {
+
+// Returns the default configuration for Symbols.
+UIImageConfiguration* SymbolConfiguration() {
+  return [UIImageSymbolConfiguration
+      configurationWithPointSize:22
+                          weight:UIImageSymbolWeightMedium];
+}
+
+}  // namespace
+
 @implementation ToolbarButtonFactory
 
 - (instancetype)initWithStyle:(ToolbarStyle)style {
@@ -39,8 +51,15 @@
 #pragma mark - Buttons
 
 - (ToolbarButton*)backButton {
+  UIImage* backImage;
+  if (base::FeatureList::IsEnabled(kUseSFSymbolsSamples)) {
+    backImage = [UIImage systemImageNamed:@"arrow.left"
+                        withConfiguration:SymbolConfiguration()];
+  } else {
+    backImage = [UIImage imageNamed:@"toolbar_back"];
+  }
   ToolbarButton* backButton = [ToolbarButton
-      toolbarButtonWithImage:[[UIImage imageNamed:@"toolbar_back"]
+      toolbarButtonWithImage:[backImage
                                  imageFlippedForRightToLeftLayoutDirection]];
   [self configureButton:backButton width:kAdaptiveToolbarButtonWidth];
   backButton.accessibilityLabel = l10n_util::GetNSString(IDS_ACCNAME_BACK);
@@ -53,8 +72,15 @@
 
 // Returns a forward button without visibility mask configured.
 - (ToolbarButton*)forwardButton {
+  UIImage* forwardImage;
+  if (base::FeatureList::IsEnabled(kUseSFSymbolsSamples)) {
+    forwardImage = [UIImage systemImageNamed:@"arrow.right"
+                           withConfiguration:SymbolConfiguration()];
+  } else {
+    forwardImage = [UIImage imageNamed:@"toolbar_forward"];
+  }
   ToolbarButton* forwardButton = [ToolbarButton
-      toolbarButtonWithImage:[[UIImage imageNamed:@"toolbar_forward"]
+      toolbarButtonWithImage:[forwardImage
                                  imageFlippedForRightToLeftLayoutDirection]];
   [self configureButton:forwardButton width:kAdaptiveToolbarButtonWidth];
   forwardButton.visibilityMask =
@@ -68,8 +94,16 @@
 }
 
 - (ToolbarTabGridButton*)tabGridButton {
-  ToolbarTabGridButton* tabGridButton = [ToolbarTabGridButton
-      toolbarButtonWithImage:[UIImage imageNamed:@"toolbar_switcher"]];
+  UIImage* tabGridImage;
+  if (base::FeatureList::IsEnabled(kUseSFSymbolsSamples)) {
+    tabGridImage = [UIImage systemImageNamed:@"square"
+                           withConfiguration:SymbolConfiguration()];
+  } else {
+    tabGridImage = [UIImage imageNamed:@"toolbar_switcher"];
+  }
+
+  ToolbarTabGridButton* tabGridButton =
+      [ToolbarTabGridButton toolbarButtonWithImage:tabGridImage];
   [self configureButton:tabGridButton width:kAdaptiveToolbarButtonWidth];
   SetA11yLabelAndUiAutomationName(tabGridButton, IDS_IOS_TOOLBAR_SHOW_TABS,
                                   kToolbarStackButtonIdentifier);
@@ -103,8 +137,16 @@
 }
 
 - (ToolbarButton*)shareButton {
-  ToolbarButton* shareButton = [ToolbarButton
-      toolbarButtonWithImage:[UIImage imageNamed:@"toolbar_share"]];
+  UIImage* shareImage;
+  if (base::FeatureList::IsEnabled(kUseSFSymbolsSamples)) {
+    shareImage = [UIImage systemImageNamed:@"square.and.arrow.up"
+                         withConfiguration:SymbolConfiguration()];
+  } else {
+    shareImage = [UIImage imageNamed:@"toolbar_share"];
+  }
+
+  ToolbarButton* shareButton =
+      [ToolbarButton toolbarButtonWithImage:shareImage];
   [self configureButton:shareButton width:kAdaptiveToolbarButtonWidth];
   SetA11yLabelAndUiAutomationName(shareButton, IDS_IOS_TOOLS_MENU_SHARE,
                                   kToolbarShareButtonIdentifier);
@@ -118,8 +160,16 @@
 }
 
 - (ToolbarButton*)reloadButton {
+  UIImage* reloadImage;
+  if (base::FeatureList::IsEnabled(kUseSFSymbolsSamples)) {
+    reloadImage = [UIImage systemImageNamed:@"arrow.clockwise"
+                          withConfiguration:SymbolConfiguration()];
+  } else {
+    reloadImage = [UIImage imageNamed:@"toolbar_reload"];
+  }
+
   ToolbarButton* reloadButton = [ToolbarButton
-      toolbarButtonWithImage:[[UIImage imageNamed:@"toolbar_reload"]
+      toolbarButtonWithImage:[reloadImage
                                  imageFlippedForRightToLeftLayoutDirection]];
   [self configureButton:reloadButton width:kAdaptiveToolbarButtonWidth];
   reloadButton.accessibilityLabel =
@@ -133,8 +183,15 @@
 }
 
 - (ToolbarButton*)stopButton {
-  ToolbarButton* stopButton = [ToolbarButton
-      toolbarButtonWithImage:[UIImage imageNamed:@"toolbar_stop"]];
+  UIImage* stopImage;
+  if (base::FeatureList::IsEnabled(kUseSFSymbolsSamples)) {
+    stopImage = [UIImage systemImageNamed:@"multiply"
+                        withConfiguration:SymbolConfiguration()];
+  } else {
+    stopImage = [UIImage imageNamed:@"toolbar_stop"];
+  }
+
+  ToolbarButton* stopButton = [ToolbarButton toolbarButtonWithImage:stopImage];
   [self configureButton:stopButton width:kAdaptiveToolbarButtonWidth];
   stopButton.accessibilityLabel = l10n_util::GetNSString(IDS_IOS_ACCNAME_STOP);
   [stopButton addTarget:self.actionHandler
@@ -145,8 +202,15 @@
 }
 
 - (ToolbarButton*)openNewTabButton {
-  ToolbarNewTabButton* newTabButton = [ToolbarNewTabButton
-      toolbarButtonWithImage:[UIImage imageNamed:@"toolbar_new_tab_page"]];
+  UIImage* newTabImage;
+  if (base::FeatureList::IsEnabled(kUseSFSymbolsSamples)) {
+    newTabImage = [UIImage systemImageNamed:@"plus"
+                          withConfiguration:SymbolConfiguration()];
+  } else {
+    newTabImage = [UIImage imageNamed:@"toolbar_new_tab_page"];
+  }
+  ToolbarNewTabButton* newTabButton =
+      [ToolbarNewTabButton toolbarButtonWithImage:newTabImage];
 
   [newTabButton addTarget:self.actionHandler
                    action:@selector(searchAction:)
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc
index eb8e0c8..224494d 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.cc
+++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -74,6 +74,9 @@
 const base::Feature kAddSettingForDefaultPageMode{
     "DefaultRequestedMode", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kUseSFSymbolsSamples{"UseSFSymbolsSamples",
+                                         base::FEATURE_DISABLED_BY_DEFAULT};
+
 bool IsContextMenuActionsRefreshEnabled() {
   return base::FeatureList::IsEnabled(kContextMenuActionsRefresh);
 }
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h
index b16954d..f4b69df 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.h
+++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -87,6 +87,9 @@
 // (Desktop/Mobile) in which the pages will be requested by default.
 extern const base::Feature kAddSettingForDefaultPageMode;
 
+// Feature flag to switch some images to SFSymbols when enabled.
+extern const base::Feature kUseSFSymbolsSamples;
+
 // Whether the ContextMenuActionsRefresh flag is enabled.
 bool IsContextMenuActionsRefreshEnabled();
 
diff --git a/ios/web/js_messaging/web_frame_impl.h b/ios/web/js_messaging/web_frame_impl.h
index 082b3c2..73c8edc 100644
--- a/ios/web/js_messaging/web_frame_impl.h
+++ b/ios/web/js_messaging/web_frame_impl.h
@@ -67,6 +67,8 @@
       base::OnceCallback<void(const base::Value*)> callback,
       base::TimeDelta timeout) override;
 
+  bool ExecuteJavaScript(const std::string& script) override;
+
   // WebFrameContentWorldAPI:
   bool CallJavaScriptFunctionInContentWorld(
       const std::string& name,
diff --git a/ios/web/js_messaging/web_frame_impl.mm b/ios/web/js_messaging/web_frame_impl.mm
index 5ca67a9..4d42c2d 100644
--- a/ios/web/js_messaging/web_frame_impl.mm
+++ b/ios/web/js_messaging/web_frame_impl.mm
@@ -260,6 +260,33 @@
   return called;
 }
 
+bool WebFrameImpl::ExecuteJavaScript(const std::string& script) {
+  DCHECK(base::ios::IsRunningOnIOS14OrLater());
+  DCHECK(frame_info_);
+
+  if (!IsMainFrame()) {
+    return false;
+  }
+
+  NSString* ns_script = base::SysUTF8ToNSString(script);
+  void (^completion_handler)(id, NSError*) = ^void(id value, NSError* error) {
+    if (error) {
+      DLOG(WARNING) << "Script execution of:"
+                    << base::SysNSStringToUTF16(ns_script)
+                    << "\nfailed with error: "
+                    << base::SysNSStringToUTF16(
+                           error.userInfo[NSLocalizedDescriptionKey]);
+    }
+  };
+
+  if (@available(iOS 14.0, *)) {
+    web::ExecuteJavaScript(frame_info_.webView, WKContentWorld.pageWorld,
+                           frame_info_, ns_script, completion_handler);
+    return true;
+  }
+  return false;
+}
+
 bool WebFrameImpl::ExecuteJavaScriptFunction(
     JavaScriptContentWorld* content_world,
     const std::string& name,
diff --git a/ios/web/js_messaging/web_frame_impl_unittest.mm b/ios/web/js_messaging/web_frame_impl_unittest.mm
index 3764b60..21f0f34 100644
--- a/ios/web/js_messaging/web_frame_impl_unittest.mm
+++ b/ios/web/js_messaging/web_frame_impl_unittest.mm
@@ -8,6 +8,7 @@
 
 #import "base/base64.h"
 #include "base/bind.h"
+#include "base/ios/ios_util.h"
 #include "base/json/json_reader.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
@@ -446,4 +447,32 @@
   EXPECT_EQ(last_script.length, 0ul);
 }
 
+// Tests that the WebFrame can execute arbitrary JavaScript.
+// if and only if it is a main frame.
+TEST_F(WebFrameImplTest, ExecuteJavaScript) {
+  if (!base::ios::IsRunningOnIOS14OrLater()) {
+    return;
+  }
+
+  FakeWebState fake_web_state;
+  GURL security_origin;
+
+  NSString* script = @"__gCrWeb = {};"
+                     @"__gCrWeb['fakeFunction'] = function() {"
+                     @"  return '10';"
+                     @"}";
+
+  WebFrameImpl web_frame([[WKFrameInfo alloc] init], kFrameId,
+                         /*is_main_frame=*/true, security_origin,
+                         &fake_web_state);
+
+  EXPECT_TRUE(web_frame.ExecuteJavaScript(base::SysNSStringToUTF8(script)));
+
+  WebFrameImpl web_frame2([[WKFrameInfo alloc] init], kFrameId,
+                          /*is_main_frame=*/false, security_origin,
+                          &fake_web_state);
+  // Executing arbitrary code on an iframe should return false.
+  EXPECT_FALSE(web_frame2.ExecuteJavaScript(base::SysNSStringToUTF8(script)));
+}
+
 }  // namespace web
diff --git a/ios/web/public/js_messaging/web_frame.h b/ios/web/public/js_messaging/web_frame.h
index ebcf8cbb26b..31ddc73 100644
--- a/ios/web/public/js_messaging/web_frame.h
+++ b/ios/web/public/js_messaging/web_frame.h
@@ -70,6 +70,9 @@
       base::OnceCallback<void(const base::Value*)> callback,
       base::TimeDelta timeout) = 0;
 
+  // Executes the given |script| and returns whether the script was run.
+  virtual bool ExecuteJavaScript(const std::string& script) = 0;
+
   // Returns the WebFrameInternal instance for this object.
   virtual WebFrameInternal* GetWebFrameInternal() = 0;
 
diff --git a/ios/web/test/fakes/fake_web_frame_impl.cc b/ios/web/test/fakes/fake_web_frame_impl.cc
index 80d01da..2f9e320d 100644
--- a/ios/web/test/fakes/fake_web_frame_impl.cc
+++ b/ios/web/test/fakes/fake_web_frame_impl.cc
@@ -145,6 +145,10 @@
   return CallJavaScriptFunction(name, parameters, std::move(callback), timeout);
 }
 
+bool FakeWebFrameImpl::ExecuteJavaScript(const std::string& script) {
+  return false;
+}
+
 void FakeWebFrameImpl::AddJsResultForFunctionCall(
     base::Value* js_result,
     const std::string& function_name) {
diff --git a/ios/web/test/fakes/fake_web_frame_impl.h b/ios/web/test/fakes/fake_web_frame_impl.h
index c52ef31..0d028845 100644
--- a/ios/web/test/fakes/fake_web_frame_impl.h
+++ b/ios/web/test/fakes/fake_web_frame_impl.h
@@ -41,6 +41,7 @@
       const std::vector<base::Value>& parameters,
       base::OnceCallback<void(const base::Value*)> callback,
       base::TimeDelta timeout) override;
+  bool ExecuteJavaScript(const std::string& script) override;
 
   // FakeWebFrame:
   std::string GetLastJavaScriptCall() const override;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index fb0b5b9..7994638 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -117,7 +117,7 @@
   // The web::PageDisplayState recorded when the page starts loading.
   web::PageDisplayState _displayStateOnStartLoading;
   // Whether or not the page has zoomed since the current navigation has been
-  // committed, either by user interaction or via |-restoreStateFromHistory|.
+  // committed by user interaction.
   BOOL _pageHasZoomed;
   // Whether a PageDisplayState is currently being applied.
   BOOL _applyingPageState;
@@ -230,9 +230,6 @@
 // may be called multiple times and thus must be idempotent.
 - (void)loadCompleteWithSuccess:(BOOL)loadSuccess
                      forContext:(web::NavigationContextImpl*)context;
-
-// Restores the state for this page from session history.
-- (void)restoreStateFromHistory;
 // Extracts the current page's viewport tag information and calls |completion|.
 // If the page has changed before the viewport tag is successfully extracted,
 // |completion| is called with nullptr.
@@ -1238,12 +1235,6 @@
 
 #pragma mark - Page State
 
-- (void)restoreStateFromHistory {
-  web::NavigationItem* item = self.currentNavItem;
-  if (item)
-    self.pageDisplayState = item->GetPageDisplayState();
-}
-
 - (void)extractViewportTagWithCompletion:(ViewportStateCompletion)completion {
   DCHECK(completion);
   web::NavigationItem* currentItem = self.currentNavItem;
@@ -1949,11 +1940,6 @@
   self.webView.allowsBackForwardNavigationGestures = NO;
 }
 
-- (void)webRequestControllerRestoreStateFromHistory:
-    (CRWWebRequestController*)requestController {
-  [self restoreStateFromHistory];
-}
-
 - (CRWWKNavigationHandler*)webRequestControllerNavigationHandler:
     (CRWWebRequestController*)requestController {
   return self.navigationHandler;
diff --git a/ios/web/web_state/ui/crw_web_request_controller.h b/ios/web/web_state/ui/crw_web_request_controller.h
index 41a1fa8b..df44272 100644
--- a/ios/web/web_state/ui/crw_web_request_controller.h
+++ b/ios/web/web_state/ui/crw_web_request_controller.h
@@ -39,11 +39,6 @@
 - (void)webRequestControllerDisableNavigationGesturesUntilFinishNavigation:
     (CRWWebRequestController*)requestController;
 
-// Tells the delegate to restores the state for current page from session
-// history.
-- (void)webRequestControllerRestoreStateFromHistory:
-    (CRWWebRequestController*)requestController;
-
 - (CRWWKNavigationHandler*)webRequestControllerNavigationHandler:
     (CRWWebRequestController*)requestController;
 
diff --git a/ios/web/web_state/ui/crw_web_request_controller.mm b/ios/web/web_state/ui/crw_web_request_controller.mm
index 0673edb..8695e94 100644
--- a/ios/web/web_state/ui/crw_web_request_controller.mm
+++ b/ios/web/web_state/ui/crw_web_request_controller.mm
@@ -362,9 +362,6 @@
                  context:(nullable const web::NavigationContextImpl*)context {
   DCHECK_EQ(web::WKNavigationState::FINISHED,
             self.navigationHandler.navigationState);
-
-  [_delegate webRequestControllerRestoreStateFromHistory:self];
-
   // Placeholder and restore session URLs are implementation details so should
   // not notify WebStateObservers. If |context| is nullptr, don't skip
   // placeholder URLs because this may be the only opportunity to update
diff --git a/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc b/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc
index 87f284c8..38ba788 100644
--- a/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc
+++ b/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc
@@ -115,7 +115,11 @@
     }
   }
 #elif BUILDFLAG(USE_LIBV4L2)
+#if defined(__aarch64__)
+  dlopen("/usr/lib64/libv4l2.so", RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
+#else
   dlopen("/usr/lib/libv4l2.so", RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
+#endif  // defined(__aarch64__)
 #endif  // BUILDFLAG(USE_VAAPI)
 
   return true;
diff --git a/remoting/client/notification/notification_client.cc b/remoting/client/notification/notification_client.cc
index 403d403..37a69cd 100644
--- a/remoting/client/notification/notification_client.cc
+++ b/remoting/client/notification/notification_client.cc
@@ -116,7 +116,18 @@
                                    int percent_int) {
   DCHECK_GE(percent_int, 0);
   DCHECK_LE(percent_int, 100);
-  return (base::FastHash(user_email) % 100) <
+
+  // If the user is not logged in, we only want to show the notification if the
+  // rollout percentage is 100. `hash("") % 100` could be anything between
+  // [0, 99] and may therefore get selected for a lower percentage, so we add
+  // special-casing for percent_int != 100.
+  // For percent_int == 100, `hash(any_string) % 100` is always smaller than
+  // 100, so no special-casing is needed.
+  if (user_email.empty() && percent_int != 100) {
+    return false;
+  }
+
+  return (base::PersistentHash(user_email) % 100) <
          static_cast<unsigned int>(percent_int);
 }
 
diff --git a/remoting/client/notification/notification_client.h b/remoting/client/notification/notification_client.h
index 32dfcab..5d4c2e01 100644
--- a/remoting/client/notification/notification_client.h
+++ b/remoting/client/notification/notification_client.h
@@ -41,6 +41,10 @@
   // notification is found then absl::nullopt will be returned. |callback| will
   // be silently dropped if |this| is deleted before the notification is
   // fetched.
+  // |user_email| is used to determine if the notification is available to the
+  // user during percentage rollout. If |user_email| is empty (i.e. user not
+  // logged in), the notification percentage must be exactly 100 for the
+  // notification to become available.
   void GetNotification(const std::string& user_email,
                        NotificationCallback callback);
 
diff --git a/remoting/client/notification/notification_client_unittest.cc b/remoting/client/notification/notification_client_unittest.cc
index ec3706588..064aaf73 100644
--- a/remoting/client/notification/notification_client_unittest.cc
+++ b/remoting/client/notification/notification_client_unittest.cc
@@ -362,4 +362,36 @@
   client_->GetNotification(kTestEmail, callback.Get());
 }
 
+TEST_F(NotificationClientTest,
+       EmptyUserEmailAndNot100PercentRollout_NoNotification) {
+  base::Value rules(base::Value::Type::LIST);
+  base::Value rule = CreateDefaultRule();
+  rule.SetIntKey("percent", 99);
+  rules.Append(std::move(rule));
+  EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
+      .WillOnce(ReturnByMove(std::move(rules)));
+
+  base::MockCallback<NotificationClient::NotificationCallback> callback;
+  EXPECT_CALL(callback, Run(NoMessage()));
+  client_->GetNotification(/* user_email= */ "", callback.Get());
+}
+
+TEST_F(NotificationClientTest,
+       EmptyUserEmailAnd100PercentRollout_ReturnsNotification) {
+  base::Value rules(base::Value::Type::LIST);
+  base::Value rule = CreateDefaultRule();
+  rule.SetIntKey("percent", 100);
+  rules.Append(std::move(rule));
+  EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
+      .WillOnce(ReturnByMove(std::move(rules)));
+  EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
+      .WillOnce(ReturnByMove(CreateDefaultTranslations("message")));
+  EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
+      .WillOnce(ReturnByMove(CreateDefaultTranslations("link")));
+
+  base::MockCallback<NotificationClient::NotificationCallback> callback;
+  EXPECT_CALL(callback, Run(MessageMatches(CreateDefaultNotification())));
+  client_->GetNotification(/* user_email= */ "", callback.Get());
+}
+
 }  // namespace remoting
\ No newline at end of file
diff --git a/remoting/ios/app/notification_presenter.h b/remoting/ios/app/notification_presenter.h
index a460b6d..ea34694 100644
--- a/remoting/ios/app/notification_presenter.h
+++ b/remoting/ios/app/notification_presenter.h
@@ -41,7 +41,7 @@
   NotificationPresenter();
   ~NotificationPresenter() = delete;
 
-  void FetchNotificationIfNecessary();
+  void FetchNotification();
   void OnNotificationFetched(absl::optional<NotificationMessage> notification);
 
   NotificationClient notification_client_;
diff --git a/remoting/ios/app/notification_presenter.mm b/remoting/ios/app/notification_presenter.mm
index ff3abb8c..6ddf6a7 100644
--- a/remoting/ios/app/notification_presenter.mm
+++ b/remoting/ios/app/notification_presenter.mm
@@ -65,9 +65,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!user_update_observer_);
 
-  if ([RemotingService.instance.authentication.user isAuthenticated]) {
-    FetchNotificationIfNecessary();
-  }
+  FetchNotification();
   user_update_observer_ = [NSNotificationCenter.defaultCenter
       addObserverForName:kUserDidUpdate
                   object:nil
@@ -75,23 +73,24 @@
               usingBlock:^(NSNotification*) {
                 // This implicitly captures |this|, but should be fine since
                 // |NotificationPresenter| is singleton.
-                FetchNotificationIfNecessary();
+                FetchNotification();
               }];
 }
 
-void NotificationPresenter::FetchNotificationIfNecessary() {
+void NotificationPresenter::FetchNotification() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (state_ != State::NOT_FETCHED) {
+  if (state_ == State::FETCHED) {
     return;
   }
   UserInfo* user = RemotingService.instance.authentication.user;
-  if (![user isAuthenticated]) {
-    // Can't show notification since user email is unknown.
-    return;
-  }
+  std::string user_email = [user isAuthenticated]
+                               ? base::SysNSStringToUTF8(user.userEmail)
+                               : std::string();
 
   state_ = State::FETCHING;
+  // If FetchNotification() is called when the timer is already running, this
+  // will restart the timer with the new user email.
   fetch_notification_timer_.Start(
       FROM_HERE, kFetchNotificationDelay,
       base::BindOnce(
@@ -101,7 +100,7 @@
                 base::BindOnce(&NotificationPresenter::OnNotificationFetched,
                                base::Unretained(that)));
           },
-          base::Unretained(this), base::SysNSStringToUTF8(user.userEmail)));
+          base::Unretained(this), user_email));
 }
 
 void NotificationPresenter::OnNotificationFetched(
diff --git a/services/preferences/public/cpp/dictionary_value_update.cc b/services/preferences/public/cpp/dictionary_value_update.cc
index 65c70097..0ced2b5d 100644
--- a/services/preferences/public/cpp/dictionary_value_update.cc
+++ b/services/preferences/public/cpp/dictionary_value_update.cc
@@ -92,8 +92,8 @@
     base::StringPiece path,
     std::unique_ptr<base::DictionaryValue> in_value) {
   RecordPath(path);
-  base::DictionaryValue* dictionary_value =
-      value_->SetDictionary(path, std::move(in_value));
+  auto* dictionary_value = static_cast<base::DictionaryValue*>(value_->SetPath(
+      path, base::Value::FromUniquePtrValue(std::move(in_value))));
 
   return std::make_unique<DictionaryValueUpdate>(
       report_update_, dictionary_value, ConcatPath(path_, path));
diff --git a/services/preferences/tracked/dictionary_hash_store_contents.cc b/services/preferences/tracked/dictionary_hash_store_contents.cc
index 74315fd..5df7bc2 100644
--- a/services/preferences/tracked/dictionary_hash_store_contents.cc
+++ b/services/preferences/tracked/dictionary_hash_store_contents.cc
@@ -88,11 +88,10 @@
                                               const std::string& split_path,
                                               const std::string& value) {
   base::DictionaryValue* macs_dict = GetMutableContents(true);
-  base::DictionaryValue* split_dict = nullptr;
-  macs_dict->GetDictionary(path, &split_dict);
+  base::Value* split_dict = macs_dict->FindDictPath(path);
   if (!split_dict) {
-    split_dict = macs_dict->SetDictionary(
-        path, std::make_unique<base::DictionaryValue>());
+    split_dict =
+        macs_dict->SetPath(path, base::Value(base::Value::Type::DICTIONARY));
   }
   split_dict->SetKey(split_path, base::Value(value));
 }
@@ -132,8 +131,8 @@
   base::DictionaryValue* macs_dict = NULL;
   storage_->GetDictionary(kPreferenceMACs, &macs_dict);
   if (!macs_dict && create_if_null) {
-    macs_dict = storage_->SetDictionary(
-        kPreferenceMACs, std::make_unique<base::DictionaryValue>());
+    macs_dict = static_cast<base::DictionaryValue*>(storage_->SetPath(
+        kPreferenceMACs, base::Value(base::Value::Type::DICTIONARY)));
   }
   return macs_dict;
 }
diff --git a/services/preferences/tracked/pref_hash_filter_unittest.cc b/services/preferences/tracked/pref_hash_filter_unittest.cc
index 9f9bca3..8ffad5c 100644
--- a/services/preferences/tracked/pref_hash_filter_unittest.cc
+++ b/services/preferences/tracked/pref_hash_filter_unittest.cc
@@ -735,10 +735,10 @@
 
 TEST_P(PrefHashFilterTest, FilterSplitPrefUpdate) {
   base::DictionaryValue root_dict;
-  base::DictionaryValue* dict_value = root_dict.SetDictionary(
-      kSplitPref, std::make_unique<base::DictionaryValue>());
-  dict_value->SetString("a", "foo");
-  dict_value->SetInteger("b", 1234);
+  base::Value* dict_value =
+      root_dict.SetKey(kSplitPref, base::Value(base::Value::Type::DICTIONARY));
+  dict_value->SetStringKey("a", "foo");
+  dict_value->SetIntKey("b", 1234);
 
   // No path should be stored on FilterUpdate.
   pref_hash_filter_->FilterUpdate(kSplitPref);
@@ -800,9 +800,9 @@
   root_dict.SetInteger(kAtomicPref2, 2);
   root_dict.SetInteger(kAtomicPref3, 3);
   root_dict.SetInteger("untracked", 4);
-  base::DictionaryValue* dict_value = root_dict.SetDictionary(
-      kSplitPref, std::make_unique<base::DictionaryValue>());
-  dict_value->SetBoolean("a", true);
+  base::Value* dict_value =
+      root_dict.SetKey(kSplitPref, base::Value(base::Value::Type::DICTIONARY));
+  dict_value->SetBoolKey("a", true);
 
   // Only update kAtomicPref, kAtomicPref3, and kSplitPref.
   pref_hash_filter_->FilterUpdate(kAtomicPref);
@@ -882,10 +882,10 @@
   base::Value* string_value =
       pref_store_contents_->SetString(kAtomicPref, "string value");
 
-  base::DictionaryValue* dict_value = pref_store_contents_->SetDictionary(
-      kSplitPref, std::make_unique<base::DictionaryValue>());
-  dict_value->SetString("a", "foo");
-  dict_value->SetInteger("b", 1234);
+  base::Value* dict_value = pref_store_contents_->SetKey(
+      kSplitPref, base::Value(base::Value::Type::DICTIONARY));
+  dict_value->SetStringKey("a", "foo");
+  dict_value->SetIntKey("b", 1234);
 
   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
   ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
@@ -947,10 +947,10 @@
   base::Value* string_value =
       pref_store_contents_->SetString(kAtomicPref, "test");
 
-  auto* dict_value = pref_store_contents_->SetDictionary(
-      kSplitPref, std::make_unique<base::DictionaryValue>());
-  dict_value->SetString("a", "foo");
-  dict_value->SetInteger("b", 1234);
+  auto* dict_value = pref_store_contents_->SetKey(
+      kSplitPref, base::Value(base::Value::Type::DICTIONARY));
+  dict_value->SetStringKey("a", "foo");
+  dict_value->SetIntKey("b", 1234);
 
   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
   ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
@@ -995,12 +995,12 @@
 TEST_P(PrefHashFilterTest, InitialValueChanged) {
   base::Value* int_value = pref_store_contents_->SetInteger(kAtomicPref, 1234);
 
-  base::DictionaryValue* dict_value = pref_store_contents_->SetDictionary(
-      kSplitPref, std::make_unique<base::DictionaryValue>());
-  dict_value->SetString("a", "foo");
-  dict_value->SetInteger("b", 1234);
-  dict_value->SetInteger("c", 56);
-  dict_value->SetBoolean("d", false);
+  base::Value* dict_value = pref_store_contents_->SetKey(
+      kSplitPref, base::Value(base::Value::Type::DICTIONARY));
+  dict_value->SetStringKey("a", "foo");
+  dict_value->SetIntKey("b", 1234);
+  dict_value->SetIntKey("c", 56);
+  dict_value->SetBoolKey("d", false);
 
   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
   ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
@@ -1104,10 +1104,10 @@
   base::Value* string_value =
       pref_store_contents_->SetString(kAtomicPref, "string value");
 
-  base::DictionaryValue* dict_value = pref_store_contents_->SetDictionary(
-      kSplitPref, std::make_unique<base::DictionaryValue>());
-  dict_value->SetString("a", "foo");
-  dict_value->SetInteger("b", 1234);
+  base::Value* dict_value = pref_store_contents_->SetKey(
+      kSplitPref, base::Value(base::Value::Type::DICTIONARY));
+  dict_value->SetStringKey("a", "foo");
+  dict_value->SetIntKey("b", 1234);
 
   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
   ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
@@ -1158,10 +1158,9 @@
   base::Value* int_value2 = pref_store_contents_->SetInteger(kAtomicPref2, 2);
   base::Value* report_only_val =
       pref_store_contents_->SetInteger(kReportOnlyPref, 3);
-  base::DictionaryValue* report_only_split_val =
-      pref_store_contents_->SetDictionary(
-          kReportOnlySplitPref, std::make_unique<base::DictionaryValue>());
-  report_only_split_val->SetInteger("a", 1234);
+  base::Value* report_only_split_val = pref_store_contents_->SetKey(
+      kReportOnlySplitPref, base::Value(base::Value::Type::DICTIONARY));
+  report_only_split_val->SetIntKey("a", 1234);
 
   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref2, NULL));
diff --git a/testing/scripts/test_traffic_annotation_auditor.py b/testing/scripts/test_traffic_annotation_auditor.py
index 2d47de1..5400eb6 100755
--- a/testing/scripts/test_traffic_annotation_auditor.py
+++ b/testing/scripts/test_traffic_annotation_auditor.py
@@ -63,7 +63,7 @@
       if pattern.search(gn_args):
         return "chromeos"
 
-    except(valueError, OSError) as e:
+    except(ValueError, OSError) as e:
       logger.info(e)
 
   return None
@@ -108,13 +108,13 @@
         annotations_filename,
       ]
       rc = common.run_command(command_line)
+      cleanup_file(config_filename)
     else:
       print("Test failed without updating the annotations sheet.")
-  except (valueError, OSError) as e:
+  except (ValueError, OSError) as e:
     print("Error updating the annotations sheet", e)
   finally:
     cleanup_file(annotations_filename)
-    cleanup_file(config_filename)
     failures = ['Please refer to stdout for errors.'] if rc else []
     common.record_local_script_results(
        'test_traffic_annotation_auditor', args.output, failures, True)
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 0fda834..4df552a 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1074,6 +1074,10 @@
 const base::Feature kForceMinorVersion100InUserAgent{
     "ForceMinorVersion100InUserAgent", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kForceMajorVersionInMinorPositionInUserAgent{
+    "ForceMajorVersionInMinorPositionInUserAgent",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enable `sec-ch-device-memory` client hint.
 const base::Feature kClientHintsDeviceMemory{"ClientHintsDeviceMemory",
                                              base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 974d9a9..93e4c8ad0 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -495,6 +495,14 @@
 BLINK_COMMON_EXPORT
 extern const base::FeatureParam<double> kCostReductionOfMultiplexedRequests;
 
+// If enabled, the major version number returned by Chrome will be locked at
+// 99. The minor version number returned by Chrome will be forced to the
+// value of the major version number. The purpose of this
+// feature is a back up plan for if the major version moving from
+// two to three digits breaks unexpected things.
+BLINK_COMMON_EXPORT extern const base::Feature
+    kForceMajorVersionInMinorPositionInUserAgent;
+
 // If enabled, the minor version number returned by Chrome will be forced to
 // 100.  This feature is only applicable for M96-M99 and will be removed after
 // M99.  The purpose of this feature is to allow testing of mitigation
diff --git a/third_party/blink/public/mojom/web_launch/web_launch.mojom b/third_party/blink/public/mojom/web_launch/web_launch.mojom
index 1ce7aecf..e9e7b42 100644
--- a/third_party/blink/public/mojom/web_launch/web_launch.mojom
+++ b/third_party/blink/public/mojom/web_launch/web_launch.mojom
@@ -9,7 +9,7 @@
 
 // Interface for getting the cause of page loads to blink. This service lives
 // in blink and is used to implement the File Handling proposal:
-// https://github.com/WICG/file-handling/blob/master/explainer.md
+// https://github.com/WICG/file-handling/blob/main/explainer.md
 // TODO(crbug.com/829689): Replace link to explainer with link to spec, when
 // available.
 //
diff --git a/third_party/blink/renderer/core/content_capture/content_capture_task.cc b/third_party/blink/renderer/core/content_capture/content_capture_task.cc
index dfb4281b..b1e1fe2 100644
--- a/third_party/blink/renderer/core/content_capture/content_capture_task.cc
+++ b/third_party/blink/renderer/core/content_capture/content_capture_task.cc
@@ -17,7 +17,6 @@
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/layout/layout_text.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
diff --git a/third_party/blink/renderer/core/css/mock_css_paint_image_generator.h b/third_party/blink/renderer/core/css/mock_css_paint_image_generator.h
index e126764e..2aa9aa1 100644
--- a/third_party/blink/renderer/core/css/mock_css_paint_image_generator.h
+++ b/third_party/blink/renderer/core/css/mock_css_paint_image_generator.h
@@ -8,6 +8,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/css/css_paint_image_generator.h"
+#include "third_party/blink/renderer/platform/graphics/image.h"
 
 using testing::ReturnRef;
 
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index 5dd9647..803d7a06 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -27,7 +27,6 @@
 #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/pre_paint_tree_walk.h"
 #include "third_party/blink/renderer/platform/bindings/microtask.h"
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index 9f20015..6d2ba7d 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -30,7 +30,6 @@
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/geometry/dom_rect.h"
 #include "third_party/blink/renderer/core/html/html_template_element.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
diff --git a/third_party/blink/renderer/core/document_transition/document_transition_test.cc b/third_party/blink/renderer/core/document_transition/document_transition_test.cc
index d140b2f..d8b10bbf 100644
--- a/third_party/blink/renderer/core/document_transition/document_transition_test.cc
+++ b/third_party/blink/renderer/core/document_transition/document_transition_test.cc
@@ -16,7 +16,6 @@
 #include "third_party/blink/renderer/core/dom/abort_signal.h"
 #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
-#include "third_party/blink/renderer/core/paint/compositing/compositing_state.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
 #include "third_party/blink/renderer/platform/testing/find_cc_layer.h"
diff --git a/third_party/blink/renderer/core/editing/finder/text_finder_test.cc b/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
index 7e390a372..298f043 100644
--- a/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
+++ b/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
index 87720e55..4f856cf5 100644
--- a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
@@ -68,7 +68,6 @@
 #include "third_party/blink/renderer/core/page/page_popup_controller.h"
 #include "third_party/blink/renderer/platform/animation/compositor_animation_timeline.h"
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #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/instrumentation/tracing/trace_event.h"
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
index d677276..aadbc75 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -97,7 +97,6 @@
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h"
 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h"
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index cce6788b0..25f9a9f 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -66,7 +66,6 @@
 #include "third_party/blink/renderer/core/page/page_widget_delegate.h"
 #include "third_party/blink/renderer/core/page/scoped_page_pauser.h"
 #include "third_party/blink/renderer/platform/graphics/apply_viewport_changes.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/touch_action.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index 57a0437..42089dc 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -144,7 +144,6 @@
 #include "third_party/blink/renderer/platform/cursors.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/keyboard_codes.h"
diff --git a/third_party/blink/renderer/core/frame/browser_controls_test.cc b/third_party/blink/renderer/core/frame/browser_controls_test.cc
index 8ea1078..58b4cb0 100644
--- a/third_party/blink/renderer/core/frame/browser_controls_test.cc
+++ b/third_party/blink/renderer/core/frame/browser_controls_test.cc
@@ -45,7 +45,6 @@
 #include "third_party/blink/renderer/core/geometry/dom_rect.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
diff --git a/third_party/blink/renderer/core/frame/frame_overlay_test.cc b/third_party/blink/renderer/core/frame/frame_overlay_test.cc
index 6036152a..a89f1b9 100644
--- a/third_party/blink/renderer/core/frame/frame_overlay_test.cc
+++ b/third_party/blink/renderer/core/frame/frame_overlay_test.cc
@@ -18,7 +18,6 @@
 #include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
diff --git a/third_party/blink/renderer/core/frame/frame_serializer_test.cc b/third_party/blink/renderer/core/frame/frame_serializer_test.cc
index 61dedc2f..343a75dc 100644
--- a/third_party/blink/renderer/core/frame/frame_serializer_test.cc
+++ b/third_party/blink/renderer/core/frame/frame_serializer_test.cc
@@ -51,6 +51,7 @@
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 8816d71..69df0491 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -177,8 +177,6 @@
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/blob/blob_data.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer_tree_as_text.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 2aa486d3..4676203 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -129,7 +129,6 @@
 #include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
 #include "third_party/blink/renderer/core/page/validation_message_client.h"
 #include "third_party/blink/renderer/core/paint/block_paint_invalidator.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/cull_rect_updater.h"
 #include "third_party/blink/renderer/core/paint/frame_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -155,7 +154,6 @@
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_settings_builder.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk_subset_recorder.h"
@@ -1178,8 +1176,8 @@
       background_attachment_fixed_objects_.begin()->Get());
   // We should not add such object in the set.
   DCHECK(!object->BackgroundTransfersToView());
-  // If the background is viewport background and it paints onto the main
-  // graphics layer only, then it doesn't need main thread scrolling.
+  // If the background is viewport background and it paints onto the border box
+  // space only, then it doesn't need main thread scrolling.
   if (IsA<LayoutView>(object) &&
       object->GetBackgroundPaintLocation() == kBackgroundPaintInBorderBoxSpace)
     return false;
@@ -2939,9 +2937,6 @@
 }
 
 void LocalFrameView::CreatePaintTimelineEvents() {
-  // For pre-CAP, this is done in CompositedLayerMapping::PaintContents()
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    return;
   if (const cc::Layer* root_layer = paint_artifact_compositor_->RootLayer()) {
     for (const auto& layer : root_layer->children()) {
       if (!layer->update_rect().IsEmpty()) {
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc
index f41715a1..b114ad27 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -55,7 +55,6 @@
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc
index 66cf13aa..e910a7b 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -43,6 +43,7 @@
 #include "cc/input/overscroll_behavior.h"
 #include "cc/layers/picture_layer.h"
 #include "cc/paint/paint_op_buffer.h"
+#include "cc/paint/paint_recorder.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/scroll_node.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -169,7 +170,6 @@
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/page/scoped_page_pauser.h"
 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/scroll/scrollbar.h"
@@ -188,7 +188,6 @@
 #include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/blob/testing/fake_blob.h"
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/keyboard_codes.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
 #include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
@@ -13431,7 +13430,7 @@
   gfx::Size page_size(500, 500);
   print_params.print_content_area.set_size(page_size);
   EXPECT_EQ(1u, frame->PrintBegin(print_params, WebNode()));
-  PaintRecorder recorder;
+  cc::PaintRecorder recorder;
   frame->PrintPagesForTesting(recorder.beginRecording(SkRect::MakeEmpty()),
                               page_size, page_size);
   frame->PrintEnd();
@@ -13509,7 +13508,7 @@
   print_params.print_content_area.set_size(page_size);
   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
   EXPECT_EQ(1u, frame->PrintBegin(print_params, WebNode()));
-  PaintRecorder recorder;
+  cc::PaintRecorder recorder;
   frame->PrintPagesForTesting(recorder.beginRecording(SkRect::MakeEmpty()),
                               page_size, page_size);
   frame->PrintEnd();
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 643e74f0..edb4d72 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -244,7 +244,6 @@
 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer_client.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
 #include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index bc6343ee..ad59358 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -316,7 +316,8 @@
 SkColorInfo CanvasRenderingContextHost::GetRenderingContextSkColorInfo() const {
   if (RenderingContext())
     return RenderingContext()->CanvasRenderingContextSkColorInfo();
-  return SkColorInfo(kN32_SkColorType, kPremul_SkAlphaType, nullptr);
+  return SkColorInfo(kN32_SkColorType, kPremul_SkAlphaType,
+                     SkColorSpace::MakeSRGB());
 }
 
 ScriptPromise CanvasRenderingContextHost::convertToBlob(
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 98f1587..2e45c9dc 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -98,7 +98,6 @@
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/image_data_buffer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
 #include "third_party/blink/renderer/platform/graphics/static_bitmap_image_to_video_frame_copier.h"
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index f8933bf..50e9fb15 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -36,6 +36,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
+#include "cc/layers/layer.h"
 #include "media/base/logging_override_if_enabled.h"
 #include "media/base/media_content_type.h"
 #include "media/base/media_switches.h"
@@ -114,7 +115,6 @@
 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/microtask.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
@@ -4290,7 +4290,6 @@
   if (cc_layer == cc_layer_)
     return;
 
-  // We need to update the GraphicsLayer when the cc layer changes.
   SetNeedsCompositingUpdate();
   cc_layer_ = cc_layer;
 }
diff --git a/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc b/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
index 2fc009e..d920bf2 100644
--- a/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
+++ b/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
@@ -18,7 +18,6 @@
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
index b970a55..5186c92e 100644
--- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
@@ -34,6 +34,7 @@
 
 #include "base/auto_reset.h"
 #include "build/build_config.h"
+#include "cc/layers/content_layer_client.h"
 #include "cc/layers/picture_layer.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/platform/platform.h"
diff --git a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
index cf339cf..96cbd46 100644
--- a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
@@ -35,7 +35,6 @@
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
 #include "third_party/blink/renderer/core/workers/worker_thread.h"
 #include "third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index bce26b78..a722891 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -41,7 +41,6 @@
 #include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 917c0a0..db7c59b 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -111,7 +111,6 @@
 #include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
 #include "third_party/blink/renderer/core/style/content_data.h"
 #include "third_party/blink/renderer/core/style/cursor_data.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
 #include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
 #include "third_party/blink/renderer/platform/graphics/touch_action.h"
@@ -1850,13 +1849,6 @@
   return GetNode() ? DOMNodeIds::IdForNode(GetNode()) : kInvalidDOMNodeId;
 }
 
-bool LayoutObject::IsPaintInvalidationContainer() const {
-  NOT_DESTROYED();
-  return HasLayer() && To<LayoutBoxModelObject>(this)
-                           ->Layer()
-                           ->IsPaintInvalidationContainer();
-}
-
 void LayoutObject::InvalidateDisplayItemClients(
     PaintInvalidationReason reason) const {
   NOT_DESTROYED();
@@ -4035,13 +4027,6 @@
   return CreatePositionWithAffinity(0);
 }
 
-CompositingState LayoutObject::GetCompositingState() const {
-  NOT_DESTROYED();
-  return HasLayer()
-             ? To<LayoutBoxModelObject>(this)->Layer()->GetCompositingState()
-             : kNotComposited;
-}
-
 bool LayoutObject::CanHaveAdditionalCompositingReasons() const {
   NOT_DESTROYED();
   return false;
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 9ca6575..509f78eb 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -52,7 +52,6 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
 #include "third_party/blink/renderer/core/layout/subtree_layout_scope.h"
 #include "third_party/blink/renderer/core/loader/resource/image_resource_observer.h"
-#include "third_party/blink/renderer/core/paint/compositing/compositing_state.h"
 #include "third_party/blink/renderer/core/paint/fragment_data.h"
 #include "third_party/blink/renderer/core/paint/paint_phase.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
@@ -2252,8 +2251,6 @@
 
   virtual void AddAnnotatedRegions(Vector<AnnotatedRegionValue>&);
 
-  CompositingState GetCompositingState() const;
-
   // True for object types which override |AdditionalCompositingReasons|.
   virtual bool CanHaveAdditionalCompositingReasons() const;
   virtual CompositingReasons AdditionalCompositingReasons() const;
@@ -2606,8 +2603,6 @@
 
   virtual CursorDirective GetCursor(const PhysicalOffset&, ui::Cursor&) const;
 
-  bool IsPaintInvalidationContainer() const;
-
   // Returns the rect that should have raster invalidated whenever this object
   // changes. The rect is in the coordinate space of the document's scrolling
   // contents. This method deals with outlines and overflow.
diff --git a/third_party/blink/renderer/core/layout/layout_shift_tracker.cc b/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
index 7588d69..f04b1ce 100644
--- a/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
+++ b/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
@@ -23,7 +23,6 @@
 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
 #include "third_party/blink/renderer/core/timing/performance_entry.h"
 #include "third_party/blink/renderer/core/timing/window_performance.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
 #include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/third_party/blink/renderer/core/layout/layout_tree_as_text.cc b/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
index 751d5d5..e9633a31 100644
--- a/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
@@ -59,7 +59,6 @@
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.h"
 #include "third_party/blink/renderer/core/page/print_context.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_paint_order_iterator.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
index a9b9300..8f5f005 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -497,7 +497,7 @@
 
   // Same as |base::span<const NGLink>|, except that:
   // * Each |NGLink| has the latest generation of post-layout. See
-  //   |NGPhysicalFragment::UpdatedFragment()| for more details.
+  //   |NGPhysicalFragment::PostLayout()| for more details.
   // * The iterator skips fragments for destroyed or moved |LayoutObject|.
   class PostLayoutChildLinkList {
     STACK_ALLOCATED();
diff --git a/third_party/blink/renderer/core/layout/scrollbars_test.cc b/third_party/blink/renderer/core/layout/scrollbars_test.cc
index f134de38..314e788 100644
--- a/third_party/blink/renderer/core/layout/scrollbars_test.cc
+++ b/third_party/blink/renderer/core/layout/scrollbars_test.cc
@@ -26,7 +26,6 @@
 #include "third_party/blink/renderer/core/testing/color_scheme_helper.h"
 #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/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -2179,7 +2178,7 @@
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
-    /* transform keeps the graphics layer */
+    /* transform keeps the composited layer */
     #div { width: 100px; height: 100px; will-change: transform; }
     .scroller{ overflow: scroll; }
     .big{ height: 2000px; }
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 d1b3d09..f110012 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
@@ -613,11 +613,8 @@
   NOT_DESTROYED();
   auto layer_type_required = LayoutReplaced::LayerTypeRequired();
   if (layer_type_required == kNoPaintLayer) {
-    // Force a paint layer so,
-    // 1) A GraphicsLayer can be created if there are directly-composited
-    // descendants.
-    // 2) The parent layer will know if there are non-isolated descendants with
-    // blend mode.
+    // Force a paint layer so the parent layer will know if there are
+    // non-isolated descendants with blend mode.
     layer_type_required = kForcedPaintLayer;
   }
   return layer_type_required;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
index fb98878f..bb56a3b 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
@@ -9,7 +9,6 @@
 #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/testing/find_cc_layer.h"
 #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
 
@@ -123,10 +122,8 @@
   EXPECT_EQ(2, count);
 }
 
-// A PaintLayer is needed for the purposes of creating a GraphicsLayer to limit
-// CompositeSVG to SVG subtrees. This PaintLayer will not be needed with
-// CompositeAfterPaint. If compositing is needed for descendants, the paint
-// layer should be self-painting. Otherwise, it should be non-self-painting.
+// A PaintLayer is needed to ensure the parent layer knows about non-isolated
+// descendants with blend mode.
 TEST_P(LayoutSVGRootTest, PaintLayerType) {
   SetBodyInnerHTML(R"HTML(
     <svg id="root" style="width: 200px; height: 200px;">
diff --git a/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc b/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
index aeec2be4..f641dfcb 100644
--- a/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
+++ b/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
@@ -691,14 +691,6 @@
   EXPECT_EQ(PhysicalRect(-2, 3, 140, 110), rect);
 }
 
-static const LayoutBoxModelObject& EnclosingCompositedContainer(
-    const LayoutObject& layout_object) {
-  DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-  return layout_object.PaintingLayer()
-      ->EnclosingLayerForPaintInvalidationCrossingFrameBoundaries()
-      ->GetLayoutObject();
-}
-
 TEST_P(VisualRectMappingTest,
        DifferentPaintInvalidaitionContainerForAbsolutePosition) {
   GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
@@ -724,9 +716,6 @@
 
   auto* normal_flow =
       To<LayoutBlock>(GetLayoutObjectByElementId("normal-flow"));
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    EXPECT_EQ(scroller, &EnclosingCompositedContainer(*normal_flow));
-
   PhysicalRect normal_flow_visual_rect = normal_flow->LocalVisualRect();
   EXPECT_EQ(PhysicalRect(0, 0, 2000, 2000), normal_flow_visual_rect);
   PhysicalRect rect = normal_flow_visual_rect;
@@ -766,8 +755,6 @@
       To<LayoutBlock>(GetLayoutObjectByElementId("stacking-context"));
   auto* absolute = To<LayoutBlock>(GetLayoutObjectByElementId("absolute"));
   auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    EXPECT_EQ(absolute->View(), &EnclosingCompositedContainer(*absolute));
   EXPECT_EQ(container, absolute->Container());
 
   PhysicalRect absolute_visual_rect = absolute->LocalVisualRect();
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc
index 24c6902..8c478e6 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -96,7 +96,6 @@
 #include "third_party/blink/renderer/platform/animation/compositor_animation_timeline.h"
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
 #include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/touch_action.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc
index 5dd9992..e3f3a3c2 100644
--- a/third_party/blink/renderer/core/page/page.cc
+++ b/third_party/blink/renderer/core/page/page.cc
@@ -83,7 +83,6 @@
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_mobile.h"
 #include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
 #include "third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
diff --git a/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc b/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
index 34e68dc5..25915399 100644
--- a/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
@@ -16,11 +16,9 @@
 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #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/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/testing/find_cc_layer.h"
 #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -449,9 +447,8 @@
 TEST_P(NonCompositedMainThreadScrollingReasonsTest,
        ForcedComositingWithLCDRelatedReasons) {
   // With "will-change:transform" we composite elements with
-  // LCDTextRelatedReasons only. For elements with other
-  // NonCompositedReasons, we don't create scrollingLayer for their
-  // CompositedLayerMapping therefore they don't get composited.
+  // LCDTextRelatedReasons only. For elements with other NonCompositedReasons,
+  // we don't composite them.
   GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
   Document* document = GetFrame()->GetDocument();
   Element* container = document->getElementById("scroller1");
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
index 0759879a..067c491d 100644
--- a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
+++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
@@ -22,7 +22,6 @@
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/scroll/scrollable_area.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "ui/gfx/geometry/size_conversions.h"
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
index 6a4581c..67df73a 100644
--- a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
@@ -31,7 +31,6 @@
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h"
 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
index 5e7b2802..1fe69e2 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
@@ -51,7 +51,6 @@
 #include "third_party/blink/renderer/core/scroll/scrollbar_layer_delegate.h"
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
index 78ea221..5cebb6d6 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
@@ -56,12 +56,10 @@
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_context.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #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/graphics/gpu/shared_gpu_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h"
 #include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h"
 #include "third_party/blink/renderer/platform/graphics/touch_action.h"
@@ -1898,7 +1896,7 @@
       )HTML");
   ForceFullCompositingUpdate();
 
-  // The non-scrolling graphics layer should have a non-scrolling region for the
+  // The non-scrolling layer should have a non-scrolling region for the
   // non-composited scroller.
   const auto* cc_layer = LayerByDOMElementId("composited_container");
   auto region = cc_layer->non_fast_scrollable_region();
@@ -1929,9 +1927,9 @@
   ForceFullCompositingUpdate();
 
   auto* container_cc_layer = LayerByDOMElementId("container");
-  // The non-fast scrollable region should be on the container's graphics layer
-  // and not one of the viewport scroll layers because the region should move
-  // when the container moves and not when the viewport scrolls.
+  // The non-fast scrollable region should be on the container's layer and not
+  // one of the viewport scroll layers because the region should move when the
+  // container moves and not when the viewport scrolls.
   auto region = container_cc_layer->non_fast_scrollable_region();
   EXPECT_EQ(region.bounds(), gfx::Rect(86, 121, 14, 14));
 }
diff --git a/third_party/blink/renderer/core/paint/background_image_geometry.cc b/third_party/blink/renderer/core/paint/background_image_geometry.cc
index b3d49b9..f8ef6383 100644
--- a/third_party/blink/renderer/core/paint/background_image_geometry.cc
+++ b/third_party/blink/renderer/core/paint/background_image_geometry.cc
@@ -13,7 +13,6 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/paint/rounded_border_geometry.h"
diff --git a/third_party/blink/renderer/core/paint/block_painter_test.cc b/third_party/blink/renderer/core/paint/block_painter_test.cc
index 289fe81b..f7df2f8 100644
--- a/third_party/blink/renderer/core/paint/block_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/block_painter_test.cc
@@ -11,7 +11,6 @@
 #include "third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h"
 #include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk.h"
diff --git a/third_party/blink/renderer/core/paint/box_paint_invalidator.cc b/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
index 18b98856..c53010ad 100644
--- a/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
@@ -7,7 +7,6 @@
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
diff --git a/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc b/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
index efe3bc8..6b3690a 100644
--- a/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
+++ b/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
@@ -13,7 +13,6 @@
 #include "third_party/blink/renderer/core/paint/paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 
diff --git a/third_party/blink/renderer/core/paint/box_painter.cc b/third_party/blink/renderer/core/paint/box_painter.cc
index 2d9c92d..6a187ac 100644
--- a/third_party/blink/renderer/core/paint/box_painter.cc
+++ b/third_party/blink/renderer/core/paint/box_painter.cc
@@ -16,7 +16,6 @@
 #include "third_party/blink/renderer/core/paint/box_decoration_data.h"
 #include "third_party/blink/renderer/core/paint/box_model_object_painter.h"
 #include "third_party/blink/renderer/core/paint/box_painter_base.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/nine_piece_image_painter.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
diff --git a/third_party/blink/renderer/core/paint/box_painter_test.cc b/third_party/blink/renderer/core/paint/box_painter_test.cc
index 9907f29d..5cbfe2b 100644
--- a/third_party/blink/renderer/core/paint/box_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/box_painter_test.cc
@@ -5,7 +5,6 @@
 #include "third_party/blink/renderer/core/paint/box_painter.h"
 
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
 #include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h"
 
diff --git a/third_party/blink/renderer/core/paint/build.gni b/third_party/blink/renderer/core/paint/build.gni
index 4de7fd1..3fe0c5b6 100644
--- a/third_party/blink/renderer/core/paint/build.gni
+++ b/third_party/blink/renderer/core/paint/build.gni
@@ -34,19 +34,8 @@
   "clip_rects.h",
   "collapsed_border_painter.cc",
   "collapsed_border_painter.h",
-  "compositing/composited_layer_mapping.cc",
-  "compositing/composited_layer_mapping.h",
-  "compositing/compositing_inputs_root.cc",
-  "compositing/compositing_inputs_root.h",
-  "compositing/compositing_layer_property_updater.cc",
-  "compositing/compositing_layer_property_updater.h",
   "compositing/compositing_reason_finder.cc",
   "compositing/compositing_reason_finder.h",
-  "compositing/compositing_state.h",
-  "compositing/graphics_layer_tree_builder.cc",
-  "compositing/graphics_layer_tree_builder.h",
-  "compositing/graphics_layer_updater.cc",
-  "compositing/graphics_layer_updater.h",
   "css_mask_painter.cc",
   "css_mask_painter.h",
   "cull_rect_updater.cc",
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
deleted file mode 100644
index 3a6ae7b..0000000
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ /dev/null
@@ -1,1687 +0,0 @@
-/*
- * Copyright (C) 2009, 2010, 2011 Apple 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
-
-#include <memory>
-
-#include "cc/layers/picture_layer.h"
-#include "third_party/blink/renderer/core/animation/element_animations.h"
-#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
-#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
-#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/frame/remote_frame.h"
-#include "third_party/blink/renderer/core/frame/settings.h"
-#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
-#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
-#include "third_party/blink/renderer/core/html/html_body_element.h"
-#include "third_party/blink/renderer/core/html/html_iframe_element.h"
-#include "third_party/blink/renderer/core/html/media/html_media_element.h"
-#include "third_party/blink/renderer/core/html/media/html_video_element.h"
-#include "third_party/blink/renderer/core/html_names.h"
-#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
-#include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
-#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
-#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
-#include "third_party/blink/renderer/core/layout/layout_embedded_object.h"
-#include "third_party/blink/renderer/core/layout/layout_html_canvas.h"
-#include "third_party/blink/renderer/core/layout/layout_inline.h"
-#include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
-#include "third_party/blink/renderer/core/layout/layout_video.h"
-#include "third_party/blink/renderer/core/layout/layout_view.h"
-#include "third_party/blink/renderer/core/page/chrome_client.h"
-#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
-#include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
-#include "third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h"
-#include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
-#include "third_party/blink/renderer/core/paint/css_mask_painter.h"
-#include "third_party/blink/renderer/core/paint/frame_paint_timing.h"
-#include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
-#include "third_party/blink/renderer/core/paint/outline_painter.h"
-#include "third_party/blink/renderer/core/paint/paint_info.h"
-#include "third_party/blink/renderer/core/paint/paint_layer_paint_order_iterator.h"
-#include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
-#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
-#include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
-#include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/platform/fonts/font_cache.h"
-#include "third_party/blink/renderer/platform/geometry/length_functions.h"
-#include "third_party/blink/renderer/platform/graphics/compositor_filter_operations.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
-#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
-#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
-#include "third_party/blink/renderer/platform/graphics/paint/ignore_paint_timing_scope.h"
-#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
-#include "ui/gfx/geometry/point_conversions.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-
-namespace blink {
-
-static PhysicalRect ContentsRect(const LayoutObject& layout_object) {
-  if (!layout_object.IsBox())
-    return PhysicalRect();
-  if (auto* replaced = DynamicTo<LayoutReplaced>(layout_object))
-    return replaced->ReplacedContentRect();
-  return To<LayoutBox>(layout_object).PhysicalContentBoxRect();
-}
-
-static bool HasBoxDecorationsOrBackgroundImage(const ComputedStyle& style) {
-  return style.HasBoxDecorations() || style.HasBackgroundImage();
-}
-
-static WebPluginContainerImpl* GetPluginContainer(LayoutObject& layout_object) {
-  if (auto* embedded_object = DynamicTo<LayoutEmbeddedObject>(layout_object))
-    return embedded_object->Plugin();
-  return nullptr;
-}
-
-// Returns true if the compositor will be responsible for applying the sticky
-// position offset for this composited layer.
-static bool UsesCompositedStickyPosition(PaintLayer& layer) {
-  return layer.GetLayoutObject().StyleRef().HasStickyConstrainedPosition() &&
-         layer.AncestorScrollContainerLayer()->NeedsCompositedScrolling();
-}
-
-// Returns the sticky position offset that should be removed from a given
-// layer for use in CompositedLayerMapping.
-//
-// If the layer is not using composited sticky position, this will return
-// gfx::PointF().
-static gfx::PointF StickyPositionOffsetForLayer(PaintLayer& layer) {
-  if (!UsesCompositedStickyPosition(layer))
-    return gfx::PointF();
-
-  const StickyConstraintsMap& constraints_map =
-      layer.AncestorScrollContainerLayer()
-          ->GetScrollableArea()
-          ->GetStickyConstraintsMap();
-  const StickyPositionScrollingConstraints* constraints =
-      constraints_map.at(&layer);
-
-  return gfx::PointF(constraints->GetOffsetForStickyPosition(constraints_map));
-}
-
-static bool NeedsDecorationOutlineLayer(const PaintLayer& paint_layer,
-                                        const LayoutObject& layout_object) {
-  const ComputedStyle& style = layout_object.StyleRef();
-  const LayoutUnit min_border_width =
-      std::min(std::min(style.BorderLeftWidth(), style.BorderTopWidth()),
-               std::min(style.BorderRightWidth(), style.BorderBottomWidth()));
-
-  bool could_obscure_decorations =
-      (paint_layer.GetScrollableArea() &&
-       paint_layer.GetScrollableArea()->UsesCompositedScrolling()) ||
-      layout_object.IsCanvas() || IsA<LayoutVideo>(layout_object);
-
-  // Unlike normal outlines (whole width is outside of the offset), focus
-  // rings can be drawn with the center of the path aligned with the offset,
-  // so only 2/3 of the width is outside of the offset.
-  const int outline_drawn_inside =
-      style.OutlineStyleIsAuto()
-          ? OutlinePainter::FocusRingWidthInsideBorderBox(style)
-          : 0;
-
-  return could_obscure_decorations && style.HasOutline() &&
-         (style.OutlineOffset().ToInt() - outline_drawn_inside) <
-             -min_border_width.ToInt();
-}
-
-CompositedLayerMapping::CompositedLayerMapping(PaintLayer& layer)
-    : owning_layer_(&layer), pending_update_scope_(kGraphicsLayerUpdateNone) {
-  CreatePrimaryGraphicsLayer();
-}
-
-CompositedLayerMapping::~CompositedLayerMapping() {
-#if DCHECK_IS_ON()
-  DCHECK(is_destroyed_);
-#endif
-}
-
-void CompositedLayerMapping::Destroy() {
-  UpdateForegroundLayer(false);
-  UpdateMaskLayer(false);
-  UpdateSquashingLayers(false);
-  if (graphics_layer_)
-    graphics_layer_.Release()->Destroy();
-  if (scrolling_contents_layer_)
-    scrolling_contents_layer_.Release()->Destroy();
-  if (mask_layer_)
-    mask_layer_.Release()->Destroy();
-  if (foreground_layer_)
-    foreground_layer_.Release()->Destroy();
-  if (layer_for_horizontal_scrollbar_)
-    layer_for_horizontal_scrollbar_.Release()->Destroy();
-  if (layer_for_vertical_scrollbar_)
-    layer_for_vertical_scrollbar_.Release()->Destroy();
-  if (layer_for_scroll_corner_)
-    layer_for_scroll_corner_.Release()->Destroy();
-  if (decoration_outline_layer_)
-    decoration_outline_layer_.Release()->Destroy();
-  if (non_scrolling_squashing_layer_)
-    non_scrolling_squashing_layer_.Release()->Destroy();
-
-#if DCHECK_IS_ON()
-  is_destroyed_ = true;
-#endif
-}
-
-Member<GraphicsLayer> CompositedLayerMapping::CreateGraphicsLayer(
-    CompositingReasons reasons,
-    SquashingDisallowedReasons squashing_disallowed_reasons) {
-  auto* graphics_layer = MakeGarbageCollected<GraphicsLayer>();
-
-  graphics_layer->SetCompositingReasons(reasons);
-  graphics_layer->SetSquashingDisallowedReasons(squashing_disallowed_reasons);
-  if (Node* owning_node = owning_layer_->GetLayoutObject().GetNode()) {
-    graphics_layer->SetOwnerNodeId(
-        static_cast<int>(DOMNodeIds::IdForNode(owning_node)));
-  }
-
-  return graphics_layer;
-}
-
-void CompositedLayerMapping::CreatePrimaryGraphicsLayer() {
-  graphics_layer_ =
-      CreateGraphicsLayer(owning_layer_->GetCompositingReasons(),
-                          owning_layer_->GetSquashingDisallowedReasons());
-
-  graphics_layer_->SetHitTestable(true);
-}
-
-void CompositedLayerMapping::UpdateCompositedBounds() {
-  // FIXME: if this is really needed for performance, it would be better to
-  // store it on Layer.
-  composited_bounds_ = owning_layer_->BoundingBoxForCompositing();
-}
-
-bool CompositedLayerMapping::UpdateGraphicsLayerConfiguration(
-    const PaintLayer* compositing_container) {
-  // Note carefully: here we assume that the compositing state of all
-  // descendants have been updated already, so it is legitimate to compute and
-  // cache the composited bounds for this layer.
-  UpdateCompositedBounds();
-
-  LayoutObject& layout_object = GetLayoutObject();
-  const ComputedStyle& style = layout_object.StyleRef();
-
-  bool layer_config_changed = false;
-
-  // If the outline needs to draw over the composited scrolling contents layer
-  // or scrollbar layers (or video or webgl) it needs to be drawn into a
-  // separate layer.
-  bool needs_decoration_outline_layer =
-      NeedsDecorationOutlineLayer(*owning_layer_, layout_object);
-
-  if (UpdateDecorationOutlineLayer(needs_decoration_outline_layer))
-    layer_config_changed = true;
-
-  if (UpdateSquashingLayers(!non_scrolling_squashed_layers_.IsEmpty()))
-    layer_config_changed = true;
-
-  bool has_mask =
-      CSSMaskPainter::MaskBoundingBox(GetLayoutObject(), PhysicalOffset())
-          .has_value();
-  bool has_mask_based_clip_path =
-      ClipPathClipper::ShouldUseMaskBasedClip(GetLayoutObject());
-  if (UpdateMaskLayer(has_mask || has_mask_based_clip_path))
-    layer_config_changed = true;
-
-  if (layer_config_changed)
-    UpdateInternalHierarchy();
-
-  if (layout_object.IsLayoutEmbeddedContent()) {
-    if (WebPluginContainerImpl* plugin = GetPluginContainer(layout_object)) {
-      graphics_layer_->SetContentsToCcLayer(plugin->CcLayer());
-    } else if (auto* frame_owner =
-                   DynamicTo<HTMLFrameOwnerElement>(layout_object.GetNode())) {
-      if (auto* remote = DynamicTo<RemoteFrame>(frame_owner->ContentFrame())) {
-        graphics_layer_->SetContentsToCcLayer(remote->GetCcLayer());
-      }
-    }
-  } else if (IsA<LayoutVideo>(layout_object)) {
-    auto* media_element = To<HTMLMediaElement>(layout_object.GetNode());
-    graphics_layer_->SetContentsToCcLayer(media_element->CcLayer());
-  } else if (layout_object.IsCanvas()) {
-    graphics_layer_->SetContentsToCcLayer(
-        To<HTMLCanvasElement>(layout_object.GetNode())->ContentsCcLayer());
-    layer_config_changed = true;
-  }
-
-  if (layer_config_changed) {
-    // Changes to either the internal hierarchy or the mask layer have an
-    // impact on painting phases, so we need to update when either are
-    // updated.
-    UpdatePaintingPhases();
-  }
-
-  UpdateElementId();
-
-  if (style.Preserves3D() && style.HasOpacity() &&
-      owning_layer_->Has3DTransformedDescendant()) {
-    UseCounter::Count(layout_object.GetDocument(),
-                      WebFeature::kOpacityWithPreserve3DQuirk);
-  }
-
-  return layer_config_changed;
-}
-
-static PhysicalOffset ComputeOffsetFromCompositedAncestor(
-    const PaintLayer* layer,
-    const PaintLayer* composited_ancestor,
-    const PhysicalOffset& local_representative_point_for_fragmentation,
-    const gfx::PointF& offset_for_sticky_position) {
-  // Add in the offset of the composited bounds from the coordinate space of
-  // the PaintLayer, since visualOffsetFromAncestor() requires the pre-offset
-  // input to be in the space of the PaintLayer. We also need to add in this
-  // offset before computation of visualOffsetFromAncestor(), because it
-  // affects fragmentation offset if compositedAncestor crosses a pagination
-  // boundary.
-  //
-  // Currently, visual fragmentation for composited layers is not implemented.
-  // For fragmented contents, we paint in the logical coordinates of the flow
-  // thread, then split the result by fragment boundary and paste each part
-  // into each fragment's physical position.
-  // Since composited layers don't support visual fragmentation, we have to
-  // choose a "representative" fragment to position the painted contents. This
-  // is where localRepresentativePointForFragmentation comes into play.
-  // The fragment that the representative point resides in will be chosen as
-  // the representative fragment for layer position purpose.
-  // For layers that are not fragmented, the point doesn't affect behavior as
-  // there is one and only one fragment.
-  PhysicalOffset offset = layer->VisualOffsetFromAncestor(
-      composited_ancestor, local_representative_point_for_fragmentation);
-  if (composited_ancestor)
-    offset += composited_ancestor->SubpixelAccumulation();
-  offset -= local_representative_point_for_fragmentation;
-  offset -= PhysicalOffset::FromPointFRound(offset_for_sticky_position);
-  return offset;
-}
-
-PhysicalOffset ComputeSubpixelAccumulation(
-    const PhysicalOffset& offset_from_composited_ancestor,
-    const PaintLayer& layer,
-    gfx::Point& snapped_offset_from_composited_ancestor) {
-  snapped_offset_from_composited_ancestor =
-      ToRoundedPoint(offset_from_composited_ancestor);
-  PhysicalOffset subpixel_accumulation =
-      offset_from_composited_ancestor -
-      PhysicalOffset(snapped_offset_from_composited_ancestor);
-  if (subpixel_accumulation.IsZero()) {
-    return subpixel_accumulation;
-  }
-  if (layer.GetCompositingReasons() &
-      CompositingReason::kPreventingSubpixelAccumulationReasons) {
-    return PhysicalOffset();
-  }
-  if (layer.GetCompositingReasons() &
-      CompositingReason::kActiveTransformAnimation) {
-    if (const Element* element =
-            To<Element>(layer.GetLayoutObject().GetNode())) {
-      DCHECK(element->GetElementAnimations());
-      if (element->GetElementAnimations()->IsIdentityOrTranslation())
-        return subpixel_accumulation;
-    }
-    return PhysicalOffset();
-  }
-  if (!layer.Transform() || layer.Transform()->IsIdentityOrTranslation()) {
-    return subpixel_accumulation;
-  }
-  return PhysicalOffset();
-}
-
-void CompositedLayerMapping::ComputeBoundsOfOwningLayer(
-    const PaintLayer* composited_ancestor,
-    gfx::Rect& local_bounds,
-    gfx::Point& snapped_offset_from_composited_ancestor) {
-  // HACK(chrishtr): adjust for position of inlines.
-  PhysicalOffset local_representative_point_for_fragmentation;
-  if (owning_layer_->GetLayoutObject().IsLayoutInline()) {
-    local_representative_point_for_fragmentation =
-        To<LayoutInline>(owning_layer_->GetLayoutObject())
-            .FirstLineBoxTopLeft();
-  }
-  // Blink will already have applied any necessary offset for sticky
-  // positioned elements. If the compositor is handling sticky offsets for
-  // this layer, we need to remove the Blink-side offset to avoid
-  // double-counting.
-  gfx::PointF offset_for_sticky_position =
-      StickyPositionOffsetForLayer(*owning_layer_);
-  PhysicalOffset offset_from_composited_ancestor =
-      ComputeOffsetFromCompositedAncestor(
-          owning_layer_, composited_ancestor,
-          local_representative_point_for_fragmentation,
-          offset_for_sticky_position);
-  PhysicalOffset subpixel_accumulation = ComputeSubpixelAccumulation(
-      offset_from_composited_ancestor, *owning_layer_,
-      snapped_offset_from_composited_ancestor);
-
-  // Invalidate the whole layer when subpixel accumulation changes, since
-  // the previous subpixel accumulation is baked into the display list.
-  // However, don't do so for directly composited layers, to avoid impacting
-  // performance.
-  if (subpixel_accumulation != owning_layer_->SubpixelAccumulation()) {
-    // Always invalidate if under-invalidation checking is on, to avoid
-    // false positives.
-    if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() ||
-        !(owning_layer_->GetCompositingReasons() &
-          CompositingReason::kComboAllDirectReasons))
-      GetLayoutObject().SetShouldCheckForPaintInvalidation();
-  }
-
-  absl::optional<gfx::Rect> mask_bounding_box =
-      CSSMaskPainter::MaskBoundingBox(GetLayoutObject(), subpixel_accumulation);
-  absl::optional<gfx::RectF> clip_path_bounding_box =
-      ClipPathClipper::LocalClipPathBoundingBox(GetLayoutObject());
-  if (clip_path_bounding_box)
-    clip_path_bounding_box->Offset(gfx::Vector2dF(subpixel_accumulation));
-
-  // Override graphics layer size to the bound of mask layer, this is because
-  // the compositor implementation requires mask layer bound to match its
-  // host layer.
-  if (mask_bounding_box) {
-    local_bounds = *mask_bounding_box;
-    if (clip_path_bounding_box)
-      local_bounds.Intersect(gfx::ToEnclosingRect(*clip_path_bounding_box));
-  } else if (clip_path_bounding_box) {
-    local_bounds = gfx::ToEnclosingRect(*clip_path_bounding_box);
-  } else {
-    // Move the bounds by the subpixel accumulation so that it pixel-snaps
-    // relative to absolute pixels instead of local coordinates.
-    PhysicalRect local_raw_compositing_bounds = CompositedBounds();
-    local_raw_compositing_bounds.Move(subpixel_accumulation);
-    local_bounds = ToPixelSnappedRect(local_raw_compositing_bounds);
-  }
-}
-
-void CompositedLayerMapping::UpdateSquashingLayerGeometry(
-    const PaintLayer* compositing_container,
-    const gfx::Point& snapped_offset_from_composited_ancestor,
-    HeapVector<Member<GraphicsLayerPaintInfo>>& layers,
-    HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation) {
-  if (!non_scrolling_squashing_layer_)
-    return;
-
-  gfx::Point graphics_layer_parent_location;
-  ComputeGraphicsLayerParentLocation(compositing_container,
-                                     graphics_layer_parent_location);
-
-  PhysicalOffset compositing_container_offset_from_parent_graphics_layer =
-      -PhysicalOffset(graphics_layer_parent_location);
-  if (compositing_container) {
-    compositing_container_offset_from_parent_graphics_layer +=
-        compositing_container->SubpixelAccumulation();
-  }
-
-  const PaintLayer* common_transform_ancestor = nullptr;
-  if (compositing_container && compositing_container->Transform()) {
-    common_transform_ancestor = compositing_container;
-  } else if (compositing_container) {
-    common_transform_ancestor = nullptr;
-  } else {
-    common_transform_ancestor = owning_layer_->Root();
-  }
-
-  // FIXME: Cache these offsets.
-  PhysicalOffset compositing_container_offset_from_transformed_ancestor;
-  if (compositing_container) {
-    compositing_container_offset_from_transformed_ancestor =
-        compositing_container->ComputeOffsetFromAncestor(
-            *common_transform_ancestor);
-  }
-
-  PhysicalRect total_squash_bounds;
-  for (wtf_size_t i = 0; i < layers.size(); ++i) {
-    PhysicalRect squashed_bounds =
-        layers[i]->paint_layer->BoundingBoxForCompositing();
-
-    // Store the local bounds of the Layer subtree before applying the offset.
-    layers[i]->composited_bounds = squashed_bounds;
-
-    PhysicalOffset squashed_layer_offset_from_transformed_ancestor =
-        layers[i]->paint_layer->ComputeOffsetFromAncestor(
-            *common_transform_ancestor);
-    PhysicalOffset squashed_layer_offset_from_compositing_container =
-        squashed_layer_offset_from_transformed_ancestor -
-        compositing_container_offset_from_transformed_ancestor;
-
-    squashed_bounds.Move(squashed_layer_offset_from_compositing_container);
-    total_squash_bounds.Unite(squashed_bounds);
-  }
-
-  // The totalSquashBounds is positioned with respect to compositingContainer.
-  // But the squashingLayer needs to be positioned with respect to the
-  // graphicsLayerParent.  The conversion between compositingContainer and the
-  // graphicsLayerParent is already computed as
-  // compositingContainerOffsetFromParentGraphicsLayer.
-  total_squash_bounds.Move(
-      compositing_container_offset_from_parent_graphics_layer);
-  const gfx::Rect squash_layer_bounds = ToEnclosingRect(total_squash_bounds);
-  const gfx::Point squash_layer_origin = squash_layer_bounds.origin();
-  const PhysicalOffset squash_layer_origin_in_compositing_container_space =
-      PhysicalOffset(squash_layer_origin) -
-      compositing_container_offset_from_parent_graphics_layer;
-
-  // Now that the squashing bounds are known, we can convert the PaintLayer
-  // painting offsets from compositingContainer space to the squashing layer
-  // space.
-  //
-  // The painting offset we want to compute for each squashed PaintLayer is
-  // essentially the position of the squashed PaintLayer described w.r.t.
-  // compositingContainer's origin.  So we just need to convert that point
-  // from compositingContainer space to the squashing layer's space. This is
-  // done by subtracting squashLayerOriginInCompositingContainerSpace, but
-  // then the offset overall needs to be negated because that's the direction
-  // that the painting code expects the offset to be.
-  for (auto& layer : layers) {
-    const PhysicalOffset squashed_layer_offset_from_transformed_ancestor =
-        layer->paint_layer->ComputeOffsetFromAncestor(
-            *common_transform_ancestor);
-    const PhysicalOffset offset_from_squash_layer_origin =
-        (squashed_layer_offset_from_transformed_ancestor -
-         compositing_container_offset_from_transformed_ancestor) -
-        squash_layer_origin_in_compositing_container_space;
-
-    gfx::Vector2d new_offset_from_layout_object =
-        -ToRoundedVector2d(offset_from_squash_layer_origin);
-    if (layer->offset_from_layout_object_set &&
-        layer->offset_from_layout_object != new_offset_from_layout_object) {
-      layers_needing_paint_invalidation.push_back(layer->paint_layer);
-    }
-    layer->offset_from_layout_object = new_offset_from_layout_object;
-    layer->offset_from_layout_object_set = true;
-  }
-
-  non_scrolling_squashing_layer_->SetSize(squash_layer_bounds.size());
-  // We can't non_scrolling_squashing_layer_->SetOffsetFromLayoutObject().
-  // Squashing layer has special paint and invalidation logic that already
-  // compensated for compositing bounds, setting it here would end up
-  // double adjustment.
-  auto new_offset = squash_layer_bounds.origin() -
-                    snapped_offset_from_composited_ancestor +
-                    graphics_layer_parent_location.OffsetFromOrigin();
-  if (new_offset != non_scrolling_squashing_layer_offset_from_layout_object_) {
-    non_scrolling_squashing_layer_offset_from_layout_object_ = new_offset;
-    // Need to update squashing LayerState according to the new offset.
-    // GraphicsLayerUpdater does this.
-    layers_needing_paint_invalidation.push_back(owning_layer_);
-  }
-
-  for (auto& layer : layers)
-    UpdateLocalClipRectForSquashedLayer(*owning_layer_, layers, *layer);
-}
-
-void CompositedLayerMapping::UpdateGraphicsLayerGeometry(
-    const PaintLayer* compositing_container,
-    HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation) {
-  gfx::Rect local_compositing_bounds;
-  gfx::Point snapped_offset_from_composited_ancestor;
-  ComputeBoundsOfOwningLayer(compositing_container, local_compositing_bounds,
-                             snapped_offset_from_composited_ancestor);
-
-  UpdateMainGraphicsLayerGeometry(local_compositing_bounds);
-  UpdateSquashingLayerGeometry(
-      compositing_container, snapped_offset_from_composited_ancestor,
-      non_scrolling_squashed_layers_, layers_needing_paint_invalidation);
-
-  UpdateMaskLayerGeometry();
-  UpdateDecorationOutlineLayerGeometry(local_compositing_bounds.size());
-  UpdateScrollingContentsLayerGeometry(layers_needing_paint_invalidation);
-  UpdateForegroundLayerGeometry();
-
-  if (owning_layer_->GetScrollableArea() &&
-      owning_layer_->GetScrollableArea()->ScrollsOverflow())
-    owning_layer_->GetScrollableArea()->PositionOverflowControls();
-
-  UpdateContentsRect();
-  UpdateDrawsContentAndPaintsHitTest();
-  UpdateElementId();
-}
-
-void CompositedLayerMapping::UpdateMainGraphicsLayerGeometry(
-    const gfx::Rect& local_compositing_bounds) {
-  graphics_layer_->SetOffsetFromLayoutObject(
-      local_compositing_bounds.OffsetFromOrigin());
-  graphics_layer_->SetSize(local_compositing_bounds.size());
-
-  // m_graphicsLayer is the corresponding GraphicsLayer for this PaintLayer
-  // and its non-compositing descendants. So, the visibility flag for
-  // m_graphicsLayer should be true if there are any non-compositing visible
-  // layers.
-  bool contents_visible = owning_layer_->HasVisibleContent() ||
-                          HasVisibleNonCompositingDescendant(owning_layer_);
-  // TODO(sunxd): Investigate and possibly implement computing hit test
-  // regions in PaintTouchActionRects code path, so that cc has correct
-  // pointer-events information. For now, there is no need to set
-  // graphics_layer_'s hit testable bit here, because it is always hit
-  // testable from cc's perspective.
-  graphics_layer_->SetContentsVisible(contents_visible);
-}
-
-void CompositedLayerMapping::ComputeGraphicsLayerParentLocation(
-    const PaintLayer* compositing_container,
-    gfx::Point& graphics_layer_parent_location) {
-  if (compositing_container) {
-    graphics_layer_parent_location = gfx::PointAtOffsetFromOrigin(
-        compositing_container->GetCompositedLayerMapping()
-            ->ParentForSublayers()
-            ->OffsetFromLayoutObject());
-  } else if (!GetLayoutObject().GetFrame()->IsLocalRoot()) {  // TODO(oopif)
-    DCHECK(!compositing_container);
-    graphics_layer_parent_location = gfx::Point();
-  }
-
-  if (compositing_container &&
-      compositing_container->NeedsCompositedScrolling()) {
-    auto& layout_box = To<LayoutBox>(compositing_container->GetLayoutObject());
-    gfx::Vector2d scroll_offset =
-        layout_box.PixelSnappedScrolledContentOffset();
-    gfx::Point scroll_origin =
-        compositing_container->GetScrollableArea()->ScrollOrigin();
-    scroll_origin -= layout_box.OriginAdjustmentForScrollbars();
-    scroll_origin.Offset(-layout_box.BorderLeft().ToInt(),
-                         -layout_box.BorderTop().ToInt());
-    graphics_layer_parent_location = gfx::PointAtOffsetFromOrigin(
-        -(scroll_origin.OffsetFromOrigin() + scroll_offset));
-  }
-}
-
-void CompositedLayerMapping::UpdateMaskLayerGeometry() {
-  if (!mask_layer_)
-    return;
-
-  mask_layer_->SetSize(graphics_layer_->Size());
-  mask_layer_->SetOffsetFromLayoutObject(
-      graphics_layer_->OffsetFromLayoutObject());
-}
-
-void CompositedLayerMapping::UpdateScrollingContentsLayerGeometry(
-    HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation) {
-  if (!scrolling_contents_layer_) {
-    DCHECK(squashed_layers_in_scrolling_contents_.IsEmpty());
-    return;
-  }
-
-  DCHECK(scrolling_contents_layer_);
-  auto& layout_box = To<LayoutBox>(GetLayoutObject());
-  gfx::Rect overflow_clip_rect = ToPixelSnappedRect(
-      layout_box.OverflowClipRect(owning_layer_->SubpixelAccumulation()));
-
-  bool scroll_container_size_changed =
-      previous_scroll_container_size_ != overflow_clip_rect.size();
-  if (scroll_container_size_changed)
-    previous_scroll_container_size_ = overflow_clip_rect.size();
-
-  PaintLayerScrollableArea* scrollable_area =
-      owning_layer_->GetScrollableArea();
-  gfx::Size scroll_size = scrollable_area->PixelSnappedContentsSize(
-      owning_layer_->SubpixelAccumulation());
-
-  // Ensure scrolling contents are at least as large as the scroll clip
-  scroll_size.SetToMin(overflow_clip_rect.size());
-
-  auto* scrolling_coordinator = owning_layer_->GetScrollingCoordinator();
-  scrolling_coordinator->UpdateCompositorScrollOffset(*layout_box.GetFrame(),
-                                                      *scrollable_area);
-
-  scrolling_contents_layer_->SetSize(scroll_size);
-
-  scrolling_contents_layer_->SetOffsetFromLayoutObject(
-      overflow_clip_rect.origin() - scrollable_area->ScrollOrigin());
-
-  for (auto& layer : squashed_layers_in_scrolling_contents_) {
-    layer->composited_bounds = layer->paint_layer->BoundingBoxForCompositing();
-    PhysicalOffset offset_from_scrolling_contents_layer =
-        layer->paint_layer->ComputeOffsetFromAncestor(*owning_layer_) +
-        owning_layer_->SubpixelAccumulation() -
-        PhysicalOffset(scrolling_contents_layer_->OffsetFromLayoutObject());
-    gfx::Vector2d new_offset_from_layout_object =
-        -ToRoundedVector2d(offset_from_scrolling_contents_layer);
-
-    if (layer->offset_from_layout_object_set &&
-        layer->offset_from_layout_object != new_offset_from_layout_object) {
-      layers_needing_paint_invalidation.push_back(layer->paint_layer);
-    }
-    layer->offset_from_layout_object = new_offset_from_layout_object;
-    layer->offset_from_layout_object_set = true;
-  }
-  for (auto& layer : squashed_layers_in_scrolling_contents_) {
-    UpdateLocalClipRectForSquashedLayer(
-        *owning_layer_, squashed_layers_in_scrolling_contents_, *layer);
-  }
-}
-
-bool CompositedLayerMapping::RequiresHorizontalScrollbarLayer() const {
-  return owning_layer_->GetScrollableArea() &&
-         owning_layer_->GetScrollableArea()->HorizontalScrollbar();
-}
-
-bool CompositedLayerMapping::RequiresVerticalScrollbarLayer() const {
-  return owning_layer_->GetScrollableArea() &&
-         owning_layer_->GetScrollableArea()->VerticalScrollbar();
-}
-
-bool CompositedLayerMapping::RequiresScrollCornerLayer() const {
-  return owning_layer_->GetScrollableArea() &&
-         !owning_layer_->GetScrollableArea()
-              ->ScrollCornerAndResizerRect()
-              .IsEmpty();
-}
-
-void CompositedLayerMapping::UpdateForegroundLayerGeometry() {
-  if (!foreground_layer_)
-    return;
-
-  // Should be equivalent to local_compositing_bounds.
-  gfx::Rect compositing_bounds(
-      gfx::PointAtOffsetFromOrigin(graphics_layer_->OffsetFromLayoutObject()),
-      graphics_layer_->Size());
-  if (scrolling_contents_layer_) {
-    // Override compositing bounds to include full overflow if composited
-    // scrolling is used.
-    compositing_bounds =
-        gfx::Rect(gfx::PointAtOffsetFromOrigin(
-                      scrolling_contents_layer_->OffsetFromLayoutObject()),
-                  scrolling_contents_layer_->Size());
-  }
-
-  foreground_layer_->SetOffsetFromLayoutObject(
-      compositing_bounds.OffsetFromOrigin());
-  foreground_layer_->SetSize(compositing_bounds.size());
-}
-
-void CompositedLayerMapping::UpdateDecorationOutlineLayerGeometry(
-    const gfx::Size& relative_compositing_bounds_size) {
-  if (!decoration_outline_layer_)
-    return;
-  decoration_outline_layer_->SetSize(relative_compositing_bounds_size);
-  decoration_outline_layer_->SetOffsetFromLayoutObject(
-      graphics_layer_->OffsetFromLayoutObject());
-}
-
-void CompositedLayerMapping::UpdateInternalHierarchy() {
-  // foreground_layer_ has to be inserted in the correct order with child
-  // layers in SetSubLayers(), so it's not inserted here.
-  graphics_layer_->RemoveFromParent();
-
-  bool overflow_controls_after_scrolling_contents =
-      owning_layer_->IsRootLayer() ||
-      (owning_layer_->GetScrollableArea() &&
-       owning_layer_->GetScrollableArea()->HasOverlayOverflowControls());
-  if (overflow_controls_after_scrolling_contents && scrolling_contents_layer_)
-    graphics_layer_->AddChild(scrolling_contents_layer_);
-
-  if (layer_for_horizontal_scrollbar_)
-    graphics_layer_->AddChild(layer_for_horizontal_scrollbar_);
-  if (layer_for_vertical_scrollbar_)
-    graphics_layer_->AddChild(layer_for_vertical_scrollbar_);
-  if (layer_for_scroll_corner_)
-    graphics_layer_->AddChild(layer_for_scroll_corner_);
-
-  if (!overflow_controls_after_scrolling_contents && scrolling_contents_layer_)
-    graphics_layer_->AddChild(scrolling_contents_layer_);
-
-  if (decoration_outline_layer_)
-    graphics_layer_->AddChild(decoration_outline_layer_);
-
-  if (mask_layer_)
-    graphics_layer_->AddChild(mask_layer_);
-
-  if (non_scrolling_squashing_layer_)
-    graphics_layer_->AddChild(non_scrolling_squashing_layer_);
-}
-
-void CompositedLayerMapping::UpdatePaintingPhases() {
-  graphics_layer_->SetPaintingPhase(PaintingPhaseForPrimaryLayer());
-  if (scrolling_contents_layer_) {
-    GraphicsLayerPaintingPhase paint_phase =
-        kGraphicsLayerPaintOverflowContents |
-        kGraphicsLayerPaintCompositedScroll;
-    if (!foreground_layer_)
-      paint_phase |= kGraphicsLayerPaintForeground;
-    scrolling_contents_layer_->SetPaintingPhase(paint_phase);
-  }
-  if (foreground_layer_) {
-    GraphicsLayerPaintingPhase paint_phase = kGraphicsLayerPaintForeground;
-    if (scrolling_contents_layer_)
-      paint_phase |= kGraphicsLayerPaintOverflowContents;
-    foreground_layer_->SetPaintingPhase(paint_phase);
-  }
-}
-
-void CompositedLayerMapping::UpdateContentsRect() {
-  graphics_layer_->SetContentsRect(ToPixelSnappedRect(ContentsBox()));
-}
-
-void CompositedLayerMapping::UpdateDrawsContentAndPaintsHitTest() {
-  bool in_overlay_fullscreen_video = false;
-  if (IsA<LayoutVideo>(GetLayoutObject())) {
-    auto* video_element = To<HTMLVideoElement>(GetLayoutObject().GetNode());
-    if (video_element->IsFullscreen() &&
-        video_element->UsesOverlayFullscreenVideo())
-      in_overlay_fullscreen_video = true;
-  }
-  bool has_painted_content =
-      in_overlay_fullscreen_video ? false : ContainsPaintedContent();
-  graphics_layer_->SetDrawsContent(has_painted_content);
-
-  // |has_painted_content| is conservative (e.g., will be true if any descendant
-  // paints content, regardless of whether the descendant content is a hit test)
-  // but an exhaustive check of descendants that paint hit tests would be too
-  // expensive.
-  bool paints_hit_test = has_painted_content ||
-                         GetLayoutObject().HasEffectiveAllowedTouchAction() ||
-                         GetLayoutObject().InsideBlockingWheelEventHandler();
-  bool paints_scroll_hit_test =
-      ((owning_layer_->GetScrollableArea() &&
-        owning_layer_->GetScrollableArea()->ScrollsOverflow()) ||
-       (GetPluginContainer(GetLayoutObject()) &&
-        GetPluginContainer(GetLayoutObject())->WantsWheelEvents()));
-  graphics_layer_->SetPaintsHitTest(paints_hit_test || paints_scroll_hit_test);
-
-  if (scrolling_contents_layer_) {
-    // scrolling_contents_layer_ only needs backing store if the scrolled
-    // contents need to paint.
-    bool has_painted_scrolling_contents =
-        !squashed_layers_in_scrolling_contents_.IsEmpty() ||
-        (owning_layer_->HasVisibleContent() &&
-         (GetLayoutObject().StyleRef().HasBackground() ||
-          GetLayoutObject().HasNonInitialBackdropFilter() || PaintsChildren()));
-    scrolling_contents_layer_->SetDrawsContent(has_painted_scrolling_contents);
-    scrolling_contents_layer_->SetPaintsHitTest(paints_hit_test);
-  }
-
-  if (has_painted_content && GetLayoutObject().IsCanvas() &&
-      To<LayoutHTMLCanvas>(GetLayoutObject())
-          .DrawsBackgroundOntoContentLayer()) {
-    has_painted_content = false;
-  }
-
-  // FIXME: we could refine this to only allocate backings for one of these
-  // layers if possible.
-  if (foreground_layer_) {
-    foreground_layer_->SetDrawsContent(has_painted_content);
-    foreground_layer_->SetPaintsHitTest(paints_hit_test);
-  }
-
-  if (decoration_outline_layer_)
-    decoration_outline_layer_->SetDrawsContent(true);
-
-  if (mask_layer_)
-    mask_layer_->SetDrawsContent(true);
-}
-
-void CompositedLayerMapping::PositionOverflowControlsLayers() {
-  if (GraphicsLayer* layer = LayerForHorizontalScrollbar()) {
-    Scrollbar* h_bar =
-        owning_layer_->GetScrollableArea()->HorizontalScrollbar();
-    if (h_bar) {
-      gfx::Rect frame_rect = h_bar->FrameRect();
-      layer->SetOffsetFromLayoutObject(frame_rect.OffsetFromOrigin());
-      layer->SetSize(frame_rect.size());
-      if (layer->HasContentsLayer())
-        layer->SetContentsRect(gfx::Rect(frame_rect.size()));
-    }
-    bool h_bar_visible = h_bar && !layer->HasContentsLayer();
-    layer->SetDrawsContent(h_bar_visible);
-    layer->SetHitTestable(h_bar_visible);
-  }
-
-  if (GraphicsLayer* layer = LayerForVerticalScrollbar()) {
-    Scrollbar* v_bar = owning_layer_->GetScrollableArea()->VerticalScrollbar();
-    if (v_bar) {
-      gfx::Rect frame_rect = v_bar->FrameRect();
-      layer->SetOffsetFromLayoutObject(frame_rect.OffsetFromOrigin());
-      layer->SetSize(frame_rect.size());
-      if (layer->HasContentsLayer())
-        layer->SetContentsRect(gfx::Rect(frame_rect.size()));
-    }
-    bool v_bar_visible = v_bar && !layer->HasContentsLayer();
-    layer->SetDrawsContent(v_bar_visible);
-    layer->SetHitTestable(v_bar_visible);
-  }
-
-  if (GraphicsLayer* layer = LayerForScrollCorner()) {
-    const gfx::Rect& scroll_corner_and_resizer =
-        owning_layer_->GetScrollableArea()->ScrollCornerAndResizerRect();
-    layer->SetOffsetFromLayoutObject(
-        scroll_corner_and_resizer.OffsetFromOrigin());
-    layer->SetSize(scroll_corner_and_resizer.size());
-    layer->SetDrawsContent(!scroll_corner_and_resizer.IsEmpty());
-    layer->SetHitTestable(!scroll_corner_and_resizer.IsEmpty());
-  }
-}
-
-template <typename Function>
-static void ApplyToGraphicsLayers(const CompositedLayerMapping* mapping,
-                                  const Function& function) {
-  auto null_checking_function = [&function](GraphicsLayer* layer) {
-    if (layer)
-      function(layer);
-  };
-
-  null_checking_function(mapping->MainGraphicsLayer());
-  null_checking_function(mapping->ScrollingContentsLayer());
-  null_checking_function(mapping->ForegroundLayer());
-  null_checking_function(mapping->MaskLayer());
-  null_checking_function(mapping->DecorationOutlineLayer());
-  null_checking_function(mapping->NonScrollingSquashingLayer());
-  null_checking_function(mapping->LayerForHorizontalScrollbar());
-  null_checking_function(mapping->LayerForVerticalScrollbar());
-  null_checking_function(mapping->LayerForScrollCorner());
-}
-
-// You receive an element id if you have an animation, or you're a scroller
-// (and might impl animate).
-//
-// The element id for the scroll layers is assigned when they're constructed,
-// since this is unconditional. However, the element id for the primary layer
-// may change according to the rules above so we update those values here.
-void CompositedLayerMapping::UpdateElementId() {
-  CompositorElementId element_id = CompositorElementIdFromUniqueObjectId(
-      owning_layer_->GetLayoutObject().UniqueId(),
-      CompositorElementIdNamespace::kPrimary);
-
-  graphics_layer_->SetElementId(element_id);
-}
-
-bool CompositedLayerMapping::UpdateForegroundLayer(
-    bool needs_foreground_layer) {
-  bool layer_changed = false;
-  if (needs_foreground_layer) {
-    if (!foreground_layer_) {
-      foreground_layer_ =
-          CreateGraphicsLayer(CompositingReason::kLayerForForeground);
-      foreground_layer_->SetHitTestable(true);
-      layer_changed = true;
-    }
-  } else if (foreground_layer_) {
-    foreground_layer_->RemoveFromParent();
-    foreground_layer_.Release()->Destroy();
-    layer_changed = true;
-  }
-
-  return layer_changed;
-}
-
-bool CompositedLayerMapping::UpdateDecorationOutlineLayer(
-    bool needs_decoration_outline_layer) {
-  bool layer_changed = false;
-  if (needs_decoration_outline_layer) {
-    if (!decoration_outline_layer_) {
-      decoration_outline_layer_ =
-          CreateGraphicsLayer(CompositingReason::kLayerForDecoration);
-      decoration_outline_layer_->SetPaintingPhase(
-          kGraphicsLayerPaintDecoration);
-      layer_changed = true;
-    }
-  } else if (decoration_outline_layer_) {
-    decoration_outline_layer_.Release()->Destroy();
-    layer_changed = true;
-  }
-
-  return layer_changed;
-}
-
-bool CompositedLayerMapping::UpdateMaskLayer(bool needs_mask_layer) {
-  bool layer_changed = false;
-  if (needs_mask_layer) {
-    if (!mask_layer_) {
-      mask_layer_ = CreateGraphicsLayer(CompositingReason::kLayerForMask);
-      mask_layer_->SetPaintingPhase(kGraphicsLayerPaintMask);
-      CompositorElementId element_id = CompositorElementIdFromUniqueObjectId(
-          GetLayoutObject().UniqueId(),
-          CompositorElementIdNamespace::kEffectMask);
-      mask_layer_->SetElementId(element_id);
-      if (GetLayoutObject().HasNonInitialBackdropFilter())
-        mask_layer_->CcLayer().SetIsBackdropFilterMask(true);
-      mask_layer_->SetHitTestable(true);
-      layer_changed = true;
-    }
-  } else if (mask_layer_) {
-    mask_layer_.Release()->Destroy();
-    layer_changed = true;
-  }
-
-  return layer_changed;
-}
-
-bool CompositedLayerMapping::UpdateSquashingLayers(
-    bool needs_squashing_layers) {
-  bool layers_changed = false;
-
-  if (needs_squashing_layers) {
-    if (!non_scrolling_squashing_layer_) {
-      non_scrolling_squashing_layer_ =
-          CreateGraphicsLayer(CompositingReason::kLayerForSquashingContents);
-      non_scrolling_squashing_layer_->SetDrawsContent(true);
-      non_scrolling_squashing_layer_->SetHitTestable(true);
-      layers_changed = true;
-    }
-    DCHECK(non_scrolling_squashing_layer_);
-  } else {
-    if (non_scrolling_squashing_layer_) {
-      non_scrolling_squashing_layer_->RemoveFromParent();
-      non_scrolling_squashing_layer_.Release()->Destroy();
-      layers_changed = true;
-    }
-    DCHECK(!non_scrolling_squashing_layer_);
-  }
-
-  return layers_changed;
-}
-
-GraphicsLayerPaintingPhase
-CompositedLayerMapping::PaintingPhaseForPrimaryLayer() const {
-  unsigned phase = kGraphicsLayerPaintBackground;
-  if (!foreground_layer_)
-    phase |= kGraphicsLayerPaintForeground;
-  if (!mask_layer_)
-    phase |= kGraphicsLayerPaintMask;
-  if (!decoration_outline_layer_)
-    phase |= kGraphicsLayerPaintDecoration;
-
-  if (scrolling_contents_layer_) {
-    phase &= ~kGraphicsLayerPaintForeground;
-    phase |= kGraphicsLayerPaintCompositedScroll;
-  }
-
-  return static_cast<GraphicsLayerPaintingPhase>(phase);
-}
-
-bool CompositedLayerMapping::PaintsChildren() const {
-  if (owning_layer_->HasVisibleContent() &&
-      owning_layer_->HasNonEmptyChildLayoutObjects())
-    return true;
-
-  if (HasVisibleNonCompositingDescendant(owning_layer_))
-    return true;
-
-  return false;
-}
-
-static bool IsCompositedPlugin(LayoutObject& layout_object) {
-  return layout_object.IsEmbeddedObject() &&
-         layout_object.AdditionalCompositingReasons();
-}
-
-bool CompositedLayerMapping::HasVisibleNonCompositingDescendant(
-    PaintLayer* parent) {
-  if (!parent->HasVisibleDescendant())
-    return false;
-
-  PaintLayerPaintOrderIterator iterator(parent, kAllChildren);
-  while (PaintLayer* child_layer = iterator.Next()) {
-    if (child_layer->HasCompositedLayerMapping())
-      continue;
-    if (child_layer->HasVisibleContent() ||
-        HasVisibleNonCompositingDescendant(child_layer))
-      return true;
-  }
-
-  return false;
-}
-
-bool CompositedLayerMapping::ContainsPaintedContent() const {
-  if (CompositedBounds().IsEmpty())
-    return false;
-
-  LayoutObject& layout_object = GetLayoutObject();
-  // FIXME: we could optimize cases where the image, video or canvas is known
-  // to fill the border box entirely, and set background color on the layer in
-  // that case, instead of allocating backing store and painting.
-  auto* layout_video = DynamicTo<LayoutVideo>(layout_object);
-  if (layout_video && layout_video->GetDisplayMode() == LayoutVideo::kVideo)
-    return owning_layer_->HasBoxDecorationsOrBackground();
-
-  if (layout_object.GetNode() && layout_object.GetNode()->IsDocumentNode()) {
-    if (owning_layer_->NeedsCompositedScrolling())
-      return BackgroundPaintsOntoGraphicsLayer();
-
-    // Look to see if the root object has a non-simple background
-    LayoutObject* root_object =
-        layout_object.GetDocument().documentElement()
-            ? layout_object.GetDocument().documentElement()->GetLayoutObject()
-            : nullptr;
-    // Reject anything that has a border, a border-radius or outline,
-    // or is not a simple background (no background, or solid color).
-    if (root_object &&
-        HasBoxDecorationsOrBackgroundImage(root_object->StyleRef()))
-      return true;
-
-    // Now look at the body's LayoutObject.
-    HTMLElement* body = layout_object.GetDocument().FirstBodyElement();
-    LayoutObject* body_object = body ? body->GetLayoutObject() : nullptr;
-    if (body_object &&
-        HasBoxDecorationsOrBackgroundImage(body_object->StyleRef()))
-      return true;
-  }
-
-  if (owning_layer_->HasVisibleBoxDecorations())
-    return true;
-
-  if (layout_object.HasMask())  // masks require special treatment
-    return true;
-
-  if (layout_object.IsAtomicInlineLevel() && !IsCompositedPlugin(layout_object))
-    return true;
-
-  if (layout_object.IsLayoutMultiColumnSet())
-    return true;
-
-  // FIXME: it's O(n^2). A better solution is needed.
-  return PaintsChildren();
-}
-
-// Return the offset from the top-left of this compositing layer at which the
-// LayoutObject's contents are painted.
-PhysicalOffset CompositedLayerMapping::ContentOffsetInCompositingLayer() const {
-  return owning_layer_->SubpixelAccumulation() -
-         PhysicalOffset(graphics_layer_->OffsetFromLayoutObject());
-}
-
-PhysicalRect CompositedLayerMapping::ContentsBox() const {
-  PhysicalRect contents_box = ContentsRect(GetLayoutObject());
-  contents_box.Move(ContentOffsetInCompositingLayer());
-  return contents_box;
-}
-
-bool CompositedLayerMapping::NeedsToReparentOverflowControls() const {
-  return owning_layer_->NeedsReorderOverlayOverflowControls();
-}
-
-wtf_size_t CompositedLayerMapping::MoveOverflowControlLayersInto(
-    GraphicsLayerVector& vector,
-    wtf_size_t position) {
-  wtf_size_t count = 0;
-  auto move_layer = [&](GraphicsLayer* layer) {
-    if (!layer)
-      return;
-    layer->RemoveFromParent();
-    vector.insert(position++, layer);
-    count++;
-  };
-  move_layer(layer_for_horizontal_scrollbar_);
-  move_layer(layer_for_vertical_scrollbar_);
-  move_layer(layer_for_scroll_corner_);
-  return count;
-}
-
-GraphicsLayer* CompositedLayerMapping::ParentForSublayers() const {
-  if (scrolling_contents_layer_)
-    return scrolling_contents_layer_;
-
-  return graphics_layer_;
-}
-
-void CompositedLayerMapping::SetSublayers(GraphicsLayerVector sublayers) {
-  GraphicsLayer* parent = ParentForSublayers();
-
-  // TODO(szager): Remove after diagnosing crash crbug.com/1092673
-  CHECK(parent);
-
-  // The caller should have inserted |foreground_layer_| into |sublayers|.
-  DCHECK(!foreground_layer_ || sublayers.Contains(foreground_layer_));
-
-  if (parent == graphics_layer_) {
-    // SetChildren() below will clobber all layers in |parent|, so we need to
-    // add layers that should stay in the children list into |sublayers|.
-    if (!NeedsToReparentOverflowControls()) {
-      if (layer_for_horizontal_scrollbar_)
-        sublayers.insert(0, layer_for_horizontal_scrollbar_);
-      if (layer_for_vertical_scrollbar_)
-        sublayers.insert(0, layer_for_vertical_scrollbar_);
-      if (layer_for_scroll_corner_)
-        sublayers.insert(0, layer_for_scroll_corner_);
-    }
-
-    if (decoration_outline_layer_)
-      sublayers.push_back(decoration_outline_layer_);
-    if (mask_layer_)
-      sublayers.push_back(mask_layer_);
-    if (non_scrolling_squashing_layer_)
-      sublayers.push_back(non_scrolling_squashing_layer_);
-  }
-
-  parent->SetChildren(sublayers);
-}
-
-GraphicsLayerUpdater::UpdateType CompositedLayerMapping::UpdateTypeForChildren(
-    GraphicsLayerUpdater::UpdateType update_type) const {
-  if (pending_update_scope_ >= kGraphicsLayerUpdateSubtree)
-    return GraphicsLayerUpdater::kForceUpdate;
-  return update_type;
-}
-
-GraphicsLayer* CompositedLayerMapping::SquashingLayer(
-    const PaintLayer& squashed_layer) const {
-  DCHECK(NonScrollingSquashingLayer());
-  return NonScrollingSquashingLayer();
-}
-
-void CompositedLayerMapping::SetNeedsCheckRasterInvalidation() {
-  ApplyToGraphicsLayers(this, [](GraphicsLayer* graphics_layer) {
-    if (graphics_layer->DrawsContent())
-      graphics_layer->SetNeedsCheckRasterInvalidation();
-  });
-}
-
-const GraphicsLayerPaintInfo* CompositedLayerMapping::ContainingSquashedLayer(
-    const LayoutObject* layout_object,
-    const HeapVector<Member<GraphicsLayerPaintInfo>>& layers,
-    unsigned max_squashed_layer_index) {
-  if (!layout_object)
-    return nullptr;
-  for (wtf_size_t i = 0; i < layers.size() && i < max_squashed_layer_index;
-       ++i) {
-    if (layout_object->IsDescendantOf(
-            &layers[i]->paint_layer->GetLayoutObject()))
-      return layers[i];
-  }
-  return nullptr;
-}
-
-const GraphicsLayerPaintInfo*
-CompositedLayerMapping::ContainingSquashedLayerInSquashingLayer(
-    const LayoutObject* layout_object,
-    unsigned max_squashed_layer_index) const {
-  return ContainingSquashedLayer(layout_object, non_scrolling_squashed_layers_,
-                                 max_squashed_layer_index);
-}
-
-void CompositedLayerMapping::UpdateLocalClipRectForSquashedLayer(
-    const PaintLayer& reference_layer,
-    const HeapVector<Member<GraphicsLayerPaintInfo>>& layers,
-    GraphicsLayerPaintInfo& paint_info) {
-  const LayoutObject* clipping_container =
-      paint_info.paint_layer->ClippingContainer();
-  if (clipping_container == reference_layer.ClippingContainer() ||
-      // When squashing into scrolling contents without other clips.
-      clipping_container == &reference_layer.GetLayoutObject()) {
-    paint_info.local_clip_rect_for_squashed_layer =
-        ClipRect(PhysicalRect(LayoutRect::InfiniteIntRect()));
-    paint_info.offset_from_clip_rect_root = PhysicalOffset();
-    paint_info.local_clip_rect_root = paint_info.paint_layer;
-    return;
-  }
-
-  DCHECK(clipping_container);
-
-  const GraphicsLayerPaintInfo* ancestor_paint_info =
-      ContainingSquashedLayer(clipping_container, layers, layers.size());
-  // Must be there, otherwise
-  // CompositingLayerAssigner::GetReasonsPreventingSquashing() would have
-  // disallowed squashing.
-  DCHECK(ancestor_paint_info);
-
-  const PaintLayer* ancestor_layer = ancestor_paint_info->paint_layer;
-  ClipRectsContext clip_rects_context(
-      ancestor_layer,
-      &ancestor_layer->GetLayoutObject().PrimaryStitchingFragment());
-  ClipRect parent_clip_rect;
-  paint_info.paint_layer
-      ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
-      .CalculateBackgroundClipRect(clip_rects_context, parent_clip_rect);
-
-  // Convert from ancestor to local coordinates.
-  gfx::Vector2d ancestor_to_local_offset =
-      paint_info.offset_from_layout_object -
-      ancestor_paint_info->offset_from_layout_object;
-  parent_clip_rect.Move(PhysicalOffset(ancestor_to_local_offset));
-  paint_info.local_clip_rect_for_squashed_layer = parent_clip_rect;
-  paint_info.offset_from_clip_rect_root =
-      PhysicalOffset(ancestor_to_local_offset);
-  paint_info.local_clip_rect_root = ancestor_paint_info->paint_layer;
-}
-
-void CompositedLayerMapping::DoPaintTask(
-    const GraphicsLayerPaintInfo& paint_info,
-    const GraphicsLayer& graphics_layer,
-    PaintLayerFlags paint_layer_flags,
-    GraphicsContext& context,
-    const gfx::Rect& clip /* In the coords of rootLayer */) const {
-  FontCachePurgePreventer font_cache_purge_preventer;
-
-  gfx::Vector2d offset = paint_info.offset_from_layout_object;
-  // The dirtyRect is in the coords of the painting root.
-  gfx::Rect dirty_rect(clip);
-  dirty_rect.Offset(offset);
-
-  if (paint_layer_flags & (kPaintLayerPaintingOverflowContents)) {
-    dirty_rect.Offset(
-        ToRoundedVector2d(paint_info.paint_layer->SubpixelAccumulation()));
-  } else {
-    PhysicalRect bounds = paint_info.composited_bounds;
-    bounds.Move(paint_info.paint_layer->SubpixelAccumulation());
-    dirty_rect.Intersect(ToPixelSnappedRect(bounds));
-  }
-
-#if DCHECK_IS_ON()
-  if (!GetLayoutObject().View()->GetFrame() ||
-      !GetLayoutObject().View()->GetFrame()->ShouldThrottleRendering())
-    paint_info.paint_layer->GetLayoutObject().AssertSubtreeIsLaidOut();
-#endif
-
-  float device_scale_factor = blink::DeviceScaleFactorDeprecated(
-      paint_info.paint_layer->GetLayoutObject().GetFrame());
-  context.SetDeviceScaleFactor(device_scale_factor);
-
-  // As a composited layer may be painted directly, we need to traverse the
-  // effect tree starting from the current node all the way up through the
-  // parents to determine which effects are opacity 0, for the purposes of
-  // correctly computing paint metrics such as First Contentful Paint and
-  // Largest Contentful Paint. For the latter we special-case the nodes where
-  // the opacity:0 depth is 1, so we need to only compute up to the first two
-  // opacity:0 effects in here and can ignore the rest.
-  absl::optional<IgnorePaintTimingScope> ignore_paint_timing_scope;
-  int num_ignores = 0;
-  DCHECK_EQ(IgnorePaintTimingScope::IgnoreDepth(), 0);
-  for (const auto* effect_node = &paint_info.paint_layer->GetLayoutObject()
-                                      .FirstFragment()
-                                      .PreEffect()
-                                      .Unalias();
-       effect_node && num_ignores < 2;
-       effect_node = effect_node->UnaliasedParent()) {
-    if (effect_node->Opacity() == 0.0f) {
-      if (!ignore_paint_timing_scope)
-        ignore_paint_timing_scope.emplace();
-      IgnorePaintTimingScope::IncrementIgnoreDepth();
-      ++num_ignores;
-    }
-  }
-
-  if (paint_info.paint_layer->GetCompositingState() !=
-      kPaintsIntoGroupedBacking) {
-    // FIXME: GraphicsLayers need a way to split for multicol.
-    PaintLayerPaintingInfo painting_info(
-        paint_info.paint_layer, CullRect(dirty_rect), kGlobalPaintNormalPhase,
-        paint_info.paint_layer->SubpixelAccumulation());
-    PaintLayerPainter(*paint_info.paint_layer)
-        .PaintLayerContents(context, painting_info, paint_layer_flags);
-  } else {
-    PaintLayerPaintingInfo painting_info(
-        paint_info.paint_layer, CullRect(dirty_rect), kGlobalPaintNormalPhase,
-        paint_info.paint_layer->SubpixelAccumulation());
-    PaintLayerPainter(*paint_info.paint_layer)
-        .Paint(context, painting_info, paint_layer_flags);
-  }
-}
-
-// TODO(eseckler): Make recording distance configurable, e.g. for use in
-// headless, where we would like to record an exact area.
-static const int kPixelDistanceToRecord = 4000;
-
-gfx::Rect CompositedLayerMapping::RecomputeInterestRect(
-    const GraphicsLayer* graphics_layer) const {
-  DCHECK(!RuntimeEnabledFeatures::CullRectUpdateEnabled());
-
-  gfx::Rect graphics_layer_bounds(graphics_layer->Size());
-
-  FloatClipRect mapping_rect((gfx::RectF(graphics_layer_bounds)));
-
-  auto source_state = graphics_layer->GetPropertyTreeState();
-
-  LayoutView* root_view = owning_layer_->GetLayoutObject().View();
-  while (root_view->GetFrame()->OwnerLayoutObject())
-    root_view = root_view->GetFrame()->OwnerLayoutObject()->View();
-
-  auto root_view_state = root_view->FirstFragment().LocalBorderBoxProperties();
-
-  // 1. Move into local transform space.
-  mapping_rect.Move(
-      gfx::Vector2dF(graphics_layer->GetOffsetFromTransformNode()));
-  // 2. Map into visible space of the root LayoutView.
-  GeometryMapper::LocalToAncestorVisualRect(source_state, root_view_state,
-                                            mapping_rect);
-
-  gfx::RectF visible_content_rect =
-      gfx::RectF(gfx::ToEnclosingRect(mapping_rect.Rect()));
-
-  gfx::RectF local_interest_rect;
-  // If the visible content rect is empty, then it makes no sense to map it
-  // back since there is nothing to map.
-  if (!visible_content_rect.IsEmpty()) {
-    local_interest_rect = visible_content_rect;
-    // 3. Map the visible content rect from root view space to local graphics
-    // layer space.
-    GeometryMapper::SourceToDestinationRect(root_view_state.Transform(),
-                                            source_state.Transform(),
-                                            local_interest_rect);
-    local_interest_rect.Offset(-graphics_layer->GetOffsetFromTransformNode());
-
-    // TODO(chrishtr): the code below is a heuristic. Instead we should detect
-    // and return whether the mapping failed.  In some cases,
-    // absoluteToLocalQuad can fail to map back to the local space, due to
-    // passing through non-invertible transforms or floating-point accuracy
-    // issues. Examples include rotation near 90 degrees or perspective. In
-    // such cases, fall back to painting the first kPixelDistanceToRecord
-    // pixels in each direction.
-
-    // Note that since the interest rect mapping above can produce extremely
-    // large numbers in cases of perspective, try our best to "normalize" the
-    // result by ensuring that none of the rect dimensions exceed some large,
-    // but reasonable, limit.
-    const float reasonable_pixel_limit = std::numeric_limits<int>::max() / 2.f;
-    auto unpadded_intersection = local_interest_rect;
-
-    // Note that by clamping X and Y, we are effectively moving the rect right
-    // / down. However, this will at most make us paint more content, which is
-    // better than erroneously deciding that the rect produced here is far
-    // offscreen.
-    if (unpadded_intersection.x() < -reasonable_pixel_limit)
-      unpadded_intersection.set_x(-reasonable_pixel_limit);
-    if (unpadded_intersection.y() < -reasonable_pixel_limit)
-      unpadded_intersection.set_y(-reasonable_pixel_limit);
-    if (unpadded_intersection.right() > reasonable_pixel_limit) {
-      unpadded_intersection.set_width(reasonable_pixel_limit -
-                                      unpadded_intersection.x());
-    }
-    if (unpadded_intersection.bottom() > reasonable_pixel_limit) {
-      unpadded_intersection.set_height(reasonable_pixel_limit -
-                                       unpadded_intersection.y());
-    }
-
-    unpadded_intersection.Intersect(gfx::RectF(graphics_layer_bounds));
-    // If our unpadded intersection is not empty, then use that before
-    // padding, since it can produce more stable results, and it would not
-    // produce any smaller area than if we used the original local interest
-    // rect.
-    if (!unpadded_intersection.IsEmpty())
-      local_interest_rect = unpadded_intersection;
-
-    // Expand by interest rect padding amount, scaled by the approximate scale
-    // of the GraphicsLayer relative to screen pixels. If width or height
-    // are zero or nearly zero, fall back to kPixelDistanceToRecord.
-    // This is the same as the else clause below.
-    float x_scale =
-        visible_content_rect.width() > std::numeric_limits<float>::epsilon()
-            ? local_interest_rect.width() / visible_content_rect.width()
-            : 1.0f;
-    float y_scale =
-        visible_content_rect.height() > std::numeric_limits<float>::epsilon()
-            ? local_interest_rect.height() / visible_content_rect.height()
-            : 1.0f;
-    // Take the max, to account for situations like rotation transforms, which
-    // swap x and y.
-    // Since at this point we can also have an extremely large scale due to
-    // perspective (see the comments above), cap it to something reasonable.
-    float scale = std::min(std::max(x_scale, y_scale),
-                           reasonable_pixel_limit / kPixelDistanceToRecord);
-    local_interest_rect.Outset(kPixelDistanceToRecord * scale);
-  } else {
-    // Expand by interest rect padding amount.
-    local_interest_rect.Outset(kPixelDistanceToRecord);
-  }
-  return gfx::IntersectRects(gfx::ToEnclosingRect(local_interest_rect),
-                             graphics_layer_bounds);
-}
-
-static const int kMinimumDistanceBeforeRepaint = 512;
-
-bool CompositedLayerMapping::InterestRectChangedEnoughToRepaint(
-    const gfx::Rect& previous_interest_rect,
-    const gfx::Rect& new_interest_rect,
-    const gfx::Size& layer_size) {
-  DCHECK(!RuntimeEnabledFeatures::CullRectUpdateEnabled());
-
-  if (previous_interest_rect.IsEmpty() && new_interest_rect.IsEmpty())
-    return false;
-
-  // Repaint when going from empty to not-empty, to cover cases where the
-  // layer is painted for the first time, or otherwise becomes visible.
-  if (previous_interest_rect.IsEmpty())
-    return true;
-
-  // Repaint if the new interest rect includes area outside of a skirt around
-  // the existing interest rect.
-  gfx::Rect expanded_previous_interest_rect(previous_interest_rect);
-  expanded_previous_interest_rect.Outset(kMinimumDistanceBeforeRepaint);
-  if (!expanded_previous_interest_rect.Contains(new_interest_rect))
-    return true;
-
-  // Even if the new interest rect doesn't include enough new area to satisfy
-  // the condition above, repaint anyway if it touches a layer edge not
-  // touched by the existing interest rect.  Because it's impossible to expose
-  // more area in the direction, repainting cannot be deferred until the
-  // exposed new area satisfies the condition above.
-  if (new_interest_rect.x() == 0 && previous_interest_rect.x() != 0)
-    return true;
-  if (new_interest_rect.y() == 0 && previous_interest_rect.y() != 0)
-    return true;
-  if (new_interest_rect.right() == layer_size.width() &&
-      previous_interest_rect.right() != layer_size.width())
-    return true;
-  if (new_interest_rect.bottom() == layer_size.height() &&
-      previous_interest_rect.bottom() != layer_size.height())
-    return true;
-
-  return false;
-}
-
-bool CompositedLayerMapping::AdjustForCompositedScrolling(
-    const GraphicsLayer* graphics_layer,
-    gfx::Vector2d& offset) const {
-  if (graphics_layer == scrolling_contents_layer_ ||
-      graphics_layer == foreground_layer_) {
-    if (PaintLayerScrollableArea* scrollable_area =
-            owning_layer_->GetScrollableArea()) {
-      if (scrollable_area->UsesCompositedScrolling()) {
-        // Note: this is the offset from the beginning of flow of the block,
-        // not the offset from the top/left of the overflow rect.
-        // offsetFromLayoutObject adds the origin offset from top/left to the
-        // beginning of flow.
-        ScrollOffset scroll_offset = scrollable_area->GetScrollOffset();
-        offset -= gfx::ToFlooredVector2d(scroll_offset);
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
-void CompositedLayerMapping::PaintScrollableArea(
-    const GraphicsLayer* graphics_layer,
-    GraphicsContext& context,
-    const gfx::Rect& interest_rect) const {
-  if (GetLayoutObject().StyleRef().Visibility() != EVisibility::kVisible)
-    return;
-
-  // cull_rect is in the space of the containing scrollable area in which
-  // Scrollbar::Paint() will paint the scrollbar.
-  CullRect cull_rect(interest_rect);
-  cull_rect.Move(graphics_layer->OffsetFromLayoutObject());
-  PaintLayerScrollableArea* scrollable_area =
-      owning_layer_->GetScrollableArea();
-  ScrollableAreaPainter painter(*scrollable_area);
-  if (graphics_layer == LayerForHorizontalScrollbar()) {
-    if (Scrollbar* scrollbar = scrollable_area->HorizontalScrollbar())
-      painter.PaintScrollbar(context, *scrollbar, gfx::Vector2d(), cull_rect);
-  } else if (graphics_layer == LayerForVerticalScrollbar()) {
-    if (Scrollbar* scrollbar = scrollable_area->VerticalScrollbar())
-      painter.PaintScrollbar(context, *scrollbar, gfx::Vector2d(), cull_rect);
-  } else if (graphics_layer == LayerForScrollCorner()) {
-    painter.PaintScrollCorner(context, gfx::Vector2d(), cull_rect);
-    painter.PaintResizer(context, gfx::Vector2d(), cull_rect);
-  }
-}
-
-bool CompositedLayerMapping::IsScrollableAreaLayer(
-    const GraphicsLayer* graphics_layer) const {
-  return graphics_layer == LayerForHorizontalScrollbar() ||
-         graphics_layer == LayerForVerticalScrollbar() ||
-         graphics_layer == LayerForScrollCorner();
-}
-
-bool CompositedLayerMapping::IsScrollableAreaLayerWhichNeedsRepaint(
-    const GraphicsLayer* graphics_layer) const {
-  if (PaintLayerScrollableArea* scrollable_area =
-          owning_layer_->GetScrollableArea()) {
-    if (graphics_layer == LayerForHorizontalScrollbar())
-      return scrollable_area->HorizontalScrollbarNeedsPaintInvalidation();
-
-    if (graphics_layer == LayerForVerticalScrollbar())
-      return scrollable_area->VerticalScrollbarNeedsPaintInvalidation();
-
-    if (graphics_layer == LayerForScrollCorner())
-      return scrollable_area->ScrollCornerNeedsPaintInvalidation();
-  }
-
-  return false;
-}
-
-void CompositedLayerMapping::Trace(Visitor* visitor) const {
-  visitor->Trace(owning_layer_);
-  visitor->Trace(graphics_layer_);
-  visitor->Trace(scrolling_contents_layer_);
-  visitor->Trace(mask_layer_);
-  visitor->Trace(foreground_layer_);
-  visitor->Trace(layer_for_horizontal_scrollbar_);
-  visitor->Trace(layer_for_vertical_scrollbar_);
-  visitor->Trace(layer_for_scroll_corner_);
-  visitor->Trace(decoration_outline_layer_);
-  visitor->Trace(non_scrolling_squashing_layer_);
-  visitor->Trace(non_scrolling_squashed_layers_);
-  visitor->Trace(squashed_layers_in_scrolling_contents_);
-}
-
-bool CompositedLayerMapping::UpdateSquashingLayerAssignmentInternal(
-    HeapVector<Member<GraphicsLayerPaintInfo>>& squashed_layers,
-    PaintLayer& squashed_layer,
-    wtf_size_t next_squashed_layer_index) {
-  GraphicsLayerPaintInfo* paint_info =
-      MakeGarbageCollected<GraphicsLayerPaintInfo>();
-  paint_info->paint_layer = &squashed_layer;
-  // NOTE: composited bounds are updated elsewhere
-  // NOTE: offsetFromLayoutObject is updated elsewhere
-
-  // Change tracking on squashing layers: at the first sign of something
-  // changed, just invalidate the layer.
-  // FIXME: Perhaps we can find a tighter more clever mechanism later.
-  if (next_squashed_layer_index < squashed_layers.size()) {
-    if (paint_info->paint_layer ==
-        squashed_layers[next_squashed_layer_index]->paint_layer)
-      return false;
-    squashed_layers.insert(next_squashed_layer_index, paint_info);
-  } else {
-    squashed_layers.push_back(paint_info);
-  }
-  return true;
-}
-
-bool CompositedLayerMapping::UpdateSquashingLayerAssignment(
-    PaintLayer& squashed_layer,
-    wtf_size_t next_squashed_layer_in_non_scrolling_squashing_layer_index,
-    wtf_size_t next_squashed_layer_in_scrolling_contents_index) {
-  return UpdateSquashingLayerAssignmentInternal(
-      non_scrolling_squashed_layers_, squashed_layer,
-      next_squashed_layer_in_non_scrolling_squashing_layer_index);
-}
-
-void CompositedLayerMapping::RemoveLayerFromSquashingGraphicsLayer(
-    const PaintLayer& layer) {
-  // We must try to remove the layer from both vectors because
-  // MayBeSquashedIntoScrollingContents() may not reflect the previous status.
-  for (wtf_size_t i = 0; i < non_scrolling_squashed_layers_.size(); ++i) {
-    if (non_scrolling_squashed_layers_[i]->paint_layer == &layer) {
-      non_scrolling_squashed_layers_.EraseAt(i);
-      return;
-    }
-  }
-  for (wtf_size_t i = 0; i < squashed_layers_in_scrolling_contents_.size();
-       ++i) {
-    if (squashed_layers_in_scrolling_contents_[i]->paint_layer == &layer) {
-      squashed_layers_in_scrolling_contents_.EraseAt(i);
-      return;
-    }
-  }
-
-  // Assert on incorrect mappings between layers and groups
-  NOTREACHED();
-}
-
-static void RemoveExtraSquashedLayers(
-    HeapVector<Member<GraphicsLayerPaintInfo>>& squashed_layers,
-    wtf_size_t new_count,
-    HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation) {
-  DCHECK_GE(squashed_layers.size(), new_count);
-  if (squashed_layers.size() == new_count)
-    return;
-  for (auto i = new_count; i < squashed_layers.size(); i++) {
-    layers_needing_paint_invalidation.push_back(
-        squashed_layers[i]->paint_layer);
-  }
-  squashed_layers.Shrink(new_count);
-}
-
-void CompositedLayerMapping::FinishAccumulatingSquashingLayers(
-    wtf_size_t new_non_scrolling_squashed_layer_count,
-    wtf_size_t new_squashed_layer_in_scrolling_contents_count,
-    HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation) {
-  RemoveExtraSquashedLayers(non_scrolling_squashed_layers_,
-                            new_non_scrolling_squashed_layer_count,
-                            layers_needing_paint_invalidation);
-  RemoveExtraSquashedLayers(squashed_layers_in_scrolling_contents_,
-                            new_squashed_layer_in_scrolling_contents_count,
-                            layers_needing_paint_invalidation);
-}
-
-String CompositedLayerMapping::DebugName(
-    const GraphicsLayer* graphics_layer) const {
-  String name;
-  if (graphics_layer == graphics_layer_) {
-    name = owning_layer_->DebugName();
-  } else if (graphics_layer == non_scrolling_squashing_layer_) {
-    name = "Squashing Layer (first squashed layer: " +
-           (non_scrolling_squashed_layers_.size() > 0
-                ? non_scrolling_squashed_layers_[0]->paint_layer->DebugName()
-                : "") +
-           ")";
-  } else if (graphics_layer == foreground_layer_) {
-    name = owning_layer_->DebugName() + " (foreground) Layer";
-  } else if (graphics_layer == mask_layer_) {
-    name = "Mask Layer";
-  } else if (graphics_layer == layer_for_horizontal_scrollbar_) {
-    name = "Horizontal Scrollbar Layer";
-  } else if (graphics_layer == layer_for_vertical_scrollbar_) {
-    name = "Vertical Scrollbar Layer";
-  } else if (graphics_layer == layer_for_scroll_corner_) {
-    name = "Scroll Corner Layer";
-  } else if (graphics_layer == scrolling_contents_layer_) {
-    name = "Scrolling Contents Layer";
-  } else if (graphics_layer == decoration_outline_layer_) {
-    name = "Decoration Layer";
-  } else {
-    NOTREACHED();
-  }
-
-  return name;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
deleted file mode 100644
index 9b31925..0000000
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (C) 2009, 2010, 2011 Apple 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITED_LAYER_MAPPING_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITED_LAYER_MAPPING_H_
-
-#include <memory>
-
-#include "base/dcheck_is_on.h"
-#include "third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/core/paint/paint_layer_painting_info.h"
-#include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "ui/gfx/geometry/point_f.h"
-
-namespace blink {
-
-// A GraphicsLayerPaintInfo contains all the info needed to paint a partial
-// subtree of Layers into a GraphicsLayer.
-struct GraphicsLayerPaintInfo
-    : public GarbageCollected<GraphicsLayerPaintInfo> {
- public:
-  Member<PaintLayer> paint_layer = nullptr;
-
-  PhysicalRect composited_bounds;
-
-  // The clip rect to apply, in the local coordinate space of the squashed
-  // layer, when painting it.
-  ClipRect local_clip_rect_for_squashed_layer;
-
-  Member<PaintLayer> local_clip_rect_root = nullptr;
-
-  PhysicalOffset offset_from_clip_rect_root;
-
-  // Offset describing where this squashed Layer paints into the shared
-  // GraphicsLayer backing.
-  gfx::Vector2d offset_from_layout_object;
-  bool offset_from_layout_object_set = false;
-
-  GraphicsLayerPaintInfo() = default;
-
-  void Trace(Visitor* visitor) const {
-    visitor->Trace(paint_layer);
-    visitor->Trace(local_clip_rect_root);
-  }
-};
-
-enum GraphicsLayerUpdateScope {
-  kGraphicsLayerUpdateNone,
-  kGraphicsLayerUpdateLocal,
-  kGraphicsLayerUpdateSubtree,
-};
-
-// CompositedLayerMapping keeps track of how PaintLayers correspond to
-// GraphicsLayers of the composited layer tree. Each instance of
-// CompositedLayerMapping manages a small cluster of GraphicsLayers and the
-// references to which Layers and paint phases contribute to each GraphicsLayer.
-//
-// - If a PaintLayer is composited,
-//   - if it paints into its own backings (GraphicsLayers), it owns a
-//     CompositedLayerMapping (PaintLayer::compositedLayerMapping()) to keep
-//     track the backings;
-//   - if it paints into grouped backing (i.e. it's squashed), it has a pointer
-//     (PaintLayer::groupedMapping()) to the CompositedLayerMapping into which
-//     the PaintLayer is squashed;
-// - Otherwise the PaintLayer doesn't own or directly reference any
-//   CompositedLayerMapping.
-class CORE_EXPORT CompositedLayerMapping final
-    : public GarbageCollected<CompositedLayerMapping> {
- public:
-  // |Destroy()| should be called when the object is no longer used.
-  explicit CompositedLayerMapping(PaintLayer&);
-  CompositedLayerMapping(const CompositedLayerMapping&) = delete;
-  CompositedLayerMapping& operator=(const CompositedLayerMapping&) = delete;
-  virtual ~CompositedLayerMapping();
-  void Destroy();
-
-  PaintLayer& OwningLayer() const { return *owning_layer_; }
-
-  bool UpdateGraphicsLayerConfiguration(
-      const PaintLayer* compositing_container);
-  void UpdateGraphicsLayerGeometry(
-      const PaintLayer* compositing_container,
-      HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation);
-
-  GraphicsLayer* MainGraphicsLayer() const { return graphics_layer_; }
-
-  GraphicsLayer* ForegroundLayer() const { return foreground_layer_; }
-
-  GraphicsLayer* DecorationOutlineLayer() const {
-    return decoration_outline_layer_;
-  }
-
-  GraphicsLayer* ScrollingContentsLayer() const {
-    return scrolling_contents_layer_;
-  }
-
-  GraphicsLayer* MaskLayer() const { return mask_layer_; }
-
-  GraphicsLayer* ParentForSublayers() const;
-  void SetSublayers(GraphicsLayerVector);
-
-  // Returns the GraphicsLayer that |layer| is squashed into, which may be
-  // NonScrollingSquashingLayer or ScrollingContentsLayer.
-  GraphicsLayer* SquashingLayer(const PaintLayer& squashed_layer) const;
-
-  GraphicsLayer* NonScrollingSquashingLayer() const {
-    return non_scrolling_squashing_layer_;
-  }
-  const gfx::Vector2d& NonScrollingSquashingLayerOffsetFromLayoutObject()
-      const {
-    return non_scrolling_squashing_layer_offset_from_layout_object_;
-  }
-
-  // Let all DrawsContent GraphicsLayers check raster invalidations after
-  // a no-change paint.
-  void SetNeedsCheckRasterInvalidation();
-
-  PhysicalRect CompositedBounds() const { return composited_bounds_; }
-
-  void PositionOverflowControlsLayers();
-
-  // Returns true if the assignment actually changed the assigned squashing
-  // layer.
-  bool UpdateSquashingLayerAssignment(
-      PaintLayer& squashed_layer,
-      wtf_size_t next_non_scrolling_squashed_layer_index,
-      wtf_size_t next_squashed_layer_in_scrolling_contents_index);
-  void RemoveLayerFromSquashingGraphicsLayer(const PaintLayer&);
-#if DCHECK_IS_ON()
-  void AssertInSquashedLayersVector(const PaintLayer&) const;
-#endif
-
-  void FinishAccumulatingSquashingLayers(
-      wtf_size_t new_non_scrolling_squashed_layer_count,
-      wtf_size_t new_squashed_layer_in_scrolling_contents_count,
-      HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation);
-
-  void UpdateElementId();
-
-  virtual void Trace(Visitor*) const;
-
-  PhysicalRect ContentsBox() const;
-
-  GraphicsLayer* LayerForHorizontalScrollbar() const {
-    return layer_for_horizontal_scrollbar_;
-  }
-  GraphicsLayer* LayerForVerticalScrollbar() const {
-    return layer_for_vertical_scrollbar_;
-  }
-  GraphicsLayer* LayerForScrollCorner() const {
-    return layer_for_scroll_corner_;
-  }
-
-  // Returns true if the overflow controls cannot be positioned within this
-  // CLM's internal hierarchy without incorrectly stacking under some
-  // scrolling content. If this returns true, these controls must be
-  // repositioned in the graphics layer tree to ensure that they stack above
-  // scrolling content.
-  bool NeedsToReparentOverflowControls() const;
-
-  // Move overflow control layers from its parent into the vector.
-  // Returns the number of layers moved.
-  wtf_size_t MoveOverflowControlLayersInto(GraphicsLayerVector&,
-                                           wtf_size_t position);
-
-  void SetBlendMode(BlendMode);
-
-  bool NeedsGraphicsLayerUpdate() {
-    return pending_update_scope_ > kGraphicsLayerUpdateNone;
-  }
-  void SetNeedsGraphicsLayerUpdate(GraphicsLayerUpdateScope scope) {
-    pending_update_scope_ = std::max(
-        static_cast<GraphicsLayerUpdateScope>(pending_update_scope_), scope);
-  }
-  void ClearNeedsGraphicsLayerUpdate() {
-    pending_update_scope_ = kGraphicsLayerUpdateNone;
-  }
-
-  GraphicsLayerUpdater::UpdateType UpdateTypeForChildren(
-      GraphicsLayerUpdater::UpdateType) const;
-
-#if DCHECK_IS_ON()
-  void AssertNeedsToUpdateGraphicsLayerBitsCleared() {
-    DCHECK_EQ(pending_update_scope_,
-              static_cast<unsigned>(kGraphicsLayerUpdateNone));
-  }
-#endif
-
-  String DebugName(const GraphicsLayer*) const;
-
-  PhysicalOffset ContentOffsetInCompositingLayer() const;
-
-  // If there is a squashed layer painting into this CLM that is an ancestor of
-  // the given LayoutObject, return it. Otherwise return nullptr.
-  const GraphicsLayerPaintInfo* ContainingSquashedLayerInSquashingLayer(
-      const LayoutObject*,
-      unsigned max_squashed_layer_index) const;
-
-  // Returns whether an adjustment happend.
-  bool AdjustForCompositedScrolling(const GraphicsLayer*,
-                                    gfx::Vector2d& offset) const;
-
- private:
-  // Returns true for layers with scrollable overflow which have a background
-  // that can be painted into the composited scrolling contents layer (i.e.
-  // the background can scroll with the content). When the background is also
-  // opaque this allows us to composite the scroller even on low DPI as we can
-  // draw with subpixel anti-aliasing.
-  bool BackgroundPaintsOntoScrollingContentsLayer() const {
-    return GetLayoutObject().GetBackgroundPaintLocation() &
-           kBackgroundPaintInContentsSpace;
-  }
-
-  // Returns true if the background paints onto the main graphics layer.
-  // In some situations, we may paint background on both the main graphics layer
-  // and the scrolling contents layer.
-  bool BackgroundPaintsOntoGraphicsLayer() const {
-    return GetLayoutObject().GetBackgroundPaintLocation() &
-           kBackgroundPaintInBorderBoxSpace;
-  }
-
-  gfx::Rect RecomputeInterestRect(const GraphicsLayer*) const;
-  static bool InterestRectChangedEnoughToRepaint(
-      const gfx::Rect& previous_interest_rect,
-      const gfx::Rect& new_interest_rect,
-      const gfx::Size& layer_size);
-
-  static const GraphicsLayerPaintInfo* ContainingSquashedLayer(
-      const LayoutObject*,
-      const HeapVector<Member<GraphicsLayerPaintInfo>>& layers,
-      unsigned max_squashed_layer_index);
-
-  // Paints the scrollbar part associated with the given graphics layer into the
-  // given context.
-  void PaintScrollableArea(const GraphicsLayer*,
-                           GraphicsContext&,
-                           const gfx::Rect& interest_rect) const;
-  // Returns whether the given layer is part of the scrollable area, if any,
-  // associated with this mapping.
-  bool IsScrollableAreaLayer(const GraphicsLayer*) const;
-
-  // Returns whether the given layer is a repaint needed part of the scrollable
-  // area, if any, associated with this mapping.
-  bool IsScrollableAreaLayerWhichNeedsRepaint(const GraphicsLayer*) const;
-
-  // Helper methods to updateGraphicsLayerGeometry:
-  void ComputeGraphicsLayerParentLocation(
-      const PaintLayer* compositing_container,
-      gfx::Point& graphics_layer_parent_location);
-  void UpdateSquashingLayerGeometry(
-      const PaintLayer* compositing_container,
-      const gfx::Point& snapped_offset_from_composited_ancestor,
-      HeapVector<Member<GraphicsLayerPaintInfo>>& layers,
-      HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation);
-  void UpdateMainGraphicsLayerGeometry(
-      const gfx::Rect& local_compositing_bounds);
-  void UpdateMaskLayerGeometry();
-  void UpdateForegroundLayerGeometry();
-  void UpdateDecorationOutlineLayerGeometry(
-      const gfx::Size& relative_compositing_bounds_size);
-  void UpdateScrollingContentsLayerGeometry(
-      HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation);
-
-  void CreatePrimaryGraphicsLayer();
-
-  Member<GraphicsLayer> CreateGraphicsLayer(
-      CompositingReasons,
-      SquashingDisallowedReasons = SquashingDisallowedReason::kNone);
-
-  LayoutBoxModelObject& GetLayoutObject() const {
-    return owning_layer_->GetLayoutObject();
-  }
-
-  void UpdateInternalHierarchy();
-  void UpdatePaintingPhases();
-  bool UpdateForegroundLayer(bool needs_foreground_layer);
-  bool UpdateDecorationOutlineLayer(bool needs_decoration_outline_layer);
-  bool UpdateMaskLayer(bool needs_mask_layer);
-  bool RequiresHorizontalScrollbarLayer() const;
-  bool RequiresVerticalScrollbarLayer() const;
-  bool RequiresScrollCornerLayer() const;
-  bool UpdateSquashingLayers(bool needs_squashing_layers);
-  void UpdateDrawsContentAndPaintsHitTest();
-  void UpdateCompositedBounds();
-
-  // Also sets subpixelAccumulation on the layer.
-  void ComputeBoundsOfOwningLayer(
-      const PaintLayer* composited_ancestor,
-      gfx::Rect& local_compositing_bounds,
-      gfx::Point& snapped_offset_from_composited_ancestor);
-
-  GraphicsLayerPaintingPhase PaintingPhaseForPrimaryLayer() const;
-
-  bool PaintsChildren() const;
-
-  // Returns true if this layer has content that needs to be displayed by
-  // painting into the backing store.
-  bool ContainsPaintedContent() const;
-
-  void UpdateContentsRect();
-
-  static bool HasVisibleNonCompositingDescendant(PaintLayer* parent);
-
-  void DoPaintTask(const GraphicsLayerPaintInfo&,
-                   const GraphicsLayer&,
-                   PaintLayerFlags,
-                   GraphicsContext&,
-                   const gfx::Rect& clip) const;
-
-  // Computes the background clip rect for the given squashed layer, up to any
-  // containing layer that is squashed into the same squashing layer and
-  // contains this squashed layer's clipping ancestor.  The clip rect is
-  // returned in the coordinate space of the given squashed layer.  If there is
-  // no such containing layer, returns the infinite rect.
-  static void UpdateLocalClipRectForSquashedLayer(
-      const PaintLayer& reference_layer,
-      const HeapVector<Member<GraphicsLayerPaintInfo>>& layers,
-      GraphicsLayerPaintInfo&);
-
-  bool UpdateSquashingLayerAssignmentInternal(
-      HeapVector<Member<GraphicsLayerPaintInfo>>& squashed_layers,
-      PaintLayer& squashed_layer,
-      wtf_size_t next_squashed_layer_index);
-
-  Member<PaintLayer> owning_layer_;
-
-  // The hierarchy of layers that is maintained by the CompositedLayerMapping
-  // looks like this:
-  //
-  //    + graphics_layer_
-  //      + layer_for_vertical_scrollbar_ [OPTIONAL][*]
-  //      + layer_for_horizontal_scrollbar_ [OPTIONAL][*]
-  //      + layer_for_scroll_corner_ [OPTIONAL][*]
-  //      + contents layers (or contents layers under scrolling_contents_layer_)
-  //      + decoration_outline_layer_ [OPTIONAL]
-  //      + mask_layer_ [ OPTIONAL ]
-  //      + non_scrolling_squashing_layer_ [ OPTIONAL ]
-  //
-  // [*] Overlay overflow controls may be placed above
-  //     scrolling_contents_layer_, or repositioned in the graphics layer tree
-  //     to ensure that they stack above scrolling content.
-  //
-  // Contents layers are directly under |graphics_layer_|, or under
-  // |scrolling_contents_layer_| when the layer is using composited scrolling.
-  // If owning_layer_ is a stacking context, contents layers include:
-  //   - negative z-index children
-  //   - foreground_layer_
-  //   - normal flow and positive z-index children
-  // If owning_layer_ is not a stacking context, contents layers are normal
-  // flow children.
-
-  Member<GraphicsLayer> graphics_layer_;
-
-  // Only used if the layer is using composited scrolling.
-  Member<GraphicsLayer> scrolling_contents_layer_;
-  gfx::Size previous_scroll_container_size_;
-
-  // Only used if we have a mask.
-  Member<GraphicsLayer> mask_layer_;
-
-  // There is one other (optional) layer whose painting is managed by the
-  // CompositedLayerMapping, but whose position in the hierarchy is maintained
-  // by the PaintLayerCompositor. This is the foreground layer. The foreground
-  // layer exists if we have composited descendants with negative z-order. We
-  // need the extra layer in this case because the layer needs to draw both
-  // below (for the background, say) and above (for the normal flow content,
-  // say) the negative z-order descendants and this is impossible with a single
-  // layer. The RLC handles inserting foreground_layer_ in the correct position
-  // in our descendant list for us (right after the neg z-order dsecendants).
-  // Only used in cases where we need to draw the foreground separately.
-  Member<GraphicsLayer> foreground_layer_;
-
-  Member<GraphicsLayer> layer_for_horizontal_scrollbar_;
-  Member<GraphicsLayer> layer_for_vertical_scrollbar_;
-  Member<GraphicsLayer> layer_for_scroll_corner_;
-
-  // DecorationLayer which paints outline.
-  Member<GraphicsLayer> decoration_outline_layer_;
-
-  // Only used when |non_scrolling_squashed_layers_| is not empty. This is
-  // the backing that |non_scrolling_squashed_layers_| paint into.
-  Member<GraphicsLayer> non_scrolling_squashing_layer_;
-  gfx::Vector2d non_scrolling_squashing_layer_offset_from_layout_object_;
-
-  // Layers that are squashed into |non_scrolling_squashing_layer_|.
-  HeapVector<Member<GraphicsLayerPaintInfo>> non_scrolling_squashed_layers_;
-
-  // Layers that are squashed into |scrolling_contents_layer_|. This is used
-  // when |owning_layer_| is scrollable but is not a stacking context, and
-  // there are scrolling stacked children that can be squashed into the
-  // scrolling contents without breaking stacking order. We don't need a special
-  // layer like |non_scrolling_squashing_layer_| because these squashed layers
-  // are always contained by |scrolling_contents_layer_|.
-  HeapVector<Member<GraphicsLayerPaintInfo>>
-      squashed_layers_in_scrolling_contents_;
-
-  PhysicalRect composited_bounds_;
-
-  unsigned pending_update_scope_ : 2;
-
-#if DCHECK_IS_ON()
-  bool is_destroyed_ = false;
-#endif
-
-  friend class CompositedLayerMappingTest;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITED_LAYER_MAPPING_H_
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.cc b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.cc
deleted file mode 100644
index fddd8d0..0000000
--- a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#include "third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.h"
-
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
-
-namespace blink {
-
-void CompositingInputsRoot::Update(PaintLayer* new_root_layer) {
-  DCHECK(new_root_layer);
-
-  if (!root_layer_) {
-    // This is the first time we call Update() so just let set the root layer.
-    root_layer_ = new_root_layer;
-    return;
-  }
-
-  if (root_layer_ == new_root_layer)
-    return;
-
-  PaintLayer* common_ancestor =
-      const_cast<PaintLayer*>(root_layer_->CommonAncestor(new_root_layer));
-  if (!common_ancestor)
-    common_ancestor = const_cast<PaintLayer*>(root_layer_->Root());
-
-  root_layer_ = common_ancestor;
-}
-
-void CompositingInputsRoot::Trace(Visitor* visitor) const {
-  visitor->Trace(root_layer_);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.h b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.h
deleted file mode 100644
index 37ccb88c..0000000
--- a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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_CORE_PAINT_COMPOSITING_COMPOSITING_INPUTS_ROOT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_INPUTS_ROOT_H_
-
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class PaintLayer;
-
-class CompositingInputsRoot {
-  DISALLOW_NEW();
-
- public:
-  PaintLayer* Get() const { return root_layer_; }
-
-  void Update(PaintLayer* new_root_layer);
-  void Clear() { root_layer_ = nullptr; }
-
-  void Trace(Visitor* visitor) const;
-
- private:
-  Member<PaintLayer> root_layer_ = nullptr;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_INPUTS_ROOT_H_
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc
deleted file mode 100644
index 8099bfb..0000000
--- a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.h"
-
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
-#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
-#include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
-#include "third_party/blink/renderer/core/paint/fragment_data.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-
-namespace {
-enum class ScrollbarOrCorner {
-  kHorizontalScrollbar,
-  kVerticalScrollbar,
-  kScrollbarCorner,
-};
-}
-
-namespace blink {
-
-void CompositingLayerPropertyUpdater::Update(const LayoutObject& object) {
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    return;
-
-  if (!object.HasLayer())
-    return;
-  const auto* paint_layer = To<LayoutBoxModelObject>(object).Layer();
-  const auto* mapping = paint_layer->GetCompositedLayerMapping();
-  if (!mapping)
-    return;
-
-  const FragmentData& fragment_data = object.PrimaryStitchingFragment();
-  DCHECK(fragment_data.HasLocalBorderBoxProperties());
-  // SPv1 compositing forces single fragment for directly composited elements.
-  DCHECK(object.IsLayoutNGObject() || !object.FirstFragment().NextFragment() ||
-         // We create multiple fragments for composited repeating fixed-position
-         // during printing.
-         object.GetDocument().Printing());
-
-  PhysicalOffset layout_snapped_paint_offset =
-      fragment_data.PaintOffset() - paint_layer->SubpixelAccumulation();
-  gfx::Vector2d snapped_paint_offset =
-      ToRoundedPoint(layout_snapped_paint_offset).OffsetFromOrigin();
-
-#if DCHECK_IS_ON()
-  // A layer without visible contents can be composited due to animation.
-  // Since the layer itself has no visible subtree, there is no guarantee
-  // that all of its ancestors have a visible subtree. An ancestor with no
-  // visible subtree can be non-composited despite we expected it to, this
-  // resulted in the paint offset used by CompositedLayerMapping to mismatch.
-  bool subpixel_accumulation_may_be_bogus = paint_layer->SubtreeIsInvisible();
-  if (!subpixel_accumulation_may_be_bogus &&
-      layout_snapped_paint_offset != PhysicalOffset(snapped_paint_offset)) {
-    // TODO(crbug.com/925377): Fix the root cause.
-    DLOG(ERROR) << "Paint offset pixel snapping error for " << object
-                << " expected: " << snapped_paint_offset.ToString()
-                << " actual: " << layout_snapped_paint_offset;
-  }
-#endif
-
-  absl::optional<PropertyTreeStateOrAlias> container_layer_state;
-  auto SetContainerLayerState =
-      [&fragment_data, &snapped_paint_offset,
-       &container_layer_state](GraphicsLayer* graphics_layer) {
-        if (graphics_layer) {
-          if (!container_layer_state)
-            container_layer_state = fragment_data.LocalBorderBoxProperties();
-          graphics_layer->SetLayerState(
-              *container_layer_state,
-              snapped_paint_offset + graphics_layer->OffsetFromLayoutObject());
-        }
-      };
-  SetContainerLayerState(mapping->MainGraphicsLayer());
-  SetContainerLayerState(mapping->DecorationOutlineLayer());
-
-  bool is_root_scroller =
-      CompositingReasonFinder::RequiresCompositingForRootScroller(*paint_layer);
-
-  auto SetContainerLayerStateForScrollbars =
-      [&object, &is_root_scroller, &fragment_data, &snapped_paint_offset,
-       &container_layer_state](GraphicsLayer* graphics_layer,
-                               ScrollbarOrCorner scrollbar_or_corner) {
-        if (!graphics_layer)
-          return;
-        PropertyTreeStateOrAlias scrollbar_layer_state =
-            container_layer_state.value_or(
-                fragment_data.LocalBorderBoxProperties());
-        // OverflowControlsClip should be applied within the scrollbar layers.
-        if (const auto* properties = fragment_data.PaintProperties()) {
-          if (const auto* clip = properties->OverflowControlsClip())
-            scrollbar_layer_state.SetClip(*clip);
-
-          if (scrollbar_or_corner == ScrollbarOrCorner::kHorizontalScrollbar) {
-            if (const auto* effect = properties->HorizontalScrollbarEffect()) {
-              scrollbar_layer_state.SetEffect(*effect);
-            }
-          } else if (scrollbar_or_corner ==
-                     ScrollbarOrCorner::kVerticalScrollbar) {
-            if (const auto* effect = properties->VerticalScrollbarEffect())
-              scrollbar_layer_state.SetEffect(*effect);
-          }
-        }
-
-        if (is_root_scroller) {
-          // The root scrollbar needs to use a transform node above the
-          // overscroll elasticity layer because the root scrollbar should not
-          // bounce with overscroll.
-          const auto* frame_view = object.GetFrameView();
-          DCHECK(frame_view);
-          const auto* page = frame_view->GetPage();
-          const auto& viewport = page->GetVisualViewport();
-          if (const auto* transform =
-                  viewport.GetOverscrollElasticityTransformNode()) {
-            DCHECK(transform->Parent());
-            scrollbar_layer_state.SetTransform(*transform->Parent());
-          }
-        }
-
-        graphics_layer->SetLayerState(
-            scrollbar_layer_state,
-            snapped_paint_offset + graphics_layer->OffsetFromLayoutObject());
-      };
-
-  SetContainerLayerStateForScrollbars(mapping->LayerForHorizontalScrollbar(),
-                                      ScrollbarOrCorner::kHorizontalScrollbar);
-  SetContainerLayerStateForScrollbars(mapping->LayerForVerticalScrollbar(),
-                                      ScrollbarOrCorner::kVerticalScrollbar);
-  SetContainerLayerStateForScrollbars(mapping->LayerForScrollCorner(),
-                                      ScrollbarOrCorner::kScrollbarCorner);
-
-  if (mapping->ScrollingContentsLayer()) {
-    // See comments for ScrollTranslation in object_paint_properties.h for the
-    // reason of adding ScrollOrigin().
-    auto contents_paint_offset =
-        snapped_paint_offset +
-        To<LayoutBox>(object).ScrollOrigin().OffsetFromOrigin();
-    auto SetScrollingContentsLayerState = [&fragment_data,
-                                           &contents_paint_offset](
-                                              GraphicsLayer* graphics_layer) {
-      if (graphics_layer) {
-        graphics_layer->SetLayerState(
-            fragment_data.ContentsProperties(),
-            contents_paint_offset + graphics_layer->OffsetFromLayoutObject());
-      }
-    };
-    SetScrollingContentsLayerState(mapping->ScrollingContentsLayer());
-    SetScrollingContentsLayerState(mapping->ForegroundLayer());
-  } else {
-    SetContainerLayerState(mapping->ForegroundLayer());
-  }
-
-  auto* main_graphics_layer = mapping->MainGraphicsLayer();
-  if (main_graphics_layer->ContentsLayer()) {
-    gfx::Vector2d offset;
-    // The offset should be zero when the layer has ReplacedContentTransform,
-    // because the offset has been baked into ReplacedContentTransform.
-    if (!fragment_data.PaintProperties() ||
-        !fragment_data.PaintProperties()->ReplacedContentTransform()) {
-      offset = main_graphics_layer->ContentsRect().OffsetFromOrigin() +
-               main_graphics_layer->GetOffsetFromTransformNode();
-    }
-    main_graphics_layer->SetContentsLayerState(
-        fragment_data.ContentsProperties(), offset);
-  }
-
-  if (auto* squashing_layer = mapping->NonScrollingSquashingLayer()) {
-    auto state = fragment_data.PreEffectProperties();
-    // The squashing layer's ClippingContainer is the common ancestor of clip
-    // state of all squashed layers, so we should use its clip state. This skips
-    // any control clips on the squashing layer's object which should not apply
-    // on squashed layers.
-    const LayoutBoxModelObject* clipping_container = nullptr;
-    state.SetClip(
-        clipping_container
-            ? clipping_container->FirstFragment().ContentsProperties().Clip()
-            : ClipPaintPropertyNode::Root());
-    squashing_layer->SetLayerState(
-        state, snapped_paint_offset +
-                   mapping->NonScrollingSquashingLayerOffsetFromLayoutObject());
-  }
-
-  if (auto* mask_layer = mapping->MaskLayer()) {
-    auto state = fragment_data.LocalBorderBoxProperties();
-    const auto* properties = fragment_data.PaintProperties();
-    DCHECK(properties);
-    DCHECK(properties->Mask() || properties->ClipPathMask());
-    DCHECK(properties->MaskClip());
-    state.SetEffect(properties->Mask() ? *properties->Mask()
-                                       : *properties->ClipPathMask());
-    state.SetClip(*properties->MaskClip());
-
-    mask_layer->SetLayerState(
-        state, snapped_paint_offset + mask_layer->OffsetFromLayoutObject());
-  }
-
-  if (object.IsSVGRoot()) {
-    main_graphics_layer->SetShouldCreateLayersAfterPaint(
-        To<LayoutSVGRoot>(object).HasDescendantCompositingReasons() &&
-        main_graphics_layer->PaintsContentOrHitTest());
-  }
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.h b/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.h
deleted file mode 100644
index ac313bab..0000000
--- a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_LAYER_PROPERTY_UPDATER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_LAYER_PROPERTY_UPDATER_H_
-
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class LayoutObject;
-
-class CompositingLayerPropertyUpdater {
-  STATIC_ONLY(CompositingLayerPropertyUpdater);
-
- public:
-  static void Update(const LayoutObject&);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_LAYER_PROPERTY_UPDATER_H_
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
index bcaac55..2a7251e 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
@@ -13,7 +13,6 @@
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/scroll/scroll_types.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
@@ -69,10 +68,6 @@
       style='width: 100px; height: 100px; transform: translateZ(0)'></div>
   )HTML");
 
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    PaintLayer* paint_layer = GetPaintLayerByElementId("target");
-    EXPECT_EQ(kPaintsIntoOwnBacking, paint_layer->GetCompositingState());
-  }
   EXPECT_REASONS(
       CompositingReason::kTrivial3DTransform,
       DirectReasonsForPaintProperties(*GetLayoutObjectByElementId("target")));
@@ -84,10 +79,6 @@
       style='width: 100px; height: 100px; transform: translateZ(1px)'></div>
   )HTML");
 
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    PaintLayer* paint_layer = GetPaintLayerByElementId("target");
-    EXPECT_EQ(kPaintsIntoOwnBacking, paint_layer->GetCompositingState());
-  }
   EXPECT_REASONS(
       CompositingReason::k3DTransform,
       DirectReasonsForPaintProperties(*GetLayoutObjectByElementId("target")));
@@ -107,10 +98,6 @@
       style='width: 100px; height: 100px; transform: translateZ(0)'></div>
   )HTML");
 
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    PaintLayer* paint_layer = GetPaintLayerByElementId("target");
-    EXPECT_EQ(kNotComposited, paint_layer->GetCompositingState());
-  }
   EXPECT_REASONS(
       CompositingReason::kNone,
       DirectReasonsForPaintProperties(*GetLayoutObjectByElementId("target")));
@@ -129,13 +116,6 @@
     </div>
   )HTML");
 
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    EXPECT_EQ(kPaintsIntoOwnBacking,
-              GetPaintLayerByElementId("sticky-top")->GetCompositingState());
-    EXPECT_EQ(
-        kNotComposited,
-        GetPaintLayerByElementId("sticky-no-anchor")->GetCompositingState());
-  }
   EXPECT_REASONS(CompositingReason::kStickyPosition,
                  DirectReasonsForPaintProperties(
                      *GetLayoutObjectByElementId("sticky-top")));
@@ -209,17 +189,6 @@
       CompositingReason::kNone,
       CompositingReasonFinder::CompositingReasonsForScrollDependentPosition(
           *overflow_hidden_no_scrolling.Layer()));
-
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    EXPECT_EQ(kPaintsIntoOwnBacking,
-              sticky_scrolling.Layer()->GetCompositingState());
-    EXPECT_EQ(kNotComposited,
-              sticky_no_scrolling.Layer()->GetCompositingState());
-    EXPECT_EQ(kPaintsIntoOwnBacking,
-              overflow_hidden_scrolling.Layer()->GetCompositingState());
-    EXPECT_EQ(kNotComposited,
-              overflow_hidden_no_scrolling.Layer()->GetCompositingState());
-  }
 }
 
 void CompositingReasonFinderTest::CheckCompositingReasonsForAnimation(
@@ -292,11 +261,6 @@
   ASSERT_TRUE(child_frame);
   LocalFrameView* child_frame_view = child_frame->View();
   ASSERT_TRUE(child_frame_view);
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    EXPECT_EQ(
-        kNotComposited,
-        child_frame_view->GetLayoutView()->Layer()->GetCompositingState());
-  }
   EXPECT_TRUE(child_frame_view->CanThrottleRendering());
 }
 
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_state.h b/third_party/blink/renderer/core/paint/compositing/compositing_state.h
deleted file mode 100644
index 5646f9f..0000000
--- a/third_party/blink/renderer/core/paint/compositing/compositing_state.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_STATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_STATE_H_
-
-namespace blink {
-
-enum CompositingState {
-  // The layer paints into its enclosing composited ancestor.
-  kNotComposited = 0,
-
-  kPaintsIntoOwnBacking = 1,
-
-  // In this state, the Layer subtree paints into a backing that is shared by
-  // several Layer subtrees.
-  kPaintsIntoGroupedBacking = 2
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_STATE_H_
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
index 029ad0ab..c0c2f92 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
@@ -23,7 +23,6 @@
 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/svg_names.h"
diff --git a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc b/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
deleted file mode 100644
index e3e797a..0000000
--- a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
- * 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h"
-
-#include "third_party/blink/renderer/core/html/media/html_media_element.h"
-#include "third_party/blink/renderer/core/html/media/html_video_element.h"
-#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/core/paint/paint_layer_paint_order_iterator.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/clear_collection_scope.h"
-
-namespace blink {
-
-GraphicsLayerTreeBuilder::GraphicsLayerTreeBuilder() = default;
-
-static bool ShouldAppendLayer(const PaintLayer& layer) {
-  auto* video_element =
-      DynamicTo<HTMLVideoElement>(layer.GetLayoutObject().GetNode());
-  if (video_element && video_element->IsFullscreen() &&
-      video_element->UsesOverlayFullscreenVideo()) {
-    return false;
-  }
-  return true;
-}
-
-void GraphicsLayerTreeBuilder::Rebuild(PaintLayer& layer,
-                                       GraphicsLayerVector& child_layers) {
-  PendingOverflowControlReparents ignored;
-  ClearCollectionScope<PendingOverflowControlReparents> scope(&ignored);
-  RebuildRecursive(layer, child_layers, ignored);
-}
-
-using PendingPair = std::pair<const PaintLayer*, wtf_size_t>;
-
-void GraphicsLayerTreeBuilder::RebuildRecursive(
-    PaintLayer& layer,
-    GraphicsLayerVector& child_layers,
-    PendingOverflowControlReparents& pending_reparents) {
-  // Make the layer compositing if necessary, and set up clipping and content
-  // layers.  Note that we can only do work here that is independent of whether
-  // the descendant layers have been processed. computeCompositingRequirements()
-  // will already have done the paint invalidation if necessary.
-
-  const bool has_composited_layer_mapping = layer.HasCompositedLayerMapping();
-  CompositedLayerMapping* current_composited_layer_mapping =
-      layer.GetCompositedLayerMapping();
-
-  // If this layer has a compositedLayerMapping, then that is where we place
-  // subsequent children GraphicsLayers.  Otherwise children continue to append
-  // to the child list of the enclosing layer.
-  GraphicsLayerVector this_layer_children;
-  GraphicsLayerVector* layer_vector_for_children =
-      has_composited_layer_mapping ? &this_layer_children : &child_layers;
-
-  PendingOverflowControlReparents this_pending_reparents_children;
-  ClearCollectionScope<PendingOverflowControlReparents> scope(
-      &this_pending_reparents_children);
-
-  PendingOverflowControlReparents* pending_reparents_for_children =
-      has_composited_layer_mapping ? &this_pending_reparents_children
-                                   : &pending_reparents;
-
-#if DCHECK_IS_ON()
-  PaintLayerListMutationDetector mutation_checker(&layer);
-#endif
-
-  bool recursion_blocked_by_display_lock =
-      layer.GetLayoutObject().ChildPrePaintBlockedByDisplayLock();
-  if (layer.IsStackingContextWithNegativeZOrderChildren()) {
-    if (!recursion_blocked_by_display_lock) {
-      PaintLayerPaintOrderIterator iterator(&layer, kNegativeZOrderChildren);
-      while (PaintLayer* child_layer = iterator.Next()) {
-        RebuildRecursive(*child_layer, *layer_vector_for_children,
-                         *pending_reparents_for_children);
-      }
-    }
-
-    // If a negative z-order child is compositing, we get a foreground layer
-    // which needs to get parented.
-    if (has_composited_layer_mapping &&
-        current_composited_layer_mapping->ForegroundLayer()) {
-      layer_vector_for_children->push_back(
-          current_composited_layer_mapping->ForegroundLayer());
-    }
-  }
-
-  if (!recursion_blocked_by_display_lock) {
-    PaintLayerPaintOrderIterator iterator(&layer,
-                                          kNormalFlowAndPositiveZOrderChildren);
-    while (PaintLayer* child_layer = iterator.Next()) {
-      RebuildRecursive(*child_layer, *layer_vector_for_children,
-                       *pending_reparents_for_children);
-    }
-  }
-
-  if (has_composited_layer_mapping) {
-    // TODO(szager): Remove after diagnosing crash crbug.com/1092673
-    CHECK(current_composited_layer_mapping);
-
-    // Apply all pending reparents by inserting the overflow controls
-    // root layers into |this_layer_children|. To do this, first sort
-    // them by index. Then insert them one-by-one into the array,
-    // incrementing |offset| by one each time to account for previous
-    // insertions.
-    wtf_size_t offset = 0;
-    Vector<PendingPair> pending;
-    for (auto& item : *pending_reparents_for_children)
-      pending.push_back(std::make_pair(item.key, item.value));
-    pending_reparents_for_children->clear();
-
-    std::sort(pending.begin(), pending.end(),
-              [](const PendingPair& a, const PendingPair& b) {
-                return a.second < b.second;
-              });
-    for (auto& item : pending) {
-      offset += item.first->GetCompositedLayerMapping()
-                    ->MoveOverflowControlLayersInto(this_layer_children,
-                                                    item.second + offset);
-    }
-
-    if (!this_layer_children.IsEmpty()) {
-      current_composited_layer_mapping->SetSublayers(
-          std::move(this_layer_children));
-    }
-
-    if (ShouldAppendLayer(layer)) {
-      child_layers.push_back(
-          current_composited_layer_mapping->MainGraphicsLayer());
-    }
-  }
-
-  // Also insert for self, to handle the case of scrollers with negative
-  // z-index children (the scrolbars should still paint on top of the
-  // scroller itself).
-  if (layer.GetLayoutObject().IsStacked() && has_composited_layer_mapping &&
-      layer.GetCompositedLayerMapping()->NeedsToReparentOverflowControls())
-    pending_reparents.Set(&layer, child_layers.size());
-
-  // Set or overwrite the entry in |pending_reparents| for this scroller.
-  // Overlay scrollbars need to paint on top of all content under the scroller,
-  // so keep overwriting if we find a PaintLayer that is later in paint order.
-  const PaintLayer* scroll_parent = layer.ScrollParent();
-  if (layer.GetLayoutObject().IsStacked() && scroll_parent &&
-      scroll_parent->HasCompositedLayerMapping() &&
-      scroll_parent->GetCompositedLayerMapping()
-          ->NeedsToReparentOverflowControls())
-    pending_reparents.Set(layer.ScrollParent(), child_layers.size());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h b/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h
deleted file mode 100644
index 8fbe89e6..0000000
--- a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
- * 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_GRAPHICS_LAYER_TREE_BUILDER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_GRAPHICS_LAYER_TREE_BUILDER_H_
-
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class PaintLayer;
-
-class GraphicsLayerTreeBuilder {
-  STACK_ALLOCATED();
-
- public:
-  GraphicsLayerTreeBuilder();
-
-  void Rebuild(PaintLayer&, GraphicsLayerVector&);
-
- private:
-  // Maps from PaintLayer::ScrollParent to index into |child_layers| (see below
-  // for child_layers parameter) at which to insert the overflow controls
-  // graphics layers for ScrollParent when reparenting them.
-  using PendingOverflowControlReparents =
-      HeapHashMap<Member<const PaintLayer>, size_t>;
-
-  void RebuildRecursive(PaintLayer&,
-                        GraphicsLayerVector& child_layers,
-                        PendingOverflowControlReparents& pending_reparents);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_GRAPHICS_LAYER_TREE_BUILDER_H_
diff --git a/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc b/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc
deleted file mode 100644
index 09bb3119..0000000
--- a/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
- * 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.h"
-
-#include "third_party/blink/renderer/core/html/media/html_media_element.h"
-#include "third_party/blink/renderer/core/layout/layout_block.h"
-#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
-#include "third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
-#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
-
-namespace blink {
-
-GraphicsLayerUpdater::UpdateContext::UpdateContext()
-    : compositing_stacking_context_(nullptr),
-      compositing_ancestor_(nullptr),
-      use_slow_path_(false) {}
-
-GraphicsLayerUpdater::UpdateContext::UpdateContext(const UpdateContext& other,
-                                                   const PaintLayer& layer)
-    : compositing_stacking_context_(other.compositing_stacking_context_),
-      compositing_ancestor_(other.CompositingContainer(layer)),
-      use_slow_path_(other.use_slow_path_) {
-  CompositingState compositing_state = layer.GetCompositingState();
-  if (compositing_state != kNotComposited &&
-      compositing_state != kPaintsIntoGroupedBacking) {
-    compositing_ancestor_ = &layer;
-    if (layer.GetLayoutObject().IsStackingContext())
-      compositing_stacking_context_ = &layer;
-  }
-  // Any composited content under SVG must be a descendant of (but not
-  // equal to, see PaintLayerCompositor::CanBeComposited)
-  // a <foreignObject> element. The rules for compositing ancestors are
-  // complicated for this situation, due to <foreignObject> being a replaced
-  // nornmal-flow stacking element
-  // (see PaintLayer::IsReplacedNormalFlowStacking). Use a slow path
-  // for these situations, to simplify the logic.
-  if (layer.GetLayoutObject().IsSVGRoot() ||
-      layer.IsReplacedNormalFlowStacking())
-    use_slow_path_ = true;
-
-  parent_object_offset_delta =
-      compositing_ancestor_ == other.compositing_ancestor_
-          ? other.parent_object_offset_delta
-          : other.object_offset_delta;
-}
-
-const PaintLayer* GraphicsLayerUpdater::UpdateContext::CompositingContainer(
-    const PaintLayer& layer) const {
-  if (use_slow_path_)
-    return layer.EnclosingLayerWithCompositedLayerMapping(kExcludeSelf);
-
-  const PaintLayer* compositing_container;
-  if (layer.GetLayoutObject().IsStacked() &&
-      !layer.IsReplacedNormalFlowStacking()) {
-    compositing_container = compositing_stacking_context_;
-  } else if ((layer.Parent() &&
-              !layer.Parent()->GetLayoutObject().IsLayoutBlock()) ||
-             layer.GetLayoutObject().IsColumnSpanAll()) {
-    // In these cases, compositingContainer may escape the normal layer
-    // hierarchy. Use the slow path to ensure correct result.
-    // See PaintLayer::containingLayer() for details.
-    compositing_container =
-        layer.EnclosingLayerWithCompositedLayerMapping(kExcludeSelf);
-  } else {
-    compositing_container = compositing_ancestor_;
-  }
-
-  // We should always get the same result as the slow path.
-  DCHECK_EQ(compositing_container,
-            layer.EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
-  return compositing_container;
-}
-
-const PaintLayer*
-GraphicsLayerUpdater::UpdateContext::CompositingStackingContext() const {
-  return compositing_stacking_context_;
-}
-
-GraphicsLayerUpdater::GraphicsLayerUpdater() : needs_rebuild_tree_(false) {}
-
-void GraphicsLayerUpdater::Update(
-    PaintLayer& layer,
-    HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation) {
-  TRACE_EVENT0("blink", "GraphicsLayerUpdater::update");
-  UpdateContext update_context;
-  UpdateRecursive(layer, kDoNotForceUpdate, update_context,
-                  layers_needing_paint_invalidation);
-}
-
-void GraphicsLayerUpdater::UpdateRecursive(
-    PaintLayer& layer,
-    UpdateType update_type,
-    UpdateContext& context,
-    HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation) {
-  if (layer.HasCompositedLayerMapping()) {
-    CompositedLayerMapping* mapping = layer.GetCompositedLayerMapping();
-
-    if (update_type == kForceUpdate || mapping->NeedsGraphicsLayerUpdate()) {
-      bool had_scrolling_layer = mapping->ScrollingContentsLayer();
-      const auto* compositing_container = context.CompositingContainer(layer);
-      if (mapping->UpdateGraphicsLayerConfiguration(compositing_container)) {
-        needs_rebuild_tree_ = true;
-        // Change of existence of scrolling layer affects visual rect offsets of
-        // descendants via LayoutObject::ScrollAdjustmentForPaintInvalidation().
-        if (had_scrolling_layer != !!mapping->ScrollingContentsLayer())
-          layers_needing_paint_invalidation.push_back(&layer);
-      }
-      mapping->UpdateGraphicsLayerGeometry(compositing_container,
-                                           layers_needing_paint_invalidation);
-      if (PaintLayerScrollableArea* scrollable_area = layer.GetScrollableArea())
-        scrollable_area->PositionOverflowControls();
-      update_type = mapping->UpdateTypeForChildren(update_type);
-      mapping->ClearNeedsGraphicsLayerUpdate();
-
-      // TODO(crbug.com/1058792): Allow multiple fragments for composited
-      // elements (passing |iterator| here is probably part of the solution).
-      CompositingLayerPropertyUpdater::Update(layer.GetLayoutObject());
-    }
-  }
-
-  PaintLayer* first_child = layer.FirstChild();
-  // If we have children but the update is blocked, then we should clear the
-  // first child to block recursion.
-  if (first_child &&
-      layer.GetLayoutObject().ChildPrePaintBlockedByDisplayLock()) {
-    first_child = nullptr;
-  }
-
-  UpdateContext child_context(context, layer);
-  for (PaintLayer* child = first_child; child; child = child->NextSibling()) {
-    UpdateRecursive(*child, update_type, child_context,
-                    layers_needing_paint_invalidation);
-  }
-}
-
-#if DCHECK_IS_ON()
-
-void GraphicsLayerUpdater::AssertNeedsToUpdateGraphicsLayerBitsCleared(
-    PaintLayer& layer) {
-  if (layer.HasCompositedLayerMapping()) {
-    layer.GetCompositedLayerMapping()
-        ->AssertNeedsToUpdateGraphicsLayerBitsCleared();
-  }
-
-  PaintLayer* first_child =
-      layer.GetLayoutObject().ChildPrePaintBlockedByDisplayLock()
-          ? nullptr
-          : layer.FirstChild();
-  for (PaintLayer* child = first_child; child; child = child->NextSibling())
-    AssertNeedsToUpdateGraphicsLayerBitsCleared(*child);
-}
-
-#endif
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.h b/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.h
deleted file mode 100644
index 830e025..0000000
--- a/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
- * 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_GRAPHICS_LAYER_UPDATER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_GRAPHICS_LAYER_UPDATER_H_
-
-#include "base/dcheck_is_on.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class PaintLayer;
-
-class GraphicsLayerUpdater {
-  STACK_ALLOCATED();
-
- public:
-  GraphicsLayerUpdater();
-
-  enum UpdateType {
-    kDoNotForceUpdate,
-    kForceUpdate,
-  };
-
-  void Update(
-      PaintLayer&,
-      HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation);
-
-  bool NeedsRebuildTree() const { return needs_rebuild_tree_; }
-
-#if DCHECK_IS_ON()
-  static void AssertNeedsToUpdateGraphicsLayerBitsCleared(PaintLayer&);
-#endif
-
-  class UpdateContext {
-    STACK_ALLOCATED();
-
-   public:
-    UpdateContext();
-    UpdateContext(const UpdateContext& other, const PaintLayer& layer);
-    const PaintLayer* CompositingContainer(const PaintLayer& layer) const;
-    const PaintLayer* CompositingStackingContext() const;
-
-    // Offset of this PaintLayer's LayoutObject relative to the position of its
-    // main GraphicsLayer.
-    gfx::Vector2d object_offset_delta;
-
-    // The object_offset_delta of the compositing ancestor.
-    gfx::Vector2d parent_object_offset_delta;
-
-   private:
-    const PaintLayer* compositing_stacking_context_;
-    const PaintLayer* compositing_ancestor_;
-    bool use_slow_path_;
-  };
-
- private:
-  void UpdateRecursive(
-      PaintLayer&,
-      UpdateType,
-      UpdateContext&,
-      HeapVector<Member<PaintLayer>>& layers_needing_paint_invalidation);
-
-  bool needs_rebuild_tree_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_GRAPHICS_LAYER_UPDATER_H_
diff --git a/third_party/blink/renderer/core/paint/frame_painter.cc b/third_party/blink/renderer/core/paint/frame_painter.cc
index 9c76d96..1af0d43 100644
--- a/third_party/blink/renderer/core/paint/frame_painter.cc
+++ b/third_party/blink/renderer/core/paint/frame_painter.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
index 9396cc29f..572a327f 100644
--- a/third_party/blink/renderer/core/paint/link_highlight_impl.cc
+++ b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
@@ -47,7 +47,6 @@
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/fragment_data_iterator.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
@@ -56,7 +55,6 @@
 #include "third_party/blink/renderer/platform/animation/compositor_keyframe_model.h"
 #include "third_party/blink/renderer/platform/animation/compositor_target_property.h"
 #include "third_party/blink/renderer/platform/animation/timing_function.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_recorder.h"
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
index 53971c2..a51c5b17 100644
--- a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
+++ b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
@@ -48,7 +48,6 @@
 #include "third_party/blink/renderer/platform/animation/compositor_animation_timeline.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index c5f9bae..a039ee1 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -30,7 +30,6 @@
 #include "third_party/blink/renderer/core/paint/box_border_painter.h"
 #include "third_party/blink/renderer/core/paint/box_decoration_data.h"
 #include "third_party/blink/renderer/core/paint/box_painter.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h"
diff --git a/third_party/blink/renderer/core/paint/object_paint_invalidator.cc b/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
index aa420b6..61d6ac8 100644
--- a/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
@@ -9,143 +9,11 @@
 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 
 namespace blink {
 
-template <typename Functor>
-static void TraverseNonCompositingDescendantsInPaintOrder(const LayoutObject&,
-                                                          const Functor&);
-
-static bool MayBeSkippedContainerForFloating(const LayoutObject& object) {
-  return !object.IsInLayoutNGInlineFormattingContext() &&
-         !object.IsLayoutBlock();
-}
-
-template <typename Functor>
-static void
-TraverseNonCompositingDescendantsBelongingToAncestorPaintInvalidationContainer(
-    const LayoutObject& object,
-    const Functor& functor) {
-  // |object| is a paint invalidation container, but is not a stacking context
-  // (legacy layout only: or is a non-block), so the paint invalidation
-  // container of stacked descendants may not belong to |object| but belong to
-  // an ancestor. This function traverses all such descendants. See (legacy
-  // layout only: Case 1a and) Case 2 below for details.
-  DCHECK(object.IsPaintInvalidationContainer() &&
-         (!object.IsStackingContext() ||
-          MayBeSkippedContainerForFloating(object)));
-
-  LayoutObject* descendant = object.NextInPreOrder(&object);
-  while (descendant) {
-    if (!descendant->HasLayer() || !descendant->IsStacked()) {
-      // Case 1: The descendant is not stacked (or is stacked but has not been
-      // allocated a layer yet during style change), so either it's a paint
-      // invalidation container in the same situation as |object|, or its paint
-      // invalidation container is in such situation. Keep searching until a
-      // stacked layer is found.
-      if (MayBeSkippedContainerForFloating(object) &&
-          descendant->IsFloating()) {
-        // The following is for legacy layout only because LayoutNG allows an
-        // inline to contain floats.
-        // Case 1a (rare): However, if the descendant is a floating object below
-        // a composited non-block object, the subtree may belong to an ancestor
-        // in paint order, thus recur into the subtree. Note that for
-        // performance, we don't check whether the floating object's container
-        // is above or under |object|, so we may traverse more than expected.
-        // Example:
-        // <span id="object" class="position: relative; will-change: transform">
-        //   <div id="descendant" class="float: left"></div>"
-        // </span>
-        TraverseNonCompositingDescendantsInPaintOrder(*descendant, functor);
-        descendant = descendant->NextInPreOrderAfterChildren(&object);
-      } else {
-        descendant = descendant->NextInPreOrder(&object);
-      }
-    } else if (!descendant->IsPaintInvalidationContainer()) {
-      // Case 2: The descendant is stacked and is not composited.
-      // The invalidation container of its subtree is our ancestor,
-      // thus recur into the subtree.
-      TraverseNonCompositingDescendantsInPaintOrder(*descendant, functor);
-      descendant = descendant->NextInPreOrderAfterChildren(&object);
-    } else if (descendant->IsStackingContext() &&
-               !MayBeSkippedContainerForFloating(*descendant)) {
-      // Case 3: The descendant is an invalidation container and is a stacking
-      // context.  No objects in the subtree can have invalidation container
-      // outside of it, thus skip the whole subtree.
-      // Legacy layout only: This excludes non-block because there might be
-      // floating objects under the descendant belonging to some ancestor in
-      // paint order (Case 1a).
-      descendant = descendant->NextInPreOrderAfterChildren(&object);
-    } else {
-      // Case 4: The descendant is an invalidation container but not a stacking
-      // context, or the descendant is a non-block stacking context.
-      // This is the same situation as |object|, thus keep searching.
-      descendant = descendant->NextInPreOrder(&object);
-    }
-  }
-}
-
-template <typename Functor>
-static void TraverseNonCompositingDescendantsInPaintOrder(
-    const LayoutObject& object,
-    const Functor& functor) {
-  functor(object);
-  LayoutObject* descendant = object.NextInPreOrder(&object);
-  while (descendant) {
-    if (!descendant->IsPaintInvalidationContainer()) {
-      functor(*descendant);
-      descendant = descendant->NextInPreOrder(&object);
-    } else if (descendant->IsStackingContext() &&
-               !MayBeSkippedContainerForFloating(*descendant)) {
-      // The descendant is an invalidation container and is a stacking context.
-      // No objects in the subtree can have invalidation container outside of
-      // it, thus skip the whole subtree.
-      // Legacy layout only: This excludes non-blocks because there might be
-      // floating objects under the descendant belonging to some ancestor in
-      // paint order (Case 1a).
-      descendant = descendant->NextInPreOrderAfterChildren(&object);
-    } else {
-      // If a paint invalidation container is not a stacking context, or the
-      // descendant is a non-block stacking context, some of its descendants may
-      // belong to the parent container.
-      TraverseNonCompositingDescendantsBelongingToAncestorPaintInvalidationContainer(
-          *descendant, functor);
-      descendant = descendant->NextInPreOrderAfterChildren(&object);
-    }
-  }
-}
-
-static void SetPaintingLayerNeedsRepaintDuringTraverse(
-    const LayoutObject& object) {
-  if (object.HasLayer() &&
-      To<LayoutBoxModelObject>(object).HasSelfPaintingLayer()) {
-    To<LayoutBoxModelObject>(object).Layer()->SetNeedsRepaint();
-  } else if (object.IsFloating() && object.Parent() &&
-             MayBeSkippedContainerForFloating(*object.Parent())) {
-    // The following is for legacy layout only because LayoutNG allows an
-    // inline to contain floats.
-    object.PaintingLayer()->SetNeedsRepaint();
-  }
-}
-
-void ObjectPaintInvalidator::
-    InvalidatePaintIncludingNonCompositingDescendants() {
-  DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-  SlowSetPaintingLayerNeedsRepaint();
-  // This method may be used to invalidate paint of objects changing paint
-  // invalidation container.
-  // TODO(vmpstr): After paint containment isolation is in place, we might not
-  // have to recurse past the paint containment boundary.
-  TraverseNonCompositingDescendantsInPaintOrder(
-      object_, [](const LayoutObject& object) {
-        SetPaintingLayerNeedsRepaintDuringTraverse(object);
-      });
-}
-
 #if DCHECK_IS_ON()
 void ObjectPaintInvalidator::CheckPaintLayerNeedsRepaint() {
   DCHECK(!object_.PaintingLayer() ||
diff --git a/third_party/blink/renderer/core/paint/object_paint_invalidator.h b/third_party/blink/renderer/core/paint/object_paint_invalidator.h
index bc53051b..2065cb6 100644
--- a/third_party/blink/renderer/core/paint/object_paint_invalidator.h
+++ b/third_party/blink/renderer/core/paint/object_paint_invalidator.h
@@ -55,8 +55,6 @@
     client.Invalidate(reason);
   }
 
-  void InvalidatePaintIncludingNonCompositingDescendants();
-
  protected:
 #if DCHECK_IS_ON()
   void CheckPaintLayerNeedsRepaint();
diff --git a/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc b/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
index 6a34e8d..e6da083 100644
--- a/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
+++ b/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
@@ -12,7 +12,6 @@
 #include "third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/json/json_values.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 
diff --git a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
index a9f8de0..71be1aa5 100644
--- a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
@@ -6,7 +6,6 @@
 
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 
@@ -398,14 +397,6 @@
   GetDocument().View()->SetTracksRasterInvalidations(false);
 }
 
-static const LayoutBoxModelObject& EnclosingCompositedContainer(
-    const LayoutObject& layout_object) {
-  DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-  return layout_object.PaintingLayer()
-      ->EnclosingLayerForPaintInvalidationCrossingFrameBoundaries()
-      ->GetLayoutObject();
-}
-
 TEST_P(PaintAndRasterInvalidationTest, NonCompositedLayoutViewResize) {
   ScopedPreferNonCompositedScrollingForTest non_composited_scrolling(true);
 
@@ -426,10 +417,6 @@
   UpdateAllLifecyclePhasesForTest();
   Element* iframe = GetDocument().getElementById("iframe");
   Element* content = ChildDocument().getElementById("content");
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    EXPECT_EQ(GetLayoutView(),
-              EnclosingCompositedContainer(*content->GetLayoutObject()));
-  }
   EXPECT_EQ(kBackgroundPaintInContentsSpace,
             content->GetLayoutObject()
                 ->View()
@@ -510,10 +497,6 @@
   UpdateAllLifecyclePhasesForTest();
   Element* iframe = GetDocument().getElementById("iframe");
   Element* content = ChildDocument().getElementById("content");
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    EXPECT_EQ(GetLayoutView(),
-              EnclosingCompositedContainer(*content->GetLayoutObject()));
-  }
 
   // Resize the content.
   GetDocument().View()->SetTracksRasterInvalidations(true);
@@ -663,8 +646,6 @@
       ASSERT_NO_EXCEPTION);
   Element* child = GetDocument().getElementById("child");
   UpdateAllLifecyclePhasesForTest();
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    EXPECT_EQ(&GetLayoutView(), EnclosingCompositedContainer(*object));
   EXPECT_EQ(kBackgroundPaintInContentsSpace,
             object->ComputeBackgroundPaintLocationIfComposited());
   EXPECT_EQ(kBackgroundPaintInBorderBoxSpace,
diff --git a/third_party/blink/renderer/core/paint/paint_controller_paint_test.h b/third_party/blink/renderer/core/paint/paint_controller_paint_test.h
index ce671821..19e2bd3 100644
--- a/third_party/blink/renderer/core/paint/paint_controller_paint_test.h
+++ b/third_party/blink/renderer/core/paint/paint_controller_paint_test.h
@@ -13,8 +13,8 @@
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_chunk_subset.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller_test.h"
 #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 28f7ddfa..1e12775 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -75,7 +75,6 @@
 #include "third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h"
 #include "third_party/blink/renderer/core/paint/box_reflection_utils.h"
 #include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
 #include "third_party/blink/renderer/core/paint/filter_effect_builder.h"
 #include "third_party/blink/renderer/core/paint/hit_testing_transform_state.h"
@@ -362,17 +361,6 @@
   return GetLayoutObject().Container() == GetLayoutObject().View();
 }
 
-bool PaintLayer::ScrollsWithRespectTo(const PaintLayer* other) const {
-  DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-  if (FixedToViewport() != other->FixedToViewport())
-    return true;
-  // If either element sticks we cannot trivially determine that the layers do
-  // not scroll with respect to each other.
-  if (SticksToScroller() || other->SticksToScroller())
-    return true;
-  return AncestorScrollingLayer() != other->AncestorScrollingLayer();
-}
-
 bool PaintLayer::IsAffectedByScrollOf(const PaintLayer* ancestor) const {
   if (this == ancestor)
     return false;
@@ -868,19 +856,6 @@
   return SlowContainingLayer(ancestor, skipped_ancestor, &layout_object);
 }
 
-PhysicalOffset PaintLayer::ComputeOffsetFromAncestor(
-    const PaintLayer& ancestor_layer) const {
-  const LayoutBoxModelObject& ancestor_object =
-      ancestor_layer.GetLayoutObject();
-  PhysicalOffset result = GetLayoutObject().LocalToAncestorPoint(
-      PhysicalOffset(), &ancestor_object, kIgnoreTransforms);
-  if (ancestor_object.UsesCompositedScrolling()) {
-    result += PhysicalOffset(
-        To<LayoutBox>(ancestor_object).PixelSnappedScrolledContentOffset());
-  }
-  return result;
-}
-
 PaintLayer* PaintLayer::CompositingContainer() const {
   if (IsReplacedNormalFlowStacking())
     return Parent();
@@ -901,73 +876,8 @@
   return nullptr;
 }
 
-bool PaintLayer::IsPaintInvalidationContainer() const {
-  return GetCompositingState() == kPaintsIntoOwnBacking ||
-         GetCompositingState() == kPaintsIntoGroupedBacking;
-}
-
-// Return the enclosingCompositedLayerForPaintInvalidation for the given Layer
-// including crossing frame boundaries.
-PaintLayer*
-PaintLayer::EnclosingLayerForPaintInvalidationCrossingFrameBoundaries() const {
-  const PaintLayer* layer = this;
-  PaintLayer* composited_layer = nullptr;
-  while (!composited_layer) {
-    composited_layer = layer->EnclosingLayerForPaintInvalidation();
-    if (!composited_layer) {
-      CHECK(layer->GetLayoutObject().GetFrame());
-      auto* owner = layer->GetLayoutObject().GetFrame()->OwnerLayoutObject();
-      if (!owner)
-        break;
-      layer = owner->EnclosingLayer();
-    }
-  }
-  return composited_layer;
-}
-
-PaintLayer* PaintLayer::EnclosingLayerForPaintInvalidation() const {
-  if (IsPaintInvalidationContainer())
-    return const_cast<PaintLayer*>(this);
-
-  for (PaintLayer* curr = CompositingContainer(); curr;
-       curr = curr->CompositingContainer()) {
-    if (curr->IsPaintInvalidationContainer())
-      return curr;
-  }
-
-  return nullptr;
-}
-
-bool PaintLayer::CanBeComposited() const {
-  LocalFrameView* frame_view = GetLayoutObject().GetFrameView();
-  // Elements within an invisible frame must not be composited because they are
-  // not drawn.
-  if (frame_view && !frame_view->IsVisible())
-    return false;
-
-  DCHECK(!frame_view->ShouldThrottleRendering());
-
-  const bool has_compositor_animation =
-      CompositingReasonFinder::CompositingReasonsForAnimation(
-          GetLayoutObject()) != CompositingReason::kNone;
-
-  return frame_view->GetFrame()
-             .GetSettings()
-             ->GetAcceleratedCompositingEnabled() &&
-         (has_compositor_animation || !SubtreeIsInvisible()) &&
-         IsSelfPaintingLayer() && !GetLayoutObject().IsLayoutFlowThread() &&
-         // Don't composite <foreignObject> for the moment, to reduce instances
-         // of the "fundamental compositing bug" breaking painting order.
-         // With CompositeSVG, foreignObjects will be correctly composited after
-         // paint in PaintArtifactCompositor without a GraphicsLayer.
-         // Composited descendants of foreignObject will still break painting
-         // order which will be fixed in CompositeAfterPaint.
-         !GetLayoutObject().IsSVGForeignObject();
-}
-
 const PaintLayer* PaintLayer::EnclosingCompositedScrollingLayerUnderPagination(
     IncludeSelfOrNot include_self_or_not) const {
-  DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
   const auto* start_layer =
       include_self_or_not == kIncludeSelf ? this : CompositingContainer();
   for (const auto* curr = start_layer; curr && curr->EnclosingPaginationLayer();
@@ -1138,8 +1048,7 @@
     if (GetLayoutObject().IsStacked(*old_style))
       DirtyStackingContextZOrderLists();
 
-    if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-        PaintLayerPainter::PaintedOutputInvisible(*old_style)) {
+    if (PaintLayerPainter::PaintedOutputInvisible(*old_style)) {
       // PaintedOutputInvisible() was true because opacity was near zero, and
       // this layer is to be removed because opacity becomes 1. Do the same as
       // StyleDidChange() on change of PaintedOutputInvisible().
@@ -1359,12 +1268,6 @@
     DirtyStackingContextZOrderLists();
 }
 
-bool PaintLayer::HasOverflowControls() const {
-  return scrollable_area_ && (scrollable_area_->HasScrollbar() ||
-                              scrollable_area_->ScrollCorner() ||
-                              GetLayoutObject().StyleRef().HasResize());
-}
-
 void PaintLayer::AppendSingleFragmentIgnoringPaginationForHitTesting(
     PaintLayerFragments& fragments,
     ShouldRespectOverflowClipType respect_overflow_clip) const {
@@ -2558,16 +2461,8 @@
 
   PaintLayerPaintOrderIterator iterator(this, kAllChildren);
   while (PaintLayer* child_layer = iterator.Next()) {
-    // Here we exclude both directly composited layers and squashing layers
-    // because those Layers don't paint into the graphics layer
-    // for this Layer. For example, the bounds of squashed Layers
-    // will be included in the computation of the appropriate squashing
-    // GraphicsLayer.
-    if ((options & kIncludeCompositedChildLayers) ||
-        child_layer->GetCompositingState() == kNotComposited) {
-      result.Unite(child_layer->BoundingBoxForCompositingInternal(
-          composited_layer, this, options));
-    }
+    result.Unite(child_layer->BoundingBoxForCompositingInternal(
+        composited_layer, this, options));
   }
 }
 
@@ -2679,25 +2574,9 @@
   return result;
 }
 
-bool PaintLayer::NeedsCompositedScrolling() const {
-  return scrollable_area_ && scrollable_area_->NeedsCompositedScrolling();
-}
-
 bool PaintLayer::PaintsWithTransform(
     GlobalPaintFlags global_paint_flags) const {
-  return Transform() && !PaintsIntoOwnBacking(global_paint_flags);
-}
-
-bool PaintLayer::PaintsIntoOwnBacking(
-    GlobalPaintFlags global_paint_flags) const {
-  return !(global_paint_flags & kGlobalPaintFlattenCompositingLayers) &&
-         GetCompositingState() == kPaintsIntoOwnBacking;
-}
-
-bool PaintLayer::PaintsIntoOwnOrGroupedBacking(
-    GlobalPaintFlags global_paint_flags) const {
-  return !(global_paint_flags & kGlobalPaintFlattenCompositingLayers) &&
-         GetCompositingState() != kNotComposited;
+  return Transform();
 }
 
 bool PaintLayer::SupportsSubsequenceCaching() const {
@@ -2725,11 +2604,6 @@
   return GetLayoutObject().IsStacked();
 }
 
-ScrollingCoordinator* PaintLayer::GetScrollingCoordinator() {
-  Page* page = GetLayoutObject().GetFrame()->GetPage();
-  return (!page) ? nullptr : page->GetScrollingCoordinator();
-}
-
 bool PaintLayer::ShouldBeSelfPaintingLayer() const {
   return GetLayoutObject().LayerTypeRequired() == kNormalPaintLayer ||
          (scrollable_area_ && scrollable_area_->HasOverlayOverflowControls()) ||
@@ -2775,38 +2649,6 @@
   return layer;
 }
 
-bool PaintLayer::HasNonEmptyChildLayoutObjects() const {
-  // Some HTML can cause whitespace text nodes to have layoutObjects, like:
-  // <div>
-  // <img src=...>
-  // </div>
-  // so test for 0x0 LayoutTexts here
-  for (const auto* child = GetLayoutObject().SlowFirstChild(); child;
-       child = child->NextSibling()) {
-    if (!child->HasLayer()) {
-      if (child->IsLayoutInline() || !child->IsBox())
-        return true;
-
-      const auto* box = To<LayoutBox>(child);
-      if (!box->Size().IsZero() || box->HasVisualOverflow())
-        return true;
-    }
-  }
-  return false;
-}
-
-bool PaintLayer::HasBoxDecorationsOrBackground() const {
-  return GetLayoutObject().StyleRef().HasBoxDecorations() ||
-         GetLayoutObject().StyleRef().HasBackground();
-}
-
-bool PaintLayer::HasVisibleBoxDecorations() const {
-  if (!HasVisibleContent())
-    return false;
-
-  return HasBoxDecorationsOrBackground() || HasOverflowControls();
-}
-
 void PaintLayer::UpdateFilters(const ComputedStyle* old_style,
                                const ComputedStyle& new_style) {
   if (!filter_on_effect_node_dirty_) {
@@ -2916,17 +2758,11 @@
         PaintLayerPainter::PaintedOutputInvisible(new_style);
     if (PaintLayerPainter::PaintedOutputInvisible(*old_style) !=
         new_painted_output_invisible) {
-      if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-        // Force repaint of the subtree for two purposes:
-        // 1. To ensure FCP/LCP will be reported. See crbug.com/1184903.
-        // 2. To update effectively_invisible flags of PaintChunks.
-        // TODO(crbug.com/1104218): Optimize this.
-        GetLayoutObject().SetSubtreeShouldDoFullPaintInvalidation();
-      } else {
-        // Change of PaintedOutputInvisible() will affect existence of paint
-        // chunks, so needs repaint.
-        SetNeedsRepaint();
-      }
+      // Force repaint of the subtree for two purposes:
+      // 1. To ensure FCP/LCP will be reported. See crbug.com/1184903.
+      // 2. To update effectively_invisible flags of PaintChunks.
+      // TODO(crbug.com/1104218): Optimize this.
+      GetLayoutObject().SetSubtreeShouldDoFullPaintInvalidation();
     }
   }
 }
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h
index 2ac2d73..adb8f23 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -58,15 +58,12 @@
 #include "third_party/blink/renderer/core/paint/paint_layer_resource_info.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_stacking_node.h"
 #include "third_party/blink/renderer/core/paint/paint_result.h"
-#include "third_party/blink/renderer/platform/graphics/compositing_reasons.h"
 #include "third_party/blink/renderer/platform/graphics/overlay_scrollbar_clip_behavior.h"
 #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
-#include "third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
 namespace blink {
 
-class CompositedLayerMapping;
 class CompositorFilterOperations;
 class ComputedStyle;
 class FilterEffect;
@@ -74,7 +71,6 @@
 class HitTestResult;
 class HitTestingTransformState;
 class PaintLayerScrollableArea;
-class ScrollingCoordinator;
 class TransformationMatrix;
 
 enum IncludeSelfOrNot { kIncludeSelf, kExcludeSelf };
@@ -298,15 +294,6 @@
 
   void UpdateTransformationMatrix();
 
-  bool IsStackingContextWithNegativeZOrderChildren() const {
-    DCHECK(!stacking_node_ || GetLayoutObject().IsStackingContext());
-    return stacking_node_ && !stacking_node_->NegZOrderList().IsEmpty();
-  }
-
-  bool SubtreeIsInvisible() const {
-    return !HasVisibleContent() && !HasVisibleDescendant();
-  }
-
   bool HasVisibleContent() const {
     DCHECK(!needs_descendant_dependent_flags_update_);
     return has_visible_content_;
@@ -319,13 +306,6 @@
 
   void DirtyVisibleContentStatus();
 
-  // True if this layer paints box decorations or a background. Touch-action
-  // rects are painted as part of the background so these are included here.
-  bool HasBoxDecorationsOrBackground() const;
-  bool HasVisibleBoxDecorations() const;
-  // True if this layer container layoutObjects that paint.
-  bool HasNonEmptyChildLayoutObjects() const;
-
   // Gets the ancestor layer that serves as the containing block (in the sense
   // of LayoutObject::container() instead of LayoutObject::containingBlock())
   // of this layer. Normally the parent layer is the containing layer, except
@@ -338,39 +318,12 @@
   PaintLayer* ContainingLayer(const PaintLayer* ancestor = nullptr,
                               bool* skipped_ancestor = nullptr) const;
 
-  bool IsPaintInvalidationContainer() const;
-
-  // Do *not* call this method unless you know what you are dooing. You probably
-  // want to call enclosingCompositingLayerForPaintInvalidation() instead.
-  // If includeSelf is true, may return this.
-  PaintLayer* EnclosingLayerWithCompositedLayerMapping(IncludeSelfOrNot) const {
-    // TODO(pdr): Remove this.
-    return nullptr;
-  }
-
-  // Returns the enclosing layer root into which this layer paints, inclusive of
-  // this one. Note that the enclosing layer may or may not have its own
-  // GraphicsLayer backing, but is nevertheless the root for a call to the
-  // Layer::paint*() methods.
-  PaintLayer* EnclosingLayerForPaintInvalidation() const;
-
-  // For CompositeAfterPaint, but not for LayoutNGBlockFragmentation.
+  // Not for LayoutNGBlockFragmentation.
   const PaintLayer* EnclosingCompositedScrollingLayerUnderPagination(
       IncludeSelfOrNot) const;
 
-  // https://crbug.com/751768, this function can return nullptr sometimes.
-  // Always check the result before using it, don't just DCHECK.
-  PaintLayer* EnclosingLayerForPaintInvalidationCrossingFrameBoundaries() const;
-
   bool HasAncestorWithFilterThatMovesPixels() const;
 
-  bool CanUseConvertToLayerCoords() const {
-    // These LayoutObjects have an impact on their layers without the
-    // layoutObjects knowing about it.
-    return !GetLayoutObject().HasTransformRelatedProperty() &&
-           !GetLayoutObject().IsSVGRoot();
-  }
-
   void ConvertToLayerCoords(const PaintLayer* ancestor_layer,
                             PhysicalOffset&) const;
   void ConvertToLayerCoords(const PaintLayer* ancestor_layer,
@@ -467,14 +420,6 @@
     return position;
   }
 
-  PhysicalOffset SubpixelAccumulation() const {
-    // TODO(pdr): Remove this.
-    return PhysicalOffset();
-  }
-
-  bool HasTransformRelatedProperty() const {
-    return GetLayoutObject().HasTransformRelatedProperty();
-  }
   // Note that this transform has the transform-origin baked in.
   TransformationMatrix* Transform() const {
     return rare_data_ ? rare_data_->transform.get() : nullptr;
@@ -495,47 +440,13 @@
            !rare_data_->transform->IsAffine();
   }
 
-  // FIXME: reflections should force transform-style to be flat in the style:
-  // https://bugs.webkit.org/show_bug.cgi?id=106959
-  bool ShouldPreserve3D() const {
-    return !GetLayoutObject().HasReflection() && Preserves3D();
-  }
-
   // Returns |true| if any property that renders using filter operations is
   // used (including, but not limited to, 'filter' and 'box-reflect').
   bool HasFilterInducingProperty() const {
     return GetLayoutObject().HasFilterInducingProperty();
   }
 
-  CompositingState GetCompositingState() const {
-    // TODO(pdr): Remove this.
-    return kNotComposited;
-  }
-
-  CompositedLayerMapping* GetCompositedLayerMapping() const {
-    // TODO(pdr): Remove this.
-    return nullptr;
-  }
-
-  bool HasCompositedLayerMapping() const {
-    // TODO(pdr): Remove this.
-    return false;
-  }
-
-  CompositedLayerMapping* GroupedMapping() const {
-    // TODO(pdr): Remove this.
-    return nullptr;
-  }
-
-  bool NeedsCompositedScrolling() const;
-
-  // Returns the ScrollingCoordinator associated with this layer, if
-  // any. Otherwise nullptr.
-  ScrollingCoordinator* GetScrollingCoordinator();
-
   bool PaintsWithTransform(GlobalPaintFlags) const;
-  bool PaintsIntoOwnBacking(GlobalPaintFlags) const;
-  bool PaintsIntoOwnOrGroupedBacking(GlobalPaintFlags) const;
 
   bool SupportsSubsequenceCaching() const;
 
@@ -612,8 +523,6 @@
   // Returns true if the layer is fixed position and will not move with
   // scrolling.
   bool FixedToViewport() const;
-  bool ScrollsWithRespectTo(const PaintLayer*) const;
-
   bool IsAffectedByScrollOf(const PaintLayer* ancestor) const;
 
   // FIXME: This should probably return a ScrollableArea but a lot of internal
@@ -631,9 +540,6 @@
 
   bool ScrollsOverflow() const;
 
-  // Whether the layer could ever be composited.
-  bool CanBeComposited() const;
-
   bool NeedsVisualOverflowRecalc() const {
     return needs_visual_overflow_recalc_;
   }
@@ -650,14 +556,9 @@
   const gfx::Rect ClippedAbsoluteBoundingBox() const;
   const gfx::Rect UnclippedAbsoluteBoundingBox() const;
 
-  // TODO(pdr): Remove this.
-  const LayoutBoxModelObject* ClippingContainer() const { return nullptr; }
   const PaintLayer* AncestorScrollContainerLayer() const {
     return ancestor_scroll_container_layer_;
   }
-  // TODO(pdr): Remove this.
-  const PaintLayer* AncestorScrollingLayer() const { return nullptr; }
-  const PaintLayer* ScrollParent() const { return nullptr; }
 
   bool HasFixedPositionDescendant() const {
     DCHECK(!needs_descendant_dependent_flags_update_);
@@ -696,11 +597,6 @@
     return CompositingReason::kNone;
   }
 
-  SquashingDisallowedReasons GetSquashingDisallowedReasons() const {
-    // TODO(pdr): Remove this.
-    return SquashingDisallowedReason::kNone;
-  }
-
   void UpdateDescendantDependentFlags();
 
   void UpdateSelfPaintingLayer();
@@ -708,11 +604,6 @@
   // like those in PaintInvalidatorContext.
   PaintLayer* EnclosingSelfPaintingLayer();
 
-  // Returned value does not include any composited scroll offset of
-  // the transform ancestor.
-  PhysicalOffset ComputeOffsetFromAncestor(
-      const PaintLayer& ancestor_layer) const;
-
   void DidUpdateScrollsOverflow();
 
   void CollectFragments(
@@ -817,10 +708,6 @@
   bool LayerListMutationAllowed() const { return layer_list_mutation_allowed_; }
 #endif
 
-  void SetNeedsCompositingLayerAssignment();
-  void ClearNeedsCompositingLayerAssignment();
-  void PropagateDescendantNeedsCompositingLayerAssignment();
-
   void DirtyStackingContextZOrderLists();
 
   PhysicalOffset OffsetForInFlowRelPosition() const {
@@ -840,8 +727,6 @@
   PhysicalRect LocalBoundingBox() const;
   PhysicalRect ClippedLocalBoundingBox(const PaintLayer& ancestor_layer) const;
 
-  bool HasOverflowControls() const;
-
   void UpdateLayerPositionRecursive(const PaintLayer* enclosing_scroller);
 
   void SetNextSibling(PaintLayer* next) { next_ = next; }
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter.cc b/third_party/blink/renderer/core/paint/paint_layer_painter.cc
index 7929c06..bcc80e7 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painter.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_painter.cc
@@ -11,7 +11,6 @@
 #include "third_party/blink/renderer/core/layout/layout_video.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
 #include "third_party/blink/renderer/core/paint/object_paint_properties.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
@@ -21,7 +20,6 @@
 #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
 #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
 #include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
 #include "third_party/blink/renderer/platform/graphics/paint/scoped_display_item_fragment.h"
@@ -38,8 +36,7 @@
                               PaintLayerFlags paint_flags) {
   PaintLayerPaintingInfo painting_info(&paint_layer_, cull_rect,
                                        global_paint_flags, PhysicalOffset());
-  if (!paint_layer_.PaintsIntoOwnOrGroupedBacking(global_paint_flags))
-    Paint(context, painting_info, paint_flags);
+  Paint(context, painting_info, paint_flags);
 }
 
 static ShouldRespectOverflowClipType ShouldRespectOverflowClip(
@@ -702,13 +699,6 @@
 
   PaintLayerPaintOrderIterator iterator(&paint_layer_, children_to_visit);
   while (PaintLayer* child = iterator.Next()) {
-    // If this Layer should paint into its own backing or a grouped backing,
-    // that will be done via CompositedLayerMapping::PaintContents() and
-    // CompositedLayerMapping::DoPaintTask().
-    if (child->PaintsIntoOwnOrGroupedBacking(
-            painting_info.GetGlobalPaintFlags()))
-      continue;
-
     if (child->IsReplacedNormalFlowStacking())
       continue;
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc b/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
index 5947d5b..201e74e3 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
@@ -6,7 +6,6 @@
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
 #include "third_party/blink/renderer/platform/testing/find_cc_layer.h"
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 6e324fb0..39fcd61 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -93,10 +93,10 @@
 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
 #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
 #include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/paint_invalidator.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_fragment.h"
 #include "third_party/blink/renderer/core/scroll/scroll_alignment.h"
 #include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
@@ -1913,13 +1913,6 @@
     resizer_->GetMutableForPainting().FirstFragment().SetPaintOffset(
         PhysicalOffset(rect.Location()));
   }
-
-  // FIXME, this should eventually be removed, once we are certain that
-  // composited controls get correctly positioned on a compositor update. For
-  // now, conservatively leaving this unchanged.
-  if (Layer()->HasCompositedLayerMapping()) {
-    Layer()->GetCompositedLayerMapping()->PositionOverflowControlsLayers();
-  }
 }
 
 void PaintLayerScrollableArea::UpdateScrollCornerStyle() {
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
index e4f7bcb..b235373 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
@@ -19,7 +19,6 @@
 #include "third_party/blink/renderer/core/scroll/scroll_types.h"
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 
 using testing::_;
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc b/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc
index c066b2b..c1f21b17 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc
@@ -51,7 +51,6 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer_test.cc b/third_party/blink/renderer/core/paint/paint_layer_test.cc
index 52b424e..85051f6 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_test.cc
@@ -188,9 +188,6 @@
 }
 
 TEST_P(PaintLayerTest, CompositedScrollingNoNeedsRepaint) {
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    return;
-
   SetBodyInnerHTML(R"HTML(
     <div id='scroll' style='width: 100px; height: 100px; overflow: scroll;
         will-change: transform'>
@@ -200,10 +197,8 @@
   )HTML");
 
   PaintLayer* scroll_layer = GetPaintLayerByElementId("scroll");
-  EXPECT_EQ(kPaintsIntoOwnBacking, scroll_layer->GetCompositingState());
 
   PaintLayer* content_layer = GetPaintLayerByElementId("content");
-  EXPECT_EQ(kNotComposited, content_layer->GetCompositingState());
   EXPECT_EQ(PhysicalOffset(), content_layer->LocationWithoutPositionOffset());
 
   scroll_layer->GetScrollableArea()->SetScrollOffset(
@@ -237,10 +232,8 @@
                    .PaintProperties()
                    ->ScrollTranslation()
                    ->HasDirectCompositingReasons());
-  EXPECT_EQ(kNotComposited, scroll_layer->GetCompositingState());
 
   PaintLayer* content_layer = GetPaintLayerByElementId("content");
-  EXPECT_EQ(kNotComposited, scroll_layer->GetCompositingState());
   EXPECT_EQ(PhysicalOffset(), content_layer->LocationWithoutPositionOffset());
 
   scroll_layer->GetScrollableArea()->SetScrollOffset(
@@ -2560,19 +2553,6 @@
   }
 }
 
-TEST_P(PaintLayerTest, HasNonEmptyChildLayoutObjectsZeroSizeOverflowVisible) {
-  SetBodyInnerHTML(R"HTML(
-    <div id="layer" style="position: relative">
-      <div style="overflow: visible; height: 0; width: 0">text</div>
-    </div>
-  )HTML");
-
-  auto* layer = GetPaintLayerByElementId("layer");
-  EXPECT_TRUE(layer->HasVisibleContent());
-  EXPECT_FALSE(layer->HasVisibleDescendant());
-  EXPECT_TRUE(layer->HasNonEmptyChildLayoutObjects());
-}
-
 TEST_P(PaintLayerTest, AddLayerNeedsRepaintAndCullRectUpdate) {
   SetBodyInnerHTML(R"HTML(
     <div id="parent" style="opacity: 0.9">
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index 907c9dda..b2af99f8 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -26,7 +26,6 @@
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/link_highlight.h"
 #include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/cull_rect_updater.h"
 #include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -360,65 +359,6 @@
 }
 #endif
 
-static LayoutBoxModelObject* ContainerForPaintInvalidation(
-    const PaintLayer* painting_layer) {
-  if (!painting_layer)
-    return nullptr;
-  if (auto* containing_paint_layer =
-          painting_layer
-              ->EnclosingLayerForPaintInvalidationCrossingFrameBoundaries())
-    return &containing_paint_layer->GetLayoutObject();
-  return nullptr;
-}
-
-void PrePaintTreeWalk::UpdatePaintInvalidationContainer(
-    const LayoutObject& object,
-    const PaintLayer* painting_layer,
-    PrePaintTreeWalkContext& context,
-    bool is_ng_painting) {
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    return;
-
-  if (object.IsPaintInvalidationContainer()) {
-    context.paint_invalidation_container = To<LayoutBoxModelObject>(&object);
-    if (object.IsStackingContext() || object.IsSVGRoot()) {
-      context.paint_invalidation_container_for_stacked_contents =
-          To<LayoutBoxModelObject>(&object);
-    }
-  } else if (IsA<LayoutView>(object)) {
-    // paint_invalidation_container_for_stacked_contents is only for stacked
-    // descendants in its own frame, because it doesn't establish stacking
-    // context for stacked contents in sub-frames.
-    // Contents stacked in the root stacking context in this frame should use
-    // this frame's PaintInvalidationContainer.
-    context.paint_invalidation_container_for_stacked_contents =
-        ContainerForPaintInvalidation(painting_layer);
-  } else if (!is_ng_painting &&
-             (object.IsColumnSpanAll() ||
-              object.IsFloatingWithNonContainingBlockParent())) {
-    // In these cases, the object may belong to an ancestor of the current
-    // paint invalidation container, in paint order.
-    // Post LayoutNG the |LayoutObject::IsFloatingWithNonContainingBlockParent|
-    // check can be removed as floats will be painted by the correct layer.
-    context.paint_invalidation_container =
-        ContainerForPaintInvalidation(painting_layer);
-  } else if (object.IsStacked() &&
-             // This is to exclude some objects (e.g. LayoutText) inheriting
-             // stacked style from parent but aren't actually stacked.
-             object.HasLayer() &&
-             !To<LayoutBoxModelObject>(object)
-                  .Layer()
-                  ->IsReplacedNormalFlowStacking() &&
-             context.paint_invalidation_container !=
-                 context.paint_invalidation_container_for_stacked_contents) {
-    // The current object is stacked, so we should use
-    // m_paintInvalidationContainerForStackedContents as its paint invalidation
-    // container on which the current object is painted.
-    context.paint_invalidation_container =
-        context.paint_invalidation_container_for_stacked_contents;
-  }
-}
-
 NGPrePaintInfo PrePaintTreeWalk::CreatePrePaintInfo(
     const NGLink& child,
     const PrePaintTreeWalkContext& context) {
@@ -567,10 +507,6 @@
 
   InvalidatePaintForHitTesting(object, context);
 
-  UpdatePaintInvalidationContainer(object,
-                                   paint_invalidator_context.painting_layer,
-                                   context, !!pre_paint_info);
-
   if (context.tree_builder_context) {
     property_changed =
         std::max(property_changed, property_tree_builder->UpdateForChildren());
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
index d31c28e..bab9dc7 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
@@ -85,10 +85,6 @@
     // fragmentainer even if the OOF / float is there.
     bool is_inside_orphaned_object = false;
 
-    const LayoutBoxModelObject* paint_invalidation_container = nullptr;
-    const LayoutBoxModelObject*
-        paint_invalidation_container_for_stacked_contents = nullptr;
-
     ContainingFragment current_fragmentainer;
     ContainingFragment absolute_positioned_container;
     ContainingFragment fixed_positioned_container;
@@ -221,11 +217,6 @@
   void InvalidatePaintForHitTesting(const LayoutObject&,
                                     PrePaintTreeWalkContext&);
 
-  void UpdatePaintInvalidationContainer(const LayoutObject& object,
-                                        const PaintLayer* painting_layer,
-                                        PrePaintTreeWalkContext& context,
-                                        bool is_ng_painting);
-
   PaintInvalidator paint_invalidator_;
 
   // List of fragments that may be missed during LayoutObject walking. See
diff --git a/third_party/blink/renderer/core/paint/replaced_painter.cc b/third_party/blink/renderer/core/paint/replaced_painter.cc
index 2c038f66..69cb7404 100644
--- a/third_party/blink/renderer/core/paint/replaced_painter.cc
+++ b/third_party/blink/renderer/core/paint/replaced_painter.cc
@@ -9,7 +9,6 @@
 #include "third_party/blink/renderer/core/layout/layout_replaced.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
 #include "third_party/blink/renderer/core/paint/box_painter.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/highlight_painting_utils.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_auto_dark_mode.h"
diff --git a/third_party/blink/renderer/core/paint/svg_container_painter_test.cc b/third_party/blink/renderer/core/paint/svg_container_painter_test.cc
index 1cec2b68..c5d95c0f 100644
--- a/third_party/blink/renderer/core/paint/svg_container_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/svg_container_painter_test.cc
@@ -8,7 +8,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk.h"
diff --git a/third_party/blink/renderer/core/paint/view_painter.cc b/third_party/blink/renderer/core/paint/view_painter.cc
index 976f6ed5..44bea3c 100644
--- a/third_party/blink/renderer/core/paint/view_painter.cc
+++ b/third_party/blink/renderer/core/paint/view_painter.cc
@@ -15,7 +15,6 @@
 #include "third_party/blink/renderer/core/paint/box_decoration_data.h"
 #include "third_party/blink/renderer/core/paint/box_model_object_painter.h"
 #include "third_party/blink/renderer/core/paint/box_painter.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_auto_dark_mode.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
diff --git a/third_party/blink/renderer/core/paint/view_painter_test.cc b/third_party/blink/renderer/core/paint/view_painter_test.cc
index 1590b7f..a0da795a 100644
--- a/third_party/blink/renderer/core/paint/view_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/view_painter_test.cc
@@ -6,7 +6,6 @@
 
 #include <gtest/gtest.h>
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h"
 #include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h"
diff --git a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
index f004a76..4a2e1f5 100644
--- a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
+++ b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
@@ -25,7 +25,6 @@
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/page/focus_controller.h"
 #include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/resize_observer/resize_observer.h"
@@ -520,8 +519,6 @@
       To<HTMLIFrameElement>(GetDocument().getElementById("frame"));
   auto* frame_view = frame_element->contentDocument()->View();
   EXPECT_FALSE(frame_view->CanThrottleRendering());
-  auto* frame_layout_view = frame_view->GetLayoutView();
-  EXPECT_TRUE(frame_layout_view->Layer()->CanBeComposited());
   auto* root_layer = WebView().MainFrameImpl()->GetFrameView()->RootCcLayer();
   EXPECT_EQ(0u, CcLayersByDOMElementId(root_layer, "container").size());
   EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "inner_frame").size());
@@ -542,7 +539,6 @@
   ASSERT_TRUE(Compositor().NeedsBeginFrame());
   CompositeFrame();
   EXPECT_FALSE(frame_view->CanThrottleRendering());
-  EXPECT_TRUE(frame_layout_view->Layer()->CanBeComposited());
   EXPECT_EQ(0u, CcLayersByDOMElementId(root_layer, "container").size());
   EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "inner_frame").size());
 }
diff --git a/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc b/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc
index 1bddf18..90a8a8e 100644
--- a/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc
+++ b/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc
@@ -10,7 +10,6 @@
 #include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
 #include "third_party/blink/renderer/platform/animation/compositor_keyframe_model.h"
 #include "third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/scroll/scroll_animator.cc b/third_party/blink/renderer/core/scroll/scroll_animator.cc
index 540a69d..dc8730fb 100644
--- a/third_party/blink/renderer/core/scroll/scroll_animator.cc
+++ b/third_party/blink/renderer/core/scroll/scroll_animator.cc
@@ -39,7 +39,6 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/core/scroll/scrollable_area.h"
 #include "third_party/blink/renderer/platform/animation/compositor_keyframe_model.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 
 // This should be after all other #includes.
diff --git a/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc b/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc
index c0980e8..f4ff6cc 100644
--- a/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc
+++ b/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc
@@ -14,8 +14,6 @@
 #include "third_party/blink/renderer/platform/animation/compositor_animation.h"
 #include "third_party/blink/renderer/platform/animation/compositor_animation_timeline.h"
 #include "third_party/blink/renderer/platform/animation/compositor_keyframe_model.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area_test.cc b/third_party/blink/renderer/core/scroll/scrollable_area_test.cc
index f23d62c..5dd13c8 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area_test.cc
+++ b/third_party/blink/renderer/core/scroll/scrollable_area_test.cc
@@ -13,7 +13,6 @@
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_mock.h"
 #include "third_party/blink/renderer/core/testing/scoped_mock_overlay_scrollbars.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc b/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
index 63aff90..2b65de7 100644
--- a/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
+++ b/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
@@ -21,6 +21,7 @@
 #include "third_party/blink/renderer/core/svg/svg_svg_element.h"
 #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/graphics/graphics_context.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index acac2f0..b7cd594 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -132,7 +132,6 @@
 #include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
 #include "third_party/blink/renderer/core/page/validation_message_client.h"
 #include "third_party/blink/renderer/core/page/viewport_description.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
@@ -175,7 +174,6 @@
 #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -2448,46 +2446,6 @@
   return layerTreeAsText(document, 0, exception_state);
 }
 
-bool Internals::scrollsWithRespectTo(Element* element1,
-                                     Element* element2,
-                                     ExceptionState& exception_state) {
-  DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-  DCHECK(element1 && element2);
-  element1->GetDocument().View()->UpdateAllLifecyclePhasesForTest();
-
-  LayoutObject* layout_object1 = element1->GetLayoutObject();
-  LayoutObject* layout_object2 = element2->GetLayoutObject();
-  if (!layout_object1 || !layout_object1->IsBox()) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidAccessError,
-        layout_object1
-            ? "The first provided element's layoutObject is not a box."
-            : "The first provided element has no layoutObject.");
-    return false;
-  }
-  if (!layout_object2 || !layout_object2->IsBox()) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidAccessError,
-        layout_object2
-            ? "The second provided element's layoutObject is not a box."
-            : "The second provided element has no layoutObject.");
-    return false;
-  }
-
-  PaintLayer* layer1 = To<LayoutBox>(layout_object1)->Layer();
-  PaintLayer* layer2 = To<LayoutBox>(layout_object2)->Layer();
-  if (!layer1 || !layer2) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidAccessError,
-        String::Format(
-            "No PaintLayer can be obtained from the %s provided element.",
-            layer1 ? "second" : "first"));
-    return false;
-  }
-
-  return layer1->ScrollsWithRespectTo(layer2);
-}
-
 String Internals::layerTreeAsText(Document* document,
                                   unsigned flags,
                                   ExceptionState& exception_state) const {
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h
index d6432695..5c6e222f 100644
--- a/third_party/blink/renderer/core/testing/internals.h
+++ b/third_party/blink/renderer/core/testing/internals.h
@@ -354,8 +354,6 @@
   String layerTreeAsText(Document*, unsigned flags, ExceptionState&) const;
   String layerTreeAsText(Document*, ExceptionState&) const;
 
-  bool scrollsWithRespectTo(Element*, Element*, ExceptionState&);
-
   String scrollingStateTreeAsText(Document*) const;
   String mainThreadScrollingReasons(Document*, ExceptionState&) const;
   DOMRectList* nonFastScrollableRects(Document*, ExceptionState&) const;
diff --git a/third_party/blink/renderer/core/testing/internals.idl b/third_party/blink/renderer/core/testing/internals.idl
index ff1c407a..7e83580 100644
--- a/third_party/blink/renderer/core/testing/internals.idl
+++ b/third_party/blink/renderer/core/testing/internals.idl
@@ -195,8 +195,6 @@
 
     [RaisesException] DOMString layerTreeAsText(Document document, optional unsigned short flags);
 
-    [RaisesException] boolean scrollsWithRespectTo(Element element1, Element element2);
-
     DOMString scrollingStateTreeAsText(Document document);
     [RaisesException] DOMString mainThreadScrollingReasons(Document document);
     [RaisesException] DOMRectList nonFastScrollableRects(Document document);
diff --git a/third_party/blink/renderer/core/testing/sim/sim_compositor.cc b/third_party/blink/renderer/core/testing/sim/sim_compositor.cc
index 7dcaab9d..c29169fe 100644
--- a/third_party/blink/renderer/core/testing/sim/sim_compositor.cc
+++ b/third_party/blink/renderer/core/testing/sim/sim_compositor.cc
@@ -11,7 +11,6 @@
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
 #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
index aed3b2a..12941713 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
@@ -584,6 +584,8 @@
         break;
       }
     }
+    if (AXObject* owned_child = ObjectFromAXID(obj_id))
+      owned_child->DetachFromParent();
   }
 }
 
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc b/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
index 5817068..27336dee 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
@@ -129,12 +129,6 @@
   return nullptr;
 }
 
-bool CheckElementComposited(const Node& target) {
-  return target.GetLayoutObject() &&
-         target.GetLayoutObject()->GetCompositingState() ==
-             kPaintsIntoOwnBacking;
-}
-
 void StartEffectOnCompositor(CompositorAnimation* animation,
                              KeyframeEffect* effect) {
   DCHECK(effect);
@@ -619,9 +613,6 @@
   if (failure_reasons != CompositorAnimations::kNoFailure)
     return false;
 
-  if (!CheckElementComposited(target))
-    return false;
-
   // If the scroll source is not composited, fall back to main thread.
   if (timeline_->IsScrollTimeline() &&
       !CompositorAnimations::CheckUsesCompositedScrolling(
@@ -629,7 +620,10 @@
     return false;
   }
 
-  return true;
+  // TODO(crbug.com/1281413): This function has returned false since the launch
+  // of CompositeAfterPaint, but that may not be intended. Should this return
+  // true?
+  return false;
 }
 
 bool WorkletAnimation::StartOnCompositor() {
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
index a85e392..91ef0823 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -1899,7 +1899,7 @@
     ExceptionState& exception_state) const {
   ImageData::ValidateAndCreateParams params;
   params.context_2d_error_mode = true;
-  params.default_color_space = GetCanvas2DColorParams().ColorSpace();
+  params.default_color_space = GetDefaultImageDataColorSpace();
   return ImageData::ValidateAndCreate(std::abs(sw), std::abs(sh), absl::nullopt,
                                       /*settings=*/nullptr, params,
                                       exception_state);
@@ -1912,7 +1912,7 @@
     ExceptionState& exception_state) const {
   ImageData::ValidateAndCreateParams params;
   params.context_2d_error_mode = true;
-  params.default_color_space = GetCanvas2DColorParams().ColorSpace();
+  params.default_color_space = GetDefaultImageDataColorSpace();
   return ImageData::ValidateAndCreate(std::abs(sw), std::abs(sh), absl::nullopt,
                                       image_data_settings, params,
                                       exception_state);
@@ -1991,7 +1991,7 @@
   ImageData::ValidateAndCreateParams validate_and_create_params;
   validate_and_create_params.context_2d_error_mode = true;
   validate_and_create_params.default_color_space =
-      GetCanvas2DColorParams().ColorSpace();
+      GetDefaultImageDataColorSpace();
 
   if (!CanCreateCanvas2dResourceProvider() || isContextLost()) {
     return ImageData::ValidateAndCreate(
@@ -2129,46 +2129,33 @@
   gfx::Rect source_rect = dest_rect;
   source_rect.Offset(-dest_offset);
 
-  // Color / format convert ImageData to context 2D settings if needed. Color /
-  // format conversion is not needed only if context 2D and ImageData are both
-  // in sRGB color space and use uint8 pixel storage format. We use RGBA pixel
-  // order for both ImageData and CanvasResourceProvider, therefore no
-  // additional swizzling is needed.
   SkPixmap data_pixmap = data->GetSkPixmap();
-  CanvasColorParams data_color_params(
-      data->GetPredefinedColorSpace(),
-      data->GetImageDataStorageFormat() != ImageDataStorageFormat::kUint8
-          ? CanvasPixelFormat::kF16
-          : CanvasPixelFormat::kUint8,
-      kNonOpaque);
-  if (data_color_params.ColorSpace() != GetCanvas2DColorParams().ColorSpace() ||
-      data_color_params.PixelFormat() !=
-          GetCanvas2DColorParams().PixelFormat() ||
-      GetCanvas2DColorParams().PixelFormat() == CanvasPixelFormat::kF16) {
-    SkImageInfo converted_info = data_pixmap.info();
-    converted_info =
-        converted_info.makeColorType(GetCanvas2DColorParams().GetSkColorType());
-    converted_info = converted_info.makeColorSpace(
-        GetCanvas2DColorParams().GetSkColorSpace());
-    if (converted_info.colorType() == kN32_SkColorType)
-      converted_info = converted_info.makeColorType(kRGBA_8888_SkColorType);
 
-    const size_t converted_data_bytes = converted_info.computeMinByteSize();
-    const size_t converted_row_bytes = converted_info.minRowBytes();
-    if (SkImageInfo::ByteSizeOverflowed(converted_data_bytes))
+  // WritePixels (called by PutByteArray) requires that the source and
+  // destination pixel formats have the same bytes per pixel.
+  if (auto* host = GetCanvasRenderingContextHost()) {
+    SkColorType dest_color_type =
+        host->GetRenderingContextSkColorInfo().colorType();
+    if (SkColorTypeBytesPerPixel(dest_color_type) !=
+        SkColorTypeBytesPerPixel(data_pixmap.colorType())) {
+      SkImageInfo converted_info =
+          data_pixmap.info().makeColorType(dest_color_type);
+      SkBitmap converted_bitmap;
+      if (!converted_bitmap.tryAllocPixels(converted_info)) {
+        exception_state.ThrowRangeError("Out of memory in putImageData");
+        return;
+      }
+      if (!converted_bitmap.writePixels(data_pixmap, 0, 0))
+        NOTREACHED() << "Failed to convert ImageData with writePixels.";
+
+      PutByteArray(converted_bitmap.pixmap(), source_rect, dest_offset);
+      GetPaintCanvasForDraw(gfx::RectToSkIRect(dest_rect),
+                            CanvasPerformanceMonitor::DrawType::kImageData);
       return;
-    std::unique_ptr<uint8_t[]> converted_pixels(
-        new uint8_t[converted_data_bytes]);
-    if (data_pixmap.readPixels(converted_info, converted_pixels.get(),
-                               converted_row_bytes)) {
-      PutByteArray(
-          SkPixmap(converted_info, converted_pixels.get(), converted_row_bytes),
-          source_rect, dest_offset);
     }
-  } else {
-    PutByteArray(data_pixmap, source_rect, dest_offset);
   }
 
+  PutByteArray(data_pixmap, source_rect, dest_offset);
   GetPaintCanvasForDraw(gfx::RectToSkIRect(dest_rect),
                         CanvasPerformanceMonitor::DrawType::kImageData);
 }
@@ -2189,7 +2176,7 @@
 
   SkImageInfo info =
       source.info().makeWH(source_rect.width(), source_rect.height());
-  if (kOpaque == GetCanvas2DColorParams().GetOpacityMode()) {
+  if (!HasAlpha()) {
     // If the surface is opaque, tell it that we are writing opaque
     // pixels.  Writing non-opaque pixels to opaque is undefined in
     // Skia.  There is some discussion about whether it should be
@@ -2199,8 +2186,6 @@
   } else {
     info = info.makeAlphaType(kUnpremul_SkAlphaType);
   }
-  if (info.colorType() == kN32_SkColorType)
-    info = info.makeColorType(kRGBA_8888_SkColorType);
 
   WritePixels(info, source.addr(source_rect.x(), source_rect.y()),
               source.rowBytes(), dest_x, dest_y);
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
index 0fcad4d..467b2ad 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
@@ -421,9 +421,9 @@
 
   void UnwindStateStack();
 
-  // The implementations of this will query the CanvasColorParams from the
-  // CanvasRenderingContext.
-  virtual CanvasColorParams GetCanvas2DColorParams() const = 0;
+  // Return the default color space to be used for calls to GetImageData or
+  // CreateImageData.
+  virtual PredefinedColorSpace GetDefaultImageDataColorSpace() const = 0;
 
   virtual bool WritePixels(const SkImageInfo& orig_info,
                            const void* pixels,
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
index 03573e5..8ad03ad0 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
@@ -1098,9 +1098,9 @@
       CanvasRenderingContext2DSettings::Create();
   settings->setAlpha(CreationAttributes().alpha);
   if (RuntimeEnabledFeatures::CanvasColorManagementEnabled())
-    settings->setColorSpace(GetCanvas2DColorParams().GetColorSpaceAsString());
+    settings->setColorSpace(color_params_.GetColorSpaceAsString());
   if (RuntimeEnabledFeatures::CanvasColorManagementV2Enabled())
-    settings->setPixelFormat(GetCanvas2DColorParams().GetPixelFormatAsString());
+    settings->setPixelFormat(color_params_.GetPixelFormatAsString());
   settings->setDesynchronized(Host()->LowLatencyEnabled());
   if (RuntimeEnabledFeatures::NewCanvas2DAPIEnabled(
           canvas()->GetTopExecutionContext()))
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
index 0130e61..c92354b0 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
@@ -213,10 +213,6 @@
                                   ImageDataSettings*,
                                   ExceptionState&) final;
 
-  CanvasColorParams ColorParamsForTest() const {
-    return GetCanvas2DColorParams();
-  }
-
   IdentifiableToken IdentifiableTextToken() const override {
     return identifiability_study_helper_.GetToken();
   }
@@ -236,13 +232,11 @@
   }
 
  protected:
-  // This reports CanvasColorParams to the CanvasRenderingContext interface.
   CanvasColorParams CanvasRenderingContextColorParams() const override {
     return color_params_;
   }
-  // This reports CanvasColorParams to the BaseRenderingContext2D interface.
-  CanvasColorParams GetCanvas2DColorParams() const override {
-    return color_params_;
+  PredefinedColorSpace GetDefaultImageDataColorSpace() const final {
+    return color_params_.ColorSpace();
   }
   bool WritePixels(const SkImageInfo& orig_info,
                    const void* pixels,
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
index 441a452..06d6d6b3 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -933,6 +933,7 @@
 static void TestDrawSingleHighBitDepthPNGOnCanvas(
     String filepath,
     CanvasRenderingContext2D* context,
+    PredefinedColorSpace context_color_space,
     Document& document,
     ImageDataSettings* color_setting,
     ScriptState* script_state) {
@@ -971,7 +972,7 @@
       resource_content->GetImage()->PaintImageForCurrentFrame().GetSwSkImage();
   ASSERT_EQ(kRGBA_F16_SkColorType, decoded_image->colorType());
   sk_sp<SkImage> color_converted_image = decoded_image->makeColorSpace(
-      context->ColorParamsForTest().GetSkColorSpace());
+      PredefinedColorSpaceToSkColorSpace(context_color_space));
   float expected_pixels[16];
   SkImageInfo expected_info_no_color_space = SkImageInfo::Make(
       2, 2, kRGBA_F32_SkColorType, kUnpremul_SkAlphaType, nullptr);
@@ -1019,8 +1020,8 @@
         full_path.Append(alpha);
         full_path.Append(".png");
         TestDrawSingleHighBitDepthPNGOnCanvas(full_path.ToString(), context,
-                                              document, color_setting,
-                                              script_state);
+                                              color_space, document,
+                                              color_setting, script_state);
       }
     }
   }
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
index 2e04d9d..a4d4f50 100644
--- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
@@ -164,13 +164,11 @@
   void FlushCanvas() override;
 
  protected:
-  // This reports CanvasColorParams to the CanvasRenderingContext interface.
   CanvasColorParams CanvasRenderingContextColorParams() const override {
     return color_params_;
   }
-  // This reports CanvasColorParams to the BaseRenderingContext2D interface.
-  CanvasColorParams GetCanvas2DColorParams() const override {
-    return color_params_;
+  PredefinedColorSpace GetDefaultImageDataColorSpace() const final {
+    return color_params_.ColorSpace();
   }
   bool WritePixels(const SkImageInfo& orig_info,
                    const void* pixels,
diff --git a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
index d74efc40..2d32a0d 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
@@ -123,8 +123,11 @@
   return GetState().GetFilterForOffscreenCanvas(container_size_, this);
 }
 
-CanvasColorParams PaintRenderingContext2D::GetCanvas2DColorParams() const {
-  return CanvasColorParams();
+PredefinedColorSpace PaintRenderingContext2D::GetDefaultImageDataColorSpace()
+    const {
+  // PaintRenderingContext2D does not call getImageData or createImageData.
+  NOTREACHED();
+  return PredefinedColorSpace::kSRGB;
 }
 
 void PaintRenderingContext2D::WillOverwriteCanvas() {
diff --git a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h
index aa167f80..69e9469 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h
@@ -106,7 +106,7 @@
   }
 
  protected:
-  CanvasColorParams GetCanvas2DColorParams() const override;
+  PredefinedColorSpace GetDefaultImageDataColorSpace() const final;
   bool IsPaint2D() const override { return true; }
   void WillOverwriteCanvas() override;
 
diff --git a/third_party/blink/renderer/modules/launch/dom_window_launch_queue.idl b/third_party/blink/renderer/modules/launch/dom_window_launch_queue.idl
index 90851e4..de85def 100644
--- a/third_party/blink/renderer/modules/launch/dom_window_launch_queue.idl
+++ b/third_party/blink/renderer/modules/launch/dom_window_launch_queue.idl
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // TODO(crbug.com/829689): Add link to spec once complete.
-// Explainer: https://github.com/WICG/file-handling/blob/master/explainer.md
+// Explainer: https://github.com/WICG/file-handling/blob/main/explainer.md
 
 [
     ImplementedAs=DOMWindowLaunchQueue,
diff --git a/third_party/blink/renderer/modules/launch/launch_params.idl b/third_party/blink/renderer/modules/launch/launch_params.idl
index 751279794..7c9fe6c 100644
--- a/third_party/blink/renderer/modules/launch/launch_params.idl
+++ b/third_party/blink/renderer/modules/launch/launch_params.idl
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // TODO(crbug.com/829689): Add link to spec once complete.
-// Explainer: https://github.com/WICG/file-handling/blob/master/explainer.md
+// Explainer: https://github.com/WICG/file-handling/blob/main/explainer.md
 
 [
     Exposed=Window,
diff --git a/third_party/blink/renderer/modules/launch/launch_queue.idl b/third_party/blink/renderer/modules/launch/launch_queue.idl
index 6bbe6aa..746d9ca 100644
--- a/third_party/blink/renderer/modules/launch/launch_queue.idl
+++ b/third_party/blink/renderer/modules/launch/launch_queue.idl
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // TODO(crbug.com/829689): Add link to spec once complete.
-// Explainer: https://github.com/WICG/file-handling/blob/master/explainer.md
+// Explainer: https://github.com/WICG/file-handling/blob/main/explainer.md
 
 [
     Exposed=Window,
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.h b/third_party/blink/renderer/modules/manifest/manifest_parser.h
index a84ae89..ff42b66 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_parser.h
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser.h
@@ -315,7 +315,7 @@
       const JSONObject* object);
 
   // Parses the 'file_handlers' field of a Manifest, as defined in:
-  // https://github.com/WICG/file-handling/blob/master/explainer.md
+  // https://github.com/WICG/file-handling/blob/main/explainer.md
   // Returns the parsed list of FileHandlers. The returned FileHandlers are
   // empty if the field didn't exist, parsing failed, or the input list was
   // empty.
@@ -323,20 +323,20 @@
       const JSONObject* object);
 
   // Parses a FileHandler from an entry in the 'file_handlers' list, as
-  // defined in: https://github.com/WICG/file-handling/blob/master/explainer.md.
+  // defined in: https://github.com/WICG/file-handling/blob/main/explainer.md.
   // Returns |absl::nullopt| if the FileHandler was invalid, or a
   // FileHandler, if parsing succeeded.
   absl::optional<mojom::blink::ManifestFileHandlerPtr> ParseFileHandler(
       const JSONObject* file_handler_entry);
 
   // Parses the 'accept' field of a FileHandler, as defined in:
-  // https://github.com/WICG/file-handling/blob/master/explainer.md.
+  // https://github.com/WICG/file-handling/blob/main/explainer.md.
   // Returns the parsed accept map. Invalid accept entries are ignored.
   HashMap<String, Vector<String>> ParseFileHandlerAccept(
       const JSONObject* accept);
 
   // Parses an extension in the 'accept' field of a FileHandler, as defined in:
-  // https://github.com/WICG/file-handling/blob/master/explainer.md. Returns
+  // https://github.com/WICG/file-handling/blob/main/explainer.md. Returns
   // whether the parsing was successful and, if so, populates |output| with the
   // parsed extension.
   bool ParseFileHandlerAcceptExtension(const JSONValue* extension,
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 88c18c5..fa9eb27 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -972,11 +972,6 @@
     "graphics/graphics_context_state.cc",
     "graphics/graphics_context_state.h",
     "graphics/graphics_context_state_saver.h",
-    "graphics/graphics_layer.cc",
-    "graphics/graphics_layer.h",
-    "graphics/graphics_layer_client.h",
-    "graphics/graphics_layer_tree_as_text.cc",
-    "graphics/graphics_layer_tree_as_text.h",
     "graphics/graphics_types.cc",
     "graphics/graphics_types.h",
     "graphics/graphics_types_3d.h",
@@ -1134,8 +1129,6 @@
     "graphics/skia/sk_size_hash.h",
     "graphics/skia/skia_utils.cc",
     "graphics/skia/skia_utils.h",
-    "graphics/squashing_disallowed_reasons.cc",
-    "graphics/squashing_disallowed_reasons.h",
     "graphics/static_bitmap_image.cc",
     "graphics/static_bitmap_image.h",
     "graphics/static_bitmap_image_to_video_frame_copier.cc",
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
index f1ee3fd..53fe9f8 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -42,13 +42,13 @@
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_context_rate_limiter.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
 #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
 #include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
 #include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_wrapper.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"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/skia/include/core/SkData.h"
 #include "third_party/skia/include/core/SkSurface.h"
diff --git a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h
index 92a6907..e91eef7 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h
@@ -9,7 +9,6 @@
 #include "cc/layers/content_layer_client.h"
 #include "cc/layers/picture_layer.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/layers_as_json.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer_client.h"
 #include "third_party/blink/renderer/platform/graphics/paint/raster_invalidator.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
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 7c3688ac..c1802ad 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
@@ -2084,8 +2084,7 @@
   masking_state.local_transform_space = &t0();
   masking_state.output_clip = &c0();
   masking_state.blend_mode = SkBlendMode::kXor;
-  masking_state.direct_compositing_reasons =
-      CompositingReason::kSquashingDisallowed;
+  masking_state.direct_compositing_reasons = CompositingReason::kOverlap;
   auto masking =
       EffectPaintPropertyNode::Create(*masked, std::move(masking_state));
 
diff --git a/third_party/blink/renderer/platform/graphics/compositing_reasons.cc b/third_party/blink/renderer/platform/graphics/compositing_reasons.cc
index 15dbc3b..545936a 100644
--- a/third_party/blink/renderer/platform/graphics/compositing_reasons.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing_reasons.cc
@@ -46,8 +46,6 @@
      "Is sticky position"},
     {CompositingReason::kOverflowScrolling, "overflowScrolling",
      "Is a scrollable overflow element"},
-    {CompositingReason::kOverflowScrollingParent, "overflowScrollingParent",
-     "Scroll parent is not an ancestor"},
     {CompositingReason::kOutOfFlowClipping, "outOfFlowClipping",
      "Has clipping ancestor"},
     {CompositingReason::kVideoOverlay, "videoOverlay",
@@ -74,8 +72,6 @@
      "Overlaps other composited content"},
     {CompositingReason::kNegativeZIndexChildren, "negativeZIndexChildren",
      "Parent with composited negative z-index content"},
-    {CompositingReason::kSquashingDisallowed, "squashingDisallowed",
-     "Layer was separately composited because it could not be squashed."},
     {CompositingReason::kOpacityWithCompositedDescendants,
      "opacityWithCompositedDescendants",
      "Has opacity that needs to be applied by compositor because of composited "
diff --git a/third_party/blink/renderer/platform/graphics/compositing_reasons.h b/third_party/blink/renderer/platform/graphics/compositing_reasons.h
index e31810e..c28de64 100644
--- a/third_party/blink/renderer/platform/graphics/compositing_reasons.h
+++ b/third_party/blink/renderer/platform/graphics/compositing_reasons.h
@@ -35,7 +35,6 @@
   V(FixedPosition)                                                            \
   V(StickyPosition)                                                           \
   V(OverflowScrolling)                                                        \
-  V(OverflowScrollingParent)                                                  \
   V(OutOfFlowClipping)                                                        \
   V(VideoOverlay)                                                             \
   V(WillChangeTransform)                                                      \
@@ -63,7 +62,6 @@
   V(AssumedOverlap)                                                           \
   V(Overlap)                                                                  \
   V(NegativeZIndexChildren)                                                   \
-  V(SquashingDisallowed)                                                      \
                                                                               \
   /* Subtree reasons that require knowing what the status of your subtree is  \
      before knowing the answer. */                                            \
@@ -141,11 +139,11 @@
     kComboScrollDependentPosition = kFixedPosition | kStickyPosition,
 
     kComboAllDirectNonStyleDeterminedReasons =
-        kVideo | kCanvas | kPlugin | kIFrame | kSVGRoot |
-        kOverflowScrollingParent | kOutOfFlowClipping | kVideoOverlay |
-        kXrOverlay | kRoot | kRootScroller | kComboScrollDependentPosition |
-        kAffectedByOuterViewportBoundsDelta | kBackfaceInvisibility3DAncestor |
-        kTransform3DSceneLeaf | kDocumentTransitionSharedElement,
+        kVideo | kCanvas | kPlugin | kIFrame | kSVGRoot | kOutOfFlowClipping |
+        kVideoOverlay | kXrOverlay | kRoot | kRootScroller |
+        kComboScrollDependentPosition | kAffectedByOuterViewportBoundsDelta |
+        kBackfaceInvisibility3DAncestor | kTransform3DSceneLeaf |
+        kDocumentTransitionSharedElement,
 
     kComboAllDirectReasons = kComboAllDirectStyleDeterminedReasons |
                              kComboAllDirectNonStyleDeterminedReasons,
@@ -167,9 +165,6 @@
                                       kComboCompositedDescendants |
                                       kCombo3DDescendants,
 
-    kComboSquashableReasons =
-        kOverlap | kAssumedOverlap | kOverflowScrollingParent,
-
     kPreventingSubpixelAccumulationReasons = kWillChangeTransform,
 
     kDirectReasonsForPaintOffsetTranslationProperty =
@@ -193,19 +188,6 @@
   };
 };
 
-// Any reasons other than overlap or assumed overlap will require the layer to
-// be separately compositing.
-inline bool RequiresCompositing(CompositingReasons reasons) {
-  return reasons & ~CompositingReason::kComboSquashableReasons;
-}
-
-// If the layer has overlap or assumed overlap, but no other reasons, then it
-// should be squashed.
-inline bool RequiresSquashing(CompositingReasons reasons) {
-  return !RequiresCompositing(reasons) &&
-         (reasons & CompositingReason::kComboSquashableReasons);
-}
-
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COMPOSITING_REASONS_H_
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index cc345448..f672aae 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -57,7 +57,7 @@
 #include "third_party/blink/renderer/platform/graphics/canvas_resource.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
+#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
 #include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
 #include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_wrapper.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
diff --git a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
index dfdfed70..a3c1153 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
@@ -21,7 +21,6 @@
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
 #include "third_party/blink/renderer/platform/graphics/color_behavior.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/image_orientation.h"
 #include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
index 4f1d914..0d50ab02 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
@@ -9,7 +9,6 @@
 #include "gpu/command_buffer/client/shared_image_interface.h"
 #include "gpu/command_buffer/client/webgpu_interface.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
deleted file mode 100644
index ebba7fc9..0000000
--- a/third_party/blink/renderer/platform/graphics/graphics_layer.cc
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * Copyright (C) 2009 Apple 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
-
-#include <algorithm>
-#include <cmath>
-#include <memory>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
-#include "base/trace_event/traced_value.h"
-#include "cc/layers/layer.h"
-#include "cc/layers/picture_layer.h"
-#include "cc/paint/display_item_list.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/platform/geometry/geometry_as_json.h"
-#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
-#include "third_party/blink/renderer/platform/geometry/region.h"
-#include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
-#include "third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h"
-#include "third_party/blink/renderer/platform/graphics/compositor_filter_operations.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer_tree_as_text.h"
-#include "third_party/blink/renderer/platform/graphics/image.h"
-#include "third_party/blink/renderer/platform/graphics/logging_canvas.h"
-#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
-#include "third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h"
-#include "third_party/blink/renderer/platform/graphics/paint/paint_chunk_subset_recorder.h"
-#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
-#include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
-#include "third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h"
-#include "third_party/blink/renderer/platform/graphics/paint/raster_invalidator.h"
-#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
-#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.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/math_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-namespace blink {
-
-GraphicsLayer::GraphicsLayer()
-    : draws_content_(false),
-      paints_hit_test_(false),
-      contents_visible_(true),
-      hit_testable_(false),
-      needs_check_raster_invalidation_(false),
-      raster_invalidated_(false),
-      should_create_layers_after_paint_(false),
-      repainted_(false),
-      painting_phase_(kGraphicsLayerPaintAllWithOverflowClip),
-      parent_(nullptr),
-      raster_invalidation_function_(
-          base::BindRepeating(&GraphicsLayer::InvalidateRaster,
-                              base::Unretained(this))) {
-  layer_ = cc::PictureLayer::Create(this);
-  layer_->SetIsDrawable(draws_content_ && contents_visible_);
-  layer_->SetHitTestable(hit_testable_);
-
-  UpdateTrackingRasterInvalidations();
-}
-
-GraphicsLayer::~GraphicsLayer() {
-#if DCHECK_IS_ON()
-  DCHECK(is_destroyed_);
-#endif
-}
-
-void GraphicsLayer::Destroy() {
-  CcLayer().ClearClient();
-  contents_layer_ = nullptr;
-
-  RemoveAllChildren();
-  RemoveFromParent();
-  DCHECK(!parent_);
-
-  // This ensures we clean-up the ElementId to cc::Layer mapping in
-  // LayerTreeHost before a new layer with the same ElementId is added. See
-  // https://crbug.com/979002 for more information.
-  SetElementId(CompositorElementId());
-
-#if DCHECK_IS_ON()
-  is_destroyed_ = true;
-#endif
-}
-
-void GraphicsLayer::AppendAdditionalInfoAsJSON(LayerTreeFlags flags,
-                                               const cc::Layer& layer,
-                                               JSONObject& json) const {
-  // Only the primary layer associated with GraphicsLayer adds additional
-  // information.  Other layer state, such as raster invalidations, don't
-  // disambiguate between specific layers.
-  if (&layer != layer_.get())
-    return;
-
-  if ((flags & (kLayerTreeIncludesInvalidations |
-                kLayerTreeIncludesDetailedInvalidations)) &&
-      IsTrackingRasterInvalidations() && GetRasterInvalidationTracking()) {
-    GetRasterInvalidationTracking()->AsJSON(
-        &json, flags & kLayerTreeIncludesDetailedInvalidations);
-  }
-
-  GraphicsLayerPaintingPhase painting_phase = PaintingPhase();
-  if ((flags & kLayerTreeIncludesPaintingPhases) && painting_phase) {
-    auto painting_phases_json = std::make_unique<JSONArray>();
-    if (painting_phase & kGraphicsLayerPaintBackground)
-      painting_phases_json->PushString("GraphicsLayerPaintBackground");
-    if (painting_phase & kGraphicsLayerPaintForeground)
-      painting_phases_json->PushString("GraphicsLayerPaintForeground");
-    if (painting_phase & kGraphicsLayerPaintMask)
-      painting_phases_json->PushString("GraphicsLayerPaintMask");
-    if (painting_phase & kGraphicsLayerPaintOverflowContents)
-      painting_phases_json->PushString("GraphicsLayerPaintOverflowContents");
-    if (painting_phase & kGraphicsLayerPaintCompositedScroll)
-      painting_phases_json->PushString("GraphicsLayerPaintCompositedScroll");
-    if (painting_phase & kGraphicsLayerPaintDecoration)
-      painting_phases_json->PushString("GraphicsLayerPaintDecoration");
-    json.SetArray("paintingPhases", std::move(painting_phases_json));
-  }
-
-  if (flags &
-      (kLayerTreeIncludesDebugInfo | kLayerTreeIncludesCompositingReasons)) {
-    bool debug = flags & kLayerTreeIncludesDebugInfo;
-    {
-      auto squashing_disallowed_reasons_json = std::make_unique<JSONArray>();
-      SquashingDisallowedReasons squashing_disallowed_reasons =
-          GetSquashingDisallowedReasons();
-      auto names = debug ? SquashingDisallowedReason::Descriptions(
-                               squashing_disallowed_reasons)
-                         : SquashingDisallowedReason::ShortNames(
-                               squashing_disallowed_reasons);
-      for (const char* name : names)
-        squashing_disallowed_reasons_json->PushString(name);
-      json.SetArray("squashingDisallowedReasons",
-                    std::move(squashing_disallowed_reasons_json));
-    }
-  }
-
-  if (ShouldCreateLayersAfterPaint()) {
-    json.SetBoolean("shouldCreateLayersAfterPaint", true);
-  } else {
-#if DCHECK_IS_ON()
-    if (HasLayerState() && cc_display_item_list_ &&
-        (flags & kLayerTreeIncludesPaintRecords)) {
-      LoggingCanvas canvas;
-      cc_display_item_list_->Raster(&canvas);
-      json.SetValue("paintRecord", canvas.Log());
-    }
-#endif
-  }
-}
-
-void GraphicsLayer::SetParent(GraphicsLayer* layer) {
-#if DCHECK_IS_ON()
-  DCHECK(!layer || !layer->HasAncestor(this));
-#endif
-  parent_ = layer;
-}
-
-#if DCHECK_IS_ON()
-
-bool GraphicsLayer::HasAncestor(GraphicsLayer* ancestor) const {
-  for (GraphicsLayer* curr = Parent(); curr; curr = curr->Parent()) {
-    if (curr == ancestor)
-      return true;
-  }
-
-  return false;
-}
-
-#endif
-
-bool GraphicsLayer::SetChildren(const GraphicsLayerVector& new_children) {
-  // If the contents of the arrays are the same, nothing to do.
-  if (new_children == children_)
-    return false;
-
-  RemoveAllChildren();
-
-  for (GraphicsLayer* new_child : new_children)
-    AddChildInternal(new_child);
-
-  NotifyChildListChange();
-
-  return true;
-}
-
-void GraphicsLayer::AddChildInternal(GraphicsLayer* child_layer) {
-  // TODO(szager): Remove CHECK after diagnosing crbug.com/1092673
-  CHECK(child_layer);
-  DCHECK_NE(child_layer, this);
-
-  if (child_layer->Parent())
-    child_layer->RemoveFromParent();
-
-  child_layer->SetParent(this);
-  children_.push_back(child_layer);
-
-  // Don't call NotifyChildListChange here, this function is used in cases where
-  // it should not be called until all children are processed.
-}
-
-void GraphicsLayer::AddChild(GraphicsLayer* child_layer) {
-  AddChildInternal(child_layer);
-  NotifyChildListChange();
-}
-
-void GraphicsLayer::RemoveAllChildren() {
-  while (!children_.IsEmpty()) {
-    GraphicsLayer* cur_layer = children_.back();
-    DCHECK(cur_layer->Parent());
-    cur_layer->RemoveFromParent();
-  }
-}
-
-void GraphicsLayer::RemoveFromParent() {
-  if (parent_) {
-    // We use reverseFind so that removeAllChildren() isn't n^2.
-    parent_->children_.EraseAt(parent_->children_.ReverseFind(this));
-    SetParent(nullptr);
-  }
-}
-
-void GraphicsLayer::SetOffsetFromLayoutObject(const gfx::Vector2d& offset) {
-  if (offset == offset_from_layout_object_)
-    return;
-
-  offset_from_layout_object_ = offset;
-  Invalidate(PaintInvalidationReason::kFullLayer);  // As DisplayItemClient.
-}
-
-void GraphicsLayer::ClearPaintStateRecursively() {
-  ForAllGraphicsLayers(
-      *this,
-      [](GraphicsLayer& layer) -> bool {
-        layer.paint_controller_ = nullptr;
-        layer.raster_invalidator_ = nullptr;
-        return true;
-      },
-      [](GraphicsLayer&, const cc::Layer&) {});
-}
-
-void GraphicsLayer::SetShouldCreateLayersAfterPaint(
-    bool should_create_layers_after_paint) {
-  if (should_create_layers_after_paint != should_create_layers_after_paint_) {
-    should_create_layers_after_paint_ = should_create_layers_after_paint;
-    // Depending on |should_create_layers_after_paint_|, raster invalidation
-    // will happen in via two different code paths. When it changes we need to
-    // fully invalidate because the incremental raster invalidations of these
-    // code paths will not work.
-    if (raster_invalidator_)
-      raster_invalidator_->ClearOldStates();
-  }
-}
-
-void GraphicsLayer::NotifyChildListChange() {}
-
-void GraphicsLayer::UpdateLayerIsDrawable() {
-  // For the rest of the accelerated compositor code, there is no reason to make
-  // a distinction between drawsContent and contentsVisible. So, for
-  // m_layer->layer(), these two flags are combined here. |m_contentsLayer|
-  // shouldn't receive the drawsContent flag, so it is only given
-  // contentsVisible.
-
-  CcLayer().SetIsDrawable(draws_content_ && contents_visible_);
-  if (contents_layer_)
-    contents_layer_->SetIsDrawable(contents_visible_);
-
-  if (draws_content_)
-    CcLayer().SetNeedsDisplay();
-}
-
-void GraphicsLayer::UpdateContentsLayerBounds() {
-  if (!contents_layer_)
-    return;
-
-  contents_layer_->SetBounds(contents_rect_.size());
-}
-
-void GraphicsLayer::SetContentsToCcLayer(
-    scoped_refptr<cc::Layer> contents_layer) {
-  DCHECK_NE(contents_layer, layer_);
-  SetContentsTo(std::move(contents_layer));
-}
-
-void GraphicsLayer::SetContentsTo(scoped_refptr<cc::Layer> layer) {
-  if (layer) {
-    if (contents_layer_ != layer) {
-      contents_layer_ = std::move(layer);
-      // It is necessary to call SetDrawsContent() as soon as we receive the new
-      // contents_layer, for the correctness of early exit conditions in
-      // SetDrawsContent() and SetContentsVisible().
-      contents_layer_->SetIsDrawable(contents_visible_);
-      contents_layer_->SetHitTestable(contents_visible_);
-      NotifyChildListChange();
-    }
-    UpdateContentsLayerBounds();
-  } else if (contents_layer_) {
-    contents_layer_ = nullptr;
-    NotifyChildListChange();
-  }
-}
-
-RasterInvalidator& GraphicsLayer::EnsureRasterInvalidator() {
-  if (!raster_invalidator_) {
-    raster_invalidator_ = std::make_unique<RasterInvalidator>();
-    raster_invalidator_->SetTracksRasterInvalidations(
-        IsTrackingRasterInvalidations());
-  }
-  return *raster_invalidator_;
-}
-
-bool GraphicsLayer::IsTrackingRasterInvalidations() const {
-#if DCHECK_IS_ON()
-  if (VLOG_IS_ON(3))
-    return true;
-#endif
-  return false;
-}
-
-void GraphicsLayer::UpdateTrackingRasterInvalidations() {
-  if (IsTrackingRasterInvalidations())
-    EnsureRasterInvalidator().SetTracksRasterInvalidations(true);
-  else if (raster_invalidator_)
-    raster_invalidator_->SetTracksRasterInvalidations(false);
-}
-
-void GraphicsLayer::ResetTrackedRasterInvalidations() {
-  if (auto* tracking = GetRasterInvalidationTracking())
-    tracking->ClearInvalidations();
-}
-
-bool GraphicsLayer::HasTrackedRasterInvalidations() const {
-  if (auto* tracking = GetRasterInvalidationTracking())
-    return tracking->HasInvalidations();
-  return false;
-}
-
-RasterInvalidationTracking* GraphicsLayer::GetRasterInvalidationTracking()
-    const {
-  return raster_invalidator_ ? raster_invalidator_->GetTracking() : nullptr;
-}
-
-void GraphicsLayer::TrackRasterInvalidation(const DisplayItemClient& client,
-                                            const gfx::Rect& rect,
-                                            PaintInvalidationReason reason) {
-  if (RasterInvalidationTracking::ShouldAlwaysTrack())
-    EnsureRasterInvalidator().EnsureTracking();
-
-  // This only tracks invalidations that the cc::Layer is fully invalidated
-  // directly, e.g. from SetContentsNeedsDisplay(), etc. Other raster
-  // invalidations are tracked in RasterInvalidator.
-  if (auto* tracking = GetRasterInvalidationTracking()) {
-    tracking->AddInvalidation(client.Id(), client.DebugName(), rect, reason);
-  }
-}
-
-String GraphicsLayer::DebugName(const cc::Layer* layer) const {
-  NOTREACHED();
-  return "";
-}
-
-const gfx::Size& GraphicsLayer::Size() const {
-  return CcLayer().bounds();
-}
-
-void GraphicsLayer::SetSize(const gfx::Size& size) {
-  DCHECK(size.width() >= 0 && size.height() >= 0);
-
-  if (size == CcLayer().bounds())
-    return;
-
-  Invalidate(PaintInvalidationReason::kIncremental);  // as DisplayItemClient.
-
-  CcLayer().SetBounds(size);
-  SetNeedsCheckRasterInvalidation();
-  // Note that we don't resize contents_layer_. It's up the caller to do that.
-}
-
-void GraphicsLayer::SetDrawsContent(bool draws_content) {
-  // NOTE: This early-exit is only correct because we also properly call
-  // cc::Layer::SetIsDrawable() whenever |contents_layer_| is set to a new
-  // layer in SetupContentsLayer().
-  if (draws_content == draws_content_)
-    return;
-
-  // This flag will be updated when the layer is repainted.
-  should_create_layers_after_paint_ = false;
-
-  draws_content_ = draws_content;
-  UpdateLayerIsDrawable();
-
-  if (!draws_content) {
-    paint_controller_.reset();
-    raster_invalidator_.reset();
-  }
-}
-
-void GraphicsLayer::SetContentsVisible(bool contents_visible) {
-  // NOTE: This early-exit is only correct because we also properly call
-  // cc::Layer::SetIsDrawable() whenever |contents_layer_| is set to a new
-  // layer in SetupContentsLayer().
-  if (contents_visible == contents_visible_)
-    return;
-
-  contents_visible_ = contents_visible;
-  UpdateLayerIsDrawable();
-}
-
-void GraphicsLayer::SetPaintsHitTest(bool paints_hit_test) {
-  if (paints_hit_test_ == paints_hit_test)
-    return;
-  // This flag will be updated when the layer is repainted.
-  should_create_layers_after_paint_ = false;
-  paints_hit_test_ = paints_hit_test;
-}
-
-void GraphicsLayer::SetHitTestable(bool should_hit_test) {
-  if (hit_testable_ == should_hit_test)
-    return;
-  hit_testable_ = should_hit_test;
-  CcLayer().SetHitTestable(should_hit_test);
-}
-
-void GraphicsLayer::InvalidateContents() {
-  if (contents_layer_) {
-    contents_layer_->SetNeedsDisplay();
-    TrackRasterInvalidation(*this, contents_rect_,
-                            PaintInvalidationReason::kFullLayer);
-  }
-}
-
-void GraphicsLayer::InvalidateRaster(const gfx::Rect& rect) {
-  DCHECK(PaintsContentOrHitTest());
-  raster_invalidated_ = true;
-  CcLayer().SetNeedsDisplayRect(rect);
-}
-
-void GraphicsLayer::SetContentsRect(const gfx::Rect& rect) {
-  if (rect == contents_rect_)
-    return;
-
-  contents_rect_ = rect;
-  UpdateContentsLayerBounds();
-}
-
-void GraphicsLayer::SetPaintingPhase(GraphicsLayerPaintingPhase phase) {
-  if (painting_phase_ == phase)
-    return;
-  painting_phase_ = phase;
-  Invalidate(PaintInvalidationReason::kFullLayer);  // As DisplayItemClient.
-}
-
-PaintController& GraphicsLayer::GetPaintController() const {
-  CHECK(PaintsContentOrHitTest());
-  if (!paint_controller_)
-    paint_controller_ = std::make_unique<PaintController>();
-  return *paint_controller_;
-}
-
-void GraphicsLayer::SetElementId(const CompositorElementId& id) {
-  CcLayer().SetElementId(id);
-}
-
-void GraphicsLayer::SetLayerState(const PropertyTreeStateOrAlias& layer_state,
-                                  const gfx::Vector2d& layer_offset) {
-  if (layer_state_) {
-    if (layer_state_->state == layer_state &&
-        layer_state_->offset == layer_offset)
-      return;
-    layer_state_->state = layer_state;
-    layer_state_->offset = layer_offset;
-  } else {
-    layer_state_ = std::make_unique<LayerState>(
-        LayerState{RefCountedPropertyTreeState(layer_state), layer_offset});
-  }
-
-  CcLayer().SetSubtreePropertyChanged();
-}
-
-void GraphicsLayer::SetContentsLayerState(
-    const PropertyTreeStateOrAlias& layer_state,
-    const gfx::Vector2d& layer_offset) {
-  DCHECK(ContentsLayer());
-
-  if (contents_layer_state_) {
-    if (contents_layer_state_->state == layer_state &&
-        contents_layer_state_->offset == layer_offset)
-      return;
-    contents_layer_state_->state = layer_state;
-    contents_layer_state_->offset = layer_offset;
-  } else {
-    contents_layer_state_ = std::make_unique<LayerState>(
-        LayerState{RefCountedPropertyTreeState(layer_state), layer_offset});
-  }
-
-  ContentsLayer()->SetSubtreePropertyChanged();
-}
-
-gfx::Rect GraphicsLayer::PaintableRegion() const {
-  return previous_interest_rect_;
-}
-
-scoped_refptr<cc::DisplayItemList> GraphicsLayer::PaintContentsToDisplayList() {
-  DCHECK(!ShouldCreateLayersAfterPaint());
-  return cc_display_item_list_;
-}
-
-size_t GraphicsLayer::ApproximateUnsharedMemoryUsageRecursive() const {
-  size_t result = sizeof(*this);
-  if (paint_controller_)
-    result += paint_controller_->ApproximateUnsharedMemoryUsage();
-  if (raster_invalidator_)
-    result += raster_invalidator_->ApproximateUnsharedMemoryUsage();
-  for (GraphicsLayer* child : Children())
-    result += child->ApproximateUnsharedMemoryUsageRecursive();
-  return result;
-}
-
-void GraphicsLayer::Trace(Visitor* visitor) const {
-  visitor->Trace(children_);
-  visitor->Trace(parent_);
-  DisplayItemClient::Trace(visitor);
-}
-
-}  // namespace blink
-
-#if DCHECK_IS_ON()
-void showGraphicsLayerTree(const blink::GraphicsLayer* layer) {
-  if (!layer) {
-    LOG(ERROR) << "Cannot showGraphicsLayerTree for (nil).";
-    return;
-  }
-
-  String output = blink::GraphicsLayerTreeAsTextForTesting(layer, 0xffffffff);
-  LOG(INFO) << output.Utf8();
-}
-#endif
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.h b/third_party/blink/renderer/platform/graphics/graphics_layer.h
deleted file mode 100644
index 0fa6a8b..0000000
--- a/third_party/blink/renderer/platform/graphics/graphics_layer.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2013 Intel Corporation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GRAPHICS_LAYER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GRAPHICS_LAYER_H_
-
-#include <memory>
-
-#include "base/dcheck_is_on.h"
-#include "cc/input/scroll_snap_data.h"
-#include "cc/layers/content_layer_client.h"
-#include "cc/layers/layer.h"
-#include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
-#include "third_party/blink/renderer/platform/graphics/color.h"
-#include "third_party/blink/renderer/platform/graphics/compositing/layers_as_json.h"
-#include "third_party/blink/renderer/platform/graphics/compositing_reasons.h"
-#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer_client.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
-#include "third_party/blink/renderer/platform/graphics/image_orientation.h"
-#include "third_party/blink/renderer/platform/graphics/paint/display_item_client.h"
-#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
-#include "third_party/blink/renderer/platform/graphics/paint/raster_invalidator.h"
-#include "third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h"
-#include "third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
-#include "ui/gfx/geometry/point_f.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size_f.h"
-
-namespace cc {
-class DisplayItemList;
-class PictureLayer;
-}  // namespace cc
-
-namespace blink {
-
-class GraphicsLayer;
-class PaintController;
-class RasterInvalidationTracking;
-class RasterInvalidator;
-
-typedef HeapVector<Member<GraphicsLayer>, 64> GraphicsLayerVector;
-
-// GraphicsLayer is an abstraction for a rendering surface with backing store,
-// which may have associated transformation and animations.
-class PLATFORM_EXPORT GraphicsLayer : public GarbageCollected<GraphicsLayer>,
-                                      public DisplayItemClient,
-                                      public LayerAsJSONClient,
-                                      private cc::ContentLayerClient {
- public:
-  // |Destroy()| shouold be called when the object is no longer used.
-  explicit GraphicsLayer();
-  GraphicsLayer(const GraphicsLayer&) = delete;
-  GraphicsLayer& operator=(const GraphicsLayer&) = delete;
-  ~GraphicsLayer() override;
-  void Destroy();
-
-  void SetCompositingReasons(CompositingReasons reasons) {
-    compositing_reasons_ = reasons;
-  }
-  CompositingReasons GetCompositingReasons() const {
-    return compositing_reasons_;
-  }
-
-  SquashingDisallowedReasons GetSquashingDisallowedReasons() const {
-    return squashing_disallowed_reasons_;
-  }
-  void SetSquashingDisallowedReasons(SquashingDisallowedReasons reasons) {
-    squashing_disallowed_reasons_ = reasons;
-  }
-
-  void SetOwnerNodeId(DOMNodeId id) { owner_node_id_ = id; }
-
-  GraphicsLayer* Parent() const { return parent_; }
-  void SetParent(GraphicsLayer*);  // Internal use only.
-
-  const HeapVector<Member<GraphicsLayer>>& Children() const {
-    return children_;
-  }
-  // Returns true if the child list changed.
-  bool SetChildren(const GraphicsLayerVector&);
-
-  // Add child layers. If the child is already parented, it will be removed from
-  // its old parent.
-  void AddChild(GraphicsLayer*);
-
-  void RemoveAllChildren();
-  void RemoveFromParent();
-
-  // The offset is the origin of the layoutObject minus the origin of the
-  // graphics layer (so either zero or negative).
-  gfx::Vector2d OffsetFromLayoutObject() const {
-    return offset_from_layout_object_;
-  }
-  void SetOffsetFromLayoutObject(const gfx::Vector2d&);
-
-  // The size of the layer.
-  const gfx::Size& Size() const;
-  void SetSize(const gfx::Size&);
-
-  bool DrawsContent() const { return draws_content_; }
-  void SetDrawsContent(bool);
-
-  // False if no hit test data will be recorded onto this GraphicsLayer.
-  // This is different from |DrawsContent| because hit test data are internal
-  // to blink and are not copied to the cc::Layer's display list.
-  bool PaintsHitTest() const { return paints_hit_test_; }
-  void SetPaintsHitTest(bool);
-
-  bool PaintsContentOrHitTest() const {
-    return draws_content_ || paints_hit_test_;
-  }
-
-  bool ContentsAreVisible() const { return contents_visible_; }
-  void SetContentsVisible(bool);
-
-  void SetHitTestable(bool);
-  bool IsHitTestable() const { return hit_testable_; }
-
-  // Some GraphicsLayers paint only the foreground or the background content
-  GraphicsLayerPaintingPhase PaintingPhase() const { return painting_phase_; }
-  void SetPaintingPhase(GraphicsLayerPaintingPhase);
-
-  void InvalidateContents();
-
-  // Set that the position/size of the contents (image or video).
-  void SetContentsRect(const gfx::Rect&);
-
-  void SetContentsToCcLayer(scoped_refptr<cc::Layer> contents_layer);
-  bool HasContentsLayer() const { return ContentsLayer(); }
-  cc::Layer* ContentsLayer() const { return contents_layer_.get(); }
-
-  const gfx::Rect& ContentsRect() const { return contents_rect_; }
-
-  // For hosting this GraphicsLayer in a native layer hierarchy.
-  cc::PictureLayer& CcLayer() const { return *layer_; }
-
-  bool IsTrackingRasterInvalidations() const;
-  void UpdateTrackingRasterInvalidations();
-  void ResetTrackedRasterInvalidations();
-  bool HasTrackedRasterInvalidations() const;
-  RasterInvalidationTracking* GetRasterInvalidationTracking() const;
-  void TrackRasterInvalidation(const DisplayItemClient&,
-                               const gfx::Rect&,
-                               PaintInvalidationReason);
-
-  PaintController& GetPaintController() const;
-
-  void SetElementId(const CompositorElementId&);
-
-  // DisplayItemClient methods
-  String DebugName() const final { return ""; }
-  DOMNodeId OwnerNodeId() const final { return owner_node_id_; }
-
-  // LayerAsJSONClient implementation.
-  void AppendAdditionalInfoAsJSON(LayerTreeFlags,
-                                  const cc::Layer&,
-                                  JSONObject&) const override;
-
-  bool HasLayerState() const { return layer_state_.get(); }
-  void SetLayerState(const PropertyTreeStateOrAlias&,
-                     const gfx::Vector2d& layer_offset);
-  PropertyTreeStateOrAlias GetPropertyTreeState() const {
-    return layer_state_->state.GetPropertyTreeState();
-  }
-  gfx::Vector2d GetOffsetFromTransformNode() const {
-    return layer_state_->offset;
-  }
-
-  void SetContentsLayerState(const PropertyTreeStateOrAlias&,
-                             const gfx::Vector2d& layer_offset);
-  PropertyTreeStateOrAlias GetContentsPropertyTreeState() const {
-    return contents_layer_state_
-               ? contents_layer_state_->state.GetPropertyTreeState()
-               : GetPropertyTreeState();
-  }
-  gfx::Vector2d GetContentsOffsetFromTransformNode() const {
-    return contents_layer_state_ ? contents_layer_state_->offset
-                                 : GetOffsetFromTransformNode();
-  }
-
-  void SetNeedsCheckRasterInvalidation() {
-    needs_check_raster_invalidation_ = true;
-  }
-
-  void SetShouldCreateLayersAfterPaint(bool);
-  bool ShouldCreateLayersAfterPaint() const {
-    return should_create_layers_after_paint_;
-  }
-
-  // Whether this GraphicsLayer is repainted in the last Paint().
-  bool Repainted() const { return repainted_; }
-
-  size_t ApproximateUnsharedMemoryUsageRecursive() const;
-
-  void Trace(Visitor* visitor) const override;
-
- protected:
-  String DebugName(const cc::Layer*) const;
-
- private:
-  friend class CompositedLayerMappingTest;
-  friend class GraphicsLayerTest;
-
-  // cc::ContentLayerClient implementation.
-  gfx::Rect PaintableRegion() const final;
-  scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList() final;
-  bool FillsBoundsCompletely() const final { return false; }
-
-  void ClearPaintStateRecursively();
-
-  // Adds a child without calling NotifyChildListChange(), so that adding
-  // children can be batched before updating.
-  void AddChildInternal(GraphicsLayer*);
-
-#if DCHECK_IS_ON()
-  bool HasAncestor(GraphicsLayer*) const;
-#endif
-
-  // Helper functions used by settors to keep layer's the state consistent.
-  void NotifyChildListChange();
-  void UpdateLayerIsDrawable();
-  void UpdateContentsLayerBounds();
-
-  void SetContentsTo(scoped_refptr<cc::Layer>);
-
-  RasterInvalidator& EnsureRasterInvalidator();
-  void InvalidateRaster(const gfx::Rect&);
-
-  // Offset from the owning layoutObject
-  gfx::Vector2d offset_from_layout_object_;
-
-  TransformationMatrix transform_;
-
-  bool draws_content_ : 1;
-  bool paints_hit_test_ : 1;
-  bool contents_visible_ : 1;
-  bool hit_testable_ : 1;
-  bool needs_check_raster_invalidation_ : 1;
-  bool raster_invalidated_ : 1;
-  // True if the cc::Layers for this GraphicsLayer should be created after
-  // paint (in PaintArtifactCompositor). This depends on the display item list
-  // and is updated after CommitNewDisplayItems.
-  bool should_create_layers_after_paint_ : 1;
-  bool repainted_ : 1;
-
-  GraphicsLayerPaintingPhase painting_phase_;
-
-  HeapVector<Member<GraphicsLayer>> children_;
-  Member<GraphicsLayer> parent_;
-
-  gfx::Rect contents_rect_;
-
-  scoped_refptr<cc::PictureLayer> layer_;
-  scoped_refptr<cc::Layer> contents_layer_;
-  scoped_refptr<cc::DisplayItemList> cc_display_item_list_;
-
-  SquashingDisallowedReasons squashing_disallowed_reasons_ =
-      SquashingDisallowedReason::kNone;
-
-  mutable std::unique_ptr<PaintController> paint_controller_;
-
-  // Used only when CullRectUpdate is not enabled.
-  gfx::Rect previous_interest_rect_;
-
-  struct LayerState {
-    // In theory, it's unnecessary to use RefCountedPropertyTreeState because
-    // when it's used, the state should always reference current paint property
-    // nodes in ObjectPaintProperties. This is to workaround under-invalidation
-    // of layer state.
-    RefCountedPropertyTreeState state;
-    gfx::Vector2d offset;
-  };
-  std::unique_ptr<LayerState> layer_state_;
-  std::unique_ptr<LayerState> contents_layer_state_;
-
-  std::unique_ptr<RasterInvalidator> raster_invalidator_;
-  RasterInvalidator::RasterInvalidationFunction raster_invalidation_function_;
-
-  DOMNodeId owner_node_id_ = kInvalidDOMNodeId;
-  CompositingReasons compositing_reasons_ = CompositingReason::kNone;
-
-#if DCHECK_IS_ON()
-  bool is_destroyed_ = false;
-#endif
-};
-
-// Iterates all graphics layers that should be seen by the compositor in
-// pre-order. |GraphicsLayerType&| matches |GraphicsLayer&| or
-// |const GraphicsLayer&|. |GraphicsLayerFunction| accepts a GraphicsLayerType
-// parameter, and returns a bool to indicate if the recursion should continue.
-template <typename GraphicsLayerType,
-          typename GraphicsLayerFunction,
-          typename ContentsLayerFunction>
-void ForAllGraphicsLayers(
-    GraphicsLayerType& layer,
-    const GraphicsLayerFunction& graphics_layer_function,
-    const ContentsLayerFunction& contents_layer_function) {
-  if (!graphics_layer_function(layer))
-    return;
-
-  if (auto* contents_layer = layer.ContentsLayer())
-    contents_layer_function(layer, *contents_layer);
-
-  for (GraphicsLayer* child : layer.Children()) {
-    ForAllGraphicsLayers(*child, graphics_layer_function,
-                         contents_layer_function);
-  }
-}
-
-// Unlike ForAllGraphicsLayers, here |GraphicsLayerFunction| should return void.
-template <typename GraphicsLayerType,
-          typename GraphicsLayerFunction,
-          typename ContentsLayerFunction>
-void ForAllActiveGraphicsLayers(
-    GraphicsLayerType& layer,
-    const GraphicsLayerFunction& graphics_layer_function,
-    const ContentsLayerFunction& contents_layer_function) {
-  ForAllGraphicsLayers(
-      layer,
-      [&graphics_layer_function](GraphicsLayerType& layer) -> bool {
-        if (layer.Client().ShouldSkipPaintingSubtree())
-          return false;
-        if (layer.PaintsContentOrHitTest() || layer.IsHitTestable())
-          graphics_layer_function(layer);
-        return true;
-      },
-      contents_layer_function);
-}
-
-template <typename GraphicsLayerType, typename Function>
-void ForAllActiveGraphicsLayers(GraphicsLayerType& layer,
-                                const Function& function) {
-  ForAllActiveGraphicsLayers(layer, function,
-                             [](GraphicsLayerType&, const cc::Layer&) {});
-}
-
-template <typename GraphicsLayerType, typename Function>
-void ForAllPaintingGraphicsLayers(GraphicsLayerType& layer,
-                                  const Function& function) {
-  ForAllActiveGraphicsLayers(layer, [&function](GraphicsLayerType& layer) {
-    if (layer.PaintsContentOrHitTest())
-      function(layer);
-  });
-}
-
-}  // namespace blink
-
-#if DCHECK_IS_ON()
-// Outside the blink namespace for ease of invocation from gdb.
-PLATFORM_EXPORT void showGraphicsLayerTree(const blink::GraphicsLayer*);
-#endif
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GRAPHICS_LAYER_H_
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer_client.h b/third_party/blink/renderer/platform/graphics/graphics_layer_client.h
deleted file mode 100644
index 66126ab..0000000
--- a/third_party/blink/renderer/platform/graphics/graphics_layer_client.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2009 Apple 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GRAPHICS_LAYER_CLIENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GRAPHICS_LAYER_CLIENT_H_
-
-namespace blink {
-
-enum GraphicsLayerPaintingPhaseFlags {
-  kGraphicsLayerPaintBackground = (1 << 0),
-  kGraphicsLayerPaintForeground = (1 << 1),
-  kGraphicsLayerPaintMask = (1 << 2),
-  kGraphicsLayerPaintOverflowContents = (1 << 3),
-  kGraphicsLayerPaintCompositedScroll = (1 << 4),
-  kGraphicsLayerPaintDecoration = (1 << 5),
-  kGraphicsLayerPaintAllWithOverflowClip =
-      (kGraphicsLayerPaintBackground | kGraphicsLayerPaintForeground |
-       kGraphicsLayerPaintMask | kGraphicsLayerPaintDecoration)
-};
-typedef unsigned GraphicsLayerPaintingPhase;
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GRAPHICS_LAYER_CLIENT_H_
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer_tree_as_text.cc b/third_party/blink/renderer/platform/graphics/graphics_layer_tree_as_text.cc
deleted file mode 100644
index cc7f3372..0000000
--- a/third_party/blink/renderer/platform/graphics/graphics_layer_tree_as_text.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/platform/graphics/graphics_layer_tree_as_text.h"
-
-#include "cc/layers/picture_layer.h"
-#include "third_party/blink/renderer/platform/geometry/geometry_as_json.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
-#include "third_party/blink/renderer/platform/json/json_values.h"
-
-namespace blink {
-
-namespace {
-
-std::unique_ptr<JSONObject> GraphicsLayerAsJSON(const GraphicsLayer* layer,
-                                                LayerTreeFlags flags) {
-  auto json = CCLayerAsJSON(layer->CcLayer(), flags);
-  // CCLayerAsJSON() doesn't know the name before paint or if the layer is a
-  // legacy GraphicsLayer which doesn't contribute to the cc layer list.
-  json->SetString("name", layer->DebugName());
-
-  // Content dumped after this point, down to AppendAdditionalInfoAsJSON, is
-  // specific to GraphicsLayer tree dumping when called from one of the methods
-  // in this file.
-
-  if (flags & kLayerTreeIncludesDebugInfo) {
-    if (layer->HasContentsLayer())
-      json->SetInteger("ccContentsLayerId", layer->ContentsLayer()->id());
-  }
-
-  if (flags & kLayerTreeIncludesDebugInfo &&
-      !layer->OffsetFromLayoutObject().IsZero()) {
-    json->SetArray("offsetFromLayoutObject",
-                   VectorAsJSONArray(layer->OffsetFromLayoutObject()));
-  }
-
-  if (!layer->ContentsAreVisible())
-    json->SetBoolean("contentsVisible", false);
-
-  if (layer->HasLayerState() && (flags & (kLayerTreeIncludesDebugInfo |
-                                          kLayerTreeIncludesPaintRecords))) {
-    json->SetString("layerState", layer->GetPropertyTreeState().ToString());
-    json->SetValue("layerOffset",
-                   VectorAsJSONArray(layer->GetOffsetFromTransformNode()));
-  }
-
-  layer->AppendAdditionalInfoAsJSON(flags, layer->CcLayer(), *json.get());
-
-  return json;
-}
-
-}  // namespace
-
-std::unique_ptr<JSONObject> GraphicsLayerTreeAsJSON(const GraphicsLayer* layer,
-                                                    LayerTreeFlags flags) {
-  DCHECK(flags & kOutputAsLayerTree);
-  std::unique_ptr<JSONObject> json = GraphicsLayerAsJSON(layer, flags);
-  if (layer->Children().size()) {
-    auto children_json = std::make_unique<JSONArray>();
-    for (wtf_size_t i = 0; i < layer->Children().size(); i++) {
-      children_json->PushObject(
-          GraphicsLayerTreeAsJSON(layer->Children()[i], flags));
-    }
-    json->SetArray("children", std::move(children_json));
-  }
-  return json;
-}
-
-String GraphicsLayerTreeAsTextForTesting(const GraphicsLayer* layer,
-                                         LayerTreeFlags flags) {
-  return GraphicsLayerTreeAsJSON(layer, flags)->ToPrettyJSONString();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer_tree_as_text.h b/third_party/blink/renderer/platform/graphics/graphics_layer_tree_as_text.h
deleted file mode 100644
index afabfcce..0000000
--- a/third_party/blink/renderer/platform/graphics/graphics_layer_tree_as_text.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GRAPHICS_LAYER_TREE_AS_TEXT_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GRAPHICS_LAYER_TREE_AS_TEXT_H_
-
-#include <memory>
-
-#include "third_party/blink/renderer/platform/graphics/compositing/layers_as_json.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-
-namespace blink {
-
-class GraphicsLayer;
-class JSONObject;
-
-PLATFORM_EXPORT std::unique_ptr<JSONObject> GraphicsLayerTreeAsJSON(
-    const GraphicsLayer*,
-    LayerTreeFlags);
-
-PLATFORM_EXPORT String GraphicsLayerTreeAsTextForTesting(const GraphicsLayer*,
-                                                         LayerTreeFlags);
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GRAPHICS_LAYER_TREE_AS_TEXT_H_
diff --git a/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.cc b/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.cc
index 67b8b90..cfbbe01 100644
--- a/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.cc
@@ -5,7 +5,6 @@
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_record.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
diff --git a/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc b/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
index 54f87768..0fef6f4 100644
--- a/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
@@ -10,7 +10,6 @@
 #include "cc/layers/picture_layer.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/layers_as_json.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.cc b/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.cc
deleted file mode 100644
index ba96b66..0000000
--- a/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.cc
+++ /dev/null
@@ -1,122 +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 "third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.h"
-
-#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-
-namespace blink {
-
-namespace {
-
-struct SquashingDisallowedReasonStringMap {
-  SquashingDisallowedReasons reason;
-  const char* short_name;
-  const char* description;
-};
-
-constexpr SquashingDisallowedReasonStringMap
-    kSquashingDisallowedReasonsStringMap[] = {
-        {SquashingDisallowedReason::kScrollsWithRespectToSquashingLayer,
-         "scrollsWithRespectToSquashingLayer",
-         "Cannot be squashed since this layer scrolls with respect to the "
-         "squashing layer"},
-        {SquashingDisallowedReason::kSquashingSparsityExceeded,
-         "squashingSparsityExceeded",
-         "Cannot be squashed as the squashing layer would become too sparse"},
-        {SquashingDisallowedReason::kClippingContainerMismatch,
-         "squashingClippingContainerMismatch",
-         "Cannot be squashed because this layer has a different clipping "
-         "container than the squashing layer"},
-        {SquashingDisallowedReason::kOpacityAncestorMismatch,
-         "squashingOpacityAncestorMismatch",
-         "Cannot be squashed because this layer has a different opacity "
-         "ancestor than the squashing layer"},
-        {SquashingDisallowedReason::kTransformAncestorMismatch,
-         "squashingTransformAncestorMismatch",
-         "Cannot be squashed because this layer has a different transform "
-         "ancestor than the squashing layer"},
-        {SquashingDisallowedReason::kPreserve3DSortingContextMismatch,
-         "squashingPreserve3DSortingContextMismatch",
-         "Cannot be squashed because this layer is part of a different 3-D"
-         "Rendering Context than the squashing layer"},
-        {SquashingDisallowedReason::kFilterMismatch,
-         "squashingFilterAncestorMismatch",
-         "Cannot be squashed because this layer has a different filter "
-         "ancestor than the squashing layer, or this layer has a filter"},
-        {SquashingDisallowedReason::kWouldBreakPaintOrder,
-         "squashingWouldBreakPaintOrder",
-         "Cannot be squashed without breaking paint order"},
-        {SquashingDisallowedReason::kSquashingVideoIsDisallowed,
-         "squashingVideoIsDisallowed", "Squashing video is not supported"},
-        {SquashingDisallowedReason::kSquashingLayoutEmbeddedContentIsDisallowed,
-         "squashingLayoutEmbeddedContentIsDisallowed",
-         "Squashing a frame, iframe or plugin is not supported."},
-        {SquashingDisallowedReason::kSquashingBlendingIsDisallowed,
-         "squashingBlendingDisallowed",
-         "Squashing a layer with blending is not supported."},
-        {SquashingDisallowedReason::kNearestFixedPositionMismatch,
-         "squashingNearestFixedPositionMismatch",
-         "Cannot be squashed because this layer has a different nearest fixed "
-         "position layer than the squashing layer"},
-        {SquashingDisallowedReason::kSquashingLayerIsAnimating,
-         "squashingLayerIsAnimating",
-         "Cannot squash into a layer that is animating."},
-        {SquashingDisallowedReason::kRenderingContextMismatch,
-         "squashingLayerRenderingContextMismatch",
-         "Cannot squash layers with different 3D contexts."},
-        {SquashingDisallowedReason::kFragmentedContent,
-         "SquashingDisallowedReasonFragmentedContent",
-         "Cannot squash layers that are inside fragmentation contexts."},
-        {SquashingDisallowedReason::kClipPathMismatch,
-         "SquashingDisallowedReasonClipPathMismatch",
-         "Cannot squash layers across clip-path boundaries."},
-        {SquashingDisallowedReason::kMaskMismatch,
-         "SquashingDisallowedReasonMaskMismatch",
-         "Cannot squash layers across mask boundaries."},
-        {SquashingDisallowedReason::kCrossesLayoutContainmentBoundary,
-         "SquashingDisallowedReasonCrossesLayoutContainmentBoundary",
-         "Cannot squash layer across layout containment boundary."},
-        {SquashingDisallowedReason::kDisabled,
-         "SquashingDisallowedReasonDisabled",
-         "Squashing is disabled by runtime flag."},
-};
-
-}  // anonymous namespace
-
-Vector<const char*> SquashingDisallowedReason::ShortNames(
-    SquashingDisallowedReasons reasons) {
-#define V(name)                                                          \
-  static_assert(SquashingDisallowedReason::k##name ==                    \
-                    kSquashingDisallowedReasonsStringMap                 \
-                        [SquashingDisallowedReason::kE##name]            \
-                            .reason,                                     \
-                "kSquashingDisallowedReasonsStringMap needs update for " \
-                "SquashingDisallowedReason::k" #name);                   \
-  FOR_EACH_COMPOSITING_REASON(V)
-#undef V
-
-  Vector<const char*> result;
-  if (reasons == kNone)
-    return result;
-  for (auto& map : kSquashingDisallowedReasonsStringMap) {
-    if (reasons & map.reason)
-      result.push_back(map.short_name);
-  }
-  return result;
-}
-
-Vector<const char*> SquashingDisallowedReason::Descriptions(
-    SquashingDisallowedReasons reasons) {
-  Vector<const char*> result;
-  if (reasons == kNone)
-    return result;
-  for (auto& map : kSquashingDisallowedReasonsStringMap) {
-    if (reasons & map.reason)
-      result.push_back(map.description);
-  }
-  return result;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.h b/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.h
deleted file mode 100644
index c9fb8c6..0000000
--- a/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.h
+++ /dev/null
@@ -1,66 +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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_SQUASHING_DISALLOWED_REASONS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_SQUASHING_DISALLOWED_REASONS_H_
-
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-using SquashingDisallowedReasons = unsigned;
-
-#define FOR_EACH_SQUASHING_DISALLOWED_REASON(V) \
-  V(ScrollsWithRespectToSquashingLayer)         \
-  V(SquashingSparsityExceeded)                  \
-  V(ClippingContainerMismatch)                  \
-  V(OpacityAncestorMismatch)                    \
-  V(TransformAncestorMismatch)                  \
-  V(Preserve3DSortingContextMismatch)           \
-  V(FilterMismatch)                             \
-  V(WouldBreakPaintOrder)                       \
-  V(SquashingVideoIsDisallowed)                 \
-  V(SquashingLayoutEmbeddedContentIsDisallowed) \
-  V(SquashingBlendingIsDisallowed)              \
-  V(NearestFixedPositionMismatch)               \
-  V(SquashingLayerIsAnimating)                  \
-  V(RenderingContextMismatch)                   \
-  V(FragmentedContent)                          \
-  V(ClipPathMismatch)                           \
-  V(MaskMismatch)                               \
-  V(CrossesLayoutContainmentBoundary)           \
-  V(Disabled)
-
-class PLATFORM_EXPORT SquashingDisallowedReason {
-  DISALLOW_NEW();
-
- private:
-  // This contains ordinal values for squashing disallowed reasons and will be
-  // used to generate the squashing disallowed reason bits.
-  enum {
-#define V(name) kE##name,
-    FOR_EACH_SQUASHING_DISALLOWED_REASON(V)
-#undef V
-  };
-
-#define V(name) static_assert(kE##name < 32, "Should fit in 32 bits");
-  FOR_EACH_SQUASHING_DISALLOWED_REASON(V)
-#undef V
-
- public:
-  static Vector<const char*> ShortNames(SquashingDisallowedReasons);
-  static Vector<const char*> Descriptions(SquashingDisallowedReasons);
-
-  enum : SquashingDisallowedReasons {
-    kNone = 0,
-#define V(name) k##name = 1u << kE##name,
-    FOR_EACH_SQUASHING_DISALLOWED_REASON(V)
-#undef V
-  };
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_SQUASHING_DISALLOWED_REASONS_H_
diff --git a/third_party/blink/tools/blinkpy/common/net/rpc.py b/third_party/blink/tools/blinkpy/common/net/rpc.py
new file mode 100644
index 0000000..d28a4f3
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/common/net/rpc.py
@@ -0,0 +1,75 @@
+# Copyright (C) 2021 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.
+
+import json
+import six
+
+from blinkpy.common.net.luci_auth import LuciAuth
+
+# These characters always appear at the beginning of the RPC response.
+SEARCHBUILDS_RESPONSE_PREFIX = b")]}'"
+
+
+class Rpc(object):
+    def __init__(self, host):
+        self._host = host
+
+    def luci_rpc(self, url, data):
+        """Fetches json data through Luci RPCs
+
+        Args:
+            url: url for the rpc call
+            data: the request body in json format
+
+        Returns:
+            On success: Returns the json representation of the response.
+            Otherwise: None
+        """
+        luci_token = LuciAuth(self._host).get_access_token()
+        headers = {
+            'Authorization': 'Bearer ' + luci_token,
+            'Accept': 'application/json',
+            'Content-Type': 'application/json',
+        }
+        if six.PY3:
+            body = json.dumps(data).encode("utf-8")
+        else:
+            body = json.dumps(data)
+        response = self._host.web.request('POST', url, data=body, headers=headers)
+        if response.getcode() == 200:
+            response_body = response.read()
+            if response_body.startswith(SEARCHBUILDS_RESPONSE_PREFIX):
+                response_body = response_body[len(SEARCHBUILDS_RESPONSE_PREFIX
+                                                  ):]
+            return json.loads(response_body)
+
+        _log.error(
+            "RPC request failed. Status=%s, url=%s" %
+            (response.status, url))
+        _log.debug("Full RPC response: %s" % str(response))
+        return None
diff --git a/third_party/blink/tools/blinkpy/common/net/rpc_mock.py b/third_party/blink/tools/blinkpy/common/net/rpc_mock.py
new file mode 100644
index 0000000..4c578de
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/common/net/rpc_mock.py
@@ -0,0 +1,38 @@
+# Copyright (C) 2011 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.
+
+
+class MockRpc(object):
+    def __init__(self, host):  # pylint: disable=unused-argument
+        self._response = None
+
+    def luci_rpc(self, url, data):  # pylint: disable=unused-argument
+        return self._response
+
+    def set_response(self, data):
+        self._response = data
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_uploader.py b/third_party/blink/tools/blinkpy/w3c/wpt_uploader.py
new file mode 100644
index 0000000..a43c7f6
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_uploader.py
@@ -0,0 +1,206 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Uploads Wpt test results from Chromium to wpt.fyi."""
+
+import argparse
+import gzip
+import json
+import logging
+import os
+import requests
+import tempfile
+
+from blinkpy.common.net.rpc import Rpc
+from blinkpy.common.system.log_utils import configure_logging
+
+_log = logging.getLogger(__name__)
+
+
+class WptReportUploader(object):
+    def __init__(self, host):
+        self._host = host
+        self._rpc = Rpc(host)
+        self._dry_run = False
+        configure_logging(logging_level=logging.INFO, include_time=True)
+
+    def main(self, argv=None):
+        """Pull wpt_report.json from latest CI runs, merge the reports and
+        upload that to wpt.fyi.
+
+        Returns:
+            A boolean: True if success, False if there were any failures.
+        """
+        options = self.parse_args(argv)
+        if options.verbose:
+            configure_logging(logging_level=logging.DEBUG, include_time=True)
+        self._dry_run = options.dry_run
+
+        rv = 0
+
+        builders = [("chromium", "ci", "android-webview-pie-x86-wpt-fyi-rel")]
+        for builder in builders:
+            reports = []
+            _log.info("Uploading report for %s" % builder[2])
+            build = self.fetch_latest_complete_build(*builder)
+            if build:
+                _log.info("Find latest completed build %d" % build.get("number"))
+                urls = self.fetch_wpt_report_urls(build.get("id"))
+                for url in urls:
+                    _log.info("Fetching wpt report from %s" % url)
+                    res = self._host.web.request("GET", url)
+                    if res.getcode() == 200:
+                        body = res.read()
+                        reports.append(json.loads(body))
+                    else:
+                        _log.error("Failed to fetch wpt report.")
+
+            merged_report = self.merge_reports(reports)
+
+            with tempfile.TemporaryDirectory() as tmpdir:
+                path = os.path.join(tmpdir, "reports.json.gz")
+                with gzip.open(path, 'wt', encoding="utf-8") as zipfile:
+                    json.dump(merged_report, zipfile)
+                rv = rv | self.upload_report(path)
+            _log.info(" ")
+
+        return rv
+
+    def fetch_wpt_report_urls(self, build_id):
+        """Get a list of fetchUrl for wpt-report from given build.
+
+        This uses the QueryArtifacts rpc format specified in
+        https://source.chromium.org/chromium/infra/infra/+/main:go/src/go.chromium.org/luci/resultdb/proto/v1/resultdb.proto
+
+        The response is a list of dicts of the following form:
+
+        {
+            'artifacts': [
+                {
+                    'name': 'some name',
+                    'artifactId': 'wpt_reports_dada.json',
+                    'fetchUrl': 'https://something...',
+                    'fetchUrlExpiration': 'some future time',
+                    'sizeBytes': '8472164'
+                },
+                ... more artifacts
+            ]
+        }
+        Returns a list of URLs for wpt report
+        """
+
+        invocation = "invocations/build-%s" % build_id
+        data = {
+            "invocations": [invocation],
+            "predicate": {
+                "followEdges": {"includedInvocations": True}
+            }
+        }
+        url = 'https://results.api.cr.dev/prpc/luci.resultdb.v1.ResultDB/QueryArtifacts'
+        res = self._rpc.luci_rpc(url, data)
+        artifacts = res.get("artifacts") if res else None
+        if not artifacts:
+            return []
+
+        rv = []
+        for artifact in artifacts:
+            if artifact.get("artifactId").startswith("wpt_reports"):
+                rv.append(artifact.get("fetchUrl"))
+        return rv
+
+    def fetch_latest_complete_build(self, project, bucket, builder_name):
+        """Gets latest successful build from a CI builder.
+
+        This uses the SearchBuilds rpc format specified in
+        https://cs.chromium.org/chromium/infra/go/src/go.chromium.org/luci/buildbucket/proto/rpc.proto
+
+        The response is a list of dicts of the following form:
+        {
+           "builds": [
+               {
+                   "id": "8828280326907235505",
+                   "builder": {
+                       "builder": "android-webview-pie-x86-wpt-fyi-rel"
+                   },
+                   "status": "SUCCESS"
+               },
+               ... more builds
+        }
+
+        This method returns the latest finished build.
+        """
+        data = {
+            "predicate": {
+                "builder": {
+                    "project": project,
+                    "bucket": bucket,
+                    "builder": builder_name
+                },
+                "status": "SUCCESS"
+            },
+            "fields": "builds.*.builder.builder,builds.*.number,builds.*.status,builds.*.id",
+            "pageSize": 10
+        }
+        url = 'https://cr-buildbucket.appspot.com/prpc/buildbucket.v2.Builds/SearchBuilds'
+        raw_results_json = self._rpc.luci_rpc(url, data)
+        if 'builds' not in raw_results_json:
+            return None
+        builds = raw_results_json['builds']
+        return builds[0] if builds else None
+
+    def upload_report(self, path_to_report):
+        """Upload the wpt report to wpt.fyi
+
+        The Api is defined at:
+        https://github.com/web-platform-tests/wpt.fyi/tree/main/api#results-creation
+        """
+        username = "chromium-ci-results-uploader"
+        password = "/!Lu:ahR%wrjb6B8x6cz"
+        url = "https://staging.wpt.fyi/api/results/upload"
+
+        session = requests.Session()
+        session.auth = (username, password)
+        with open(path_to_report, 'rb') as fp:
+            files = {'result_file': fp}
+            if self._dry_run:
+                _log.info("Dry run, no report uploaded.")
+                return 0
+            res = session.post(url=url, files=files)
+            if res.status_code == 200:
+                _log.info("Successfully uploaded wpt report with response: " + res.text)
+                report_id = res.text.split()[1]
+                _log.info("Report uploaded to https://staging.wpt.fyi/api/runs?run_id=%s" % report_id)
+                return 0
+            else:
+                _log.error("Upload wpt report failed with status code: %d", res.status_code)
+                return 1
+
+    def merge_reports(self, reports):
+        if not reports:
+            return {}
+
+        merged_report = {}
+        merged_report['run_info'] = reports[0]['run_info']
+        merged_report['time_start'] = reports[0]['time_start']
+        merged_report['results'] = []
+        merged_report['time_end'] = reports[0]['time_end']
+        for report in reports:
+            merged_report['time_start'] = min(merged_report['time_start'],
+                                              report['time_start'])
+            merged_report['results'].extend(report['results'])
+            merged_report['time_end'] = max(merged_report['time_end'],
+                                            report['time_end'])
+        return merged_report
+
+    def parse_args(self, argv):
+        parser = argparse.ArgumentParser(description=__doc__)
+        parser.add_argument(
+            '-v',
+            '--verbose',
+            action='store_true',
+            help='log extra details that may be helpful when debugging')
+        parser.add_argument(
+            '--dry-run',
+            action='store_true',
+            help='See what would be done without actually uploading any report.')
+        return parser.parse_args(argv)
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_uploader_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_uploader_unittest.py
new file mode 100644
index 0000000..576201a1
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_uploader_unittest.py
@@ -0,0 +1,128 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from blinkpy.common.host_mock import MockHost
+from blinkpy.common.net.rpc_mock import MockRpc
+from blinkpy.common.system.log_testing import LoggingTestCase
+from blinkpy.w3c.wpt_uploader import WptReportUploader
+
+
+class WptReportUploaderTest(LoggingTestCase):
+    def setUp(self):
+        super(WptReportUploaderTest, self).setUp()
+        self.host = MockHost()
+
+    def test_fetch_wpt_report_urls(self):
+        uploader = WptReportUploader(self.host)
+        uploader._rpc = MockRpc(self.host)
+        res = {'artifacts': [{'name': 'report1',
+                              'artifactId': 'wpt_reports_dada.json',
+                              'fetchUrl': 'https://a.b.c/report1.json',
+                              'sizeBytes': '8472164'},
+                             {'name': 'report2',
+                              'artifactId': 'wpt_reports_dada.json',
+                              'fetchUrl': 'https://a.b.c/report2.json',
+                              'sizeBytes': '8455564'},
+                             {'name': 'other',
+                              'artifactId': 'other_dada.json',
+                              'fetchUrl': 'https://a.b.c/other.json',
+                              'sizeBytes': '9845'}]}
+        uploader._rpc.set_response(res)
+        self.assertEqual(uploader.fetch_wpt_report_urls("31415926535"),
+                         ['https://a.b.c/report1.json',
+                          'https://a.b.c/report2.json'])
+
+        res = {'artifacts': [{'name': 'other',
+                              'artifactId': 'other_dada.json',
+                              'fetchUrl': 'https://a.b.c/other.json',
+                              'sizeBytes': '9845'}]}
+        uploader._rpc.set_response(res)
+        self.assertEqual(uploader.fetch_wpt_report_urls("31415926535"), [])
+
+        res = {}
+        uploader._rpc.set_response(res)
+        self.assertEqual(uploader.fetch_wpt_report_urls("31415926535"), [])
+
+    def test_fetch_latest_complete_build(self):
+        uploader = WptReportUploader(self.host)
+        uploader._rpc = MockRpc(self.host)
+        builder = ("chromium", "ci", "test_builder")
+        expected = {"id": "31415926535",
+                    "builder": {"builder": "test_builder"},
+                    "status": "SUCCESS",
+                    "number": "100"}
+        res = {"builds": [expected,
+                          {"id": "89793238462",
+                           "builder": {"builder": "test_builder"},
+                           "status": "SUCCESS",
+                           "number": "99"},
+                          {"id": "64338327950",
+                           "builder": {"builder": "test_builder"},
+                           "status": "SUCCESS",
+                           "number": "98"}]}
+        uploader._rpc.set_response(res)
+        build = uploader.fetch_latest_complete_build(*builder)
+        self.assertEqual(build, expected)
+
+        res = {"builds": []}
+        uploader._rpc.set_response(res)
+        build = uploader.fetch_latest_complete_build(*builder)
+        self.assertIsNone(build)
+
+    def test_merge_reports(self):
+        uploader = WptReportUploader(self.host)
+        report0 = {"run_info": {"os": "linux",
+                                "processor": "x86_64",
+                                "product": "android_webview",
+                                "revision": "1408b119ac563b427a3e00a5514eef697c8da268"},
+                   "time_start": 4248,
+                   "results": [{"test": "foo1.html",
+                                "status": "PASS",
+                                "duration": 2100},
+                               {"test": "foo2.html",
+                                "status": "FAIL",
+                                "duration": 300}],
+                   "time_end": 7293}
+        self.assertEqual(uploader.merge_reports([report0]), report0)
+
+        report1 = {"run_info": {"os": "linux",
+                                "processor": "x86_64",
+                                "product": "android_webview",
+                                "revision": "1408b119ac563b427a3e00a5514eef697c8da268"},
+                   "time_start": 4200,
+                   "results": [{"test": "bar.html",
+                                "status": "PASS",
+                                "duration": 990}],
+                   "time_end": 7200}
+
+        report2 = {"run_info": {"os": "linux",
+                                "processor": "x86_64",
+                                "product": "android_webview",
+                                "revision": "1408b119ac563b427a3e00a5514eef697c8da268"},
+                   "time_start": 5200,
+                   "results": [{"test": "test.html",
+                                "status": "PASS",
+                                "duration": 990}],
+                   "time_end": 7999}
+
+        _expect = {"run_info": {"os": "linux",
+                                "processor": "x86_64",
+                                "product": "android_webview",
+                                "revision": "1408b119ac563b427a3e00a5514eef697c8da268"},
+                   "time_start": 4200,
+                   "results": [{"test": "foo1.html",
+                                "status": "PASS",
+                                "duration": 2100},
+                               {"test": "foo2.html",
+                                "status": "FAIL",
+                                "duration": 300},
+                               {"test": "bar.html",
+                                "status": "PASS",
+                                "duration": 990},
+                               {"test": "test.html",
+                                "status": "PASS",
+                                "duration": 990}],
+                   "time_end": 7999}
+        self.assertEqual(uploader.merge_reports([report0, report1, report2]),
+                         _expect)
diff --git a/third_party/blink/tools/wpt_upload.py b/third_party/blink/tools/wpt_upload.py
new file mode 100755
index 0000000..39259d4
--- /dev/null
+++ b/third_party/blink/tools/wpt_upload.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env vpython3
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Pulls the test results from CI builders and upload that to wpt.fyi."""
+
+from blinkpy.common import exit_codes
+from blinkpy.common.host import Host
+from blinkpy.common.path_finder import add_depot_tools_dir_to_os_path
+from blinkpy.w3c.wpt_uploader import WptReportUploader
+
+
+def main():
+    add_depot_tools_dir_to_os_path()
+    host = Host()
+    uploader = WptReportUploader(host)
+    try:
+        host.exit(uploader.main())
+    except KeyboardInterrupt:
+        host.print_("Interrupted, exiting")
+        host.exit(exit_codes.INTERRUPTED_EXIT_STATUS)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
index 5cbf3bf..318c28ab 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
+++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -795,6 +795,7 @@
 crbug.com/591099 fast/writing-mode/flipped-blocks-inline-map-local-to-container.html [ Failure ]
 
 ### external/wpt/html/rendering
+crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-block-size.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-containing-block.html [ Failure ]
 crbug.com/880062 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-content-before-legend.html [ Failure ]
 crbug.com/880062 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-generated-content.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 7d42846..bb3a721 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1728,6 +1728,28 @@
 crbug.com/490511 external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/width.html [ Failure ]
 crbug.com/692560 external/wpt/html/semantics/document-metadata/styling/LinkStyle.html [ Failure Pass ]
 
+crbug.com/895846 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-margins.html [ Failure ]
+crbug.com/895846 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-margins-2.html [ Failure ]
+crbug.com/1223214 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-painting-order.html [ Failure ]
+crbug.com/1223214 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-rendering.html [ Failure ]
+crbug.com/1223214 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-tall.html [ Failure ]
+crbug.com/1172023 external/wpt/html/rendering/non-replaced-elements/tables/table-border-3s.html [ Failure ]
+crbug.com/1172023 external/wpt/html/rendering/non-replaced-elements/tables/table-border-3q.html [ Failure ]
+crbug.com/962936 external/wpt/html/rendering/widgets/button-layout/anonymous-button-content-box.html [ Failure ]
+crbug.com/962936 external/wpt/html/rendering/widgets/button-layout/inline-level.html [ Failure ]
+crbug.com/707210 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1i.html [ Failure ]
+crbug.com/707210 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1j.html [ Failure ]
+crbug.com/707210 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1k.html [ Failure ]
+crbug.com/707210 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1l.html [ Failure ]
+crbug.com/707210 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2i.html [ Failure ]
+crbug.com/707210 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2j.html [ Failure ]
+crbug.com/707210 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2k.html [ Failure ]
+crbug.com/707210 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2l.html [ Failure ]
+
+# These were crashing only on DCHECK-enabled release builds, but maybe don't now.
+# crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/margin-collapsing-quirks/multicol-quirks-mode.html [ Crash Pass ]
+# crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/margin-collapsing-quirks/multicol-standards-mode.html [ Crash Failure Pass ]
+
 crbug.com/860211 [ Mac ] external/wpt/editing/run/delete.html [ Failure ]
 
 crbug.com/821455 editing/pasteboard/drag-files-to-editable-element.html [ Failure ]
@@ -4664,8 +4686,6 @@
 crbug.com/626703 [ Mac10.12 ] external/wpt/preload/download-resources.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/preload/download-resources.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/preload/onload-event.html [ Failure Skip Timeout ]
-crbug.com/626703 external/wpt/html/rendering/widgets/button-layout/anonymous-button-content-box.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/widgets/button-layout/inline-level.html [ Failure ]
 crbug.com/626703 external/wpt/xhr/abort-after-stop.any.worker.html [ Timeout ]
 crbug.com/626703 external/wpt/speech-api/SpeechSynthesisUtterance-volume-manual.html [ Skip ]
 crbug.com/626703 crbug.com/606367 external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch.html [ Failure Pass Timeout ]
@@ -4676,8 +4696,6 @@
 crbug.com/626703 external/wpt/media-source/mediasource-correct-frames.html [ Failure Pass Skip Timeout ]
 crbug.com/626703 external/wpt/payment-method-basic-card/steps_for_selecting_the_payment_handler.html [ Timeout ]
 crbug.com/626703 external/wpt/payment-method-basic-card/apply_the_modifiers.html [ Timeout ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/tables/table-border-3s.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/tables/table-border-3q.html [ Failure ]
 crbug.com/626703 external/wpt/screen-orientation/onchange-event.html [ Timeout ]
 crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html [ Skip Timeout ]
 crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html [ Skip Timeout ]
@@ -4734,7 +4752,6 @@
 
 
 ### See crbug.com/891427 comment near the top of this file:
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-margins-2.html [ Failure ]
 crbug.com/367760 external/wpt/svg/pservers/reftests/meshgradient-basic-004.svg [ Failure ]
 crbug.com/367760 external/wpt/svg/pservers/reftests/meshgradient-basic-001.svg [ Failure ]
 
@@ -4758,9 +4775,6 @@
 crbug.com/367760 external/wpt/svg/pservers/reftests/meshgradient-basic-005.svg [ Failure ]
 crbug.com/367760 external/wpt/svg/pservers/reftests/meshgradient-basic-002.svg [ Failure ]
 crbug.com/367760 external/wpt/svg/pservers/reftests/meshgradient-basic-003.svg [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-margins.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-rendering.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-tall.html [ Failure ]
 crbug.com/626703 external/wpt/speech-api/SpeechSynthesis-pause-resume.tentative.html [ Timeout ]
 crbug.com/626703 external/wpt/css/CSS2/floats/float-nowrap-9.html [ Failure ]
 crbug.com/626703 external/wpt/css/CSS2/floats/float-nowrap-8.html [ Failure ]
@@ -4786,7 +4800,6 @@
 crbug.com/626703 external/wpt/css/selectors/old-tests/css3-modsel-159.xml [ Skip ]
 crbug.com/626703 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.html [ Timeout ]
 crbug.com/626703 external/wpt/quirks/text-decoration-doesnt-propagate-into-tables/quirks.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-painting-order.html [ Failure ]
 crbug.com/626703 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.html [ Timeout ]
 crbug.com/875411 external/wpt/svg/text/reftests/text-complex-002.svg [ Failure ]
 crbug.com/875411 external/wpt/svg/text/reftests/text-shape-inside-001.svg [ Failure ]
@@ -4862,14 +4875,6 @@
 crbug.com/626703 [ Linux ] external/wpt/css/css-color/t425-hsla-onscreen-multiple-boxes-c.xht [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/css/css-color/t425-hsla-onscreen-b.xht [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/css/css-color/t425-hsla-onscreen-b.xht [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1i.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1j.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1k.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1l.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2i.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2j.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2k.html [ Failure ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2l.html [ Failure ]
 crbug.com/626703 external/wpt/acid/acid2/reftest.html [ Failure Pass ]
 crbug.com/626703 external/wpt/acid/acid3/test.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-ui/cursor-auto-006.html [ Skip ]
@@ -5014,8 +5019,6 @@
 # Crashes with DCHECK enabled, but not on normal Release builds.
 crbug.com/809935 external/wpt/css/css-fonts/variations/font-style-interpolation.html [ Skip Timeout ]
 crbug.com/626703 external/wpt/css/css-ui/text-overflow-011.html [ Crash Failure Pass ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/margin-collapsing-quirks/multicol-quirks-mode.html [ Crash Pass ]
-crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/margin-collapsing-quirks/multicol-standards-mode.html [ Crash Failure Pass ]
 
 # Other untriaged test failures, timeouts and crashes from newly-imported WPT tests.
 crbug.com/626703 external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 29b04f6..259b263 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -959,6 +959,7 @@
               "accessibility/virtual-node-repair-document.html",
               "external/wpt/accessibility/crashtests/aria-hidden-with-select.html",
               "external/wpt/accessibility/crashtests/aria-owns-destroyed-by-content-replacement.html",
+              "external/wpt/accessibility/crashtests/aria-owns-reparent.html",
               "external/wpt/accessibility/crashtests/content-visibility-generated-content-removal.html",
               "external/wpt/accessibility/crashtests/included-descendant-dom-removal.html",
               "external/wpt/accessibility/crashtests/included-descendant-layout-removal.html",
diff --git a/third_party/blink/web_tests/external/wpt/accessibility/crashtests/aria-owns-reparent.html b/third_party/blink/web_tests/external/wpt/accessibility/crashtests/aria-owns-reparent.html
new file mode 100644
index 0000000..2eaceb66
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/accessibility/crashtests/aria-owns-reparent.html
@@ -0,0 +1,21 @@
+<html class="test-wait">
+<script>
+document.addEventListener("DOMContentLoaded", () => {
+  requestAnimationFrame(() => {
+    requestAnimationFrame(() => {
+      document.getElementById('owner').setAttribute('aria-owns','x');
+      document.body.setAttribute('aria-hidden', 'true');
+      document.documentElement.className = '';
+    });
+  });
+});
+</script>
+</head>
+<body>
+<p id='owner'></p>
+
+<div>
+  <fieldset id='x'></fieldset>
+</div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001-ref.html
new file mode 100644
index 0000000..db3ae40
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001-ref.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<title>CSS Test (Backgrounds): border-radius clipping on overflow:hidden with transforms</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<style>
+
+#outer {
+  border: 10px solid #000;
+  border-radius: 60px;
+  width: 200px;
+  height: 200px;
+  background: blue;
+  position: absolute;
+  top: 10px;
+  left: 10px;
+}
+
+#coverinner, #coverouter {
+  position: absolute;
+  border: 4px solid fuchsia;
+  filter: grayscale(30%);
+}
+
+#coverinner {
+  width: 196px;
+  height: 196px;
+  top: 18px;
+  left: 18px;
+  border-radius: 52px;
+}
+
+#coverouter {
+  width: 216px;
+  height: 216px;
+  top: 8px;
+  left: 8px;
+  border-radius: 62px;
+}
+
+</style>
+
+<div id="outer">
+</div>
+<div id="coverinner">
+</div>
+<div id="coverouter">
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001.html
new file mode 100644
index 0000000..e7d173b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<title>CSS Test (Backgrounds): border-radius clipping on overflow:hidden with transforms</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1207151">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#corner-clipping">
+<link rel="match" href="border-radius-clipping-with-transform-001-ref.html">
+<meta name="assert" content="The content should be clipped correctly, despite the interesting transforms.">
+<style>
+
+#outer {
+  border: 10px solid #000;
+  border-radius: 60px;
+  width: 200px;
+  height: 200px;
+  overflow: hidden;
+  transform: rotate(90deg);
+  position: absolute;
+  top: 10px;
+  left: 10px;
+}
+#inner {
+  width: 100%;
+  height: 100%;
+  background: blue;
+  transform: translateZ(0);
+}
+
+#coverinner, #coverouter {
+  position: absolute;
+  border: 4px solid fuchsia;
+  filter: grayscale(30%);
+}
+
+#coverinner {
+  width: 196px;
+  height: 196px;
+  top: 18px;
+  left: 18px;
+  border-radius: 52px;
+}
+
+#coverouter {
+  width: 216px;
+  height: 216px;
+  top: 8px;
+  left: 8px;
+  border-radius: 62px;
+}
+
+</style>
+
+<div id="outer">
+  <div id="inner">
+  </div>
+</div>
+<div id="coverinner">
+</div>
+<div id="coverouter">
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-block-size.html b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-block-size.html
new file mode 100644
index 0000000..e124763
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-block-size.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<link rel="help" href="https://html.spec.whatwg.org/C/#the-fieldset-and-legend-elements">
+<!-- A test for the following paragraph:
+For the purpose of calculating the used 'block-size', if the computed
+'block-size' is not 'auto', the space allocated for the rendered legend's
+margin box that spills out past the border, if any, is expected to be
+subtracted from the 'block-size'. If the content box's block-size would be
+negative, then let the content box's block-size be zero instead.
+-->
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+fieldset {
+  margin: 0;
+  padding: 0;
+  border: 2px solid black;
+}
+legend {
+  height: 102px;
+  background-color: yellow;
+}
+.content {
+  background-color: lime;
+}
+</style>
+<fieldset style="block-size: 200px;">
+<legend>Legend</legend>
+<div class="content" style="height:100%"></div>
+</fieldset>
+
+<fieldset style="block-size: 40px;">
+<legend>Legend</legend>
+<div class="content" style="height:100%"></div>
+</fieldset>
+
+<script>
+test(() => {
+  let cs = document.querySelectorAll('.content');
+  assert_equals(cs[0].offsetHeight, Math.max(202 - 102, 0));
+  assert_equals(cs[1].offsetHeight, Math.max(42 - 102, 0));
+}, 'Test content\'s block-size');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-position-centering.html b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-position-centering.html
new file mode 100644
index 0000000..a4eda6e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-position-centering.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<link rel="help" href="https://html.spec.whatwg.org/C/#the-fieldset-and-legend-elements">
+<!-- A test for the following paragraph:
+The element is expected to be positioned in the block-flow direction such that
+its border box is centered over the border on the block-start side of the
+fieldset element.
+-->
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+fieldset {
+  margin: 0;
+  padding: 0;
+  border: 100px solid black;
+}
+legend {
+  height: 0px;
+  border-color: yellow;
+  border-style: solid;
+}
+</style>
+<fieldset>
+<legend style="border-width:50px"></legend>
+<br>
+</fieldset>
+<br>
+
+<fieldset>
+<legend style="border-width:25px 50px"></legend>
+<br>
+</fieldset>
+<br>
+
+<fieldset>
+<legend style="border-width:10px 50px 40px 50px"></legend>
+<br>
+</fieldset>
+<br>
+
+<fieldset>
+<legend style="border-width:40px 50px 10px 50px"></legend>
+<br>
+</fieldset>
+
+<script>
+function legendBlockOffset(fieldset) {
+  let legend = fieldset.querySelector('legend');
+  return legend.getBoundingClientRect().y - fieldset.getBoundingClientRect().y;
+}
+
+test(() => {
+  let fieldsets = document.querySelectorAll('fieldset');
+  assert_equals(legendBlockOffset(fieldsets[0]), 0);
+  assert_equals(legendBlockOffset(fieldsets[1]), 25);
+  assert_equals(legendBlockOffset(fieldsets[2]), 25);
+  assert_equals(legendBlockOffset(fieldsets[3]), 25);
+}, 'Legend\'s border-box should be centere on the fieldset border');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-inline-position-with-fieldset-padding.html b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-inline-position-with-fieldset-padding.html
new file mode 100644
index 0000000..0b26248
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-inline-position-with-fieldset-padding.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<link rel="help" href="https://html.spec.whatwg.org/C/#the-fieldset-and-legend-elements">
+<!-- A test for the following paragraphs:
+The element's box is expected to be constrained in the inline direction by
+the inline content size of the fieldset as if it had used its computed
+inline padding.
+Example:
+For example, if the fieldset has a specified padding of 50px, then the
+rendered legend will be positioned 50px in from the fieldset's border. The
+padding will further apply to the anonymous fieldset content box instead
+of the fieldset element itself.
+-->
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+fieldset {
+  width: 400px;
+  margin: 0;
+  padding: 0 50px;
+  border: 2px solid black;
+}
+legend {
+  width: 100%;
+  padding: 0;
+  background-color: yellow;
+}
+.content {
+  background-color: lime;
+}
+</style>
+<fieldset>
+<legend>Legend</legend>
+</fieldset>
+
+<script>
+test(() => {
+  let fieldset = document.querySelector('fieldset');
+  let legend = document.querySelector('legend');
+  assert_equals(legend.offsetLeft - fieldset.offsetLeft, 52);
+  assert_equals(legend.offsetWidth, 400);
+}, 'Test legend\'s inline-size in a fieldset with inline paddings');
+</script>
diff --git a/third_party/blink/web_tests/virtual/file-handling/README.md b/third_party/blink/web_tests/virtual/file-handling/README.md
index 8b2dac5..0de4f12 100644
--- a/third_party/blink/web_tests/virtual/file-handling/README.md
+++ b/third_party/blink/web_tests/virtual/file-handling/README.md
@@ -1,5 +1,5 @@
 # File Handling
-This directory contains (tentative) tests for the [File Handling](https://github.com/WICG/file-handling/blob/master/explainer.md) proposal.
+This directory contains (tentative) tests for the [File Handling](https://github.com/WICG/file-handling/blob/main/explainer.md) proposal.
 
 **This suite runs the tests with**
 `--enable-features=NativeFilesystemAPI,FileHandlingAPI`
diff --git a/third_party/blink/web_tests/virtual/file-handling/file-handling/launchQueue-exists.tentative.window.html b/third_party/blink/web_tests/virtual/file-handling/file-handling/launchQueue-exists.tentative.window.html
index 2542dc39..94d543f 100644
--- a/third_party/blink/web_tests/virtual/file-handling/file-handling/launchQueue-exists.tentative.window.html
+++ b/third_party/blink/web_tests/virtual/file-handling/file-handling/launchQueue-exists.tentative.window.html
@@ -1,6 +1,6 @@
 <!doctype html>
 <title>Launch Params are available from JavaScript.</title>
-<link rel="help" href="https://github.com/WICG/file-handling/blob/master/explainer.md">
+<link rel="help" href="https://github.com/WICG/file-handling/blob/main/explainer.md">
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
 <script>
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/csp.html
new file mode 100644
index 0000000..39d0d9e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/csp.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+  <title>Test Content Security Policy</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="resources/utils.js"></script>
+
+  <body>
+
+    <script>
+      promise_test(async () => {
+        const csp_key = KEYS["csp"];
+
+        // The 'csp' property does not appear in the IDL definition for
+        // fenced frames, so ensure that the 'csp' property didn't
+        // leak over from the IFrame prototype.
+        assert_equals(HTMLFencedFrameElement.prototype.hasOwnProperty('csp'),
+                      false);
+
+        const new_frame = document.createElement('fencedframe');
+        new_frame.src = "resources/csp-inner.html";
+
+        // This attribute will be ignored since the IDL for
+        // fenced frames do not support the 'csp' attribute.
+        new_frame.setAttribute("csp", "style-src 'none';");
+        document.body.append(new_frame);
+
+        // Get the result for the top-level fenced frame.
+        const fenced_frame_result = await nextValueFromServer(csp_key);
+        assert_equals(fenced_frame_result, "pass");
+
+      }, "Fenced Frames should not honor the csp attribute from parent page");
+    </script>
+
+  </body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/csp-inner.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/csp-inner.html
new file mode 100644
index 0000000..0f34450
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/csp-inner.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+  <script src="utils.js"></script>
+
+  <style>
+    body {background-color: red;}
+  </style>
+
+  <title>Fenced frame content to test Content Security Policies</title>
+
+  <body>
+    <script>
+      const csp_key = KEYS["csp"];
+
+      function fail() {
+        writeValueToServer(csp_key,
+          "FAIL: img-src policy was not honored in fenced frame");
+      }
+
+      function pass() {
+        // The parent page is going to attempt to pass a
+        // style-src: 'none' CSP to the fenced frame. Make sure that
+        // the header is not honored.
+        const bgcolor = window.getComputedStyle(document.body, null)
+                        .getPropertyValue('background-color');
+
+        if (bgcolor != "rgb(255, 0, 0)") {
+          writeValueToServer(csp_key,
+            "FAIL: style-src policy was passed to fenced frame");
+          return;
+        }
+
+        writeValueToServer(csp_key, "pass");
+      }
+    </script>
+    <img src="csp.png" id="my_img" onload="fail();" onerror="pass();">
+  </body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/csp-inner.html.headers b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/csp-inner.html.headers
new file mode 100644
index 0000000..e89be70
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/csp-inner.html.headers
@@ -0,0 +1,2 @@
+Supports-Loading-Mode: fenced-frame
+Content-Security-Policy: img-src 'none'
\ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/csp.png b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/csp.png
new file mode 100644
index 0000000..53a9748
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/csp.png
Binary files differ
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js
index a0b28f58..58acdc4 100644
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js
@@ -107,6 +107,8 @@
   "resize_lock_inner_page_is_ready"             : "00000000-0000-0000-0000-000000000038",
   "resize_lock_resize_is_done"                  : "00000000-0000-0000-0000-000000000039",
   "resize_lock_report_inner_dimensions"         : "00000000-0000-0000-0000-00000000004A",
+
+  "csp"                                         : "00000000-0000-0000-0000-00000000004B",
   // Add keys above this list, incrementing the key UUID in hexadecimal
 }
 
diff --git a/third_party/googletest/README.chromium b/third_party/googletest/README.chromium
index e80a50c..2875768 100644
--- a/third_party/googletest/README.chromium
+++ b/third_party/googletest/README.chromium
@@ -150,5 +150,5 @@
 ### Other Resources
 
 * [AutoRoller](https://autoroll.skia.org/r/googletest-chromium-autoroll) and
-  accompanying [configuration file](https://skia.googlesource.com/buildbot/+/master/autoroll/config/googletest-chromium.cfg)
+  accompanying [configuration file](https://skia.googlesource.com/skia-autoroll-internal-config.git/+/main/skia-public/googletest-chromium.cfg)
 * [Bug tracking substantial roll](https://crbug.com/1163396)
diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py
index 26a093ab..736d362 100644
--- a/tools/json_schema_compiler/cc_generator.py
+++ b/tools/json_schema_compiler/cc_generator.py
@@ -972,8 +972,7 @@
           c.Append('%(dst_var)s = temp.value();')
     elif underlying_type.property_type == PropertyType.OBJECT:
       if is_ptr:
-        (c.Append('const base::DictionaryValue* dictionary = nullptr;')
-          .Sblock('if (!%(src_var)s.GetAsDictionary(&dictionary)) {')
+        (c.Sblock('if (!%(src_var)s.is_dict()) {')
           .Concat(self._AppendError16(
             'u"\'%%(key)s\': expected dictionary, got " + ' +
             self._util_cc_helper.GetValueTypeString('%%(src_var)s')))
@@ -983,7 +982,7 @@
           .Sblock('else {')
           .Append('auto temp = std::make_unique<%(cpp_type)s>();')
           .Append('if (!%%(cpp_type)s::Populate(%s)) {' % self._GenerateArgs(
-            ('*dictionary', 'temp.get()')))
+            ('%(src_var)s', 'temp.get()')))
           .Append('  return %(failure_value)s;')
         )
         (c.Append('}')
@@ -992,15 +991,14 @@
           .Eblock('}')
         )
       else:
-        (c.Append('const base::DictionaryValue* dictionary = nullptr;')
-          .Sblock('if (!%(src_var)s.GetAsDictionary(&dictionary)) {')
+        (c.Sblock('if (!%(src_var)s.is_dict()) {')
           .Concat(self._AppendError16(
             'u"\'%%(key)s\': expected dictionary, got " + ' +
             self._util_cc_helper.GetValueTypeString('%%(src_var)s')))
           .Append('return %(failure_value)s;')
           .Eblock('}')
           .Append('if (!%%(cpp_type)s::Populate(%s)) {' % self._GenerateArgs(
-            ('*dictionary', '&%(dst_var)s')))
+            ('%(src_var)s', '&%(dst_var)s')))
           .Append('  return %(failure_value)s;')
           .Append('}')
         )
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 6ada213f..f9d53c8a 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -37780,18 +37780,6 @@
   <int value="2" label="Not found"/>
 </enum>
 
-<enum name="FingerprintError">
-  <int value="0" label="Unknown error"/>
-  <int value="1" label="Hardware unavailable"/>
-  <int value="2" label="Unable to process"/>
-  <int value="3" label="Timeout"/>
-  <int value="4" label="No space available for a template"/>
-  <int value="5" label="Canceled"/>
-  <int value="6" label="Unable to remove record"/>
-  <int value="7" label="Hardware is locked"/>
-  <int value="8" label="No templates"/>
-</enum>
-
 <enum name="FingerprintRecordFormatVersion">
   <int value="0" label="None"/>
   <int value="1" label="Record format version without validation value"/>
@@ -51697,6 +51685,8 @@
   <int value="-843496368" label="AutofillRejectCompanyBirthyear:disabled"/>
   <int value="-842438090" label="enable-md-feedback"/>
   <int value="-839664591" label="enable-web-authentication-testing-api"/>
+  <int value="-838719204"
+      label="ForceMajorVersionInMinorPositionInUserAgent:disabled"/>
   <int value="-837650216" label="DisableCryptAuthV1DeviceSync:disabled"/>
   <int value="-837473047" label="AutofillEnableStickyPaymentsBubble:disabled"/>
   <int value="-836123854" label="wallet-service-use-sandbox"/>
@@ -53992,6 +53982,8 @@
   <int value="877432034" label="DisableQuickAnswersV2Translation:enabled"/>
   <int value="877907263" label="StrictExtensionIsolation:disabled"/>
   <int value="878773995" label="ChromeHomeBottomNavLabels:disabled"/>
+  <int value="879538323"
+      label="ForceMajorVersionInMinorPositionInUserAgent:enabled"/>
   <int value="879699575" label="disable-gesture-tap-highlight"/>
   <int value="879992337" label="disable-pull-to-refresh-effect"/>
   <int value="880510010" label="enable-permissions-bubbles"/>
diff --git a/tools/metrics/histograms/metadata/event/histograms.xml b/tools/metrics/histograms/metadata/event/histograms.xml
index 86e5be6..fa258d0 100644
--- a/tools/metrics/histograms/metadata/event/histograms.xml
+++ b/tools/metrics/histograms/metadata/event/histograms.xml
@@ -374,6 +374,9 @@
 
 <histogram name="Event.FractionOfTimeWithoutUserInput" units="%"
     expires_after="2021-06-16">
+  <obsolete>
+    Removed December 2021.
+  </obsolete>
   <owner>sullivan@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/fingerprint/histograms.xml b/tools/metrics/histograms/metadata/fingerprint/histograms.xml
index 3253643..80612ec8 100644
--- a/tools/metrics/histograms/metadata/fingerprint/histograms.xml
+++ b/tools/metrics/histograms/metadata/fingerprint/histograms.xml
@@ -22,19 +22,6 @@
 
 <histograms>
 
-<histogram name="Fingerprint.Auth.Error" enum="FingerprintError"
-    expires_after="2022-04-10">
-  <owner>patrykd@google.com</owner>
-  <owner>tomhughes@chromium.org</owner>
-  <owner>cros-oac@google.com</owner>
-  <owner>chromeos-fingerprint@google.com</owner>
-  <summary>
-    Tracks the error during fingerprint authentication session. It is recorded
-    every time authentication session (unlock screen, web auth, etc.) ends with
-    error.
-  </summary>
-</histogram>
-
 <histogram name="Fingerprint.Auth.ScanResult" enum="FingerprintScanResult"
     expires_after="2022-04-10">
   <owner>rsorokin@chromium.org</owner>
@@ -44,7 +31,7 @@
   <summary>
     Tracks the scan result during fingerprint authentication session. It is
     recorded every time user touches the fingerprint sensor while authenticating
-    (unlock screen, web auth, etc.) and session is not finished with error.
+    (unlock screen, web auth, etc.).
   </summary>
 </histogram>
 
@@ -88,7 +75,7 @@
 </histogram>
 
 <histogram name="Fingerprint.SetContext.Success" enum="BooleanSuccess"
-    expires_after="2022-01-02">
+    expires_after="2023-01-02">
   <owner>hesling@chromium.org</owner>
   <owner>chromeos-fingerprint@google.com</owner>
   <summary>Whether setting FPMCU mode succeeded.</summary>
@@ -156,7 +143,7 @@
 </histogram>
 
 <histogram name="Fingerprint.Unlock.Match.PositiveMatchSecretCorrect"
-    enum="BooleanCorrect" expires_after="2022-01-02">
+    enum="BooleanCorrect" expires_after="2023-01-02">
   <owner>hesling@chromium.org</owner>
   <owner>chromeos-fingerprint@google.com</owner>
   <summary>
@@ -250,9 +237,8 @@
 
 <histogram name="Fingerprint.UnlockEnabled" enum="BooleanEnabled"
     expires_after="2022-04-03">
-  <owner>rsorokin@chromium.org</owner>
-  <owner>jessejames@chromium.org</owner>
-  <owner>cros-oac@google.com</owner>
+  <owner>tomhughes@chromium.org</owner>
+  <owner>chromeos-fingerprint@google.com</owner>
   <summary>
     Track whether fingerprint is enabled to unlock the screen, when the user
     logs in.
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index 8941175..8cf9b2f5 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -3007,6 +3007,18 @@
   </summary>
 </histogram>
 
+<histogram name="Network.Shill.Wifi.TimeFromRekeyToFailureSeconds"
+    units="seconds" expires_after="2022-12-01">
+  <owner>billyzhao@chromium.org</owner>
+  <owner>cros-network-metrics@google.com</owner>
+  <summary>
+    Time spent between network rekey attempt to connection failure. The metric
+    timer starts when a rekey is initiated and stops once a connection failure
+    is reported or another rekey is initiated. The metric is only reported if
+    the timer is stopped by a connection failure within 180 seconds.
+  </summary>
+</histogram>
+
 <histogram name="Network.Shill.Wifi.TimeOnline" units="seconds"
     expires_after="2022-04-24">
   <owner>norvez@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml
index cf7ef551..d78d9b4d 100644
--- a/tools/metrics/histograms/metadata/omnibox/histograms.xml
+++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -745,8 +745,8 @@
 </histogram>
 
 <histogram name="Omnibox.Search.OffTheRecord" enum="BooleanOffTheRecord"
-    expires_after="2022-02-02">
-  <owner>rhalavati@chromium.org</owner>
+    expires_after="2022-08-02">
+  <owner>sideyilmaz@chromium.org</owner>
   <owner>chrome-incognito@google.com</owner>
   <summary>
     This histogram records the number of searches done from omnibox using
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 87022dd..28570ab 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -2650,13 +2650,15 @@
 </histogram>
 
 <histogram name="ChildProcess.Crashed.UtilityProcessHash"
-    enum="UtilityProcessNameHash" expires_after="2022-06-12">
+    enum="UtilityProcessNameHash" expires_after="never">
+<!-- expires-never: Critical stability metrics. go/chrome-stability-metrics -->
+
   <owner>wfh@chromium.org</owner>
   <owner>chrome-stability-core@google.com</owner>
   <summary>
     Count of child utility process crashes, bucketed by the hash of their
     process name. The process name is typically the service name of the mojo
-    service.
+    service. Recorded when a Utility process crashes.
   </summary>
 </histogram>
 
@@ -2763,6 +2765,44 @@
   </summary>
 </histogram>
 
+<histogram name="ChildProcess.LaunchFailed.UtilityProcessErrorCode"
+    enum="LaunchErrorCodes" expires_after="never">
+<!-- expires-never: Critical stability metrics. go/chrome-stability-metrics -->
+
+  <owner>wfh@chromium.org</owner>
+  <owner>chrome-stability-core@google.com</owner>
+  <summary>
+    A platform-specific error code returned from the attempt to launch a Utility
+    process. Recorded when a Utility process fails to launch.
+  </summary>
+</histogram>
+
+<histogram name="ChildProcess.LaunchFailed.UtilityProcessHash"
+    enum="UtilityProcessNameHash" expires_after="never">
+<!-- expires-never: Critical stability metrics. go/chrome-stability-metrics -->
+
+  <owner>wfh@chromium.org</owner>
+  <owner>chrome-stability-core@google.com</owner>
+  <summary>
+    Count of child utility process launch failures, bucketed by the hash of
+    their process name. The process name is typically the service name of the
+    mojo service. Recorded when a Utility process fails to launch.
+  </summary>
+</histogram>
+
+<histogram name="ChildProcess.LaunchFailed.WinLastError" enum="WinGetLastError"
+    expires_after="never">
+<!-- expires-never: Critical stability metrics. go/chrome-stability-metrics -->
+
+  <owner>wfh@chromium.org</owner>
+  <owner>chrome-stability-core@google.com</owner>
+  <summary>
+    An extended Windows error code returned from GetLastError when failing to
+    launch a utility process. Recorded when a Utility process fails to launch on
+    Windows.
+  </summary>
+</histogram>
+
 <histogram name="ChromiumAndroidLinker.BrowserLoadTime" units="ms"
     expires_after="2022-10-01">
   <obsolete>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index ead501ec..66719062 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -1473,9 +1473,9 @@
 </histogram>
 
 <histogram name="PasswordManager.FormSubmission.PerProfileType"
-    enum="BrowserProfileType" expires_after="2022-02-02">
-  <owner>rhalavati@chromium.org</owner>
-  <owner>chrome-privacy-core@google.com</owner>
+    enum="BrowserProfileType" expires_after="2022-08-02">
+  <owner>sideyilmaz@chromium.org</owner>
+  <owner>chrome-incognito@google.com</owner>
   <summary>
     This histogram records the browser profile type when a password form is
     submitted.
@@ -2393,6 +2393,40 @@
   </token>
 </histogram>
 
+<histogram
+    name="PasswordManager.PasswordStoreProxyBackend.{ModifyingFunction}.{Metric}.{Measurement}"
+    units="count" expires_after="2022-06-30">
+  <owner>fhorschig@chromium.org</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    Records the number of password store changes {Metric}{Measurement} Recorded
+    when the asynchronous job for {ModifyingFunction} has returned. Recorded
+    only for non-syncing users and only after initial migration is finished.
+  </summary>
+  <token key="ModifyingFunction">
+    <variant name="AddLoginAsync" summary="AddLoginAsync()"/>
+  </token>
+  <token key="Metric">
+    <variant name="Diff"
+        summary="in either the main or the shadow backend but not in both of
+                 them"/>
+    <variant name="InconsistentPasswords"
+        summary="that occur in both the main and the shadow backend but
+                 differ in their stored passwords"/>
+    <variant name="MainMinusShadow"
+        summary="in the main backend that are not in the shadow backend"/>
+    <variant name="ShadowMinusMain"
+        summary="in the shadow backend that are not the main backend"/>
+  </token>
+  <token key="Measurement">
+    <variant name="Abs" summary="."/>
+    <variant name="Rel"
+        summary=", divided by the total number of password store changes, as
+                 a percentage rounded up to the next integer. If the
+                 denominator is zero, no value is emitted."/>
+  </token>
+</histogram>
+
 <histogram name="PasswordManager.PasswordSyncState" enum="PasswordSyncState"
     expires_after="2022-06-12">
   <owner>kazinova@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml
index 93e2cd1..f23fa904 100644
--- a/tools/metrics/histograms/metadata/power/histograms.xml
+++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -972,6 +972,15 @@
   </summary>
 </histogram>
 
+<histogram name="Power.IOPMPowerSource.SamplingEventDelta" units="ms"
+    expires_after="2022-03-01">
+  <owner>pmonette@chromium.org</owner>
+  <owner>catan-team@chromium.org</owner>
+  <summary>
+    Records the time between each IOPMPowerSource event. Only recorded on MacOS.
+  </summary>
+</histogram>
+
 <histogram name="Power.KernelResumeTimeOnAC" units="ms"
     expires_after="2021-10-17">
   <owner>puthik@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/profile/histograms.xml b/tools/metrics/histograms/metadata/profile/histograms.xml
index abc8aeb..28f4398 100644
--- a/tools/metrics/histograms/metadata/profile/histograms.xml
+++ b/tools/metrics/histograms/metadata/profile/histograms.xml
@@ -359,6 +359,9 @@
     Recorded during BrowserProcess teardown. Indicates that a Profile still has
     ScopedProfileKeepAlive objects referencing it, of the given origin. This is
     a sign of a bug, or incorrect usage of the ScopedProfileKeepAlive API.
+
+    Only regular Profiles are considered for this metric (no Incognito, Guest,
+    or System Profiles).
   </summary>
 </histogram>
 
@@ -369,7 +372,8 @@
   <summary>
     Number of Profiles that are currently loaded in memory, with a non-zero
     refcount. Recorded 30 minutes after startup, and every 30 minutes
-    afterwards.
+    afterwards. Only regular Profiles are considered for this metric (no
+    Incognito, Guest, or System Profiles).
 
     See also Profile.ZombieProfileCount, the number of Profiles with a refcount
     of 0.
@@ -835,9 +839,10 @@
   <owner>cbe-eng@google.com</owner>
   <summary>
     Number of Profiles that are in a &quot;zombie&quot; state. Recorded 30
-    minutes after startup, and every 30 minutes afterwards. A &quot;zombie&quot;
-    profile is one of 2 things, depending on the DestroyProfileOnBrowserClose
-    (DPoBC) variation:
+    minutes after startup, and every 30 minutes afterwards. Only regular
+    Profiles are considered for this metric (no Incognito, Guest, or System
+    Profiles). A &quot;zombie&quot; profile is one of 2 things, depending on the
+    DestroyProfileOnBrowserClose (DPoBC) variation:
 
     If DPoBC is false: the Profile has a refcount of 0, but is still loaded in
     memory.
diff --git a/tools/metrics/histograms/metadata/settings/histograms.xml b/tools/metrics/histograms/metadata/settings/histograms.xml
index 08a6ee7e..f7a7f1ef 100644
--- a/tools/metrics/histograms/metadata/settings/histograms.xml
+++ b/tools/metrics/histograms/metadata/settings/histograms.xml
@@ -166,7 +166,7 @@
 </histogram>
 
 <histogram name="Settings.OpenSettingsFromMenu.PerProfileType"
-    enum="BrowserProfileType" expires_after="2021-12-31">
+    enum="BrowserProfileType" expires_after="2022-08-02">
   <owner>sideyilmaz@chromium.org</owner>
   <owner>chrome-incognito@google.com</owner>
   <summary>
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 556bc46..5a646828 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -316,7 +316,6 @@
  <item id="app_suggestion_get_favicon" added_in_milestone="98" content_hash_code="07fca800" os_list="chromeos" file_path="chrome/browser/ui/app_list/search/app_service_app_result.cc" />
  <item id="url_icon_source_fetch" added_in_milestone="98" content_hash_code="0297f30b" os_list="chromeos" file_path="chrome/browser/ui/app_list/search/common/url_icon_source.cc" />
  <item id="launcher_item_suggest" added_in_milestone="98" content_hash_code="04a4041e" os_list="chromeos" file_path="chrome/browser/ui/app_list/search/files/item_suggest_cache.cc" />
- <item id="cros_launcher_omnibox" added_in_milestone="98" content_hash_code="04c3a59e" os_list="chromeos" file_path="chrome/browser/ui/app_list/search/omnibox_result.cc" />
  <item id="ambient_client" added_in_milestone="98" content_hash_code="062d821f" os_list="chromeos" file_path="chrome/browser/ui/ash/ambient/ambient_client_impl.cc" />
  <item id="calendar_get_events" added_in_milestone="98" content_hash_code="0108842a" os_list="chromeos" file_path="chrome/browser/ui/ash/calendar/calendar_keyed_service.cc" />
  <item id="side_search_availability_test" added_in_milestone="98" content_hash_code="04410970" os_list="chromeos" file_path="chrome/browser/ui/side_search/side_search_tab_contents_helper.cc" />
diff --git a/tools/traffic_annotation/summary/grouping.xml b/tools/traffic_annotation/summary/grouping.xml
index f5a07e5b..308838f 100644
--- a/tools/traffic_annotation/summary/grouping.xml
+++ b/tools/traffic_annotation/summary/grouping.xml
@@ -60,7 +60,6 @@
       <traffic_annotation unique_id="calendar_get_events"/>
       <traffic_annotation unique_id="chrome_plugin_vm_api"/>
       <traffic_annotation unique_id="chromebook_mail_api"/>
-      <traffic_annotation unique_id="cros_launcher_omnibox"/>
       <traffic_annotation unique_id="customization_wallpaper_downloader"/>
       <traffic_annotation unique_id="edu_account_login_profile_image_fetcher"/>
       <traffic_annotation unique_id="fast_pair_footprints_request"/>
diff --git a/ui/android/java/res/values-night/colors.xml b/ui/android/java/res/values-night/colors.xml
index 40c73952..835cb50 100644
--- a/ui/android/java/res/values-night/colors.xml
+++ b/ui/android/java/res/values-night/colors.xml
@@ -102,5 +102,6 @@
     <color name="menu_chip_background_color_disabled">@color/menu_chip_background_color_disabled_light</color>
     <color name="iph_highlight_blue">@color/iph_highlight_blue_light</color>
     <color name="rating_star_yellow">@color/rating_star_yellow_light</color>
-    <color name="price_drop_annotation_bg_color">@color/google_green_800</color>
+    <color name="price_drop_annotation_bg_color">@color/price_drop_annotation_bg_color_dark</color>
+    <color name="price_drop_annotation_text_green">@color/price_drop_annotation_text_green_dark</color>
 </resources>
diff --git a/ui/android/java/res/values-v17/styles.xml b/ui/android/java/res/values-v17/styles.xml
index 51df0a0..46440fa 100644
--- a/ui/android/java/res/values-v17/styles.xml
+++ b/ui/android/java/res/values-v17/styles.xml
@@ -343,11 +343,6 @@
         <item name="android:textColor">@color/chip_text_color_secondary</item>
     </style>
 
-    <!-- Toast UI -->
-    <style name="TextAppearance.Toast" parent="TextAppearance.TextSmall">
-        <item name="android:textColor">@color/default_text_color_light</item>
-    </style>
-
     <!-- Dividers -->
     <style name="HorizontalDivider"
            tools:ignore="UnusedResources">
diff --git a/ui/android/java/res/values/color_palette.xml b/ui/android/java/res/values/color_palette.xml
index b1093a60..5e21334 100644
--- a/ui/android/java/res/values/color_palette.xml
+++ b/ui/android/java/res/values/color_palette.xml
@@ -69,10 +69,10 @@
     <color name="baseline_secondary_300_with_neutral_100_alpha_8">#53A7E1</color>
     <color name="baseline_secondary_300_with_neutral_100_alpha_24">#448FC4</color>
     <color name="baseline_secondary_900">#001D35</color>
-    <color name="baseline_tertiary_50">#E7F8ED</color>
+    <color name="baseline_tertiary_100">#C4EED0</color>
     <color name="baseline_tertiary_200">#6DD58C</color>
     <color name="baseline_tertiary_600">#146C2E</color>
-    <color name="baseline_tertiary_800">#0A3818</color>
+    <color name="baseline_tertiary_700">#0F5223</color>
 
     <!-- Remapped to 2021 color palette. Do not add new references to these. -->
     <color name="modern_white">@color/baseline_neutral_0</color>
@@ -88,10 +88,8 @@
     <color name="modern_blue_700">@color/baseline_primary_700</color>
     <color name="modern_blue_800" tools:ignore="UnusedResources">@color/baseline_primary_800</color>
 
-    <color name="google_green_50">@color/baseline_tertiary_50</color>
     <color name="google_green_300">@color/baseline_tertiary_200</color>
     <color name="google_green_600">@color/baseline_tertiary_600</color>
-    <color name="google_green_800">@color/baseline_tertiary_800</color>
     <color name="modern_grey_50" tools:ignore="UnusedResources">@color/baseline_neutral_50</color>
     <color name="modern_grey_100">@color/baseline_neutral_100</color>
     <color name="modern_grey_100_alpha_38">@color/baseline_neutral_100_alpha_38</color>
diff --git a/ui/android/java/res/values/semantic_colors_adaptive.xml b/ui/android/java/res/values/semantic_colors_adaptive.xml
index 32abfcb..91864bd 100644
--- a/ui/android/java/res/values/semantic_colors_adaptive.xml
+++ b/ui/android/java/res/values/semantic_colors_adaptive.xml
@@ -134,5 +134,6 @@
     <color name="menu_chip_background_color_disabled">@color/menu_chip_background_color_disabled_dark</color>
     <color name="iph_highlight_blue">@color/iph_highlight_blue_dark</color>
     <color name="rating_star_yellow">@color/rating_star_yellow_dark</color>
-    <color name="price_drop_annotation_bg_color">@color/google_green_50</color>
+    <color name="price_drop_annotation_bg_color">@color/price_drop_annotation_bg_color_light</color>
+    <color name="price_drop_annotation_text_green">@color/price_drop_annotation_text_green_light</color>
 </resources>
diff --git a/ui/android/java/res/values/semantic_colors_non_adaptive.xml b/ui/android/java/res/values/semantic_colors_non_adaptive.xml
index bd216f2..efda394d 100644
--- a/ui/android/java/res/values/semantic_colors_non_adaptive.xml
+++ b/ui/android/java/res/values/semantic_colors_non_adaptive.xml
@@ -189,4 +189,10 @@
 
     <!-- Toast colors -->
     <color name="toast_bg_color">@color/baseline_neutral_900_with_neutral_200_alpha_11_with_primary_200_alpha_2</color>
+
+    <!-- Price-tracking colors -->
+    <color name="price_drop_annotation_bg_color_light">@color/baseline_tertiary_100</color>
+    <color name="price_drop_annotation_bg_color_dark">@color/baseline_tertiary_700</color>
+    <color name="price_drop_annotation_text_green_light">@color/baseline_tertiary_600</color>
+    <color name="price_drop_annotation_text_green_dark">@color/baseline_tertiary_200</color>
 </resources>
diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc
index 8e7624e..52c3578 100644
--- a/ui/aura/window_event_dispatcher.cc
+++ b/ui/aura/window_event_dispatcher.cc
@@ -516,11 +516,6 @@
   Window* target_window = static_cast<Window*>(target);
   CHECK(window()->Contains(target_window));
 
-  if (!(event->flags() & ui::EF_IS_SYNTHESIZED)) {
-    fraction_of_time_without_user_input_recorder_.RecordEventAtTime(
-        event->time_stamp());
-  }
-
   WindowTracker target_window_tracker;
   target_window_tracker.Add(target_window);
   if (!dispatching_held_event_) {
diff --git a/ui/aura/window_event_dispatcher.h b/ui/aura/window_event_dispatcher.h
index e64765a3..1c3b3676 100644
--- a/ui/aura/window_event_dispatcher.h
+++ b/ui/aura/window_event_dispatcher.h
@@ -25,7 +25,6 @@
 #include "ui/events/event_constants.h"
 #include "ui/events/event_processor.h"
 #include "ui/events/event_targeter.h"
-#include "ui/events/fraction_of_time_without_user_input_recorder.h"
 #include "ui/events/gestures/gesture_recognizer.h"
 #include "ui/events/gestures/gesture_types.h"
 #include "ui/events/types/event_type.h"
@@ -299,9 +298,6 @@
   raw_ptr<Window> event_dispatch_target_ = nullptr;
   raw_ptr<Window> old_dispatch_target_ = nullptr;
 
-  ui::FractionOfTimeWithoutUserInputRecorder
-      fraction_of_time_without_user_input_recorder_;
-
   bool synthesize_mouse_move_ = false;
 
   // Whether a OnWindowTargetTransformChanging() call didn't have its
diff --git a/ui/aura/window_event_dispatcher_unittest.cc b/ui/aura/window_event_dispatcher_unittest.cc
index 336344c9..6fd75c2 100644
--- a/ui/aura/window_event_dispatcher_unittest.cc
+++ b/ui/aura/window_event_dispatcher_unittest.cc
@@ -3106,37 +3106,6 @@
   w->RemovePreTargetHandler(&recorder);
 }
 
-// Tests that we correctly report the fraction of time without user input via
-// UMA.
-TEST_F(WindowEventDispatcherTest, FractionOfTimeWithoutUserInputRecorded) {
-  const char* kHistogram = "Event.FractionOfTimeWithoutUserInput";
-  base::HistogramTester tester;
-
-  std::unique_ptr<aura::Window> window(
-      test::CreateTestWindowWithId(1234, root_window()));
-
-  ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
-                        gfx::Point(10, 10), ui::EventTimeStampFromSeconds(4), 0,
-                        0);
-
-  // To flush the idle fraction reporter, we need to dispatch two events. The
-  // first event causes us to record the previous active period, and the second
-  // flushes the previous active period.
-  ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
-                        gfx::Point(10, 10), ui::EventTimeStampFromSeconds(16),
-                        0, 0);
-
-  ui::MouseEvent mouse3(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
-                        gfx::Point(10, 10), ui::EventTimeStampFromSeconds(30),
-                        0, 0);
-
-  DispatchEventUsingWindowDispatcher(&mouse1);
-  DispatchEventUsingWindowDispatcher(&mouse2);
-  DispatchEventUsingWindowDispatcher(&mouse3);
-
-  tester.ExpectTotalCount(kHistogram, 1);
-}
-
 TEST_F(WindowEventDispatcherTest, TouchEventWithScaledWindow) {
   WindowEventDispatcher* dispatcher = host()->dispatcher();
 
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index c571db8..bdc40a6b 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -101,8 +101,6 @@
     "event_switches.cc",
     "event_switches.h",
     "events_base_export.h",
-    "fraction_of_time_without_user_input_recorder.cc",
-    "fraction_of_time_without_user_input_recorder.h",
     "gesture_curve.h",
     "gesture_event_details.cc",
     "gesture_event_details.h",
@@ -621,7 +619,6 @@
       "event_rewriter_unittest.cc",
       "event_target_unittest.cc",
       "event_unittest.cc",
-      "fraction_of_time_without_user_input_recorder_unittest.cc",
       "gesture_detection/bitset_32_unittest.cc",
       "gesture_detection/filtered_gesture_provider_unittest.cc",
       "gesture_detection/gesture_event_data_packet_unittest.cc",
diff --git a/ui/events/fraction_of_time_without_user_input_recorder.cc b/ui/events/fraction_of_time_without_user_input_recorder.cc
deleted file mode 100644
index 8733301d..0000000
--- a/ui/events/fraction_of_time_without_user_input_recorder.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/fraction_of_time_without_user_input_recorder.h"
-
-#include <algorithm>
-
-#include "base/metrics/histogram_macros.h"
-
-namespace {
-
-constexpr base::TimeDelta DEFAULT_WINDOW_SIZE = base::Seconds(10);
-constexpr base::TimeDelta DEFAULT_IDLE_TIMEOUT = base::Seconds(0.05);
-
-}  // namespace
-
-namespace ui {
-
-FractionOfTimeWithoutUserInputRecorder::FractionOfTimeWithoutUserInputRecorder()
-    : window_size_(DEFAULT_WINDOW_SIZE), idle_timeout_(DEFAULT_IDLE_TIMEOUT) {}
-
-void FractionOfTimeWithoutUserInputRecorder::RecordEventAtTime(
-    base::TimeTicks start_time) {
-  base::TimeTicks event_end_time = start_time + idle_timeout_;
-
-  if (active_duration_start_time_.is_null())
-    active_duration_start_time_ = start_time;
-  if (previous_event_end_time_.is_null())
-    previous_event_end_time_ = start_time;
-
-  // The user is no longer interacting with the browser. Report the previous
-  // active duration.
-  if (previous_event_end_time_ < start_time) {
-    RecordActiveInterval(active_duration_start_time_, previous_event_end_time_);
-    active_duration_start_time_ = start_time;
-  }
-
-  previous_event_end_time_ = event_end_time;
-}
-
-void FractionOfTimeWithoutUserInputRecorder::RecordActiveInterval(
-    base::TimeTicks start_time,
-    base::TimeTicks end_time) {
-  if (window_start_time_.is_null())
-    window_start_time_ = start_time;
-
-  base::TimeTicks window_end_time;
-
-  while (true) {
-    window_end_time = window_start_time_ + window_size_;
-    base::TimeDelta interval_in_window_duration =
-        std::min(end_time, window_end_time) -
-        std::max(start_time, window_start_time_);
-    interval_in_window_duration =
-        std::max(interval_in_window_duration, base::TimeDelta());
-
-    current_window_active_time_ += interval_in_window_duration;
-
-    // If we haven't exceeded the window bounds, we're done.
-    if (end_time < window_end_time)
-      break;
-
-    RecordToUma(current_window_active_time_ / window_size_);
-
-    current_window_active_time_ = base::TimeDelta();
-    window_start_time_ = window_end_time;
-  }
-}
-
-void FractionOfTimeWithoutUserInputRecorder::RecordToUma(
-    float fraction_active) const {
-  UMA_HISTOGRAM_PERCENTAGE("Event.FractionOfTimeWithoutUserInput",
-                           std::round((1 - fraction_active) * 100));
-}
-
-}  // namespace ui
diff --git a/ui/events/fraction_of_time_without_user_input_recorder.h b/ui/events/fraction_of_time_without_user_input_recorder.h
deleted file mode 100644
index 82b7688..0000000
--- a/ui/events/fraction_of_time_without_user_input_recorder.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_FRACTION_OF_TIME_WITHOUT_USER_INPUT_RECORDER_H_
-#define UI_EVENTS_FRACTION_OF_TIME_WITHOUT_USER_INPUT_RECORDER_H_
-
-#include "base/time/time.h"
-#include "ui/events/events_base_export.h"
-
-namespace ui {
-
-// Receives as input a set of timestamps indicating when events were
-// received. Reports via UMA the fraction of the time per |window_size_| that
-// the user was interacting.
-class EVENTS_BASE_EXPORT FractionOfTimeWithoutUserInputRecorder {
- public:
-  FractionOfTimeWithoutUserInputRecorder();
-  void RecordEventAtTime(base::TimeTicks start_time);
-
- protected:
-  virtual void RecordActiveInterval(base::TimeTicks start_time,
-                                    base::TimeTicks end_time);
-  void RecordToUma(float idle_fraction) const;
-  void set_window_size(base::TimeDelta window_size) {
-    window_size_ = window_size;
-  }
-  void set_idle_timeout(base::TimeDelta idle_timeout) {
-    idle_timeout_ = idle_timeout;
-  }
-
- private:
-  // Within the current period of length |window_size_|, how long has the user
-  // been active?
-  base::TimeDelta current_window_active_time_;
-  // If the user is currently active, when did they start being active?
-  base::TimeTicks active_duration_start_time_;
-  base::TimeTicks window_start_time_;
-  base::TimeTicks previous_event_end_time_;
-
-  // We report the fraction of the time we were idle once per |window_size_|.
-  base::TimeDelta window_size_;
-
-  // Two events within |idle_timeout_| of one another are considered to be in
-  // the same period of user activity.
-  base::TimeDelta idle_timeout_;
-};
-
-}  // namespace ui
-
-#endif  // UI_EVENTS_FRACTION_OF_TIME_WITHOUT_USER_INPUT_RECORDER_H_
diff --git a/ui/events/fraction_of_time_without_user_input_recorder_unittest.cc b/ui/events/fraction_of_time_without_user_input_recorder_unittest.cc
deleted file mode 100644
index fb4efbc..0000000
--- a/ui/events/fraction_of_time_without_user_input_recorder_unittest.cc
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/fraction_of_time_without_user_input_recorder.h"
-
-#include "base/test/metrics/histogram_tester.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/base_event_utils.h"
-
-namespace ui {
-
-namespace {
-
-using base::Bucket;
-using testing::ElementsAre;
-using testing::Pair;
-
-const char* kHistogram = "Event.FractionOfTimeWithoutUserInput";
-
-class TestFractionOfTimeWithoutUserInputRecorder
-    : public FractionOfTimeWithoutUserInputRecorder {
- public:
-  void RecordActiveInterval(base::TimeTicks start_time,
-                            base::TimeTicks end_time) override {
-    active_intervals_.push_back(std::make_pair(start_time, end_time));
-    FractionOfTimeWithoutUserInputRecorder::RecordActiveInterval(start_time,
-                                                                 end_time);
-  }
-
-  void set_window_size_for_test(base::TimeDelta window_size) {
-    set_window_size(window_size);
-  }
-
-  void set_idle_timeout_for_test(base::TimeDelta idle_timeout) {
-    set_idle_timeout(idle_timeout);
-  }
-
-  const std::vector<std::pair<base::TimeTicks, base::TimeTicks>>&
-  active_intervals() {
-    return active_intervals_;
-  }
-
- private:
-  std::vector<std::pair<base::TimeTicks, base::TimeTicks>> active_intervals_;
-};
-
-TEST(FractionOfTimeWithoutUserInputRecorderTest, IntervalIncludesIdleTimeout) {
-  TestFractionOfTimeWithoutUserInputRecorder idle_fraction_recorder;
-  idle_fraction_recorder.set_idle_timeout_for_test(base::Seconds(0.1));
-
-  idle_fraction_recorder.RecordEventAtTime(EventTimeStampFromSeconds(0.5));
-
-  // Flush the previous event.
-  idle_fraction_recorder.RecordEventAtTime(EventTimeStampFromSeconds(100));
-
-  // We observed a single event, so the we consider it to have lasted a duration
-  // of one idle timeout.
-  EXPECT_THAT(idle_fraction_recorder.active_intervals(),
-              ElementsAre(Pair(EventTimeStampFromSeconds(0.5),
-                               EventTimeStampFromSeconds(0.6))));
-}
-
-TEST(FractionOfTimeWithoutUserInputRecorderTest, TwoLongIntervals) {
-  TestFractionOfTimeWithoutUserInputRecorder idle_fraction_recorder;
-  idle_fraction_recorder.set_idle_timeout_for_test(base::Seconds(0.1));
-
-  // Send events regularly between 0.1 seconds and 0.1 + 20 * 0.05 = 1.10
-  // seconds.
-  base::TimeTicks time = base::TimeTicks() + base::Seconds(0.1);
-  idle_fraction_recorder.RecordEventAtTime(time);
-
-  for (int i = 0; i < 20; ++i) {
-    time += base::Seconds(0.05);
-    idle_fraction_recorder.RecordEventAtTime(time);
-  }
-
-  // Send events regularly between 2.2 seconds and 2.2 + 20 * 0.05 = 3.20
-  // seconds.
-  time = base::TimeTicks() + base::Seconds(2.2);
-  idle_fraction_recorder.RecordEventAtTime(time);
-
-  for (int i = 0; i < 20; ++i) {
-    time += base::Seconds(0.05);
-    idle_fraction_recorder.RecordEventAtTime(time);
-  }
-
-  // Flush the previous event.
-  idle_fraction_recorder.RecordEventAtTime(EventTimeStampFromSeconds(100));
-
-  // Interval end times include idle timeout.
-  EXPECT_THAT(idle_fraction_recorder.active_intervals(),
-              ElementsAre(Pair(EventTimeStampFromSeconds(0.1),
-                               EventTimeStampFromSeconds(1.2)),
-                          Pair(EventTimeStampFromSeconds(2.2),
-                               EventTimeStampFromSeconds(3.3))));
-}
-
-TEST(FractionOfTimeWithoutUserInputRecorderTest, SingleShortRange) {
-  TestFractionOfTimeWithoutUserInputRecorder idle_fraction_recorder;
-  idle_fraction_recorder.set_window_size_for_test(base::Seconds(1));
-
-  base::HistogramTester tester;
-  // Start window at 1 second.
-  idle_fraction_recorder.RecordActiveInterval(EventTimeStampFromSeconds(1),
-                                              EventTimeStampFromSeconds(1));
-
-  idle_fraction_recorder.RecordActiveInterval(EventTimeStampFromSeconds(1.1),
-                                              EventTimeStampFromSeconds(1.6));
-
-  // Flush the previous interval.
-  idle_fraction_recorder.RecordActiveInterval(EventTimeStampFromSeconds(2),
-                                              EventTimeStampFromSeconds(2));
-
-  EXPECT_THAT(tester.GetAllSamples(kHistogram), ElementsAre(Bucket(50, 1)));
-}
-
-TEST(FractionOfTimeWithoutUserInputRecorderTest, SingleLongRange) {
-  TestFractionOfTimeWithoutUserInputRecorder idle_fraction_recorder;
-  idle_fraction_recorder.set_window_size_for_test(base::Seconds(1));
-
-  base::HistogramTester tester;
-
-  // Start window at 1 second.
-  idle_fraction_recorder.RecordActiveInterval(EventTimeStampFromSeconds(1),
-                                              EventTimeStampFromSeconds(1));
-
-  idle_fraction_recorder.RecordActiveInterval(EventTimeStampFromSeconds(1.1),
-                                              EventTimeStampFromSeconds(4.2));
-
-  // Flush the previous interval.
-  idle_fraction_recorder.RecordActiveInterval(EventTimeStampFromSeconds(5),
-                                              EventTimeStampFromSeconds(5));
-
-  // The windows contain: [1.1, 2], [2, 3], [3, 4], [4, 4.2].
-  EXPECT_THAT(tester.GetAllSamples(kHistogram),
-              ElementsAre(Bucket(0, 2), Bucket(10, 1), Bucket(80, 1)));
-}
-
-TEST(FractionOfTimeWithoutUserInputRecorderTest, TwoLongRanges) {
-  TestFractionOfTimeWithoutUserInputRecorder idle_fraction_recorder;
-  idle_fraction_recorder.set_window_size_for_test(base::Seconds(1));
-
-  base::HistogramTester tester;
-
-  // Start window at 1 second.
-  idle_fraction_recorder.RecordActiveInterval(EventTimeStampFromSeconds(1),
-                                              EventTimeStampFromSeconds(1));
-
-  idle_fraction_recorder.RecordActiveInterval(EventTimeStampFromSeconds(1.1),
-                                              EventTimeStampFromSeconds(2.2));
-
-  idle_fraction_recorder.RecordActiveInterval(EventTimeStampFromSeconds(2.6),
-                                              EventTimeStampFromSeconds(3.2));
-
-  // Flush the previous interval.
-  idle_fraction_recorder.RecordActiveInterval(EventTimeStampFromSeconds(4),
-                                              EventTimeStampFromSeconds(4));
-
-  // The windows contain:
-  // 1: 1.1 - 2.0
-  // 2: 2.0 - 2.2, 2.6 - 3.0
-  // 3: 3.0 - 3.2
-  EXPECT_THAT(tester.GetAllSamples(kHistogram),
-              ElementsAre(Bucket(10, 1), Bucket(40, 1), Bucket(80, 1)));
-}
-
-}  // namespace
-
-}  // namespace ui
diff --git a/ui/gfx/geometry/transform.cc b/ui/gfx/geometry/transform.cc
index eee5af7..ef9e268 100644
--- a/ui/gfx/geometry/transform.cc
+++ b/ui/gfx/geometry/transform.cc
@@ -485,8 +485,23 @@
 }
 
 bool Transform::TransformRRectF(RRectF* rrect) const {
+  // We want this to fail only in cases where our
+  // Transform::Preserves2dAxisAlignment returns false.  However,
+  // SkMatrix::preservesAxisAlignment is stricter (it lacks the kEpsilon
+  // test).  So after converting our skia::Matrix44 to SkMatrix, round
+  // relevant values less than kEpsilon to zero.
+  SkMatrix rounded_matrix(matrix_);
+  if (std::abs(rounded_matrix.get(SkMatrix::kMScaleX)) < kEpsilon)
+    rounded_matrix.set(SkMatrix::kMScaleX, 0.0f);
+  if (std::abs(rounded_matrix.get(SkMatrix::kMSkewX)) < kEpsilon)
+    rounded_matrix.set(SkMatrix::kMSkewX, 0.0f);
+  if (std::abs(rounded_matrix.get(SkMatrix::kMSkewY)) < kEpsilon)
+    rounded_matrix.set(SkMatrix::kMSkewY, 0.0f);
+  if (std::abs(rounded_matrix.get(SkMatrix::kMScaleY)) < kEpsilon)
+    rounded_matrix.set(SkMatrix::kMScaleY, 0.0f);
+
   SkRRect result;
-  if (!SkRRect(*rrect).transform(SkMatrix(matrix_), &result))
+  if (!SkRRect(*rrect).transform(rounded_matrix, &result))
     return false;
   *rrect = gfx::RRectF(result);
   return true;
diff --git a/ui/gfx/geometry/transform_unittest.cc b/ui/gfx/geometry/transform_unittest.cc
index 127c203..fb57d8a 100644
--- a/ui/gfx/geometry/transform_unittest.cc
+++ b/ui/gfx/geometry/transform_unittest.cc
@@ -2645,6 +2645,14 @@
   EXPECT_TRUE(rotation_90_Clock.TransformRRectF(&rrect));
   EXPECT_EQ(expected.ToString(), rrect.ToString());
 
+  Transform rotation_90_unrounded;
+  rotation_90_unrounded.Rotate(90.0);
+  rrect = RRectF(gfx::RectF(0, 0, 20.f, 25.f),
+                 gfx::RoundedCornersF(1.f, 2.f, 3.f, 4.f));
+  EXPECT_TRUE(rotation_90_unrounded.Preserves2dAxisAlignment());
+  EXPECT_TRUE(rotation_90_unrounded.TransformRRectF(&rrect));
+  EXPECT_EQ(expected.ToString(), rrect.ToString());
+
   Transform scale;
   scale.Scale(2.f, 2.f);
   rrect = RRectF(gfx::RectF(0, 0, 20.f, 25.f),
diff --git a/ui/gtk/gtk_ui.cc b/ui/gtk/gtk_ui.cc
index 62b05ec..c8eb5c7 100644
--- a/ui/gtk/gtk_ui.cc
+++ b/ui/gtk/gtk_ui.cc
@@ -933,11 +933,7 @@
   colors_[ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON] = tab_text_color;
   colors_[ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON_HOVERED] = tab_text_color;
   colors_[ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON_PRESSED] = tab_text_color;
-  colors_[ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE] =
-      tab_text_color;
-  colors_[ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE] =
-      tab_text_color;
-  colors_[ThemeProperties::COLOR_BOOKMARK_TEXT] = tab_text_color;
+  colors_[ThemeProperties::COLOR_TOOLBAR_TEXT] = tab_text_color;
 
   colors_[ThemeProperties::COLOR_NTP_LINK] =
       color_provider->GetColor(ui::kColorTextfieldSelectionBackground);
diff --git a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
index 13b89bda..b94fff1 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
@@ -54,6 +54,10 @@
 constexpr uint32_t kDndActionWindowDrag =
     WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
 
+// Value intentionally high to exit the horizontal rail threshold in
+// SnapScrollController, in case of an upwards tab dragging detach with touch.
+constexpr int kHorizontalRailExitThreshold = -1000;
+
 }  // namespace
 
 class WaylandWindowDragController::ExtendedDragSource {
@@ -292,8 +296,28 @@
   // ideally be reworked in the future, at higher level layers such that they
   // properly handle platforms that do not support global screen coordinates,
   // like Wayland.
-  if (state_ == State::kAttached)
+  //
+  // TODO(https://crbug.com/1282186): Find a better solution for upwards tab
+  // detaching.
+  if (state_ != State::kAttached)
+    return;
+
+  if (*drag_source_ == DragSource::kMouse) {
     pointer_delegate_->OnPointerMotionEvent({pointer_location_.x(), -1});
+  } else {
+    base::TimeTicks timestamp = base::TimeTicks::Now();
+    auto touch_pointer_ids = touch_delegate_->GetActiveTouchPointIds();
+    DCHECK_EQ(touch_pointer_ids.size(), 1u);
+
+    // If an user starts dragging a tab horizontally with touch, Chrome enters
+    // in "horizontal snapping" mode (see ScrollSnapController for details).
+    // Hence, in case of touch driven dragging, use a higher negative dy
+    // to work around the threshold in ScrollSnapController otherwise,
+    // the drag event is discarded.
+    touch_delegate_->OnTouchMotionEvent(
+        {pointer_location_.x(), kHorizontalRailExitThreshold}, timestamp,
+        touch_pointer_ids[0]);
+  }
 }
 
 void WaylandWindowDragController::OnDragDrop() {
diff --git a/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
index 0663a84..ecd049c 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
@@ -751,6 +751,48 @@
             screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
 }
 
+// Verifies wl_data_device::leave events are properly handled and propagated
+// while in window dragging "attached" mode.
+TEST_P(WaylandWindowDragControllerTest, DragExitAttached_TOUCH) {
+  // Ensure there is no window currently focused
+  EXPECT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow());
+  EXPECT_EQ(gfx::kNullAcceleratedWidget,
+            screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
+
+  // SendPointerEnter(window_.get(), &delegate_);
+  // SendPointerPress(window_.get(), &delegate_, BTN_LEFT);
+  // SendPointerMotion(window_.get(), &delegate_, {10, 10});
+  SendTouchDown(window_.get(), &delegate_, 0 /*point id*/, {0, 0} /*location*/);
+  SendTouchMotion(window_.get(), &delegate_, 0 /*point id*/,
+                  {10, 10} /*location*/);
+  Sync();
+  EXPECT_EQ(window_->GetWidget(),
+            screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
+
+  auto* wayland_extension = GetWaylandExtension(*window_);
+  wayland_extension->StartWindowDraggingSessionIfNeeded();
+  Sync();
+  EXPECT_EQ(State::kAttached, drag_controller()->state());
+
+  // Emulate a [motion => leave] event sequence and make sure the correct
+  // ui::Events are dispatched in response.
+  SendDndMotion({50, 50});
+  EXPECT_CALL(delegate_, DispatchEvent(_)).Times(1);
+  Sync();
+
+  SendDndLeave();
+  EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce([&](Event* event) {
+    EXPECT_EQ(ET_TOUCH_MOVED, event->type());
+    EXPECT_EQ(gfx::Point(50, -1000).ToString(),
+              event->AsTouchEvent()->location().ToString());
+  });
+  Sync();
+
+  SendDndDrop();
+  EXPECT_CALL(delegate_, DispatchEvent(_)).Times(1);
+  Sync();
+}
+
 TEST_P(WaylandWindowDragControllerTest, RestoreDuringWindowDragSession) {
   const gfx::Rect original_bounds = window_->GetBounds();
   wl::ScopedWlArray states({XDG_TOPLEVEL_STATE_ACTIVATED});
diff --git a/ui/ozone/platform/wayland/test/scoped_wl_array.cc b/ui/ozone/platform/wayland/test/scoped_wl_array.cc
index 9977ca1..64aea2c 100644
--- a/ui/ozone/platform/wayland/test/scoped_wl_array.cc
+++ b/ui/ozone/platform/wayland/test/scoped_wl_array.cc
@@ -35,7 +35,7 @@
 }
 
 void ScopedWlArray::AddStateToWlArray(uint32_t state) {
-  *static_cast<uint32_t*>(wl_array_add(&array_, sizeof array_)) = state;
+  *static_cast<uint32_t*>(wl_array_add(&array_, sizeof(uint32_t))) = state;
 }
 
 }  // namespace wl
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc
index 906a983..2780d3f 100644
--- a/ui/views/controls/combobox/combobox.cc
+++ b/ui/views/controls/combobox/combobox.cc
@@ -363,6 +363,10 @@
   OnPropertyChanged(&selected_index_, kPropertyEffectsPreferredSizeChanged);
 }
 
+bool Combobox::IsMenuRunning() const {
+  return menu_runner_ && menu_runner_->IsRunning();
+}
+
 void Combobox::OnThemeChanged() {
   View::OnThemeChanged();
   SetBackground(
@@ -678,7 +682,7 @@
 
   // Allow |menu_runner_| to be set by the testing API, but if this method is
   // ever invoked recursively, ensure the old menu is closed.
-  if (!menu_runner_ || menu_runner_->IsRunning()) {
+  if (!menu_runner_ || IsMenuRunning()) {
     menu_runner_ = std::make_unique<MenuRunner>(
         menu_model_.get(), MenuRunner::COMBOBOX,
         base::BindRepeating(&Combobox::OnMenuClosed, base::Unretained(this),
diff --git a/ui/views/controls/combobox/combobox.h b/ui/views/controls/combobox/combobox.h
index 32c4cec..29dba45 100644
--- a/ui/views/controls/combobox/combobox.h
+++ b/ui/views/controls/combobox/combobox.h
@@ -104,6 +104,13 @@
   void SetSizeToLargestLabel(bool size_to_largest_label);
   bool GetSizeToLargestLabel() const { return size_to_largest_label_; }
 
+  // Use the time when combobox was closed in order for parent view to not
+  // treat a user event already treated by the combobox.
+  base::TimeTicks GetClosedTime() { return closed_time_; }
+
+  // Returns whether or not the menu is currently running.
+  bool IsMenuRunning() const;
+
   // Overridden from View:
   gfx::Size CalculatePreferredSize() const override;
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;